From 74ba92ebc78e60ad140198db9694777a17d4fa16 Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Sun, 26 Sep 2010 15:01:28 +0200 Subject: fixed several hangs/slowdowns/bugs in playlist selection code --- plugins/gtkui/callbacks.c | 8 +++++ plugins/gtkui/ddblistview.c | 85 ++++++++++++++++++++++++++++++++++---------- plugins/gtkui/ddblistview.h | 4 +++ plugins/gtkui/mainplaylist.c | 7 +++- plugins/gtkui/search.c | 7 +++- 5 files changed, 91 insertions(+), 20 deletions(-) diff --git a/plugins/gtkui/callbacks.c b/plugins/gtkui/callbacks.c index 433649d8..cd06eff3 100644 --- a/plugins/gtkui/callbacks.c +++ b/plugins/gtkui/callbacks.c @@ -249,6 +249,10 @@ on_select_all1_activate (GtkMenuItem *menuitem, deadbeef->pl_select_all (); DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist")); ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_EXPOSE_LIST); + pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist")); + if (pl) { + ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_EXPOSE_LIST); + } } @@ -932,6 +936,10 @@ on_deselect_all1_activate (GtkMenuItem *menuitem, deadbeef->pl_unlock (); DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist")); ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_EXPOSE_LIST); + pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist")); + if (pl) { + ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_EXPOSE_LIST); + } } diff --git a/plugins/gtkui/ddblistview.c b/plugins/gtkui/ddblistview.c index d17ded26..1109e902 100644 --- a/plugins/gtkui/ddblistview.c +++ b/plugins/gtkui/ddblistview.c @@ -42,6 +42,7 @@ #define DEFAULT_GROUP_TITLE_HEIGHT 30 #define SCROLL_STEP 20 #define AUTOSCROLL_UPDATE_FREQ 0.01f +#define NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW 10 //#define trace(...) { fprintf(stderr, __VA_ARGS__); } #define trace(fmt,...) @@ -320,6 +321,9 @@ ddb_listview_init(DdbListview *listview) listview->cursor_sz = NULL; listview->cursor_drag = NULL; + listview->area_selection_start = 0; + listview->area_selection_end = 0; + GtkWidget *hbox; GtkWidget *vbox; @@ -1307,29 +1311,44 @@ ddb_listview_header_expose (DdbListview *ps, int x, int y, int w, int h) { void ddb_listview_select_single (DdbListview *ps, int sel) { + int nchanged = 0; int idx=0; DdbListviewIter it = ps->binding->head (); for (; it; idx++) { if (idx == sel) { if (!ps->binding->is_selected (it)) { ps->binding->select (it, 1); - ddb_listview_draw_row (ps, idx, it); - ps->binding->selection_changed (it, idx); + if (nchanged < NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) { + ddb_listview_draw_row (ps, idx, it); + ps->binding->selection_changed (it, idx); + } + nchanged++; } else if (ps->binding->cursor () == idx) { - ddb_listview_draw_row (ps, idx, it); + if (nchanged < NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) { + ddb_listview_draw_row (ps, idx, it); + } } } else if (ps->binding->is_selected (it)) { ps->binding->select (it, 0); - ddb_listview_draw_row (ps, idx, it); - ps->binding->selection_changed (it, idx); + if (nchanged < NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) { + ddb_listview_draw_row (ps, idx, it); + ps->binding->selection_changed (it, idx); + } + nchanged++; } DdbListviewIter next = PL_NEXT (it); UNREF (it); it = next; } UNREF (it); + if (nchanged >= NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) { + ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_EXPOSE_LIST); + ps->binding->selection_changed (it, -1); // that means "selection changed a lot, redraw everything" + } + ps->area_selection_start = sel; + ps->area_selection_end = sel; } void @@ -1722,26 +1741,45 @@ ddb_listview_list_mousemove (DdbListview *ps, GdkEventMotion *ev, int ex, int ey int start = min (y, ps->shift_sel_anchor); int end = max (y, ps->shift_sel_anchor); - idx=0; - DdbListviewIter it; - for (it = ps->binding->head (); it; idx++) { + int nchanged = 0; + + // don't touch anything in process_start/end range + int process_start = min (start, ps->area_selection_start); + int process_end = max (end, ps->area_selection_end); + + idx=process_start; + DdbListviewIter it = ps->binding->get_for_idx (idx); + for (; it && idx <= process_end; idx++) { + int selected = ps->binding->is_selected (it); if (idx >= start && idx <= end) { - if (!ps->binding->is_selected (it)) { + if (!selected) { ps->binding->select (it, 1); - ddb_listview_draw_row (ps, idx, it); - ps->binding->selection_changed (it, idx); + nchanged++; + if (nchanged < NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) { + ddb_listview_draw_row (ps, idx, it); + ps->binding->selection_changed (it, idx); + } } } - else if (ps->binding->is_selected (it)) { + else if (selected) { ps->binding->select (it, 0); - ddb_listview_draw_row (ps, idx, it); - ps->binding->selection_changed (it, idx); + nchanged++; + if (nchanged < NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) { + ddb_listview_draw_row (ps, idx, it); + ps->binding->selection_changed (it, idx); + } } DdbListviewIter next = PL_NEXT(it); UNREF (it); it = next; } UNREF (it); + if (nchanged >= NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) { + ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_EXPOSE_LIST); + ps->binding->selection_changed (it, -1); // that means "selection changed a lot, redraw everything" + } + ps->area_selection_start = start; + ps->area_selection_end = end; } if (sel != -1 && sel != prev) { if (prev != -1) { @@ -1903,25 +1941,36 @@ ddb_listview_handle_keypress (DdbListview *ps, int keyval, int state) { // select all between shift_sel_anchor and deadbeef->pl_get_cursor (ps->iterator) int start = min (cursor, ps->shift_sel_anchor); int end = max (cursor, ps->shift_sel_anchor); + + int nchanged = 0; int idx=0; + DdbListviewIter it; for (it = ps->binding->head (); it; idx++) { if (idx >= start && idx <= end) { ps->binding->select (it, 1); - ddb_listview_draw_row (ps, idx, it); - ps->binding->selection_changed (it, idx); + if (nchanged < NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) { + ddb_listview_draw_row (ps, idx, it); + ps->binding->selection_changed (it, idx); + } } else if (ps->binding->is_selected (it)) { ps->binding->select (it, 0); - ddb_listview_draw_row (ps, idx, it); - ps->binding->selection_changed (it, idx); + if (nchanged < NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) { + ddb_listview_draw_row (ps, idx, it); + ps->binding->selection_changed (it, idx); + } } DdbListviewIter next = PL_NEXT(it); UNREF (it); it = next; } UNREF (it); + if (nchanged >= NUM_CHANGED_ROWS_BEFORE_FULL_REDRAW) { + ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_EXPOSE_LIST); + ps->binding->selection_changed (it, -1); // that means "selection changed a lot, redraw everything" + } } } else { diff --git a/plugins/gtkui/ddblistview.h b/plugins/gtkui/ddblistview.h index 9ffaa5d5..20b5f72c 100644 --- a/plugins/gtkui/ddblistview.h +++ b/plugins/gtkui/ddblistview.h @@ -145,6 +145,10 @@ struct _DdbListview { int block_redraw_on_scroll; int grouptitle_height; + // previous area selection range + int area_selection_start; + int area_selection_end; + GdkCursor *cursor_sz; GdkCursor *cursor_drag; }; diff --git a/plugins/gtkui/mainplaylist.c b/plugins/gtkui/mainplaylist.c index 84e62951..2df3bd0e 100644 --- a/plugins/gtkui/mainplaylist.c +++ b/plugins/gtkui/mainplaylist.c @@ -148,7 +148,12 @@ void main_handle_doubleclick (DdbListview *listview, DdbListviewIter iter, int i void main_selection_changed (DdbListviewIter it, int idx) { DdbListview *search = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist")); - ddb_listview_draw_row (search, search_get_idx ((DB_playItem_t *)it), it); + if (idx == -1) { + ddb_listview_refresh (search, DDB_REFRESH_LIST | DDB_EXPOSE_LIST); + } + else { + ddb_listview_draw_row (search, search_get_idx ((DB_playItem_t *)it), it); + } } void main_draw_group_title (DdbListview *listview, GdkDrawable *drawable, DdbListviewIter it, int x, int y, int width, int height) { diff --git a/plugins/gtkui/search.c b/plugins/gtkui/search.c index 4d73f659..ee096930 100644 --- a/plugins/gtkui/search.c +++ b/plugins/gtkui/search.c @@ -369,7 +369,12 @@ void search_handle_doubleclick (DdbListview *listview, DdbListviewIter iter, int void search_selection_changed (DdbListviewIter it, int idx) { DdbListview *main = DDB_LISTVIEW (lookup_widget (mainwin, "playlist")); - ddb_listview_draw_row (main, main_get_idx ((DB_playItem_t *)it), it); + if (idx == -1) { + ddb_listview_refresh (main, DDB_REFRESH_LIST | DDB_EXPOSE_LIST); + } + else { + ddb_listview_draw_row (main, main_get_idx ((DB_playItem_t *)it), it); + } } void -- cgit v1.2.3