diff --git a/data/themes/default.edc b/data/themes/default.edc index 227ab8b..8ba5c1c 100644 --- a/data/themes/default.edc +++ b/data/themes/default.edc @@ -497,6 +497,41 @@ collections { } } + part { name: "rage.browser"; type: SWALLOW; + description { state: "default" 0.0; + rel1.relative: 1.0 0.0; + rel1.offset: 40 0; + rel2.relative: 2.0 0.0; + rel2.offset: -41 -1; + rel2.to_y: "controlbar"; + fixed: 1 1; + visible: 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 0.0; + color: 255 255 255 255; + visible: 1; + } + } + program { + signal: "browser,state,visible"; source: "rage"; + action: STATE_SET "visible" 0.0; + transition: DECELERATE 0.3; + target: "rage.browser"; + } + program { + signal: "browser,state,hidden"; source: "rage"; + action: STATE_SET "default" 0.0; + transition: ACCELERATE 0.5; + target: "rage.browser"; + after: "browser_hidden"; + } + program { name: "browser_hidden"; + action: SIGNAL_EMIT "browser,state,hidden,finished" "rage"; + } + part { name: "rage.list"; type: SWALLOW; description { state: "default" 0.0; align: 0.0 0.5; @@ -2073,4 +2108,177 @@ collections { } } } + + + + + + + + group { name: "rage/browser/entry"; + parts { + part { name: "rage.title"; type: TEXT; mouse_events: 0; + scale: 1; + description { state: "default" 0.0; + fixed: 0 1; + align: 0.0 0.0; + rel1.offset: 0 40; + rel2.offset: -1 40; + rel2.relative: 1.0 0.0; + color: 255 255 255 255; + text { font: "Sans:style=Bold"; size: 20; + align: 0.0 0.0; + min: 0 1; + elipsis: 0; + } + } + } + part { name: "rage.content"; type: SWALLOW; + description { state: "default" 0.0; + rel1.to_y: "rage.title"; + rel1.relative: 0.0 1.0; + rel1.offset: 0 40; + rel2.offset: -1 -41; + } + } + } + } + + group { name: "rage/browser/item"; + images.image: "win_shadow.png" COMP; + images.image: "win_glow.png" COMP; + images.image: "bg_shine.png" COMP; + images.image: "bg_glint.png" COMP; + + parts { + part { name: "shadow"; mouse_events: 0; + description { state: "default" 0.0; + fixed: 1 1; + rel1.to: "clip"; + rel2.to: "clip"; + image.normal: "win_shadow.png"; + image.border: 14 14 14 14; + image.middle: 0; + rel1.offset: -7 -3; + rel2.offset: 6 11; + fill.smooth: 0; + } + } + part { name: "base"; type: RECT; mouse_events: 0; + description { state: "default" 0.0; + color: 0 0 0 255; + rel1.to: "clip"; + rel2.to: "clip"; + } + } + part { name: "glow"; mouse_events: 0; + description { state: "default" 0.0; + image.normal: "win_glow.png"; + image.border: 9 9 9 9; + image.middle: 0; + rel1.to: "clip"; + rel1.offset: -5 -5; + rel2.to: "clip"; + rel2.offset: 4 4; + fill.smooth: 0; + color: 255 255 255 0; + visible: 0; + } + description { state: "selected" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + visible: 1; + } + } + program { + signal: "rage,state,selected"; source: "rage"; + action: STATE_SET "selected" 0.0; + transition: SINUSOIDAL 0.1; + target: "glow"; + } + program { + signal: "rage,state,unselected"; source: "rage"; + action: STATE_SET "default" 0.0; + transition: SINUSOIDAL 0.3; + target: "glow"; + } + + part { name: "clip"; type: RECT; + description { state: "default" 0.0; + rel1.offset: 4 4; + rel2.offset: -5 -5; + } + } + part { name: "glintclip"; type: RECT; + description { state: "default" 0.0; + rel1.to: "clip"; + rel2.to: "clip"; + rel1.offset: 0 -10; + } + } + part { name: "rage.content"; type: SWALLOW; + clip_to: "clip"; + description { state: "default" 0.0; + rel1.to: "clip"; + rel2.to: "clip"; + } + } + part { name: "shine"; mouse_events: 0; + clip_to: "clip"; + description { state: "default" 0.0; + image.normal: "bg_shine.png"; + fill.smooth: 0; + rel1.to: "clip"; + rel2.to: "clip"; + align: 0.5 0.0; + aspect: (255/120) (255/120); + aspect_preference: HORIZONTAL; + } + } + part { name: "glint"; mouse_events: 0; + clip_to: "glintclip"; + description { state: "default" 0.0; + fixed: 1 1; + min: 79 5; + max: 79 5; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + to: "clip"; + } + rel2 { + relative: 1.0 0.0; + offset: -1 0; + to: "clip"; + } + image.normal: "bg_glint.png"; + } + } + part { name: "rage.title"; type: TEXT; mouse_events: 0; + scale: 1; + description { state: "default" 0.0; + fixed: 1 1; + align: 0.0 1.0; + rel1.offset: 4 4; + rel2.offset: -5 -5; + color: 255 255 255 255; + text { font: "Sans"; size: 12; + align: 0.0 1.0; + min: 0 1; + elipsis: 0; + } + } + } + part { name: "event"; type: RECT; + ignore_flags: ON_HOLD; + description { state: "default" 0.0; + color: 0 0 0 0; + } + } + program { + signal: "mouse,clicked,1"; source: "event"; + action: SIGNAL_EMIT "rage,selected" "rage"; + } + } + } } diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index 6e39b02..e16a942 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -9,6 +9,8 @@ src_bin_rage_LDADD = @RAGE_LIBS@ src_bin_rage_SOURCES = \ src/bin/albumart.c \ src/bin/albumart.h \ +src/bin/browser.c \ +src/bin/browser.h \ src/bin/config.c \ src/bin/config.h \ src/bin/controls.c \ @@ -39,6 +41,8 @@ internal_bin_PROGRAMS = src/bin/rage_thumb src_bin_rage_thumb_SOURCES = \ src/bin/thumb.c \ +src/bin/albumart.c \ +src/bin/albumart.h \ src/bin/sha1.c \ src/bin/sha1.h diff --git a/src/bin/albumart.c b/src/bin/albumart.c index 1e635ae..d32a532 100644 --- a/src/bin/albumart.c +++ b/src/bin/albumart.c @@ -17,7 +17,9 @@ static Eina_Strbuf *sb_result = NULL; static Eina_Bool fetch_image = EINA_FALSE; static char *fetchfile = NULL; static FILE *fout = NULL; -static Evas_Object *fetchwin = NULL; +static void (*_fetch_done) (void *data) = NULL; +static void *_fetch_data = NULL; + static char * _inpath(const char *file) @@ -107,17 +109,10 @@ _cb_http_complete(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) if (ev->url_con != fetch) return EINA_TRUE; if (fetch_image) { - char *path; - fetch_image = EINA_FALSE; fclose(fout); fout = NULL; - path = _thumbpath(fetchfile); - if (path) - { - win_art(fetchwin, path); - free(path); - } + if (_fetch_done) _fetch_done(_fetch_data); } else { @@ -190,7 +185,10 @@ _cb_http_complete(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) free(fetchfile); fetchfile = NULL; } + if (_fetch_done) _fetch_done(_fetch_data); } + _fetch_done = NULL; + _fetch_data = NULL; return EINA_FALSE; } @@ -225,9 +223,10 @@ _search_append(Eina_Strbuf *sb, const char *str, Eina_Bool hadword) } void -albumart_find(Evas_Object *win, Evas_Object *vid) +albumart_find(const char *file, + const char *artist, const char *album, const char *title, + void (*fetch_done) (void *data), void *fetch_data) { - const char *file, *album, *artist, *title; Eina_Strbuf *sb; char *path; @@ -252,7 +251,7 @@ albumart_find(Evas_Object *win, Evas_Object *vid) sb_result = NULL; } fetch_image = EINA_FALSE; - if (!vid) return; + if (!file) return; if (!handle_data) handle_data = ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, @@ -261,16 +260,18 @@ albumart_find(Evas_Object *win, Evas_Object *vid) handle_complete = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _cb_http_complete, NULL); - file = video_file_get(vid); if (!file) return; fetchfile = _inpath(file); + _fetch_done = fetch_done; + _fetch_data = _fetch_data; + path = _thumbpath(fetchfile); if (path) { if (ecore_file_exists(path)) { - win_art(win, path); + if (fetch_done) fetch_done(fetch_data); free(path); free(fetchfile); fetchfile = NULL; @@ -278,14 +279,10 @@ albumart_find(Evas_Object *win, Evas_Object *vid) } else free(path); } - fetchwin = win; sb = eina_strbuf_new(); eina_strbuf_append(sb, Q_START); - title = video_meta_title_get(vid); - artist = video_meta_artist_get(vid); - album = video_meta_album_get(vid); if ((title) || (album) || (artist)) { Eina_Bool had = EINA_FALSE; diff --git a/src/bin/albumart.h b/src/bin/albumart.h index 3a803c3..d19bb73 100644 --- a/src/bin/albumart.h +++ b/src/bin/albumart.h @@ -1,7 +1,9 @@ #ifndef _ALBUMART_H__ #define _ALBUMART_H__ 1 -void albumart_find(Evas_Object *win, Evas_Object *vid); +void albumart_find(const char *file, + const char *artist, const char *album, const char *title, + void (*fetch_done) (void *data), void *fetch_data); char *albumart_file_get(const char *file); #endif diff --git a/src/bin/browser.c b/src/bin/browser.c new file mode 100644 index 0000000..de771fe --- /dev/null +++ b/src/bin/browser.c @@ -0,0 +1,828 @@ +#include +#include "main.h" +#include "win.h" +#include "winvid.h" +#include "browser.h" +#include "videothumb.h" +#include "key.h" + +typedef struct _Message Message; +typedef struct _Entry Entry; + +typedef enum _Type +{ + TYPE_NEW, + TYPE_UPDATE, + TYPE_FINISH +} Type; + +struct _Message +{ + Type type; + Entry *entry; +}; + +struct _Entry +{ + Eina_Lock lock; + Entry *parent; // what is above + Eina_Stringshare *path; // full path + Eina_List *dirs; // entries fo subdir entires + Eina_List *files; // strings of just filenames in path dir + Eina_List *sels; + Evas_Object *base; + Evas_Object *box; + Evas_Object *table; + Evas_Object *sizer; + Evas_Coord iw, ih; + int cols, rows; + int sel_x, sel_y; + Eina_Bool sel : 1; +}; + +static Evas_Object *bx = NULL; +static Evas_Object *sc, *bt; +static Ecore_Thread *fill_thread = NULL; +static Entry *dir_entry = NULL; + +static void +_item_size_get(Evas_Object *win, Evas_Coord *w, Evas_Coord *h) +{ + Evas_Coord sz = 0; + + elm_coords_finger_size_adjust(1, &sz, 1, &sz); + evas_object_geometry_get(win, NULL, NULL, w, h); + *w = *w / 5; + *h = *h / 5; + if (*w < sz) *w = sz; + if (*h < sz) *h = sz; +} + +static Eina_Bool +_video_ok(const char *path) +{ + const char *exts[] = + { + ".asf", ".avi", ".bdm", ".bdmv", ".clpi", ".cpi", ".dv", ".fla", + ".flv", ".m1v", ".m2t", ".m2v", ".m4v", ".mkv", ".mov", ".mp2", + ".mp2ts", ".mp4", ".mpe", ".mpeg", ".mpg", ".mpl", ".mpls", ".mts", + ".mxf", ".nut", ".nuv", ".ogg", ".ogm", ".ogv", ".qt", ".rm", ".rmj", + ".rmm", ".rms", ".rmvb", ".rmx", ".rv", ".swf", ".ts", ".weba", + ".webm", ".wmv", ".3g2", ".3gp", ".3gp2", ".3gpp", ".3gpp2", ".3p2", + ".264", + NULL + }; + int i; + const char *ext = strrchr(path, '.'); + if (!ext) return EINA_FALSE; + for (i = 0; exts[i]; i++) + { + if (!strcasecmp(ext, exts[i])) return EINA_TRUE; + } + return EINA_FALSE; +} + +static Eina_Bool +_audio_ok(const char *path) +{ + const char *exts[] = + { + ".mp3", ".m4a", ".oga", ".aac", ".flac", ".wav", + NULL + }; + int i; + const char *ext = strrchr(path, '.'); + if (!ext) return EINA_FALSE; + for (i = 0; exts[i]; i++) + { + if (!strcasecmp(ext, exts[i])) return EINA_TRUE; + } + return EINA_FALSE; +} + +static void +_fill_message(Ecore_Thread *th, Type type, Entry *entry) +{ + Message *message = calloc(1, sizeof(Message)); + if (!message) return; + message->type = type; + message->entry = entry; + ecore_thread_feedback(th, message); +} + +static Entry * +_fill_scan(Ecore_Thread *th, Entry *parent, const char *dir) +{ + Eina_List *files; + char *file; + Entry *entry = NULL; + + entry = calloc(1, sizeof(Entry)); + if (!entry) return NULL; + files = ecore_file_ls(dir); + if (!files) + { + free(entry); + return NULL; + } + eina_lock_new(&(entry->lock)); + entry->parent = parent; + entry->path = eina_stringshare_add(dir); + if (parent) + { + eina_lock_take(&(parent->lock)); + parent->dirs = eina_list_append(parent->dirs, entry); + eina_lock_release(&(parent->lock)); + } + _fill_message(th, TYPE_NEW, entry); + EINA_LIST_FREE(files, file) + { + if (!ecore_thread_check(th)) + { + if (file[0] != '.') + { + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), "%s/%s", dir, file); + if (ecore_file_is_dir(buf)) + { + _fill_scan(th, entry, buf); + _fill_message(th, TYPE_UPDATE, entry); + } + else + { + if (_video_ok(file) || _audio_ok(file)) + { + eina_lock_take(&(entry->lock)); + entry->files = eina_list_append + (entry->files, eina_stringshare_add(file)); + eina_lock_release(&(entry->lock)); + _fill_message(th, TYPE_UPDATE, entry); + } + } + } + } + free(file); + } + _fill_message(th, TYPE_FINISH, entry); + return entry; +} + +static void +_fill_thread(void *data EINA_UNUSED, Ecore_Thread *th) +{ + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), "%s/Videos", eina_environment_home_get()); + _fill_scan(th, NULL, buf); +} + +static void +_cb_vidthumb_data(void *data EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED) +{ + int w, h; + + videothumb_size_get(obj, &w, &h); + evas_object_size_hint_aspect_set(obj, EVAS_ASPECT_CONTROL_BOTH, w, h); +} + +static void +_activate(Evas_Object *win, Entry *entry, const char *file) +{ + Eina_List *list = NULL; + Winvid_Entry *vid; + char buf[PATH_MAX]; + + vid = calloc(1, sizeof(Winvid_Entry)); + if (vid) + { + snprintf(buf, sizeof(buf), "%s/%s", entry->path, file); + vid->file = eina_stringshare_add(buf); + list = eina_list_append(list, vid); + } + win_video_file_list_set(win, list); + EINA_LIST_FREE(list, vid) + { + if (vid->file) eina_stringshare_del(vid->file); + if (vid->sub) eina_stringshare_del(vid->sub); + if (vid->uri) efreet_uri_free(vid->uri); + free(vid); + } + browser_hide(win); +} + +static void +_cb_file_selected(void *data, Evas_Object *obj, const char *sig EINA_UNUSED, const char *src EINA_UNUSED) +{ + Evas_Object *win = data; + Entry *entry = evas_object_data_get(obj, "entry"); + const char *file = evas_object_data_get(obj, "file"); + + elm_layout_signal_emit(obj, "rage,state,selected", "rage"); + _activate(win, entry, file); +} + +static void +_entry_files_pop(Evas_Object *win, Entry *entry) +{ + Evas_Object *o, *base; + int i = 0, j = 0; + Eina_List *l; + const char *file; + char buf[PATH_MAX], *p; + + if (evas_object_data_get(entry->table, "populated")) return; + evas_object_data_set(entry->table, "populated", entry->table); + + EINA_LIST_FOREACH(entry->files, l, file) + { + base = o = elm_layout_add(win); + entry->sels = eina_list_append(entry->sels, o); + evas_object_data_set(o, "entry", entry); + evas_object_data_set(o, "file", file); + elm_object_focus_allow_set(o, EINA_FALSE); + snprintf(buf, sizeof(buf), "%s/themes/default.edj", elm_app_data_dir_get()); + elm_layout_file_set(o, buf, "rage/browser/item"); + snprintf(buf, sizeof(buf), "%s", file); + p = strrchr(buf, '.'); + if (p) *p = 0; + elm_object_part_text_set(o, "rage.title", buf); + evas_object_size_hint_weight_set(o, 0.0, 0.0); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_table_pack(entry->table, o, i, j, 1, 1); + evas_object_show(o); + + elm_layout_signal_callback_add(o, "rage,selected", "rage", _cb_file_selected, win); + + o = videothumb_add(win); + evas_object_smart_callback_add(o, "data", _cb_vidthumb_data, base); + evas_object_data_set(o, "entry", entry); + evas_object_data_set(o, "file", file); + snprintf(buf, sizeof(buf), "%s/%s", entry->path, file); + videothumb_file_set(o, buf, 0.0); + videothumb_autocycle_set(o, EINA_TRUE); + elm_object_part_content_set(base, "rage.content", o); + evas_object_show(o); + + if ((entry->sel) && (entry->sel_x == i) && (entry->sel_y == j)) + elm_layout_signal_emit(base, "rage,state,selected", "rage"); + + i++; + if (i == entry->cols) + { + i = 0; + j++; + } + } + if ((entry->cols > 0) && (entry->rows > 0)) + elm_table_pack(entry->table, entry->sizer, 0, 0, entry->cols, entry->rows); + else + elm_table_pack(entry->table, entry->sizer, 0, 0, 1, 1); +} + +static void +_entry_files_unpop(Evas_Object *win EINA_UNUSED, Entry *entry) +{ + evas_object_size_hint_min_set(entry->sizer, + entry->cols * entry->iw, + entry->rows * entry->ih); + if (!evas_object_data_get(entry->table, "populated")) return; + entry->sels = eina_list_free(entry->sels); + evas_object_data_del(entry->table, "populated"); + elm_table_unpack(entry->table, entry->sizer); + elm_table_clear(entry->table, EINA_TRUE); + if ((entry->cols > 0) && (entry->rows > 0)) + elm_table_pack(entry->table, entry->sizer, 0, 0, entry->cols, entry->rows); + else + elm_table_pack(entry->table, entry->sizer, 0, 0, 1, 1); +} + +static void +_entry_files_redo(Evas_Object *win, Entry *entry) +{ + Evas_Coord x, y,w, h, iw = 1, ih = 1, ww, wh; + int num, cols, rows; + Eina_Rectangle r1, r2; + + eina_lock_take(&(entry->lock)); + + num = eina_list_count(entry->files); + evas_object_geometry_get(win, NULL, NULL, &ww, &wh); + evas_object_geometry_get(entry->table, &x, &y, &w, &h); + if (w < 40) goto done; + + if (w > (ww - 20)) w = (ww - 20); + + _item_size_get(win, &iw, &ih); + cols = w / iw; + if (cols < 1) cols = 1; + if (cols > 0) rows = (num + (cols - 1)) / cols; + else rows = 0; + + entry->iw = iw; + entry->ih = ih; + entry->cols = cols; + entry->rows = rows; + + r1.x = 0; r1.y = 0; r1.w = ww; r1.h = wh; + r2.x = x; r2.y = y; r2.w = w; r2.h = h; + + _entry_files_unpop(win, entry); + if (eina_rectangles_intersect(&r1, &r2)) _entry_files_pop(win, entry); + +done: + eina_lock_release(&(entry->lock)); +} + +static void +_cb_entry_table_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) +{ + Entry *entry = data; + Evas_Object *win = evas_object_data_get(obj, "win"); + Evas_Coord x, y,w, h, ww, wh; + Eina_Rectangle r1, r2; + + eina_lock_take(&(entry->lock)); + + evas_object_geometry_get(win, NULL, NULL, &ww, &wh); + evas_object_geometry_get(entry->table, &x, &y, &w, &h); + if (w < 40) goto done; + + if (w > (ww - 20)) w = (ww - 20); + + r1.x = 0; r1.y = 0; r1.w = ww; r1.h = wh; + r2.x = x; r2.y = y; r2.w = w; r2.h = h; + + if (eina_rectangles_intersect(&r1, &r2)) _entry_files_pop(win, entry); + else _entry_files_unpop(win, entry); + +done: + eina_lock_release(&(entry->lock)); +} + +static void +_cb_entry_table_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) +{ + Entry *entry = data; + Evas_Object *win = evas_object_data_get(obj, "win"); + _entry_files_redo(win, entry); +} + +static void +_fill_feedback(void *data, Ecore_Thread *th, void *msg) +{ + Evas_Object *win = data; + Message *message = msg; + Evas_Object *o; + char buf[PATH_MAX]; + + if ((th == fill_thread) && (bx)) + { + Entry *entry = message->entry; + + if ((message->type == TYPE_NEW) && (!dir_entry)) dir_entry = entry; + + if (message->type == TYPE_NEW) + { + eina_lock_take(&(entry->lock)); + if ((entry->dirs) || (entry->files)) + { + if (!entry->base) + { + const char *file; + + entry->base = o = elm_layout_add(win); + elm_object_focus_allow_set(o, EINA_FALSE); + snprintf(buf, sizeof(buf), "%s/themes/default.edj", elm_app_data_dir_get()); + elm_layout_file_set(o, buf, "rage/browser/entry"); + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5); + + if (entry->parent) + { + file = entry->path + strlen(dir_entry->path) + 1; + elm_object_part_text_set(o, "rage.title", file); + } + + entry->box = o = elm_box_add(win); + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_object_part_content_set(entry->base, "rage.content", o); + evas_object_show(o); + + entry->table = o = elm_table_add(win); + elm_table_homogeneous_set(o, EINA_TRUE); + evas_object_data_set(o, "win", win); + evas_object_event_callback_add(o, EVAS_CALLBACK_MOVE, _cb_entry_table_move, entry); + evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, _cb_entry_table_resize, entry); + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5); + elm_box_pack_end(entry->box, o); + evas_object_show(o); + + entry->sizer = o = evas_object_rectangle_add(evas_object_evas_get(win)); + evas_object_color_set(o, 0, 0, 0, 0); + evas_object_size_hint_min_set(o, 10, 10); + elm_table_pack(entry->table, o, 0, 0, 1, 1); + evas_object_show(o); + + if (!entry->parent) + elm_box_pack_end(bx, entry->base); + else + elm_box_pack_end(entry->parent->box, entry->base); + evas_object_show(entry->base); + } + } + eina_lock_release(&(entry->lock)); + } + else if ((message->type == TYPE_FINISH) && (entry->parent)) + { + _entry_files_redo(win, entry); + } + } + free(msg); +} + +static void +_fill_end(void *data EINA_UNUSED, Ecore_Thread *th) +{ + if (th == fill_thread) fill_thread = NULL; +} + +static void +_fill_cancel(void *data EINA_UNUSED, Ecore_Thread *th) +{ + if (th == fill_thread) fill_thread = NULL; +} + +static void +_entry_free(Entry *entry) +{ + Entry *subentry; + Eina_Stringshare *str; + if (!entry) return; + entry->sels = eina_list_free(entry->sels); + if (entry->base) evas_object_del(entry->base); + EINA_LIST_FREE(entry->files, str) eina_stringshare_del(str); + EINA_LIST_FREE(entry->dirs, subentry) _entry_free(subentry); + eina_stringshare_del(entry->path); + eina_lock_free(&(entry->lock)); + free(entry); +} + +static void +_fill(Evas_Object *win) +{ + if (fill_thread) + { + ecore_thread_cancel(fill_thread); + ecore_thread_wait(fill_thread, 10.0); + } + _entry_free(dir_entry); + dir_entry = NULL; + fill_thread = ecore_thread_feedback_run(_fill_thread, _fill_feedback, + _fill_end, _fill_cancel, + win, EINA_TRUE); +} + +static Entry * +_sel_find(Entry *entry) +{ + Eina_List *l; + Entry *subentry, *tmpentry; + + eina_lock_take(&(entry->lock)); + if (entry->sel) + { + eina_lock_release(&(entry->lock)); + return entry; + } + EINA_LIST_FOREACH(entry->dirs, l, subentry) + { + tmpentry = _sel_find(subentry); + if (tmpentry) + { + eina_lock_release(&(entry->lock)); + return tmpentry; + } + } + eina_lock_release(&(entry->lock)); + return NULL; +} + +static Evas_Object * +_sel_object_find(Entry *entry) +{ + int num = (entry->sel_y * entry->cols) + entry->sel_x; + Evas_Object *o = eina_list_nth(entry->sels, num); + return o; +} + +static const char * +_sel_file_find(Entry *entry) +{ + int num = (entry->sel_y * entry->cols) + entry->sel_x; + const char *file = eina_list_nth(entry->files, num); + return file; +} + +static Eina_List * +_entry_list_flatten(Eina_List *list, Entry *entry) +{ + Eina_List *l; + Entry *subentry; + + eina_lock_take(&(entry->lock)); + if (entry->files) list = eina_list_append(list, entry); + EINA_LIST_FOREACH(entry->dirs, l, subentry) + { + list = _entry_list_flatten(list, subentry); + } + eina_lock_release(&(entry->lock)); + return list; +} + +static void +_sel_go(Evas_Object *win EINA_UNUSED, Entry *base_entry, int x, int y) +{ + Evas_Object *o; + Evas_Coord bxx, bxy, tbx, tby; + + if (!base_entry) return; + evas_object_geometry_get(bx, &bxx, &bxy, NULL, NULL); + Entry *entry = _sel_find(base_entry); + if (!entry) + { + Eina_List *flatlist = _entry_list_flatten(NULL, base_entry); + + if (flatlist) + { + entry = flatlist->data; + eina_lock_take(&(entry->lock)); + entry->sel = EINA_TRUE; + entry->sel_x = 0; + entry->sel_y = 0; + o = _sel_object_find(entry); + elm_layout_signal_emit(o, "rage,state,selected", "rage"); + eina_lock_release(&(entry->lock)); + eina_list_free(flatlist); + } + } + else + { + int sel_x, sel_y, num; + Entry *subentry; + Eina_List *l; + Eina_List *flatlist = _entry_list_flatten(NULL, base_entry); + + eina_lock_take(&(entry->lock)); + sel_x = entry->sel_x + x; + sel_y = entry->sel_y + y; + if (sel_x >= entry->cols) + { + sel_y++; + sel_x = 0; + } + else if (sel_x < 0) + { + sel_y--; + sel_x = entry->cols - 1; + } + num = (sel_y * entry->cols) + sel_x; + if (num < 0) + { + EINA_LIST_FOREACH(flatlist, l, subentry) + { + if (subentry == entry) + { + if (l->prev) + { + subentry = l->prev->data; + entry->sel = EINA_FALSE; + subentry->sel = EINA_TRUE; + if (sel_x < subentry->cols) + subentry->sel_x = sel_x; + else + subentry->sel_x = subentry->cols - 1; + subentry->sel_y = subentry->rows - 1; + num = eina_list_count(subentry->files) - 1 - + ((subentry->sel_y * subentry->cols) + + subentry->sel_x); + if (num < 0) subentry->sel_x += num; + evas_object_geometry_get(subentry->table, &tbx, &tby, NULL, NULL); + o = _sel_object_find(entry); + if (o) elm_layout_signal_emit(o, "rage,state,unselected", "rage"); + o = _sel_object_find(subentry); + if (o) elm_layout_signal_emit(o, "rage,state,selected", "rage"); + elm_scroller_region_bring_in + (sc, + (tbx - bxx) + (subentry->sel_x * subentry->iw), + (tby - bxy) + (subentry->sel_y * subentry->ih), + entry->iw, entry->ih); + } + break; + } + } + } + else if (num >= (int)eina_list_count(entry->files)) + { + EINA_LIST_FOREACH(flatlist, l, subentry) + { + if (subentry == entry) + { + if (l->next) + { + subentry = l->next->data; + entry->sel = EINA_FALSE; + subentry->sel = EINA_TRUE; + if (sel_x < subentry->cols) + subentry->sel_x = sel_x; + else + subentry->sel_x = subentry->cols - 1; + subentry->sel_y = 0; + num = eina_list_count(subentry->files) - 1 - + ((subentry->sel_y * subentry->cols) + + subentry->sel_x); + if (num < 0) subentry->sel_x += num; + evas_object_geometry_get(subentry->table, &tbx, &tby, NULL, NULL); + o = _sel_object_find(entry); + if (o) elm_layout_signal_emit(o, "rage,state,unselected", "rage"); + o = _sel_object_find(subentry); + if (o) elm_layout_signal_emit(o, "rage,state,selected", "rage"); + elm_scroller_region_bring_in + (sc, + (tbx - bxx) + (subentry->sel_x * subentry->iw), + (tby - bxy) + (subentry->sel_y * subentry->ih), + entry->iw, entry->ih); + } + break; + } + } + } + else + { + o = _sel_object_find(entry); + if (o) elm_layout_signal_emit(o, "rage,state,unselected", "rage"); + entry->sel_x = sel_x; + entry->sel_y = sel_y; + evas_object_geometry_get(entry->table, &tbx, &tby, NULL, NULL); + o = _sel_object_find(entry); + if (o) elm_layout_signal_emit(o, "rage,state,selected", "rage"); + elm_scroller_region_bring_in + (sc, + (tbx - bxx) + (entry->sel_x * entry->iw), + (tby - bxy) + (entry->sel_y * entry->ih), + entry->iw, entry->ih); + } + eina_lock_release(&(entry->lock)); + eina_list_free(flatlist); + } +} + +static void +_sel_do(Evas_Object *win, Entry *base_entry) +{ + Entry *entry; + + if (!base_entry) return; + entry = _sel_find(base_entry); + if (entry) + { + eina_lock_take(&(entry->lock)); + Evas_Object *o = _sel_object_find(entry); + const char *file = _sel_file_find(entry); + if (file) + { + elm_layout_signal_emit(o, "rage,state,selected", "rage"); + _activate(win, entry, file); + } + eina_lock_release(&(entry->lock)); + } +} + +static void +_cb_key_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ + Evas_Event_Key_Down *ev = event_info; + Evas_Object *win = data; + if ((!strcmp(ev->key, "Left")) || + (!strcmp(ev->key, "bracketleft"))) + { + _sel_go(win, dir_entry, -1, 0); + } + else if ((!strcmp(ev->key, "Right")) || + (!strcmp(ev->key, "bracketright"))) + { + _sel_go(win, dir_entry, 1, 0); + } + else if ((!strcmp(ev->key, "Up")) || + (!strcmp(ev->key, "Prior")) || + (!strcmp(ev->key, "XF86AudioPrev"))) + { + _sel_go(win, dir_entry, 0, -1); + } + else if ((!strcmp(ev->key, "Down")) || + (!strcmp(ev->key, "Next")) || + (!strcmp(ev->key, "XF86AudioNext"))) + { + _sel_go(win, dir_entry, 0, 1); + } + else if ((!strcmp(ev->key, "space")) || + (!strcmp(ev->key, "Pause")) || + (!strcmp(ev->keyname, "p")) || + (!strcmp(ev->key, "XF86AudioPlay")) || + (!strcmp(ev->key, "Return")) || + (!strcmp(ev->key, "KP_Enter"))) + { + _sel_do(win, dir_entry); + } + else if ((!strcmp(ev->keyname, "q")) || + (!strcmp(ev->key, "Escape")) || + (!strcmp(ev->key, "e"))) + { + browser_hide(win); + } + else key_handle(win, ev); +} + +void +browser_show(Evas_Object *win) +{ + Inf *inf = evas_object_data_get(win, "inf"); + + if (!bx) + { + bx = elm_box_add(win); + + sc = elm_scroller_add(win); + elm_object_style_set(sc, "noclip"); + elm_object_focus_allow_set(sc, EINA_FALSE); + evas_object_size_hint_weight_set(sc, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(sc, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_scroller_content_min_limit(sc, EINA_TRUE, EINA_FALSE); + + bx = elm_box_add(win); + elm_object_focus_allow_set(bx, EINA_FALSE); + evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.5); + elm_object_content_set(sc, bx); + evas_object_show(bx); + + elm_object_part_content_set(inf->lay, "rage.browser", sc); + evas_object_show(sc); + + _fill(win); + + // a dummy button to collect key events and have focus + bt = elm_button_add(win); + elm_object_focus_highlight_style_set(bt, "blank"); + evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, bt); + evas_object_lower(bt); + evas_object_show(bt); + elm_object_focus_set(bt, EINA_TRUE); + evas_object_event_callback_add(bt, EVAS_CALLBACK_KEY_DOWN, + _cb_key_down, win); + } + elm_layout_signal_emit(inf->lay, "browser,state,visible", "rage"); +} + +static void +_cb_hidden(void *data, Evas_Object *obj, const char *sig EINA_UNUSED, const char *src EINA_UNUSED) +{ + elm_layout_signal_callback_del(obj, "browser,state,hidden,finished", "rage", + _cb_hidden); + if (fill_thread) ecore_thread_cancel(fill_thread); + evas_object_del(bx); + bx = NULL; + evas_object_del(bt); + bt = NULL; + evas_object_del(sc); + sc = NULL; + elm_object_focus_next(data, ELM_FOCUS_PREVIOUS); +} + +void +browser_hide(Evas_Object *win) +{ + Inf *inf = evas_object_data_get(win, "inf"); + + if (!bx) return; + elm_layout_signal_callback_add(inf->lay, "browser,state,hidden,finished", "rage", + _cb_hidden, win); + elm_layout_signal_emit(inf->lay, "browser,state,hidden", "rage"); +} + +void +browser_toggle(Evas_Object *win) +{ + if (bx) browser_hide(win); + else browser_show(win); +} + +void +browser_size_update(Evas_Object *win EINA_UNUSED) +{ + if (!bx) return; + // XXX: unpop + repop +} diff --git a/src/bin/browser.h b/src/bin/browser.h new file mode 100644 index 0000000..287bab2 --- /dev/null +++ b/src/bin/browser.h @@ -0,0 +1,9 @@ +#ifndef _BROWSER_H__ +#define _BROWSER_H__ 1 + +void browser_show(Evas_Object *win); +void browser_hide(Evas_Object *win); +void browser_toggle(Evas_Object *win); +void browser_size_update(Evas_Object *win); + +#endif diff --git a/src/bin/key.c b/src/bin/key.c index 7fab4c2..69de77d 100644 --- a/src/bin/key.c +++ b/src/bin/key.c @@ -5,6 +5,7 @@ #include "video.h" #include "key.h" #include "winlist.h" +#include "browser.h" void key_handle(Evas_Object *win, Evas_Event_Key_Down *ev) @@ -110,6 +111,7 @@ key_handle(Evas_Object *win, Evas_Event_Key_Down *ev) { video_stop(inf->vid); elm_layout_signal_emit(inf->lay, "action,stop", "rage"); + if (inf->browse_mode) browser_show(win); } else if (!strcmp(ev->keyname, "c")) { @@ -178,7 +180,8 @@ key_handle(Evas_Object *win, Evas_Event_Key_Down *ev) } else if (!strcmp(ev->keyname, "backslash")) { - win_list_toggle(win); + if (inf->browse_mode) browser_toggle(win); + else win_list_toggle(win); } else if (!strcmp(ev->keyname, "y")) { diff --git a/src/bin/main.c b/src/bin/main.c index 31cf605..3746431 100644 --- a/src/bin/main.c +++ b/src/bin/main.c @@ -3,6 +3,7 @@ #include "win.h" #include "winvid.h" #include "winlist.h" +#include "browser.h" #include "config.h" static Eina_Bool @@ -20,6 +21,7 @@ static void _cb_resize(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { win_list_size_update(obj); + browser_size_update(obj); } EAPI_MAIN int @@ -32,6 +34,8 @@ elm_main(int argc, char **argv) Inf *inf; Config *config; Winvid_Entry *vid = NULL; + Eina_Bool fullscreen = EINA_FALSE; + int file_num = 0; elm_need_efreet(); config_init(); @@ -47,6 +51,8 @@ elm_main(int argc, char **argv) " -h | -help | --help\n" " This help\n" "\n" + " -f\n" + " Enable fullscreen mode at start\n" " -e ENGINE\n" " ENGINE is one of gstreamer1, xine or vlc\n" " The default is gstreamer1\n" @@ -68,6 +74,10 @@ elm_main(int argc, char **argv) config->emotion_engine = eina_stringshare_add(argv[i]); } } + else if (!strcmp(argv[i], "-f")) + { + fullscreen = EINA_TRUE; + } else if (!strcmp(argv[i], "-sub")) { if (i < (argc - 1)) @@ -81,6 +91,7 @@ elm_main(int argc, char **argv) vid = calloc(1, sizeof(Winvid_Entry)); if (vid) { + file_num++; vid->file = eina_stringshare_add(argv[i]); list = eina_list_append(list, vid); } @@ -112,8 +123,8 @@ elm_main(int argc, char **argv) evas_object_event_callback_add(win, EVAS_CALLBACK_RESIZE, _cb_resize, NULL); evas_object_resize(win, - 320 * elm_config_scale_get(), - 200 * elm_config_scale_get()); + 600 * elm_config_scale_get(), + 360 * elm_config_scale_get()); win_video_init(win); win_video_file_list_set(win, list); @@ -125,10 +136,14 @@ elm_main(int argc, char **argv) free(vid); } + if (fullscreen) elm_win_fullscreen_set(win, EINA_TRUE); + inf = evas_object_data_get(win, "inf"); - if (argc <= 1) + if (file_num <= 0) { - elm_layout_signal_emit(inf->lay, "about,show", "rage"); + inf->browse_mode = EINA_TRUE; + browser_show(win); +// elm_layout_signal_emit(inf->lay, "about,show", "rage"); evas_object_show(win); } else diff --git a/src/bin/thumb.c b/src/bin/thumb.c index 8996b57..4c07a64 100644 --- a/src/bin/thumb.c +++ b/src/bin/thumb.c @@ -1,18 +1,46 @@ #include +#include #include "sha1.h" +#include "albumart.h" static Evas_Object *win = NULL, *subwin = NULL, *image = NULL; static Evas_Object *vidimage = NULL; static int iw, ih; static unsigned char sum[20]; -static Eet_File *ef; +static Eet_File *ef = NULL; +static Ecore_Timer *vid_timeout = NULL; + +static void +_cb_fetched(void *data EINA_UNUSED) +{ + elm_exit(); +} + +static void +_cb_loaded(void *data, Evas_Object *obj, void *info EINA_UNUSED) +{ + const char *file, *title, *artist, *album; + + file = data; + title = emotion_object_meta_info_get(obj, EMOTION_META_INFO_TRACK_TITLE); + artist = emotion_object_meta_info_get(obj, EMOTION_META_INFO_TRACK_ARTIST); + album = emotion_object_meta_info_get(obj, EMOTION_META_INFO_TRACK_ALBUM); + + albumart_find(file, title, artist, album, _cb_fetched, (void *)file); +} + +static Eina_Bool +_cb_timeout(void *data EINA_UNUSED) +{ + vid_timeout = NULL; + elm_exit(); + return EINA_FALSE; +} EAPI_MAIN int elm_main(int argc, char **argv) { - char buf_base[PATH_MAX]; - char buf_file[PATH_MAX]; - unsigned int pos, incr; + Eina_Bool is_audio = EINA_FALSE; if (argc < 3) exit(1); elm_need_efreet(); @@ -33,54 +61,88 @@ elm_main(int argc, char **argv) elm_win_norender_push(subwin); elm_win_norender_push(win); - vidimage = evas_object_image_filled_add(evas_object_evas_get(subwin)); - evas_object_show(vidimage); - - evas_object_image_file_set(vidimage, argv[1], NULL); - evas_object_image_size_get(vidimage, &iw, &ih); - if (!sha1((unsigned char *)argv[1], strlen(argv[1]), sum)) exit(2); - if (!efreet_cache_home_get()) exit(3); - snprintf(buf_base, sizeof(buf_base), "%s/rage/thumb/%02x", - efreet_cache_home_get(), sum[0]); - snprintf(buf_file, sizeof(buf_base), - "%s/%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" - "%02x%02x%02x%02x%02x%02x%02x%02x.eet", - buf_base, - sum[1], sum[2], sum[3], - sum[4], sum[5], sum[6], sum[7], - sum[8], sum[9], sum[10], sum[11], - sum[12], sum[13], sum[14], sum[15], - sum[16], sum[17], sum[18], sum[19]); - if (!ecore_file_mkpath(buf_base)) exit(4); - ef = eet_open(buf_file, EET_FILE_MODE_WRITE); - if (!ef) exit(5); - pos = 0; - incr = atoi(argv[2]); - for (pos = 0; ; pos += incr) + const char *extn = strchr(argv[1], '.'); + if (extn) { - int w, h; - int *pixels; - char key[128]; - - snprintf(key, sizeof(key), "%i", pos); - evas_object_image_file_set(vidimage, argv[1], key); - evas_object_image_size_get(vidimage, &iw, &ih); - if ((iw <= 0) || (ih <= 0)) break; - w = 160; - h = (ih * 160) / iw; - if (h < 1) h = 1; - evas_object_resize(vidimage, w, h); - evas_object_resize(subwin, w, h); - elm_win_render(subwin); - pixels = evas_object_image_data_get(image, EINA_FALSE); - if (pixels) - eet_data_image_write(ef, key, pixels, w, h, - 0, 0, 70, EET_IMAGE_JPEG); - else - exit(6); - evas_object_image_data_set(image, pixels); + if ((!strcasecmp(extn, ".mp3")) || + (!strcasecmp(extn, ".m4a")) || + (!strcasecmp(extn, ".oga")) || + (!strcasecmp(extn, ".aac")) || + (!strcasecmp(extn, ".flac")) || + (!strcasecmp(extn, ".wav"))) + { + is_audio = EINA_TRUE; + } + } + if (is_audio) + { + Evas_Object *vid; + + vid = emotion_object_add(evas_object_evas_get(win)); + if (emotion_object_init(vid, NULL)) + { + evas_object_smart_callback_add(vid, "open_done", + _cb_loaded, argv[1]); + emotion_object_file_set(vid, argv[1]); + vid_timeout = ecore_timer_add(2.0, _cb_timeout, NULL); + elm_run(); + } + } + else + { + char buf_base[PATH_MAX]; + char buf_file[PATH_MAX]; + unsigned int pos, incr; + + vidimage = evas_object_image_filled_add(evas_object_evas_get(subwin)); + evas_object_show(vidimage); + + evas_object_image_file_set(vidimage, argv[1], NULL); + evas_object_image_size_get(vidimage, &iw, &ih); + if (!sha1((unsigned char *)argv[1], strlen(argv[1]), sum)) exit(2); + if (!efreet_cache_home_get()) exit(3); + snprintf(buf_base, sizeof(buf_base), "%s/rage/thumb/%02x", + efreet_cache_home_get(), sum[0]); + snprintf(buf_file, sizeof(buf_base), + "%s/%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x.eet", + buf_base, + sum[1], sum[2], sum[3], + sum[4], sum[5], sum[6], sum[7], + sum[8], sum[9], sum[10], sum[11], + sum[12], sum[13], sum[14], sum[15], + sum[16], sum[17], sum[18], sum[19]); + if (!ecore_file_mkpath(buf_base)) exit(4); + ef = eet_open(buf_file, EET_FILE_MODE_WRITE); + if (!ef) exit(5); + pos = 0; + incr = atoi(argv[2]); + for (pos = 0; ; pos += incr) + { + int w, h; + int *pixels; + char key[128]; + + snprintf(key, sizeof(key), "%i", pos); + evas_object_image_file_set(vidimage, argv[1], key); + evas_object_image_size_get(vidimage, &iw, &ih); + if ((iw <= 0) || (ih <= 0)) break; + w = 160; + h = (ih * 160) / iw; + if (h < 1) h = 1; + evas_object_resize(vidimage, w, h); + evas_object_resize(subwin, w, h); + elm_win_render(subwin); + pixels = evas_object_image_data_get(image, EINA_FALSE); + if (pixels) + eet_data_image_write(ef, key, pixels, w, h, + 0, 0, 70, EET_IMAGE_JPEG); + else + exit(6); + evas_object_image_data_set(image, pixels); + } + eet_close(ef); } - eet_close(ef); elm_shutdown(); return 0; } diff --git a/src/bin/video.c b/src/bin/video.c index 292c49d..1bc6c53 100644 --- a/src/bin/video.c +++ b/src/bin/video.c @@ -552,7 +552,6 @@ void video_file_set(Evas_Object *obj, const char *file) { Video *sd = evas_object_smart_data_get(obj); - const char *extn; if (!sd) return; evas_object_hide(sd->o_img); evas_object_hide(sd->o_vid); @@ -562,10 +561,11 @@ video_file_set(Evas_Object *obj, const char *file) video_position_set(obj, 0.0); if ((sd->file) && (sd->doart)) { - extn = strchr(sd->file, '.'); + const char *extn = strchr(sd->file, '.'); if (extn) { if ((!strcasecmp(extn, ".mp3")) || + (!strcasecmp(extn, ".m4a")) || (!strcasecmp(extn, ".oga")) || (!strcasecmp(extn, ".aac")) || (!strcasecmp(extn, ".flac")) || diff --git a/src/bin/videothumb.c b/src/bin/videothumb.c index 0dc3c90..222fde6 100644 --- a/src/bin/videothumb.c +++ b/src/bin/videothumb.c @@ -1,15 +1,18 @@ #include #include "videothumb.h" #include "sha1.h" +#include "albumart.h" typedef struct _Videothumb Videothumb; struct _Videothumb { Evas_Object_Smart_Clipped_Data __clipped_data; - Evas_Object *o_img; + Evas_Object *o_img, *o_img2; Ecore_Exe *thumb_exe; Ecore_Event_Handler *exe_handler; + Ecore_Timer *cycle_timer; + Ecore_Timer *launch_timer; const char *file; const char *realfile; char *realpath; @@ -26,6 +29,12 @@ static Evas_Smart_Class _parent_sc = EVAS_SMART_CLASS_INIT_NULL; static Eina_List *busy_thumbs = NULL; static Eina_List *vidthumbs = NULL; +static int _thumb_running = 0; + +static Eina_Bool _cb_thumb_exe(void *data, int type EINA_UNUSED, void *event); +static void _videothumb_eval(Evas_Object *obj, Eina_Bool force); +static void _smart_calculate(Evas_Object *obj); + static Eina_Bool _busy_add(const char *file) { @@ -66,14 +75,25 @@ _thumb_update(Evas_Object *obj) if (!sd) return; snprintf(buf, sizeof(buf), "%u", sd->realpos); - evas_object_image_file_set(sd->o_img, NULL, NULL); - evas_object_image_file_set(sd->o_img, sd->realfile, buf); - evas_object_image_size_get(sd->o_img, &(sd->iw), &(sd->ih)); + evas_object_image_file_set(sd->o_img2, NULL, NULL); + evas_object_image_file_set(sd->o_img2, sd->realfile, buf); + evas_object_image_size_get(sd->o_img2, &(sd->iw), &(sd->ih)); if ((sd->iw <= 0) || (sd->ih <= 0)) { - evas_object_del(sd->o_img); - sd->o_img = NULL; - evas_object_smart_callback_call(obj, "failed", NULL); + if (sd->cycle_timer) + { + sd->pos = 0.0; + if (!sd->thumb_exe) + { + _videothumb_eval(obj, EINA_TRUE); + } + } + else + { + evas_object_del(sd->o_img2); + sd->o_img2 = NULL; + evas_object_smart_callback_call(obj, "failed", NULL); + } } else { @@ -88,9 +108,79 @@ _thumb_match_update(Evas_Object *obj, const char *file) Videothumb *sd = evas_object_smart_data_get(obj); if (!sd) return; + if (!sd->realpath) return; if (!strcmp(sd->realpath, file)) _thumb_update(obj); } +static void +_videothumb_launch_do(Evas_Object *obj) +{ + Videothumb *sd = evas_object_smart_data_get(obj); + char buf[PATH_MAX]; + const char *libdir; + char *s; + + if (!sd) return; + ecore_exe_run_priority_set(10); + if (sd->thumb_exe) + { + _busy_del(sd->realpath); + ecore_exe_kill(sd->thumb_exe); + ecore_exe_free(sd->thumb_exe); + sd->thumb_exe = NULL; + _thumb_running--; + } + s = ecore_file_escape_name(sd->realpath); + if (s) + { + libdir = elm_app_lib_dir_get(); + if (libdir) + { + if (_busy_add(sd->realpath)) + { + if (!sd->exe_handler) + sd->exe_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, + _cb_thumb_exe, obj); + snprintf(buf, sizeof(buf), + "%s/rage/utils/rage_thumb %s 10000 >& /dev/null", + libdir, s); + sd->thumb_exe = ecore_exe_pipe_run(buf, + ECORE_EXE_TERM_WITH_PARENT | + ECORE_EXE_NOT_LEADER, + obj); + _thumb_running++; + } + else return; + } + free(s); + } +} + +static Eina_Bool +_cb_videothumb_delay(void *data) +{ + Evas_Object *obj = data; + Videothumb *sd = evas_object_smart_data_get(obj); + if (!sd) return EINA_FALSE; + if (_thumb_running < (eina_cpu_count() + 1)) + { + sd->launch_timer = NULL; + _videothumb_launch_do(obj); + return EINA_FALSE; + } + return EINA_TRUE; +} + +static void +_videothumb_launch(Evas_Object *obj) +{ + Videothumb *sd = evas_object_smart_data_get(obj); + + if (!sd) return; + if (sd->launch_timer) return; + sd->launch_timer = ecore_timer_add(1.0, _cb_videothumb_delay, obj); +} + static Eina_Bool _cb_thumb_exe(void *data, int type EINA_UNUSED, void *event) { @@ -105,6 +195,8 @@ _cb_thumb_exe(void *data, int type EINA_UNUSED, void *event) Evas_Object *o; _busy_del(sd->realpath); + sd->thumb_exe = NULL; + _thumb_running--; EINA_LIST_FOREACH(vidthumbs, l, o) { _thumb_match_update(o, sd->realpath); @@ -117,7 +209,6 @@ _cb_thumb_exe(void *data, int type EINA_UNUSED, void *event) sd->exe_handler = NULL; } } - sd->thumb_exe = NULL; return EINA_FALSE; } return EINA_TRUE; @@ -129,6 +220,9 @@ _cb_preload(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void Videothumb *sd = evas_object_smart_data_get(data); if (!sd) return; + if (sd->o_img) evas_object_del(sd->o_img); + sd->o_img = sd->o_img2; + sd->o_img2 = NULL; evas_object_show(sd->o_img); evas_object_smart_callback_call(data, "data", NULL); } @@ -140,35 +234,61 @@ _videothumb_image_load(Evas_Object *obj) char buf_base[PATH_MAX]; char buf_file[PATH_MAX]; char buf[PATH_MAX]; - char *s; - const char *libdir; unsigned char sum[20]; + Eina_Bool is_audio = EINA_FALSE; if (!sd) return; if (!sd->file) return; - sd->o_img = evas_object_image_filled_add(evas_object_evas_get(obj)); - evas_object_smart_member_add(sd->o_img, obj); - if (!sha1((unsigned char *)sd->realpath, strlen(sd->realpath), sum)) return; - snprintf(buf_base, sizeof(buf_base), "%s/rage/thumb/%02x", - efreet_cache_home_get(), sum[0]); - snprintf(buf_file, sizeof(buf_base), - "%s/%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" - "%02x%02x%02x%02x%02x%02x%02x%02x.eet", - buf_base, - sum[1], sum[2], sum[3], - sum[4], sum[5], sum[6], sum[7], - sum[8], sum[9], sum[10], sum[11], - sum[12], sum[13], sum[14], sum[15], - sum[16], sum[17], sum[18], sum[19]); - if (sd->realfile) eina_stringshare_del(sd->realfile); - sd->realfile = eina_stringshare_add(buf_file); - sd->realpos = (((unsigned int)(sd->pos * 1000.0)) / 10000) * 10000; - snprintf(buf, sizeof(buf), "%u", sd->realpos); - evas_object_event_callback_add(sd->o_img, + sd->o_img2 = evas_object_image_filled_add(evas_object_evas_get(obj)); + evas_object_smart_member_add(sd->o_img2, obj); + const char *extn = strchr(sd->realpath, '.'); + if (extn) + { + if ((!strcasecmp(extn, ".mp3")) || + (!strcasecmp(extn, ".m4a")) || + (!strcasecmp(extn, ".oga")) || + (!strcasecmp(extn, ".aac")) || + (!strcasecmp(extn, ".flac")) || + (!strcasecmp(extn, ".wav"))) + { + is_audio = EINA_TRUE; + } + } + if (is_audio) + { + char *artfile = albumart_file_get(sd->realpath); + if (artfile) + { + sd->realfile = eina_stringshare_add(artfile); + free(artfile); + } + } + else + { + if (!sha1((unsigned char *)sd->realpath, strlen(sd->realpath), sum)) + return; + snprintf(buf_base, sizeof(buf_base), "%s/rage/thumb/%02x", + efreet_cache_home_get(), sum[0]); + snprintf(buf_file, sizeof(buf_base), + "%s/%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x.eet", + buf_base, + sum[1], sum[2], sum[3], + sum[4], sum[5], sum[6], sum[7], + sum[8], sum[9], sum[10], sum[11], + sum[12], sum[13], sum[14], sum[15], + sum[16], sum[17], sum[18], sum[19]); + if (sd->realfile) eina_stringshare_del(sd->realfile); + sd->realfile = eina_stringshare_add(buf_file); + sd->realpos = (((unsigned int)(sd->pos * 1000.0)) / 10000) * 10000; + snprintf(buf, sizeof(buf), "%u", sd->realpos); + } + evas_object_event_callback_add(sd->o_img2, EVAS_CALLBACK_IMAGE_PRELOADED, _cb_preload, obj); - evas_object_image_file_set(sd->o_img, sd->realfile, buf); - evas_object_image_size_get(sd->o_img, &(sd->iw), &(sd->ih)); + evas_object_image_file_set(sd->o_img2, sd->realfile, buf); + evas_object_image_size_get(sd->o_img2, &(sd->iw), &(sd->ih)); + _smart_calculate(obj); if (sd->iw > 0) { Eina_Bool ok = EINA_FALSE; @@ -183,33 +303,28 @@ _videothumb_image_load(Evas_Object *obj) } if (ok) { - evas_object_image_preload(sd->o_img, EINA_FALSE); + evas_object_image_preload(sd->o_img2, EINA_FALSE); return; } } - if (!_busy_add(sd->realpath)) return; - ecore_exe_run_priority_set(10); - if (sd->thumb_exe) + if (sd->iw <= 0) { - ecore_exe_free(sd->thumb_exe); - sd->thumb_exe = NULL; - } - s = ecore_file_escape_name(sd->realpath); - if (s) - { - libdir = elm_app_lib_dir_get(); - if (libdir) + Eina_Bool ok = EINA_FALSE; + struct stat st1, st2; + + if (stat(sd->realpath, &st1) == 0) { - if (!sd->exe_handler) - sd->exe_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, - _cb_thumb_exe, obj); - snprintf(buf, sizeof(buf), - "%s/rage/utils/rage_thumb %s 10000 >& /dev/null", - libdir, s); - sd->thumb_exe = ecore_exe_pipe_run(buf, - ECORE_EXE_TERM_WITH_PARENT | - ECORE_EXE_NOT_LEADER, - obj); + if (stat(sd->realfile, &st2) == 0) + { + if (st1.st_mtime < st2.st_mtime) + { + ok = EINA_TRUE; + } + } + } + if (!ok) + { + _videothumb_launch(obj); } } } @@ -231,14 +346,14 @@ _videothumb_eval(Evas_Object *obj, Eina_Bool force) if (force) { sd->seen = seen; - if (sd->o_img) + if (sd->o_img2) { - evas_object_del(sd->o_img); - sd->o_img = NULL; + evas_object_del(sd->o_img2); + sd->o_img2 = NULL; } _videothumb_image_load(obj); - evas_object_move(sd->o_img, ox, oy); - evas_object_resize(sd->o_img, ow, oh); + evas_object_move(sd->o_img2, ox, oy); + evas_object_resize(sd->o_img2, ow, oh); } else { @@ -247,21 +362,21 @@ _videothumb_eval(Evas_Object *obj, Eina_Bool force) sd->seen = seen; if (sd->seen) { - if (sd->o_img) + if (sd->o_img2) { - evas_object_del(sd->o_img); - sd->o_img = NULL; + evas_object_del(sd->o_img2); + sd->o_img2 = NULL; } _videothumb_image_load(obj); - evas_object_move(sd->o_img, ox, oy); - evas_object_resize(sd->o_img, ow, oh); + evas_object_move(sd->o_img2, ox, oy); + evas_object_resize(sd->o_img2, ow, oh); } else { - if (sd->o_img) + if (sd->o_img2) { - evas_object_del(sd->o_img); - sd->o_img = NULL; + evas_object_del(sd->o_img2); + sd->o_img2 = NULL; } } } @@ -285,12 +400,24 @@ _smart_del(Evas_Object *obj) Videothumb *sd = evas_object_smart_data_get(obj); if (!sd) return; vidthumbs = eina_list_remove(vidthumbs, obj); + if (sd->thumb_exe) + { + if (sd->realpath) _busy_del(sd->realpath); + _thumb_running--; + ecore_exe_kill(sd->thumb_exe); + ecore_exe_free(sd->thumb_exe); + } + if (sd->launch_timer) + { + ecore_timer_del(sd->launch_timer); + } if (sd->file) eina_stringshare_del(sd->file); if (sd->realfile) eina_stringshare_del(sd->realfile); if (sd->realpath) free(sd->realpath); if (sd->o_img) evas_object_del(sd->o_img); - if (sd->thumb_exe) ecore_exe_free(sd->thumb_exe); + if (sd->o_img2) evas_object_del(sd->o_img2); if (sd->exe_handler) ecore_event_handler_del(sd->exe_handler); + if (sd->cycle_timer) ecore_timer_del(sd->cycle_timer); _parent_sc.del(obj); } @@ -321,6 +448,11 @@ _smart_calculate(Evas_Object *obj) evas_object_move(sd->o_img, ox, oy); evas_object_resize(sd->o_img, ow, oh); } + if (sd->o_img2) + { + evas_object_move(sd->o_img2, ox, oy); + evas_object_resize(sd->o_img2, ow, oh); + } } static void @@ -389,6 +521,39 @@ videothumb_file_set(Evas_Object *obj, const char *file, double pos) _videothumb_eval(obj, EINA_TRUE); } +static Eina_Bool +_cb_cycle(void *data) +{ + Evas_Object *obj = data; + Videothumb *sd = evas_object_smart_data_get(obj); + sd->pos += 10.0; + if (!sd->thumb_exe) + { + _videothumb_eval(obj, EINA_TRUE); + if (sd->iw <= 0) + { + sd->pos = 0; + _videothumb_eval(obj, EINA_TRUE); + } + } + return EINA_TRUE; +} + +void +videothumb_autocycle_set(Evas_Object *obj, Eina_Bool enabled) +{ + Videothumb *sd = evas_object_smart_data_get(obj); + if (!sd) return; + if (!enabled) + { + if (sd->cycle_timer) ecore_timer_del(sd->cycle_timer); + sd->cycle_timer = NULL; + return; + } + if (sd->cycle_timer) return; + sd->cycle_timer = ecore_timer_add(0.5, _cb_cycle, obj); +} + void videothumb_size_get(Evas_Object *obj, int *w, int *h) { diff --git a/src/bin/videothumb.h b/src/bin/videothumb.h index ce0029a..ab5c703 100644 --- a/src/bin/videothumb.h +++ b/src/bin/videothumb.h @@ -3,6 +3,7 @@ Evas_Object *videothumb_add(Evas_Object *parent); void videothumb_file_set(Evas_Object *obj, const char *file, double pos); +void videothumb_autocycle_set(Evas_Object *obj, Eina_Bool enabled); void videothumb_size_get(Evas_Object *obj, int *w, int *h); #endif diff --git a/src/bin/win.c b/src/bin/win.c index 4b95e9f..69151ca 100644 --- a/src/bin/win.c +++ b/src/bin/win.c @@ -9,6 +9,7 @@ #include "controls.h" #include "gesture.h" #include "albumart.h" +#include "browser.h" static void _cb_fullscreen(void *data EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED) @@ -23,9 +24,12 @@ static void _cb_unfullscreen(void *data EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED) { Inf *inf = evas_object_data_get(obj, "inf"); - elm_layout_signal_emit(inf->lay, "state,win,normal", "rage"); - elm_win_noblank_set(obj, EINA_FALSE); - evas_object_hide(inf->event2); + if (!elm_win_fullscreen_get(obj)) + { + elm_layout_signal_emit(inf->lay, "state,win,normal", "rage"); + elm_win_noblank_set(obj, EINA_FALSE); + evas_object_hide(inf->event2); + } } static void @@ -98,6 +102,23 @@ _cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, elm_win_fullscreen_set(data, !elm_win_fullscreen_get(data)); } +static void +_cb_fetched(void *data) +{ + Evas_Object *win = data; + Inf *inf = evas_object_data_get(win, "inf"); + const char *file; + + if (!inf->vid) return; + file = video_file_get(inf->vid); + if (file) + { + char *path = albumart_file_get(file); + win_art(win, path); + free(path); + } +} + static Eina_Bool _cb_albumart_delay(void *data) { @@ -109,8 +130,15 @@ _cb_albumart_delay(void *data) if (!inf->vid) return EINA_FALSE; if ((!video_has_video_get(inf->vid)) && (video_has_audio_get(inf->vid))) - albumart_find(win, inf->vid); - else albumart_find(win, NULL); + { + const char *file = video_file_get(inf->vid); + const char *title = video_meta_title_get(inf->vid); + const char *artist = video_meta_artist_get(inf->vid); + const char *album = video_meta_album_get(inf->vid); + + albumart_find(file, title, artist, album, _cb_fetched, win); + } + else albumart_find(NULL, NULL, NULL, NULL, NULL, NULL); return EINA_FALSE; } @@ -234,7 +262,8 @@ win_video_next(Evas_Object *win) else l = inf->file_cur->next; if (!l) { - elm_exit(); + if (inf->browse_mode) browser_show(win); + else elm_exit(); return; } inf->file_cur = l; diff --git a/src/bin/win.h b/src/bin/win.h index 049a858..16a26b6 100644 --- a/src/bin/win.h +++ b/src/bin/win.h @@ -23,6 +23,7 @@ struct _Inf Eina_Bool playing : 1; Eina_Bool was_playing : 1; Eina_Bool dragging : 1; + Eina_Bool browse_mode : 1; }; // ui high level controls diff --git a/src/bin/winvid.c b/src/bin/winvid.c index 1fd7da7..8e98a0d 100644 --- a/src/bin/winvid.c +++ b/src/bin/winvid.c @@ -5,6 +5,7 @@ #include "winlist.h" #include "winvid.h" #include "videothumb.h" +#include "browser.h" static void _cb_resize(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) @@ -36,7 +37,11 @@ _cb_stop(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) if (inf->next_job) ecore_job_del(inf->next_job); inf->next_job = ecore_job_add(_cb_stop_next, data); } - else elm_exit(); + else + { + if (inf->browse_mode) browser_show(data); + else elm_exit(); + } } static void @@ -210,6 +215,15 @@ win_video_file_list_set(Evas_Object *win, Eina_List *list) Eina_List *l, *list2 = NULL; Winvid_Entry *vid; + inf->file_cur = NULL; + EINA_LIST_FREE(inf->file_list, vid) + { + if (vid->file) eina_stringshare_del(vid->file); + if (vid->sub) eina_stringshare_del(vid->sub); + if (vid->uri) efreet_uri_free(vid->uri); + free(vid); + } + EINA_LIST_FOREACH(list, l, vid) { Winvid_Entry *vid2; @@ -224,7 +238,7 @@ win_video_file_list_set(Evas_Object *win, Eina_List *list) } } inf->file_list = list2; - win_video_next(win); + win_video_first(win); } void