/* * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 */ #include #include "e_mod_main.h" #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #define MAX_SONG_LENGTH 255 typedef struct _Instance Instance; struct _Instance { E_Gadcon_Client *gcc; Evas_Object *empris; Evas_Object *o_popup; Config_Item *ci; E_Gadcon_Popup *popup; int cur_track; /* E_DBus_Signal_Handler *cb_tracklist_change = NULL; */ E_DBus_Signal_Handler *cb_player_track_change; E_DBus_Signal_Handler *cb_player_status_change; }; /* Func Proto Requirements for Gadcon */ static E_Gadcon_Client *_gc_init (E_Gadcon * gc, const char *name, const char *id, const char *style); static void _gc_shutdown (E_Gadcon_Client * gcc); static void _gc_orient (E_Gadcon_Client * gcc, E_Gadcon_Orient orient); static char *_gc_label (E_Gadcon_Client_Class *client_class); static Evas_Object *_gc_icon (E_Gadcon_Client_Class *client_class, Evas * evas); static const char *_gc_id_new (E_Gadcon_Client_Class *client_class); /* Module Protos */ static void _empris_cb_mouse_down (void *data, Evas * e, Evas_Object * obj, void *event_info); static void _empris_cb_mouse_in (void *data, Evas * e, Evas_Object * obj, void *event_info); static void _empris_cb_mouse_out (void *data, Evas * e, Evas_Object * obj, void *event_info); static void _empris_menu_cb_configure (void *data, E_Menu * m, E_Menu_Item * mi); static void _empris_menu_cb_post (void *data, E_Menu * m); static void _empris_cb_play (void *data, Evas_Object * obj, const char *emission, const char *source); static void _empris_cb_stop (void *data, Evas_Object * obj, const char *emission, const char *source); static void _empris_cb_pause (void *data, Evas_Object * obj, const char *emission, const char *source); static void _empris_cb_next (void *data, Evas_Object * obj, const char *emission, const char *source); static void _empris_cb_previous (void *data, Evas_Object * obj, const char *emission, const char *source); static Config_Item *_empris_config_item_get (const char *id); static void _set_status(Instance *inst, DBusMessage *msg); static void _dbus_cb_tracklist_metadata(void *data, DBusMessage *reply, DBusError *error); static void _dbus_cb_get_status(void *data, DBusMessage *reply, DBusError *error); static void _dbus_cb_track_change(void *data, DBusMessage *msg); static void _dbus_cb_current_track(void *data, DBusMessage *reply, DBusError *error); static void _dbus_cb_list_names(void *data, DBusMessage *msg, DBusError *err); static void _dbus_cb_name_owner_changed(void *data, DBusMessage *msg); static void _dbus_cb_status_change(void *data, DBusMessage *msg); static DBusPendingCall *_dbus_send_msg(const char *path, const char *method, E_DBus_Method_Return_Cb _cb, void *data); static char * _util_unescape(const char *string, int length); static E_Config_DD *conf_edd = NULL; static E_Config_DD *conf_item_edd = NULL; static E_DBus_Connection *conn = NULL; static DBusPendingCall *pending_get_name_owner = NULL; static E_DBus_Signal_Handler *cb_name_owner_changed = NULL; static const char *bus_name = NULL; static const char mpris_interface[] = "org.freedesktop.MediaPlayer"; static const char fdo_bus_name[] = "org.freedesktop.DBus"; static const char fdo_interface[] = "org.freedesktop.DBus"; static const char fdo_path[] = "/org/freedesktop/DBus"; static Eina_List *players = NULL; static Eina_Bool active = EINA_FALSE; Config *empris_config = NULL; /* Define the class and gadcon functions this module provides */ static const E_Gadcon_Client_Class _gc_class = { GADCON_CLIENT_CLASS_VERSION, "empris", {_gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL, e_gadcon_site_is_not_toolbar}, E_GADCON_CLIENT_STYLE_PLAIN }; static void _empris_popup_destroy (Instance * inst); static void _empris_popup_create (Instance * inst, const char *dir); static E_Gadcon_Client * _gc_init (E_Gadcon * gc, const char *name, const char *id, const char *style) { Evas_Object *o; E_Gadcon_Client *gcc; Evas *evas; Instance *inst; char buf[4096]; inst = E_NEW (Instance, 1); inst->ci = _empris_config_item_get (id); if (!inst->ci->id) inst->ci->id = eina_stringshare_add (id); o = edje_object_add (gc->evas); snprintf (buf, sizeof (buf), "%s/empris.edj", e_module_dir_get (empris_config->module)); if (!e_theme_edje_object_set (o, "base/theme/modules/empris", "modules/empris/main")) edje_object_file_set (o, buf, "modules/empris/main"); evas_object_show (o); gcc = e_gadcon_client_new (gc, name, id, style, o); gcc->data = inst; inst->gcc = gcc; inst->empris = o; _empris_popup_create(inst, buf); evas_object_event_callback_add (o, EVAS_CALLBACK_MOUSE_DOWN, _empris_cb_mouse_down, inst); evas_object_event_callback_add (inst->empris, EVAS_CALLBACK_MOUSE_IN, _empris_cb_mouse_in, inst); evas_object_event_callback_add (inst->empris, EVAS_CALLBACK_MOUSE_OUT, _empris_cb_mouse_out, inst); edje_object_signal_callback_add (o, "empris,play", "", _empris_cb_play, inst); edje_object_signal_callback_add (o, "empris,stop", "", _empris_cb_stop, inst); edje_object_signal_callback_add (o, "empris,pause", "", _empris_cb_pause, inst); edje_object_signal_callback_add (o, "empris,next", "", _empris_cb_next, inst); edje_object_signal_callback_add (o, "empris,previous", "", _empris_cb_previous, inst); inst->cb_player_track_change = e_dbus_signal_handler_add (conn, bus_name, "/Player", mpris_interface, "TrackChange", _dbus_cb_track_change, inst); inst->cb_player_status_change = e_dbus_signal_handler_add (conn, bus_name, "/Player", mpris_interface, "StatusChange", _dbus_cb_status_change, inst); _dbus_send_msg("/TrackList", "GetCurrentTrack", _dbus_cb_current_track, inst); empris_config->instances = eina_list_append (empris_config->instances, inst); return gcc; } static void _gc_shutdown (E_Gadcon_Client * gcc) { Instance *inst; inst = gcc->data; if (inst->cb_player_track_change) e_dbus_signal_handler_del(conn, inst->cb_player_track_change); if (inst->cb_player_status_change) e_dbus_signal_handler_del(conn, inst->cb_player_status_change); empris_config->instances = eina_list_remove (empris_config->instances, inst); evas_object_event_callback_del (inst->empris, EVAS_CALLBACK_MOUSE_DOWN, _empris_cb_mouse_down); evas_object_event_callback_del (inst->empris, EVAS_CALLBACK_MOUSE_IN, _empris_cb_mouse_in); evas_object_event_callback_del (inst->empris, EVAS_CALLBACK_MOUSE_OUT, _empris_cb_mouse_out); _empris_popup_destroy (inst); evas_object_del (inst->empris); free (inst); inst = NULL; } static void _gc_orient (E_Gadcon_Client * gcc, E_Gadcon_Orient orient) { Instance *inst; Evas_Coord mw, mh; inst = gcc->data; edje_object_size_min_calc (inst->empris, &mw, &mh); e_gadcon_client_min_size_set (gcc, mw, mh); } static char * _gc_label (E_Gadcon_Client_Class *client_class) { return D_ ("Empris"); } static Evas_Object * _gc_icon (E_Gadcon_Client_Class *client_class, Evas * evas) { Evas_Object *o; char buf[4096]; o = edje_object_add (evas); snprintf (buf, sizeof (buf), "%s/e-module-empris.edj", e_module_dir_get (empris_config->module)); edje_object_file_set (o, buf, "icon"); return o; } static const char * _gc_id_new (E_Gadcon_Client_Class *client_class) { Config_Item *ci; ci = _empris_config_item_get (NULL); return ci->id; } static void _empris_cb_mouse_down (void *data, Evas * e, Evas_Object * obj, void *event_info) { Instance *inst; Evas_Event_Mouse_Down *ev; inst = data; ev = event_info; if ((ev->button == 3) && (!empris_config->menu)) { E_Menu *mn; E_Menu_Item *mi; int x, y, w, h; mn = e_menu_new (); e_menu_post_deactivate_callback_set (mn, _empris_menu_cb_post, inst); empris_config->menu = mn; mi = e_menu_item_new (mn); e_menu_item_label_set (mi, D_ ("Configuration")); e_util_menu_item_theme_icon_set(mi, "preferences-system"); e_menu_item_callback_set (mi, _empris_menu_cb_configure, inst); mi = e_menu_item_new (mn); e_menu_item_separator_set (mi, 1); e_gadcon_client_util_menu_items_append (inst->gcc, mn, 0); e_gadcon_canvas_zone_geometry_get (inst->gcc->gadcon, &x, &y, &w, &h); e_menu_activate_mouse (mn, e_util_zone_current_get (e_manager_current_get ()), x + ev->output.x, y + ev->output.y, 1, 1, E_MENU_POP_DIRECTION_DOWN, ev->timestamp); evas_event_feed_mouse_up (inst->gcc->gadcon->evas, ev->button, EVAS_BUTTON_NONE, ev->timestamp, NULL); } else if (ev->button == 1) { //e_gadcon_popup_toggle_pinned(inst->popup); } } static void _empris_cb_mouse_in (void *data, Evas * e, Evas_Object * obj, void *event_info) { Instance *inst; if ((!(inst = data)) || (!inst->ci->show_popup) || (!inst->popup)) return; e_gadcon_popup_show (inst->popup); } static void _empris_cb_mouse_out (void *data, Evas * e, Evas_Object * obj, void *event_info) { Instance *inst; if ((!(inst = data)) || ((!inst->ci->show_popup) && (inst->popup))) return; e_gadcon_popup_hide (inst->popup); } static void _empris_menu_cb_post (void *data, E_Menu * m) { if (!empris_config->menu) return; e_object_del (E_OBJECT (empris_config->menu)); empris_config->menu = NULL; } static void _empris_menu_cb_configure (void *data, E_Menu * m, E_Menu_Item * mi) { Instance *inst; inst = data; _config_empris_module (inst->ci); } void _empris_config_updated (Config_Item * ci) { Eina_List *l; if (!empris_config) return; for (l = empris_config->instances; l; l = l->next) { Instance *inst; inst = l->data; if (inst->ci != ci) continue; /* TODO choose player */ if (inst->ci->show_popup) { if (!inst->popup) { _empris_popup_create(inst, NULL); } } else { if (inst->popup) { _empris_popup_destroy(inst); } } break; } } static void _empris_cb_play (void *data, Evas_Object * obj, const char *emission, const char *source) { _dbus_send_msg("/Player", "Play", NULL, NULL); } static void _empris_cb_previous (void *data, Evas_Object * obj, const char *emission, const char *source) { _dbus_send_msg("/Player", "Prev", NULL, NULL); } static void _empris_cb_next (void *data, Evas_Object * obj, const char *emission, const char *source) { _dbus_send_msg("/Player", "Next", NULL, NULL); } static void _empris_cb_stop (void *data, Evas_Object * obj, const char *emission, const char *source) { _dbus_send_msg("/Player", "Stop", NULL, NULL); } static void _empris_cb_pause (void *data, Evas_Object * obj, const char *emission, const char *source) { _dbus_send_msg("/Player", "Pause", NULL, NULL); } static Config_Item * _empris_config_item_get (const char *id) { Eina_List *l; Config_Item *ci; char buf[128]; if (!id) { int num = 0; /* Create id */ if (empris_config->items) { const char *p; ci = eina_list_last (empris_config->items)->data; p = strrchr (ci->id, '.'); if (p) num = atoi (p + 1) + 1; } snprintf (buf, sizeof (buf), "%s.%d", _gc_class.name, num); id = buf; } else { for (l = empris_config->items; l; l = l->next) { ci = l->data; if (!ci->id) continue; if (!strcmp (ci->id, id)) return ci; } } ci = E_NEW (Config_Item, 1); ci->id = eina_stringshare_add (id); ci->player = eina_stringshare_add (""); ci->show_popup = 1; empris_config->items = eina_list_append (empris_config->items, ci); return ci; } EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Empris" }; EAPI void * e_modapi_init (E_Module * m) { char buf[4096]; snprintf (buf, sizeof (buf), "%s/locale", e_module_dir_get (m)); bindtextdomain (PACKAGE, buf); bind_textdomain_codeset (PACKAGE, "UTF-8"); conf_item_edd = E_CONFIG_DD_NEW ("Empris_Config_Item", Config_Item); #undef T #undef D #define T Config_Item #define D conf_item_edd E_CONFIG_VAL (D, T, id, STR); E_CONFIG_VAL (D, T, player, STR); E_CONFIG_VAL (D, T, show_popup, UCHAR); conf_edd = E_CONFIG_DD_NEW ("Empris_Config", Config); #undef T #undef D #define T Config #define D conf_edd E_CONFIG_LIST (D, T, items, conf_item_edd); empris_config = e_config_domain_load ("module.empris", conf_edd); if (!empris_config) { Config_Item *ci; empris_config = E_NEW (Config, 1); ci = E_NEW (Config_Item, 1); ci->id = eina_stringshare_add ("0"); ci->player = eina_stringshare_add (""); ci->show_popup = 1; empris_config->items = eina_list_append (empris_config->items, ci); } empris_config->module = m; conn = e_dbus_bus_get(DBUS_BUS_SESSION); if (!conn) return NULL; cb_name_owner_changed = e_dbus_signal_handler_add (conn, fdo_bus_name, fdo_path, fdo_interface, "NameOwnerChanged", _dbus_cb_name_owner_changed, NULL); e_dbus_list_names(conn, _dbus_cb_list_names, NULL); e_gadcon_provider_register (&_gc_class); e_module_delayed_set(m, 1); return m; } EAPI int e_modapi_shutdown (E_Module * m) { char *player; empris_config->module = NULL; e_gadcon_provider_unregister (&_gc_class); if (conn) { if (cb_name_owner_changed) e_dbus_signal_handler_del(conn, cb_name_owner_changed); e_dbus_connection_close(conn); } EINA_LIST_FREE(players, player) eina_stringshare_del(player); if (empris_config->config_dialog) e_object_del (E_OBJECT (empris_config->config_dialog)); if (empris_config->menu) { e_menu_post_deactivate_callback_set (empris_config->menu, NULL, NULL); e_object_del (E_OBJECT (empris_config->menu)); empris_config->menu = NULL; } while (empris_config->items) { Config_Item *ci; ci = empris_config->items->data; empris_config->items = eina_list_remove_list (empris_config->items, empris_config->items); if (ci->id) eina_stringshare_del (ci->id); free (ci); ci = NULL; } free (empris_config); empris_config = NULL; E_CONFIG_DD_FREE (conf_item_edd); E_CONFIG_DD_FREE (conf_edd); return 1; } EAPI int e_modapi_save (E_Module * m) { e_config_domain_save ("module.empris", conf_edd, empris_config); return 1; } static void _empris_popup_destroy (Instance * inst) { if (inst->popup) e_object_del (E_OBJECT (inst->popup)); inst->popup = NULL; if (inst->o_popup) evas_object_del(inst->o_popup); inst->o_popup = NULL; } static void _empris_popup_create (Instance * inst, const char *dir) { Evas *evas; Evas_Object *o_popup; char buf[4096]; if (inst->ci->show_popup) { inst->popup = e_gadcon_popup_new (inst->gcc); evas = inst->popup->win->evas; o_popup = edje_object_add (evas); if (!e_theme_edje_object_set (o_popup, "base/theme/modules/empris", "modules/empris/popup")) { if (dir) { edje_object_file_set (o_popup, dir, "modules/empris/popup"); } else { snprintf(buf, sizeof(buf), "%s/empris.edj", e_module_dir_get(empris_config->module)); edje_object_file_set(o_popup, buf, "modules/empris/popup"); } } evas_object_show (o_popup); e_gadcon_popup_content_set (inst->popup, o_popup); edje_object_size_min_calc (o_popup, NULL, NULL); inst->o_popup = o_popup; edje_object_signal_callback_add (o_popup, "empris,play", "", _empris_cb_play, inst); edje_object_signal_callback_add (o_popup, "empris,stop", "", _empris_cb_stop, inst); edje_object_signal_callback_add (o_popup, "empris,pause", "", _empris_cb_pause, inst); edje_object_signal_callback_add (o_popup, "empris,next", "", _empris_cb_next, inst); edje_object_signal_callback_add (o_popup, "empris,previous", "", _empris_cb_previous, inst); } else { inst->popup = NULL; inst->o_popup = NULL; } } static int _dbus_check_msg(DBusMessage *reply, DBusError *error) { if (error && dbus_error_is_set(error)) { printf("Error: %s - %s\n", error->name, error->message); return 0; } return (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN); } static DBusPendingCall * _dbus_send_msg(const char *path, const char *method, E_DBus_Method_Return_Cb _cb, void *data) { DBusMessage *msg; DBusPendingCall *pnd; if (!active) return NULL; msg = dbus_message_new_method_call(bus_name, path, mpris_interface, method); pnd = e_dbus_message_send(conn, msg, _cb, -1, data); dbus_message_unref(msg); return pnd; } static DBusPendingCall * _dbus_send_msg_int(const char *path, const char *method, E_DBus_Method_Return_Cb _cb, void *data, int num) { DBusMessage *msg; DBusPendingCall *pnd; if (!active) return NULL; msg = dbus_message_new_method_call(bus_name, path, mpris_interface, method); dbus_message_append_args(msg, DBUS_TYPE_INT32, &num, DBUS_TYPE_INVALID); pnd = e_dbus_message_send(conn, msg, _cb, -1, data); dbus_message_unref(msg); return pnd; } static void _dbus_cb_current_track(void *data, DBusMessage *reply, DBusError *error) { Instance *inst = data; DBusMessage *msg; int num; if (!_dbus_check_msg(reply, error)) return; dbus_message_get_args(reply, error, DBUS_TYPE_INT32, (dbus_int32_t*) &(num), DBUS_TYPE_INVALID); /* XXX inst->pnd*/ _dbus_send_msg_int("/TrackList", "GetMetadata", _dbus_cb_tracklist_metadata, inst, num); } static void _dbus_cb_status_change(void *data, DBusMessage *msg) { DBusMessageIter iter, array; dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRUCT) { _set_status(data, msg); } else if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) { /* XXX audacious.. */ _dbus_send_msg("/Player", "GetStatus", _dbus_cb_get_status, data); } _dbus_send_msg("/TrackList", "GetCurrentTrack", _dbus_cb_current_track, data); } static void _dbus_cb_track_change(void *data, DBusMessage *msg) { _dbus_cb_tracklist_metadata(data, msg, NULL); } static void _dbus_cb_tracklist_metadata(void *data, DBusMessage *reply, DBusError *error) { DBusMessageIter array, item, iter, iter_val; Instance *inst = data; int type, cnt = 0; char *key, *tmp, *location = NULL; int title = 0; Evas_Object *empris = inst->empris; Evas_Object *o_popup = inst->o_popup; if (error) { if (!_dbus_check_msg(reply, error)) { printf("dbus garbage!\n"); goto error; } } edje_object_part_text_set (empris, "empris.artist", ""); edje_object_part_text_set (o_popup, "empris.artist", ""); edje_object_part_text_set (empris, "empris.title", ""); edje_object_part_text_set (o_popup, "empris.title", ""); edje_object_part_text_set (empris, "empris.album", ""); edje_object_part_text_set (o_popup, "empris.album", ""); dbus_message_iter_init(reply, &array); if(dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_ARRAY) { dbus_message_iter_recurse(&array, &item); while(dbus_message_iter_get_arg_type(&item) == DBUS_TYPE_DICT_ENTRY) { dbus_message_iter_recurse(&item, &iter); if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) { dbus_message_iter_get_basic(&iter, &key); } else { printf("not string{n"); goto error; } dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { printf("not variant\n"); goto error; } if (!strcmp(key, "artist")) { dbus_message_iter_recurse (&iter, &iter_val); dbus_message_iter_get_basic (&iter_val, &tmp); if (tmp && tmp[0]) { edje_object_part_text_set (empris, "empris.artist", tmp); edje_object_part_text_set (o_popup, "empris.artist", tmp); } } else if (!strcmp(key, "title")) { dbus_message_iter_recurse (&iter, &iter_val); dbus_message_iter_get_basic (&iter_val, &tmp); if (tmp && tmp[0]) { edje_object_part_text_set (empris, "empris.title", tmp); edje_object_part_text_set (o_popup, "empris.title", tmp); title = 1; } } else if (!strcmp(key, "location")) { dbus_message_iter_recurse (&iter, &iter_val); dbus_message_iter_get_basic (&iter_val, &tmp); if (tmp && tmp[0]) { location = strdup(tmp); } } else if (!strcmp(key, "album")) { dbus_message_iter_recurse (&iter, &iter_val); dbus_message_iter_get_basic (&iter_val, &tmp); if (tmp && tmp[0]) { edje_object_part_text_set (empris, "empris.album", tmp); edje_object_part_text_set (o_popup, "empris.album", tmp); } } /* else if (!strcmp(key, "mtime")) * { * dbus_message_iter_recurse (&iter, &iter_val); * dbus_message_iter_get_basic (&iter_val, &(t->length)); * } */ dbus_message_iter_next(&item); } } if (!title && location) { char *tmp = _util_unescape(ecore_file_file_get(location), 0); if (tmp) { edje_object_part_text_set (empris, "empris.title", tmp); edje_object_part_text_set (o_popup, "empris.title", tmp); free(tmp); } free(location); } error: return; } static void _set_status(Instance *inst, DBusMessage *msg) { DBusMessageIter iter, array; int status; dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRUCT) { edje_object_part_text_set (inst->empris, "empris.status", D_ ("Unknown")); edje_object_part_text_set (inst->o_popup, "empris.status", D_ ("Unknown")); printf("no dbus struct\n"); return; } dbus_message_iter_recurse(&iter, &array); dbus_message_iter_get_basic(&array, &status); /* dbus_message_iter_next(&array); */ /* dbus_message_iter_get_basic(&array, &(p->status.random)); * dbus_message_iter_next(&array); * dbus_message_iter_get_basic(&array, &(p->status.repeat)); * dbus_message_iter_next(&array); * dbus_message_iter_get_basic(&array, &(p->status.loop)); * DBG("status %d", p->status.playing); */ if (status == 0) { edje_object_part_text_set (inst->empris, "empris.status", D_ ("Stopped")); edje_object_part_text_set (inst->o_popup, "empris.status", D_ ("Stopped")); } else if (status == 2) { edje_object_part_text_set (inst->empris, "empris.status", D_ ("Playing")); edje_object_part_text_set (inst->o_popup, "empris.status", D_ ("Playing")); } else if (status == 1) { edje_object_part_text_set (inst->empris, "empris.status", D_ ("Paused")); edje_object_part_text_set (inst->o_popup, "empris.status", D_ ("Paused")); } else { edje_object_part_text_set (inst->empris, "empris.status", D_ ("Unknown")); edje_object_part_text_set (inst->o_popup, "empris.status", D_ ("Unknown")); } } static void _dbus_cb_get_status(void *data, DBusMessage *reply, DBusError *error) { if (!_dbus_check_msg(reply, error)) return; _set_status(data, reply); } static void _dbus_cb_name_owner_changed(void *data, DBusMessage *msg) { DBusError err; Eina_List *l; const char *tmp; const char *name, *from, *to; if (!conn) return; dbus_error_init(&err); if (!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &from, DBUS_TYPE_STRING, &to, DBUS_TYPE_INVALID)) { printf("could not get NameOwnerChanged arguments: %s: %s\n", err.name, err.message); dbus_error_free(&err); return; } if (strncmp(name, "org.mpris.", 10) != 0) return; printf("NameOwnerChanged from=[%s] to=[%s]\n", from, to); tmp = eina_stringshare_add(name); if (to[0] == '\0') { players = eina_list_remove(players, tmp); /* vanished player was current? */ if (tmp == bus_name) { /* make another player current */ if (eina_list_count(players) > 0) { bus_name = players->data; printf("use::%s", bus_name); active = EINA_TRUE; } else { active = EINA_FALSE; } } eina_stringshare_del(tmp); } else { /* new player appeared? */ if (!eina_list_data_find(players, tmp)) { eina_stringshare_ref(tmp); players = eina_list_append(players, tmp); } /* no active player - make player current */ if (!active) { bus_name = tmp; active = EINA_TRUE; } } eina_stringshare_del(tmp); } static void _dbus_cb_list_names(void *data, DBusMessage *msg, DBusError *err) { DBusMessageIter array, iter, item, iter_val; char *name; if (!_dbus_check_msg(msg, err)) return; dbus_message_iter_init(msg, &array); if(dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_ARRAY) { dbus_message_iter_recurse(&array, &item); while(dbus_message_iter_get_arg_type(&item) == DBUS_TYPE_STRING) { dbus_message_iter_get_basic(&item, &name); if (strncmp(name, "org.mpris.", 10) == 0) { printf("found %s", name); players = eina_list_append(players, eina_stringshare_add(name)); } dbus_message_iter_next(&item); } } if (eina_list_count(players) > 0) { bus_name = players->data; printf("use::%s", bus_name); active = EINA_TRUE; } } /* taken from curl: * * Copyright (C) 1998 - 2010, Daniel Stenberg, , et * al. * * Unescapes the given URL escaped string of given length. Returns a * pointer to a malloced string with length given in *olen. * If length == 0, the length is assumed to be strlen(string). * If olen == NULL, no output length is stored. */ #define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x))) static char * _util_unescape(const char *string, int length) { int alloc = (length?length:(int)strlen(string))+1; char *ns = malloc(alloc); unsigned char in; int strindex=0; unsigned long hex; if( !ns ) return NULL; while(--alloc > 0) { in = *string; if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { /* this is two hexadecimal digits following a '%' */ char hexstr[3]; char *ptr; hexstr[0] = string[1]; hexstr[1] = string[2]; hexstr[2] = 0; hex = strtoul(hexstr, &ptr, 16); in = (unsigned char)(hex & (unsigned long) 0xFF); // in = ultouc(hex); /* this long is never bigger than 255 anyway */ string+=2; alloc-=2; } ns[strindex++] = in; string++; } ns[strindex]=0; /* terminate it */ return ns; } #undef ISXDIGIT