From 89959af3eb25dfbf7daad8c66e6c43a1d1b579b2 Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Tue, 4 Feb 2020 23:26:48 +0000 Subject: [PATCH] browser - optimize to only load the file entries as they appear so as you scroll it'll load/create and not per dir. this gets rid of big stalls as a whole dir worth of edje and thumb/album objects are created and packed etc. ... now it's far more smooth. i could try and spread the entry creation over time too instead of all of them that appear at any time which might be smoother, but pretty good right now. it also destroys as items go out of the window --- src/bin/browser.c | 332 +++++++++++++++++++++++++++++++--------------- 1 file changed, 222 insertions(+), 110 deletions(-) diff --git a/src/bin/browser.c b/src/bin/browser.c index 38bd48c..65e1ec4 100644 --- a/src/bin/browser.c +++ b/src/bin/browser.c @@ -36,6 +36,7 @@ struct _Entry Evas_Object *table; Evas_Object *sizer; Evas_Coord iw, ih; + Evas_Object **file_obj; int cols, rows; int sel_x, sel_y; Eina_Bool sel : 1; @@ -58,6 +59,7 @@ static Entry *dir_entry = NULL; static Eina_List *entries = NULL; static Ecore_Timer *_browser_hide_focus_restore_timer = NULL; static Eina_Semaphore step_sema; +static Ecore_Timer *initial_update_timer = NULL; static void _sel_go(Evas_Object *win EINA_UNUSED, Entry *base_entry, int x, int y); @@ -294,74 +296,151 @@ _cb_file_selected(void *data, Evas_Object *obj, const char *sig EINA_UNUSED, con } static void -_entry_files_pop(Evas_Object *win, Entry *entry) +_entry_files_pop_clear(Entry *entry) +{ + int i, k; + + // if we had any content at all before - nuke it all + if ((entry->sels) && (entry->file_obj)) + { + entry->sels = eina_list_free(entry->sels); + k = entry->cols * entry->rows; + for (i = 0; i < k; i++) + { + if (entry->file_obj[i]) + { + evas_object_del(entry->file_obj[i]); + entry->file_obj[i] = NULL; + } + } + } +} + +static void +_entry_files_pop_eval(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; + Eina_List *l; + Evas_Object **obj; + Evas_Coord win_w, win_h, ent_x, ent_y, ent_w, ent_h; + int i = 0, j = 0; + Eina_Rectangle win_rect, file_rect; - if (evas_object_data_get(entry->table, "populated")) return; - evas_object_data_set(entry->table, "populated", entry->table); + evas_object_geometry_get(entry->table, &ent_x, &ent_y, &ent_w, &ent_h); + evas_object_geometry_get(win, NULL, NULL, &win_w, &win_h); + win_rect.x = 0; + win_rect.y = 0; + win_rect.w = win_w; + win_rect.h = win_h; + // if we're not in the viewport at all empty all content + file_rect.x = ent_x; + file_rect.y = ent_y; + file_rect.w = ent_w; + file_rect.h = ent_h; + file_rect.x -= 80; + file_rect.y -= 80; + file_rect.w += 160; + file_rect.h += 160; + if (!eina_rectangles_intersect(&win_rect, &file_rect)) + { + _entry_files_pop_clear(entry); + return; + } + // walk files to find which intersect the window 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"); - if (elm_win_fullscreen_get(win)) - elm_layout_signal_emit(base, "state,fullscreen", "rage"); + file_rect.x = ent_x + ((i * ent_w) / entry->cols); + file_rect.y = ent_y + ((j * ent_h) / entry->rows); + file_rect.w = (ent_w / entry->cols); + file_rect.h = (ent_h / entry->rows); + file_rect.x -= 80; + file_rect.y -= 80; + file_rect.w += 160; + file_rect.h += 160; + obj = &(entry->file_obj[(j * entry->cols) + i]); + if (eina_rectangles_intersect(&win_rect, &file_rect)) + { + if (!(*obj)) + { + Evas_Object *o, *base; + char buf[PATH_MAX], *p; + + base = o = elm_layout_add(win); + *obj = o; + 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"); + if (elm_win_fullscreen_get(win)) + elm_layout_signal_emit(base, "state,fullscreen", "rage"); + else + elm_layout_signal_emit(base, "state,normal", "rage"); + snprintf(buf, sizeof(buf), "%s", file); + for (p = buf; *p; p++) + { + // nuke stupid characters from the label that may be + // in filename + if ((*p == '_') || (*p == '#') || (*p == '$') || + (*p == '%') || (*p == '*') || (*p == '+') || + (*p == '[') || (*p == ']') || (*p == ';') || + (*p == '<') || (*p == '=') || (*p == '>') || + (*p == '^') || (*p == '`') || (*p == '{') || + (*p == '}') || (*p == '|') || (*p == '~') || + (*p == 127) || (*p == '\'') || (*p == '\\')) + { + *p = ' '; + } + else if (*p == '.') + { + *p = 0; + break; + } + } + 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); + videothumb_poster_mode_set(o, EINA_TRUE); + 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"); + evas_object_raise(base); + } + } + } else - elm_layout_signal_emit(base, "state,normal", "rage"); - snprintf(buf, sizeof(buf), "%s", file); - for (p = buf; *p; p++) { - // nuke stupid characters from the label that may be in filename - if ((*p == '_') || (*p == '#') || (*p == '$') || (*p == '%') || - (*p == '*') || (*p == '+') || (*p == '[') || (*p == ']') || - (*p == ';') || (*p == '<') || (*p == '=') || (*p == '>') || - (*p == '^') || (*p == '`') || (*p == '{') || (*p == '}') || - (*p == '|') || (*p == '~') || (*p == 127) || - (*p == '\'') || (*p == '\\')) + if (*obj) { - *p = ' '; - } - else if (*p == '.') - { - *p = 0; - break; + entry->sels = eina_list_remove(entry->sels, *obj); + evas_object_del(*obj); + *obj = NULL; } } - 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); - videothumb_poster_mode_set(o, EINA_TRUE); - 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"); - evas_object_raise(base); - } - i++; if (i == entry->cols) { @@ -369,27 +448,14 @@ _entry_files_pop(Evas_Object *win, Entry *entry) 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) +_entry_update(Evas_Object *win, 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); + eina_lock_take(&(entry->lock)); + _entry_files_pop_eval(win, entry); + eina_lock_release(&(entry->lock)); } static void @@ -411,10 +477,8 @@ _entry_files_redo(Evas_Object *win, Entry *entry) { Evas_Coord x, y,w, h, iw = 1, ih = 1, ww, wh, sw, sh; int num, cols, rows; - Eina_Rectangle r1, r2; eina_lock_take(&(entry->lock)); - if (elm_win_fullscreen_get(win)) elm_layout_signal_emit(entry->base, "state,fullscreen", "rage"); else @@ -426,6 +490,10 @@ _entry_files_redo(Evas_Object *win, Entry *entry) elm_scroller_region_get(sc, NULL, NULL, &sw, &sh); if (sw < w) w = sw; + _entry_files_pop_clear(entry); + free(entry->file_obj); + entry->file_obj = NULL; + _item_size_get(win, &iw, &ih); cols = w / iw; if (cols < 1) cols = 1; @@ -436,11 +504,17 @@ _entry_files_redo(Evas_Object *win, Entry *entry) 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); + entry->file_obj = calloc(entry->cols * entry->rows, + sizeof(Evas_Object *)); + 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); + evas_object_size_hint_min_set(entry->sizer, + entry->cols * entry->iw, + entry->rows * entry->ih); + _entry_files_pop_eval(win, entry); if (selfile) { @@ -471,32 +545,16 @@ _cb_entry_table_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *in { 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)); + if (initial_update_timer) return; + _entry_update(win, entry); } static void -_cb_entry_table_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) +_cb_entry_table_resize(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) { Entry *entry = data; Evas_Object *win = evas_object_data_get(obj, "win"); + if (initial_update_timer) return; _entry_files_redo(win, entry); } @@ -506,14 +564,30 @@ _cb_scroller_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSE Inf *inf = evas_object_data_get(data, "inf"); Eina_List *l; Entry *entry; - if (!inf) return; - if (!bx) return; + if ((!inf) || (!bx)) return; + if (initial_update_timer) return; EINA_LIST_FOREACH(entries, l, entry) { _entry_files_redo(data, entry); } } +static Eina_Bool +_cb_initial_update_timer(void *data) +{ + Inf *inf = evas_object_data_get(data, "inf"); + Eina_List *l; + Entry *entry; + + initial_update_timer = NULL; + if ((!inf) || (!bx)) return EINA_FALSE; + EINA_LIST_FOREACH(entries, l, entry) + { + _entry_files_redo(data, entry); + } + return EINA_FALSE; +} + static void _fill_feedback(void *data, Ecore_Thread *th, void *msg) { @@ -575,7 +649,6 @@ _fill_feedback(void *data, Ecore_Thread *th, void *msg) 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) || ((entry->parent) && (!entry->parent->parent)) || @@ -584,6 +657,7 @@ _fill_feedback(void *data, Ecore_Thread *th, void *msg) else elm_box_pack_end(entry->parent->box, entry->base); evas_object_show(entry->base); + } } entries = eina_list_append(entries, entry); @@ -591,7 +665,36 @@ _fill_feedback(void *data, Ecore_Thread *th, void *msg) } else if ((message->type == TYPE_FINISH) && (entry->parent)) { - _entry_files_redo(win, entry); + if (!initial_update_timer) + _entry_files_redo(win, entry); + else + { + int iw, ih, cols, rows, num; + Evas_Coord w, h; + + eina_lock_take(&(entry->lock)); + num = eina_list_count(entry->files); + evas_object_geometry_get(entry->table, NULL, NULL, &w, &h); + _item_size_get(win, &iw, &ih); + cols = w / iw; + if (cols < 1) cols = 1; + rows = (num + (cols - 1)) / cols; + + entry->iw = iw - 1; + entry->ih = ih - 1; + entry->cols = cols; + entry->rows = rows; + + evas_object_size_hint_min_set(entry->sizer, + entry->cols * entry->iw, + entry->rows * entry->ih); + 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); + eina_lock_release(&(entry->lock)); + } } } // allow the freedback thread to step more @@ -626,14 +729,15 @@ _entry_free(Entry *entry) if (!entry) return; eina_lock_take(&(entry->lock)); entry->sels = eina_list_free(entry->sels); + free(entry->file_obj); EINA_LIST_FREE(entry->files, str) eina_stringshare_del(str); EINA_LIST_FREE(entry->dirs, subentry) _entry_free(subentry); if (entry->base) evas_object_del(entry->base); eina_stringshare_del(entry->path); - eina_lock_release(&(entry->lock)); - eina_lock_free(&(entry->lock)); if (entry == selentry) selentry = NULL; entries = eina_list_remove(entries, entry); + eina_lock_release(&(entry->lock)); + eina_lock_free(&(entry->lock)); free(entry); } @@ -688,7 +792,8 @@ 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); + if (!entry->file_obj) return NULL; + Evas_Object *o = entry->file_obj[num]; return o; } @@ -1021,6 +1126,7 @@ browser_show(Evas_Object *win) focus_timer = ecore_timer_add(0.7, _browser_focus_timer_cb, bt); } elm_layout_signal_emit(inf->lay, "browser,state,visible", "rage"); + initial_update_timer = ecore_timer_add(0.2, _cb_initial_update_timer, win); } static void @@ -1054,6 +1160,11 @@ browser_hide(Evas_Object *win) Inf *inf = evas_object_data_get(win, "inf"); if (!bx) return; + if (initial_update_timer) + { + ecore_timer_del(initial_update_timer); + initial_update_timer = NULL; + } if (focus_timer) ecore_timer_del(focus_timer); focus_timer = NULL; elm_layout_signal_callback_add(inf->lay, "browser,state,hidden,finished", "rage", @@ -1078,10 +1189,10 @@ browser_size_update(Evas_Object *win) Entry *entry; if (!inf) return; if (!bx) return; + if (initial_update_timer) return; EINA_LIST_FOREACH(entries, l, entry) { - _cb_entry_table_move(entry, evas_object_evas_get(entry->table), - entry->table, NULL); + _entry_files_redo(win, entry); } } @@ -1093,6 +1204,7 @@ browser_fullscreen(Evas_Object *win, EINA_UNUSED Eina_Bool enabled) Entry *entry; if (!inf) return; if (!bx) return; + if (initial_update_timer) return; EINA_LIST_FOREACH(entries, l, entry) { _entry_files_redo(win, entry);