#include "private.h" #include #ifndef ENGINE /* todo: move to preferences */ #define ENGINE "xine" #endif #define MSG_VOLUME 1 #define MSG_POSITION 2 #define MSG_RATING 3 typedef struct Win { Evas_Object *win; Evas_Object *layout; Evas_Object *edje; Evas_Object *emotion; Evas_Object *list; const char *db_path; DB *db; Song *song; struct { double position, length; double volume; Eina_Bool playing:1; } play; struct { Evas_Coord w, h; } min; struct { Eina_List *add, *del; } scan; struct { Ecore_Job *scan; Ecore_Job *populate; } job; struct { Ecore_Thread *scan; } thread; } Win; static Win _win; static void _win_populate_job(void *data) { Win *w = data; w->job.populate = NULL; if (w->db) db_close(w->db); w->db = db_open(w->db_path); if (!w->db) { CRITICAL("no database at %s!", w->db_path); // TODO: remove me! create library manager and start it from here printf("SCAN and LIBRARY MANAGER are not implemeted yet!\n" "Meanwhile please run " "(./test = binary from lightmediascanner/src/bin):\n" " ./test -p id3 -i 5000 -s %s/Music %s\n" "sorry about the inconvenience!\n", getenv("HOME"), w->db_path); exit(-1); } list_populate(w->list, w->db); } static void _win_scan_job(void *data) { Win *w = data; w->job.scan = NULL; DBG("TODO"); printf("SCAN IS NOT IMPLEMENTED!\n" "Meanwhile please run " "(./test = binary from lightmediascanner/src/bin):\n"); Eina_List *l; const char *path; EINA_LIST_FOREACH(w->scan.add, l, path) printf(" ./test -p id3 -i 5000 -s %s %s\n", path, w->db_path); EINA_LIST_FOREACH(w->scan.del, l, path) printf(" sqlite3 %s \"delete from files where path like '%s%%'\"\n", w->db_path, path); // notify win (should stop lists from updating) // create lms // w->thread.scan = ecore_thread_...: create thread // emit delete as sqlite statements // start lms process + check from thread // finish thread -> unmark it from Win // notify win (should reload lists) if (!w->job.populate) w->job.populate = ecore_job_add(_win_populate_job, w); } static void _win_toolbar_eval(Win *w) { printf("eval toolbar: prev=%hhu, next=%hhu\n", list_prev_exists(w->list), list_next_exists(w->list)); if (list_prev_exists(w->list)) edje_object_signal_emit(w->edje, "ejy,prev,enable", "ejy"); else edje_object_signal_emit(w->edje, "ejy,prev,disable", "ejy"); if (list_next_exists(w->list)) edje_object_signal_emit(w->edje, "ejy,next,enable", "ejy"); else edje_object_signal_emit(w->edje, "ejy,next,disable", "ejy"); if (w->song) { edje_object_signal_emit(w->edje, "ejy,action,play,enable", "ejy"); edje_object_signal_emit(w->edje, "ejy,action,pause,enable", "ejy"); edje_object_signal_emit(w->edje, "ejy,mode,list,enable", "ejy"); edje_object_signal_emit(w->edje, "ejy,mode,nowplaying,enable", "ejy"); } else { edje_object_signal_emit(w->edje, "ejy,action,play,disable", "ejy"); edje_object_signal_emit(w->edje, "ejy,action,pause,disable", "ejy"); edje_object_signal_emit(w->edje, "ejy,mode,list,disable", "ejy"); edje_object_signal_emit(w->edje, "ejy,mode,nowplaying,disable", "ejy"); } } static void _win_play_eval(Win *w) { Edje_Message_Float_Set *mf; mf = alloca(sizeof(Edje_Message_Float_Set) + sizeof(double)); mf->count = 2; mf->val[0] = w->play.position; mf->val[1] = w->play.length; edje_object_message_send(w->edje, EDJE_MESSAGE_FLOAT_SET, MSG_POSITION, mf); if (w->play.playing) { edje_object_signal_emit(w->edje, "ejy,action,play,hide", "ejy"); edje_object_signal_emit(w->edje, "ejy,action,pause,show", "ejy"); } else { edje_object_signal_emit(w->edje, "ejy,action,pause,hide", "ejy"); edje_object_signal_emit(w->edje, "ejy,action,play,show", "ejy"); } } static void _win_song_set(Win *w, Song *s) { Edje_Message_Int mi; char str[32]; w->play.position = 0.0; w->play.length = 0.0; w->song = s; if (!s) goto end; if (s->trackno > 0) snprintf(str, sizeof(str), "%d", s->trackno); else str[0] = '\0'; edje_object_part_text_set(w->edje, "ejy.text.trackno", str); edje_object_part_text_set(w->edje, "ejy.text.title", s->title); edje_object_part_text_set(w->edje, "ejy.text.album", s->album); edje_object_part_text_set(w->edje, "ejy.text.artist", s->artist); edje_object_part_text_set(w->edje, "ejy.text.genre", s->genre); mi.val = s->rating; edje_object_message_send(w->edje, EDJE_MESSAGE_INT, MSG_RATING, &mi); emotion_object_file_set(w->emotion, s->path); // TODO: emotion_object_audio_volume_set(w->emotion, w->play.volume); w->play.playing = EINA_TRUE; emotion_object_play_set(w->emotion, EINA_TRUE); end: _win_play_eval(w); _win_toolbar_eval(w); } static void _win_play_pos_update(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) { Win *w = data; _win_play_eval(w); } static void _win_play_end(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) { Win *w = data; Song *s = list_next_go(w->list); _win_song_set(w, s); } static void _win_list_selected(void *data, Evas_Object *list __UNUSED__, void *event_info) { Win *w = data; Song *s = event_info; _win_song_set(w, s); } static void _win_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) { Win *w = data; if (w->emotion) evas_object_del(w->emotion); if (w->job.scan) ecore_job_del(w->job.scan); if (w->job.populate) ecore_job_del(w->job.populate); if (w->thread.scan) ecore_thread_cancel(w->thread.scan); if (w->db_path) eina_stringshare_del(w->db_path); } static void _win_prev(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { Win *w = data; Song *s = list_prev_go(w->list); INF("prev song=%p (%s)", s, s ? s->path : NULL); if (s) _win_song_set(w, s); } static void _win_next(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { Win *w = data; Song *s = list_next_go(w->list); INF("next song=%p (%s)", s, s ? s->path : NULL); if (s) _win_song_set(w, s); } static void _win_action_play(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { Win *w = data; INF("play song=%p (%s)", w->song, w->song ? w->song->path : NULL); w->play.playing = EINA_TRUE; emotion_object_play_set(w->emotion, EINA_TRUE); _win_play_eval(w); } static void _win_action_pause(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { Win *w = data; INF("pause song=%p (%s)", w->song, w->song ? w->song->path : NULL); w->play.playing = EINA_FALSE; emotion_object_play_set(w->emotion, EINA_FALSE); _win_play_eval(w); } static void _win_mode_list(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { Win *w = data; edje_object_signal_emit(w->edje, "ejy,mode,list,hide", "ejy"); edje_object_signal_emit(w->edje, "ejy,mode,nowplaying,show", "ejy"); } static void _win_mode_nowplaying(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { Win *w = data; edje_object_signal_emit(w->edje, "ejy,mode,nowplaying,hide", "ejy"); edje_object_signal_emit(w->edje, "ejy,mode,list,show", "ejy"); } static void _win_more(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { Win *w = data; DBG("todo"); } //#define EDJE_SIGNAL_DEBUG 1 #ifdef EDJE_SIGNAL_DEBUG static void _edje_signal_debug(void *data __UNUSED__, Evas_Object *o __UNUSED__, const char *emission, const char *source) { DBG("emission=%s, source=%s", emission, source); } #endif static void _win_edje_msg(void *data, Evas_Object *o __UNUSED__, Edje_Message_Type type, int id, void *msg) { Win *w = data; switch (id) { case MSG_VOLUME: if (type != EDJE_MESSAGE_FLOAT) ERR("message for volume got type %d instead of %d", type, EDJE_MESSAGE_FLOAT); else { Edje_Message_Float *m = msg; w->play.volume = m->val; emotion_object_audio_volume_set(w->emotion, w->play.volume); } break; case MSG_POSITION: if (type != EDJE_MESSAGE_FLOAT) ERR("message for position/seek got type %d instead of %d", type, EDJE_MESSAGE_FLOAT); else { Edje_Message_Float *m = msg; w->play.position = m->val; emotion_object_position_set(w->emotion, w->play.position); } break; case MSG_RATING: if (type != EDJE_MESSAGE_INT) ERR("message for rating got type %d instead of %d", type, EDJE_MESSAGE_INT); else { Edje_Message_Int *m = msg; if (!w->song) ERR("setting rating without song?"); else db_song_rating_set(w->db, w->song, m->val); } break; default: ERR("unknown edje message id: %d of type: %d", id, type); } } Evas_Object * win_new(App *app) { Win *w = &_win; const char *s; Evas_Coord iw = 320, ih = 240; char path[PATH_MAX]; memset(w, 0, sizeof(*w)); w->win = elm_win_add(NULL, PACKAGE_NAME, ELM_WIN_BASIC); if (!w->win) return NULL; evas_object_data_set(w->win, "_enjoy", &w); evas_object_event_callback_add(w->win, EVAS_CALLBACK_DEL, _win_del, w); elm_win_autodel_set(w->win, 1); // TODO elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); snprintf(path, sizeof(path), "%s/media.db", app->configdir); w->db_path = eina_stringshare_add(path); w->emotion = emotion_object_add(evas_object_evas_get(w->win)); if (!emotion_object_init(w->emotion, ENGINE)) { CRITICAL("cannot create emotion engine %s", ENGINE); goto error; } emotion_object_video_mute_set(w->emotion, EINA_TRUE); evas_object_show(w->emotion); // req? evas_object_resize(w->emotion, 10, 10); // req? evas_object_smart_callback_add (w->emotion, "position_update", _win_play_pos_update, w); evas_object_smart_callback_add (w->emotion, "length_change", _win_play_pos_update, w); evas_object_smart_callback_add (w->emotion, "decode_stop", _win_play_end, w); w->layout = elm_layout_add(w->win); if (!w->layout) goto error; evas_object_size_hint_weight_set (w->layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set (w->layout, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_win_resize_object_add(w->win, w->layout); if (!elm_layout_file_set(w->layout, PACKAGE_DATA_DIR "/default.edj", "win")) { CRITICAL("no theme for 'win' at %s", PACKAGE_DATA_DIR "/default.edj"); goto error; } w->list = list_add(w->layout); if (!w->list) { CRITICAL("cannot create list"); goto error; } elm_layout_content_set(w->layout, "ejy.swallow.list", w->list); evas_object_smart_callback_add(w->list, "selected", _win_list_selected, w); w->edje = elm_layout_edje_get(w->layout); edje_object_size_min_get(w->edje, &(w->min.w), &(w->min.h)); edje_object_size_min_restricted_calc (w->edje, &(w->min.w), &(w->min.h), w->min.w, w->min.h); s = edje_object_data_get(w->edje, "initial_size"); if (!s) WRN("no initial size specified."); else { if (sscanf(s, "%d %d", &iw, &ih) != 2) { ERR("invalid initial_size format %s.", s); iw = 320; ih = 240; } } s = edje_object_data_get(w->edje, "alpha"); if (s) elm_win_alpha_set(w->win, !!atoi(s)); s = edje_object_data_get(w->edje, "borderless"); if (s) elm_win_borderless_set(w->win, !!atoi(s)); #ifdef EDJE_SIGNAL_DEBUG edje_object_signal_callback_add(w->edje, "*", "*", _edje_signal_debug, w); #endif edje_object_signal_callback_add (w->edje, "ejy,prev,clicked", "ejy", _win_prev, w); edje_object_signal_callback_add (w->edje, "ejy,next,clicked", "ejy", _win_next, w); edje_object_signal_callback_add (w->edje, "ejy,action,play,clicked", "ejy", _win_action_play, w); edje_object_signal_callback_add (w->edje, "ejy,action,pause,clicked", "ejy", _win_action_pause, w); edje_object_signal_callback_add (w->edje, "ejy,mode,list,clicked", "ejy", _win_mode_list, w); edje_object_signal_callback_add (w->edje, "ejy,mode,nowplaying,clicked", "ejy", _win_mode_nowplaying, w); edje_object_signal_callback_add (w->edje, "ejy,more,clicked", "ejy", _win_more, w); edje_object_message_handler_set(w->edje, _win_edje_msg, w); edje_object_signal_emit(w->edje, "ejy,prev,disable", "ejy"); edje_object_signal_emit(w->edje, "ejy,next,disable", "ejy"); edje_object_signal_emit(w->edje, "ejy,action,pause,hide", "ejy"); edje_object_signal_emit(w->edje, "ejy,action,play,show", "ejy"); edje_object_signal_emit(w->edje, "ejy,action,play,disable", "ejy"); edje_object_signal_emit(w->edje, "ejy,mode,nowplaying,show", "ejy"); edje_object_signal_emit(w->edje, "ejy,mode,list,show", "ejy"); edje_object_signal_emit(w->edje, "ejy,mode,list,disable", "ejy"); edje_object_signal_emit(w->edje, "ejy,more,disable", "ejy"); evas_object_show(w->layout); printf("initial size: %dx%d\n", iw, ih); evas_object_resize(w->win, iw, ih); evas_object_size_hint_min_set(w->win, w->min.w, w->min.h); elm_win_title_set(w->win, PACKAGE_STRING); evas_object_show(w->win); if ((app->add_dirs) || (app->del_dirs)) { w->scan.add = app->add_dirs; w->scan.del = app->del_dirs; w->job.scan = ecore_job_add(_win_scan_job, w); } else w->job.populate = ecore_job_add(_win_populate_job, w); return w->win; error: evas_object_del(w->win); /* should delete everything */ return NULL; }