885 lines
24 KiB
C
885 lines
24 KiB
C
#include "private.h"
|
|
#include "mpris.h"
|
|
#include <Emotion.h>
|
|
|
|
typedef struct Win
|
|
{
|
|
Evas_Object *win;
|
|
Evas_Object *layout;
|
|
Evas_Object *edje;
|
|
Evas_Object *emotion;
|
|
Evas_Object *list;
|
|
Evas_Object *nowplaying;
|
|
const char *db_path;
|
|
DB *db;
|
|
Libmgr *mgr;
|
|
Song *song;
|
|
struct {
|
|
double position, length;
|
|
double volume;
|
|
Eina_Bool mute:1;
|
|
Eina_Bool playing:1;
|
|
Eina_Bool playing_last:1;
|
|
Eina_Bool repeat:1;
|
|
Eina_Bool shuffle:1;
|
|
} play;
|
|
struct {
|
|
Evas_Coord w, h;
|
|
} min;
|
|
struct {
|
|
Eina_List *add, *del;
|
|
} scan;
|
|
struct {
|
|
Ecore_Timer *play_eval;
|
|
} timer;
|
|
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;
|
|
|
|
/*
|
|
* Efreet is initialized here so it doesn't take longer to open the window.
|
|
*/
|
|
efreet_mime_init();
|
|
|
|
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_finished(void *data, Eina_Bool success __UNUSED__)
|
|
{
|
|
Win *w = data;
|
|
list_thaw(w->list);
|
|
w->job.populate = ecore_job_add(_win_populate_job, w);
|
|
}
|
|
|
|
static void
|
|
_win_scan_job(void *data)
|
|
{
|
|
Win *w = data;
|
|
w->job.scan = NULL;
|
|
|
|
Eina_List *l;
|
|
const char *path;
|
|
EINA_LIST_FOREACH(w->scan.add, l, path)
|
|
libmgr_scanpath_add(w->mgr, path);
|
|
EINA_LIST_FOREACH(w->scan.del, l, path)
|
|
printf(" sqlite3 %s \"delete from files where path like '%s%%'\"\n",
|
|
w->db_path, path);
|
|
|
|
if (w->job.populate)
|
|
{
|
|
ecore_job_del(w->job.populate);
|
|
w->job.populate = NULL;
|
|
}
|
|
list_freeze(w->list);
|
|
|
|
libmgr_scan_start(w->mgr, _win_scan_job_finished, w);
|
|
|
|
// TODO
|
|
// emit delete as sqlite statements
|
|
// 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)
|
|
{
|
|
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 ((w->play.shuffle) || (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");
|
|
}
|
|
|
|
mpris_signal_player_caps_change(enjoy_caps_get());
|
|
}
|
|
|
|
static void
|
|
_win_play_pause_toggle(Win *w)
|
|
{
|
|
int playback, shuffle, repeat, endless;
|
|
enjoy_status_get(&playback, &shuffle, &repeat, &endless);
|
|
mpris_signal_player_status_change(playback, shuffle, repeat, endless);
|
|
mpris_signal_player_caps_change(enjoy_caps_get());
|
|
|
|
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_play_eval(Win *w)
|
|
{
|
|
Edje_Message_Float_Set *mf;
|
|
|
|
w->play.position = emotion_object_position_get(w->emotion);
|
|
w->play.length = emotion_object_play_length_get(w->emotion);
|
|
|
|
if ((w->song) && (w->song->length != (int)w->play.length))
|
|
{
|
|
db_song_length_set(w->db, w->song, w->play.length);
|
|
// why do this? item doesnt have any new fields in the item.
|
|
// list_song_updated(w->list);
|
|
}
|
|
|
|
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(elm_layout_edje_get(w->nowplaying), EDJE_MESSAGE_FLOAT_SET, MSG_POSITION, mf);
|
|
|
|
if (w->play.playing_last == w->play.playing) return;
|
|
w->play.playing_last = !w->play.playing;
|
|
_win_play_pause_toggle(w);
|
|
|
|
mpris_signal_player_caps_change(enjoy_caps_get());
|
|
}
|
|
|
|
static Eina_Bool
|
|
_win_play_eval_timer(void *data)
|
|
{
|
|
_win_play_eval(data);
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
_win_nowplaying_update(Win *w)
|
|
{
|
|
Evas_Object *cover;
|
|
int label_size;
|
|
char *artist_title;
|
|
const char *s1, *s2;
|
|
cover = cover_album_fetch_by_id(w->win, w->db,w->song->album_id, 480); // TODO: size!
|
|
elm_layout_content_set(w->nowplaying, "ejy.swallow.cover", cover);
|
|
|
|
db_song_artist_fetch(w->db, w->song);
|
|
s1 = w->song->title;
|
|
s2 = w->song->artist;
|
|
if (!s1) s1 = "";
|
|
if (!s2) s2 = "";
|
|
label_size = strlen(s1) + strlen(s2) + 4;
|
|
artist_title = malloc(label_size);
|
|
if (!artist_title)
|
|
return;
|
|
|
|
if (snprintf(artist_title, label_size, "%s - %s", s1, s2) >= label_size)
|
|
{
|
|
CRITICAL("could not set nowplaying title");
|
|
goto nowplaying_error;
|
|
}
|
|
edje_object_part_text_set(elm_layout_edje_get(w->nowplaying), "ejy.text.title", eina_stringshare_add(artist_title));
|
|
|
|
nowplaying_error:
|
|
free(artist_title);
|
|
}
|
|
|
|
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(elm_layout_edje_get(w->nowplaying), EDJE_MESSAGE_INT, MSG_RATING, &mi);
|
|
|
|
emotion_object_file_set(w->emotion, s->path);
|
|
emotion_object_position_set(w->emotion, w->play.position);
|
|
w->play.playing = EINA_TRUE;
|
|
w->play.playing_last = EINA_FALSE;
|
|
emotion_object_play_set(w->emotion, EINA_TRUE);
|
|
emotion_object_audio_volume_set(w->emotion, w->play.volume);
|
|
|
|
end:
|
|
if ((!w->play.playing) && (w->timer.play_eval))
|
|
{
|
|
ecore_timer_del(w->timer.play_eval);
|
|
w->timer.play_eval = NULL;
|
|
}
|
|
else if ((w->play.playing) && (!w->timer.play_eval))
|
|
w->timer.play_eval = ecore_timer_loop_add
|
|
(0.1, _win_play_eval_timer, w);
|
|
|
|
_win_nowplaying_update(w);
|
|
_win_play_eval(w);
|
|
_win_toolbar_eval(w);
|
|
|
|
mpris_signal_player_caps_change(enjoy_caps_get());
|
|
mpris_signal_player_track_change(s);
|
|
}
|
|
|
|
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_begin(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
|
|
{
|
|
Win *w = data;
|
|
_win_play_eval(w);
|
|
}
|
|
|
|
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_list_changed(void *data, Evas_Object *list __UNUSED__, void *event_info __UNUSED__)
|
|
{
|
|
Win *w = data;
|
|
_win_song_set(w, list_selected_get(w->list));
|
|
if (list_songs_exists(w->list))
|
|
edje_object_signal_emit(w->edje, "ejy,songs,show", "ejy");
|
|
else
|
|
edje_object_signal_emit(w->edje, "ejy,songs,hide", "ejy");
|
|
}
|
|
|
|
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->timer.play_eval) ecore_timer_del(w->timer.play_eval);
|
|
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;
|
|
if (w->play.shuffle)
|
|
s = list_random_go(w->list);
|
|
else
|
|
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_play_end(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
|
|
{
|
|
Win *w = data;
|
|
Song *s;
|
|
|
|
if (w->play.repeat)
|
|
{
|
|
s = w->song;
|
|
_win_song_set(w, s);
|
|
}
|
|
else
|
|
_win_next(data, NULL, NULL, NULL);
|
|
}
|
|
|
|
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_pause_toggle(w);
|
|
_win_play_eval(w);
|
|
|
|
mpris_signal_player_caps_change(enjoy_caps_get());
|
|
}
|
|
|
|
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_pause_toggle(w);
|
|
_win_play_eval(w);
|
|
|
|
mpris_signal_player_caps_change(enjoy_caps_get());
|
|
}
|
|
|
|
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");
|
|
edje_object_signal_emit(w->edje, "ejy,screen,nowplaying,hide", "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");
|
|
edje_object_signal_emit(w->edje, "ejy,screen,nowplaying,show", "ejy");
|
|
}
|
|
|
|
static void
|
|
_win_more(void *data __UNUSED__, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
|
|
{
|
|
//Win *w = data;
|
|
DBG("todo");
|
|
}
|
|
|
|
static void
|
|
_win_songs(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
|
|
{
|
|
Win *w = data;
|
|
if (!list_songs_show(w->list)) return;
|
|
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_repeat_on(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
|
|
{
|
|
Win *w = data;
|
|
w->play.repeat = EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
_win_repeat_off(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
|
|
{
|
|
Win *w = data;
|
|
w->play.repeat = EINA_FALSE;
|
|
}
|
|
|
|
static void
|
|
_win_shuffle_on(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
|
|
{
|
|
Win *w = data;
|
|
w->play.shuffle = EINA_TRUE;
|
|
_win_toolbar_eval(w);
|
|
}
|
|
|
|
static void
|
|
_win_shuffle_off(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
|
|
{
|
|
Win *w = data;
|
|
w->play.shuffle = EINA_FALSE;
|
|
_win_toolbar_eval(w);
|
|
}
|
|
|
|
//#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);
|
|
w->play.mute = EINA_FALSE;
|
|
emotion_object_audio_mute_set(w->emotion, w->play.mute);
|
|
}
|
|
break;
|
|
|
|
case MSG_MUTE:
|
|
if (type != EDJE_MESSAGE_INT)
|
|
ERR("message for volume got type %d instead of %d",
|
|
type, EDJE_MESSAGE_INT);
|
|
else
|
|
{
|
|
Edje_Message_Int *m = msg;
|
|
w->play.mute = m->val;
|
|
emotion_object_audio_mute_set(w->emotion, w->play.mute);
|
|
if (w->play.mute)
|
|
emotion_object_audio_volume_set(w->emotion, 0);
|
|
else
|
|
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);
|
|
}
|
|
}
|
|
|
|
void
|
|
enjoy_control_next(void)
|
|
{
|
|
Win *w = &_win;
|
|
_win_next(w, NULL, NULL, NULL);
|
|
}
|
|
|
|
void
|
|
enjoy_control_previous(void)
|
|
{
|
|
Win *w = &_win;
|
|
_win_prev(w, NULL, NULL, NULL);
|
|
}
|
|
|
|
void
|
|
enjoy_control_pause(void)
|
|
{
|
|
Win *w = &_win;
|
|
_win_action_pause(w, NULL, NULL, NULL);
|
|
}
|
|
|
|
void
|
|
enjoy_control_stop(void)
|
|
{
|
|
Win *w = &_win;
|
|
_win_action_pause(&_win, NULL, NULL, NULL);
|
|
w->play.position = 0.0;
|
|
emotion_object_position_set(w->emotion, w->play.position);
|
|
}
|
|
|
|
void
|
|
enjoy_control_play(void)
|
|
{
|
|
Win *w = &_win;
|
|
_win_action_play(w, NULL, NULL, NULL);
|
|
}
|
|
|
|
void
|
|
enjoy_control_seek(uint64_t position)
|
|
{
|
|
Win *w = &_win;
|
|
double seek_to;
|
|
|
|
seek_to = w->play.position + w->play.length / ((double)position / 1e6);
|
|
if (seek_to <= 0.0)
|
|
seek_to = 0.0;
|
|
else if (seek_to >= 1.0)
|
|
seek_to = 1.0;
|
|
|
|
w->play.position = seek_to;
|
|
emotion_object_position_set(w->emotion, w->play.position);
|
|
}
|
|
|
|
void
|
|
enjoy_quit(void)
|
|
{
|
|
ecore_main_loop_quit();
|
|
}
|
|
|
|
int
|
|
enjoy_caps_get(void)
|
|
{
|
|
Win *w = &_win;
|
|
int caps = 0;
|
|
|
|
if (list_prev_exists(w->list)) caps |= CAN_GO_PREV;
|
|
if ((w->play.shuffle) || (list_next_exists(w->list))) caps |= CAN_GO_NEXT;
|
|
if (w->song)
|
|
{
|
|
caps |= CAN_PAUSE;
|
|
caps |= CAN_PLAY;
|
|
if (emotion_object_seekable_get(w->emotion))
|
|
caps |= CAN_SEEK;
|
|
caps |= CAN_PROVIDE_METADATA;
|
|
caps |= CAN_HAS_TRACKLIST;
|
|
}
|
|
|
|
return caps;
|
|
}
|
|
|
|
void
|
|
enjoy_status_get(int *playback, int *shuffle, int *repeat, int *endless)
|
|
{
|
|
Win *w = &_win;
|
|
if (playback)
|
|
{
|
|
if (w->play.playing)
|
|
*playback = 0;
|
|
else if (w->play.position == 0.0)
|
|
*playback = 2;
|
|
else
|
|
*playback = 1;
|
|
}
|
|
|
|
if (shuffle) *shuffle = !!w->play.shuffle;
|
|
if (repeat) *repeat = !!w->play.repeat;
|
|
if (endless) *endless = 0;
|
|
}
|
|
|
|
void
|
|
enjoy_repeat_set(Eina_Bool repeat)
|
|
{
|
|
Win *w = &_win;
|
|
w->play.repeat = !!repeat;
|
|
}
|
|
|
|
Eina_Bool
|
|
enjoy_repeat_get(void)
|
|
{
|
|
Win *w = &_win;
|
|
return w->play.repeat;
|
|
}
|
|
|
|
void
|
|
enjoy_position_set(int32_t position)
|
|
{
|
|
Win *w = &_win;
|
|
|
|
w->play.position = w->play.length / ((double)position / 1e6);
|
|
if (w->play.position < 0.0)
|
|
w->play.position = 0.0;
|
|
else if (w->play.position > 1.0)
|
|
w->play.position = 1.0;
|
|
|
|
emotion_object_position_set(w->emotion, w->play.position);
|
|
}
|
|
|
|
int32_t
|
|
enjoy_position_get(void)
|
|
{
|
|
Win *w = &_win;
|
|
return w->play.position * w->play.length;
|
|
}
|
|
|
|
int32_t
|
|
enjoy_volume_get(void)
|
|
{
|
|
Win *w = &_win;
|
|
return w->play.volume * 100;
|
|
}
|
|
|
|
void
|
|
enjoy_volume_set(int32_t volume)
|
|
{
|
|
Win *w = &_win;
|
|
w->play.volume = (double)volume / 100.0;
|
|
emotion_object_audio_volume_set(w->emotion, w->play.volume);
|
|
}
|
|
|
|
Song *
|
|
enjoy_song_current_get(void)
|
|
{
|
|
Win *w = &_win;
|
|
return w->song;
|
|
}
|
|
|
|
Song *
|
|
enjoy_song_position_get(int32_t position)
|
|
{
|
|
Win *w = &_win;
|
|
return db_song_get(w->db, position);
|
|
}
|
|
|
|
void
|
|
enjoy_control_loop_set(Eina_Bool param)
|
|
{
|
|
Win *w = &_win;
|
|
param = !!param;
|
|
edje_object_message_send(elm_layout_edje_get(w->nowplaying),
|
|
EDJE_MESSAGE_INT, MSG_LOOP, ¶m);
|
|
}
|
|
|
|
void
|
|
enjoy_control_shuffle_set(Eina_Bool param)
|
|
{
|
|
Win *w = &_win;
|
|
param = !!param;
|
|
edje_object_message_send(elm_layout_edje_get(w->nowplaying),
|
|
EDJE_MESSAGE_INT, MSG_SHUFFLE, ¶m);
|
|
}
|
|
|
|
int32_t
|
|
enjoy_playlist_current_position_get(void)
|
|
{
|
|
Win *w = &_win;
|
|
if (!w->list) return 0;
|
|
return list_song_selected_n_get(w->list);
|
|
}
|
|
|
|
Song *
|
|
enjoy_playlist_song_position_get(int32_t position)
|
|
{
|
|
Win *w = &_win;
|
|
if (!w->list) return NULL;
|
|
return list_song_nth_get(w->list, position);
|
|
}
|
|
|
|
Evas_Object *
|
|
win_new(App *app)
|
|
{
|
|
Win *w = &_win;
|
|
const char *s;
|
|
Evas_Coord iw = 320, ih = 240;
|
|
char path[PATH_MAX];
|
|
Evas_Object *nowplaying_edje;
|
|
|
|
memset(w, 0, sizeof(*w));
|
|
|
|
w->play.volume = 0.8;
|
|
|
|
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->mgr = libmgr_new(w->db_path);
|
|
|
|
w->emotion = emotion_object_add(evas_object_evas_get(w->win));
|
|
if (!emotion_object_init(w->emotion, NULL))
|
|
{
|
|
CRITICAL("could not create emotion 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, "frame_decode", _win_play_pos_update, w);
|
|
evas_object_smart_callback_add
|
|
(w->emotion, "playback_started", _win_play_begin, w);
|
|
evas_object_smart_callback_add
|
|
(w->emotion, "playback_finished", _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);
|
|
evas_object_smart_callback_add(w->list, "changed", _win_list_changed, w);
|
|
|
|
w->nowplaying = nowplaying_add(w->layout);
|
|
nowplaying_edje = elm_layout_edje_get(w->nowplaying);
|
|
edje_object_message_handler_set(nowplaying_edje, _win_edje_msg, w);
|
|
edje_object_signal_callback_add
|
|
(nowplaying_edje, "ejy,repeat,on", "ejy", _win_repeat_on, w);
|
|
edje_object_signal_callback_add
|
|
(nowplaying_edje, "ejy,repeat,off", "ejy", _win_repeat_off, w);
|
|
edje_object_signal_callback_add
|
|
(nowplaying_edje, "ejy,shuffle,on", "ejy", _win_shuffle_on, w);
|
|
edje_object_signal_callback_add
|
|
(nowplaying_edje, "ejy,shuffle,off", "ejy", _win_shuffle_off, w);
|
|
elm_layout_content_set(w->layout, "ejy.swallow.nowplaying", w->nowplaying);
|
|
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_signal_callback_add
|
|
(w->edje, "ejy,songs,clicked", "ejy", _win_songs, 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,disable", "ejy");
|
|
edje_object_signal_emit(w->edje, "ejy,mode,list,hide", "ejy");
|
|
edje_object_signal_emit(w->edje, "ejy,mode,nowplaying,disable", "ejy");
|
|
edje_object_signal_emit(w->edje, "ejy,more,disable", "ejy");
|
|
|
|
evas_object_show(w->layout);
|
|
|
|
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);
|
|
|
|
srand(ecore_time_unix_get());
|
|
|
|
return w->win;
|
|
|
|
error:
|
|
evas_object_del(w->win); /* should delete everything */
|
|
return NULL;
|
|
}
|