rage - add "browser" when run with no args - index ~/Videos

this adds a video browser that indexes everything in ~/Videos
flattening subdirs into categories. It also will handle music and
fetch album art. browser can be mouse or key controlled. makes rage
almost media-centerey. not intended as a replacement tho, but just
that it's handy to throw in.
This commit is contained in:
Carsten Haitzler 2015-10-10 16:51:49 +09:00
parent 1d492a6847
commit b4b380ce1f
15 changed files with 1489 additions and 151 deletions

View File

@ -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";
}
}
}
}

View File

@ -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

View File

@ -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;

View File

@ -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

828
src/bin/browser.c Normal file
View File

@ -0,0 +1,828 @@
#include <Elementary.h>
#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
}

9
src/bin/browser.h Normal file
View File

@ -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

View File

@ -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"))
{

View File

@ -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

View File

@ -1,18 +1,46 @@
#include <Elementary.h>
#include <Emotion.h>
#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;
}

View File

@ -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")) ||

View File

@ -1,15 +1,18 @@
#include <Elementary.h>
#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)
{

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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