From 736c68a680d001271c19a2c45fbad5a35579f96c Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Sun, 28 Feb 2010 21:46:13 +0100 Subject: cover art WIP --- deadbeef.h | 1 + pixmaps/Makefile.am | 3 +- pixmaps/blank_cd.jpg | Bin 0 -> 9577 bytes plugins.c | 1 + plugins/artwork/artwork.c | 195 ++++++++++++++++++++++++++++++++++++------- plugins/gtkui/coverart.c | 79 ++++++++++++++---- plugins/gtkui/ddblistview.c | 45 +++++++--- plugins/gtkui/ddblistview.h | 2 +- plugins/gtkui/mainplaylist.c | 29 +++++-- threading.h | 3 + threading_pthread.c | 4 +- 11 files changed, 289 insertions(+), 73 deletions(-) create mode 100644 pixmaps/blank_cd.jpg diff --git a/deadbeef.h b/deadbeef.h index 89578987..16c114ae 100644 --- a/deadbeef.h +++ b/deadbeef.h @@ -270,6 +270,7 @@ typedef struct { intptr_t (*thread_start) (void (*fn)(void *ctx), void *ctx); int (*thread_join) (intptr_t tid); uintptr_t (*mutex_create) (void); + uintptr_t (*mutex_create_nonrecursive) (void); void (*mutex_free) (uintptr_t mtx); int (*mutex_lock) (uintptr_t mtx); int (*mutex_unlock) (uintptr_t mtx); diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am index fd8452cd..024279af 100644 --- a/pixmaps/Makefile.am +++ b/pixmaps/Makefile.am @@ -9,7 +9,8 @@ pause_24.png\ play_24.png\ prev_24.png\ random_24.png\ -stop_24.png +stop_24.png\ +blank_cd.jpg EXTRA_DIST = $(pixmaps_DATA) diff --git a/pixmaps/blank_cd.jpg b/pixmaps/blank_cd.jpg new file mode 100644 index 00000000..53d62cb6 Binary files /dev/null and b/pixmaps/blank_cd.jpg differ diff --git a/plugins.c b/plugins.c index b9d327e2..748f1e9e 100644 --- a/plugins.c +++ b/plugins.c @@ -93,6 +93,7 @@ static DB_functions_t deadbeef_api = { .thread_start = thread_start, .thread_join = thread_join, .mutex_create = mutex_create, + .mutex_create_nonrecursive = mutex_create_nonrecursive, .mutex_free = mutex_free, .mutex_lock = mutex_lock, .mutex_unlock = mutex_unlock, diff --git a/plugins/artwork/artwork.c b/plugins/artwork/artwork.c index a136d29e..6f34b8ce 100644 --- a/plugins/artwork/artwork.c +++ b/plugins/artwork/artwork.c @@ -5,17 +5,85 @@ #include #include #include +#include #include "../../deadbeef.h" #include "artwork.h" #include "lastfm.h" #include "albumartorg.h" +#define min(x,y) ((x)<(y)?(x):(y)) //#define trace(...) { fprintf(stderr, __VA_ARGS__); } #define trace(...) +#define DEFAULT_COVER_PATH (PREFIX "/share/deadbeef/pixmaps/blank_cd.jpg") + static DB_artwork_plugin_t plugin; DB_functions_t *deadbeef; + +typedef struct cover_query_s { + char *artist; + char *album; + artwork_callback callback; + struct cover_query_s *next; +} cover_query_t; + +cover_query_t *queue; +cover_query_t *queue_tail; +uintptr_t mutex; +int terminate; +intptr_t tid; + +void +queue_add (const char *artist, const char *album, artwork_callback callback) { + if (!artist) { + artist = ""; + } + if (!album) { + album = ""; + } + printf ("queue_add %s %s\n", album, artist); + deadbeef->mutex_lock (mutex); + + for (cover_query_t *q = queue; q; q = q->next) { + if (!strcasecmp (artist, q->artist) || !strcasecmp (album, q->album)) { + deadbeef->mutex_unlock (mutex); + return; // already in queue + } + } + + cover_query_t *q = malloc (sizeof (cover_query_t)); + memset (q, 0, sizeof (cover_query_t)); + q->artist = strdup (artist); + q->album = strdup (album); + q->callback = callback; + if (queue_tail) { + queue_tail->next = q; + queue_tail = q; + } + else { + queue = queue_tail = q; + } + deadbeef->mutex_unlock (mutex); + printf ("queue_added %s %s\n", album, artist); +} + +void +queue_pop (void) { + printf ("queue_pop\n"); + deadbeef->mutex_lock (mutex); + cover_query_t *next = queue ? queue->next : NULL; + free (queue->artist); + free (queue->album); + free (queue); + queue = next; + if (!queue) { + queue_tail = NULL; + } + deadbeef->mutex_unlock (mutex); + printf ("queue_popped\n"); +} + int fetch_to_stream (const char *url, FILE *stream) { @@ -47,8 +115,9 @@ fetch_to_file (const char *url, const char *filename) return 0; } ret = fetch_to_stream (url, stream); - if (ret != 0) - printf ("Failed to fetch %s\n", url); + if (ret != 0) { +// printf ("Failed to fetch %s\n", url); + } fclose (stream); if (0 == ret) { @@ -99,34 +168,90 @@ check_dir (const char *dir, mode_t mode) return 1; } -typedef struct -{ - const char *artist; - const char *album; - artwork_callback callback; -} fetcher_thread_param_t; +#define BUFFER_SIZE 4096 + +static int +copy_file (const char *in, const char *out) { + char *buf = malloc (BUFFER_SIZE); + if (!buf) { + fprintf (stderr, "artwork: failed to alloc %d bytes\n", BUFFER_SIZE); + return -1; + } + FILE *fin = fopen (in, "rb"); + if (!fin) { + fprintf (stderr, "artwork: failed to open file %s\n", in); + return -1; + } + FILE *fout = fopen (out, "w+b"); + if (!fout) { + fclose (fin); + fprintf (stderr, "artwork: failed to open file %s\n", out); + return -1; + } + + fseek (fin, 0, SEEK_END); + size_t sz = ftell (fin); + rewind (fin); + + while (sz > 0) { + int rs = min (sz, BUFFER_SIZE); + if (fread (buf, rs, 1, fin) != 1) { + fprintf (stderr, "artwork: failed to read file %s\n", in); + break; + } + if (fwrite (buf, rs, 1, fout) != 1) { + fprintf (stderr, "artwork: failed to write file %s\n", out); + break; + } + sz -= rs; + } + free (buf); + fclose (fin); + fclose (fout); + if (sz > 0) { + unlink (out); + } + return 0; +} static void -fetcher_thread (fetcher_thread_param_t *param) +fetcher_thread (void *none) { - char path [1024]; + while (!terminate) { + if (!queue) { + usleep (100000); + continue; + } + cover_query_t *param = queue; - snprintf (path, sizeof (path), "%s/artcache/%s", deadbeef->get_config_dir (), param->artist); - if (!check_dir (path, 0755)) - goto finalize; + printf ("fetching cover for %s %s\n", param->album, param->artist); - snprintf (path, sizeof (path), "%s/artcache/%s/%s.jpg", deadbeef->get_config_dir (), param->artist, param->album); + char path [1024]; + snprintf (path, sizeof (path), "%s/artcache/%s", deadbeef->get_config_dir (), param->artist); + if (!check_dir (path, 0755)) { + queue_pop (); + printf ("failed to create folder for %s %s\n", param->album, param->artist); + continue; + } - if (!fetch_from_lastfm (param->artist, param->album, path)) - if (!fetch_from_albumart_org (param->artist, param->album, path)) - goto finalize; + snprintf (path, sizeof (path), "%s/artcache/%s/%s.jpg", deadbeef->get_config_dir (), param->artist, param->album); - if (param->callback) - param->callback (param->artist, param->album); + if (!fetch_from_lastfm (param->artist, param->album, path)) { + if (!fetch_from_albumart_org (param->artist, param->album, path)) { + printf ("art not found for %s %s\n", param->album, param->artist); + queue_pop (); + copy_file (DEFAULT_COVER_PATH, path); + continue; + } + } -finalize: - free (param); - return; + printf ("downloaded art for %s %s\n", param->album, param->artist); + if (param->callback) { + param->callback (param->artist, param->album); + } + queue_pop (); + } + tid = 0; } static int @@ -177,27 +302,22 @@ get_album_art (DB_playItem_t *track, artwork_callback callback) if (!artist || !*artist || !album || !*album) { //give up - return PREFIX "/share/deadbeef/pixmaps/blank_cd.jpg"; + return strdup (DEFAULT_COVER_PATH); } snprintf (path, sizeof (path), "%s/artcache/%s/%s.jpg", deadbeef->get_config_dir (), artist, album); +// printf ("looking for %s in cache\n", path); struct stat stat_buf; if (0 == stat (path, &stat_buf)) { char *res = strdup (path); -// printf ("Found in cache: %s\n", res); +// printf ("found %s in cache\n", path); return res; } - /* Downloading from internet */ - trace ("Downloading: %s %s\n", artist, album); - fetcher_thread_param_t *param = malloc (sizeof (fetcher_thread_param_t)); - param->artist = artist; - param->album = album; - param->callback = callback; - deadbeef->thread_start ((void (*)(void *))fetcher_thread, param); - return PREFIX "/share/deadbeef/pixmaps/blank_cd.jpg"; + queue_add (artist, album, callback); + return strdup (DEFAULT_COVER_PATH); } DB_plugin_t * @@ -209,11 +329,22 @@ artwork_load (DB_functions_t *api) { static int artwork_plugin_start (void) { + terminate = 0; + mutex = deadbeef->mutex_create (); + tid = deadbeef->thread_start (fetcher_thread, NULL); } static int artwork_plugin_stop (void) { + if (tid) { + terminate = 1; + deadbeef->thread_join (tid); + } + if (mutex) { + deadbeef->mutex_free (mutex); + mutex = 0; + } } // define plugin interface diff --git a/plugins/gtkui/coverart.c b/plugins/gtkui/coverart.c index 7d042e5f..27c9e953 100644 --- a/plugins/gtkui/coverart.c +++ b/plugins/gtkui/coverart.c @@ -17,43 +17,88 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include +#include +#include +#include #include "coverart.h" #include "../artwork/artwork.h" extern DB_artwork_plugin_t *coverart_plugin; +#define MAX_ID 256 +#define CACHE_SIZE 20 + +typedef struct { + struct timeval tm; + char *fname; + int width; + GdkPixbuf *pixbuf; +} cached_pixbuf_t; + +static cached_pixbuf_t cache[CACHE_SIZE]; + void cover_avail_callback (const char *artist, const char *album) { } static GdkPixbuf * get_pixbuf (const char *fname, int width) { + int requested_width = width; + // find in cache + int cache_min = 0; + for (int i = 0; i < CACHE_SIZE; i++) { + if (!cache[i].pixbuf) { + cache_min = i; + } + if (cache[i].pixbuf) { + if (!strcmp (fname, cache[i].fname) && cache[i].width == width) { + gettimeofday (&cache[i].tm, NULL); + return cache[i].pixbuf; + } + } + if (cache[cache_min].pixbuf && cache[i].pixbuf) { + if (cache[cache_min].tm.tv_sec < cache[i].tm.tv_sec) { + cache_min = i; + } + } + } + + printf ("loading image %s\n", fname); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (fname, NULL); if (!pixbuf) { return NULL; } + int w, h; w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); - if (w == width) { - return pixbuf; + if (w != width) { + int height; + if (w > h) { + height = width * h / w; + } + else if (h > w) { + height = width; + width = height * w / h; + } + else { + height = width; + } + GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); + pixbuf = scaled; } - int height; - if (w > h) { - height = width * h / w; + if (cache[cache_min].pixbuf) { + g_object_unref (cache[cache_min].pixbuf); } - else if (h > w) { - height = width; - width = height * w / h; + if (cache[cache_min].fname) { + free (cache[cache_min].fname); } - else { - height = width; - } - printf ("width=%d/%d, height=%d/%d\n", width, w, height, h); - - GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR); - g_object_unref (pixbuf); - return scaled; + cache[cache_min].pixbuf = pixbuf; + cache[cache_min].fname = strdup (fname); + gettimeofday (&cache[cache_min].tm, NULL); + cache[cache_min].width = requested_width; + return pixbuf; } GdkPixbuf * @@ -63,7 +108,7 @@ get_cover_art (DB_playItem_t *it, int width) { } const char *fname = coverart_plugin->get_album_art (it, cover_avail_callback); if (fname) { - printf ("loading %s\n", fname); +// printf ("loading %s\n", fname); return get_pixbuf (fname, width); } return NULL; diff --git a/plugins/gtkui/ddblistview.c b/plugins/gtkui/ddblistview.c index b8b419f7..71f4bd1c 100644 --- a/plugins/gtkui/ddblistview.c +++ b/plugins/gtkui/ddblistview.c @@ -106,7 +106,7 @@ ddb_listview_list_expose (DdbListview *ps, int x, int y, int w, int h); void ddb_listview_list_render_row_background (DdbListview *ps, DdbListviewIter it, int even, int cursor, int x, int y, int w, int h); void -ddb_listview_list_render_row_foreground (DdbListview *ps, DdbListviewIter it, int even, int cursor, int group_y, int x, int y, int w, int h); +ddb_listview_list_render_row_foreground (DdbListview *ps, DdbListviewIter it, DdbListviewIter group_it, int even, int cursor, int group_y, int x, int y, int w, int h); void ddb_listview_list_render_row (DdbListview *ps, int row, DdbListviewIter it, int expose); void @@ -595,31 +595,46 @@ ddb_listview_list_render (DdbListview *listview, int x, int y, int w, int h) { } draw_begin ((uintptr_t)listview->backbuf); + int ii = 0; while (grp && grp_y < y + h + listview->scrollpos) { // render title DdbListviewIter it = grp->head; listview->binding->ref (it); int grpheight = grp->height; + if (grp_y >= y + h + listview->scrollpos) { + break; + } if (grp_y + GROUP_TITLE_HEIGHT >= y + listview->scrollpos && grp_y < y + h + listview->scrollpos) { ddb_listview_list_render_row_background (listview, NULL, idx & 1, 0, -listview->hscrollpos, grp_y - listview->scrollpos, listview->totalwidth, GROUP_TITLE_HEIGHT); listview->binding->draw_group_title (listview, listview->backbuf, it, -listview->hscrollpos, grp_y - listview->scrollpos, listview->totalwidth, GROUP_TITLE_HEIGHT); } for (int i = 0; i < grp->num_items; i++) { - if (grp_y + GROUP_TITLE_HEIGHT + (i+1) * listview->rowheight >= y + listview->scrollpos && grp_y + GROUP_TITLE_HEIGHT + i * listview->rowheight< y + h + listview->scrollpos) { + ii++; +// if (grp_y + GROUP_TITLE_HEIGHT + (i+1) * listview->rowheight >= y + h + listview->scrollpos) { +// break; +// } + if (grp_y + GROUP_TITLE_HEIGHT + i * listview->rowheight >= y + h + listview->scrollpos) { + break; + } + if (grp_y + GROUP_TITLE_HEIGHT + (i+1) * listview->rowheight >= y + listview->scrollpos + && grp_y + GROUP_TITLE_HEIGHT + i * listview->rowheight < y + h + listview->scrollpos) { gdk_draw_rectangle (listview->backbuf, listview->list->style->bg_gc[GTK_STATE_NORMAL], TRUE, -listview->hscrollpos, grp_y + GROUP_TITLE_HEIGHT + i * listview->rowheight - listview->scrollpos, listview->totalwidth, listview->rowheight); ddb_listview_list_render_row_background (listview, it, (idx + 1 + i) & 1, (idx+i) == listview->binding->cursor () ? 1 : 0, -listview->hscrollpos, grp_y + GROUP_TITLE_HEIGHT + i * listview->rowheight - listview->scrollpos, listview->totalwidth, listview->rowheight); - ddb_listview_list_render_row_foreground (listview, it, (idx + 1 + i) & 1, (idx+i) == listview->binding->cursor () ? 1 : 0, i * listview->rowheight, -listview->hscrollpos, grp_y + GROUP_TITLE_HEIGHT + i * listview->rowheight - listview->scrollpos, listview->totalwidth, listview->rowheight); + ddb_listview_list_render_row_foreground (listview, it, grp->head, (idx + 1 + i) & 1, (idx+i) == listview->binding->cursor () ? 1 : 0, i * listview->rowheight, -listview->hscrollpos, grp_y + GROUP_TITLE_HEIGHT + i * listview->rowheight - listview->scrollpos, listview->totalwidth, listview->rowheight); } DdbListviewIter next = listview->binding->next (it); listview->binding->unref (it); it = next; } + if (it) { + listview->binding->unref (it); + } idx += grp->num_items + 1; int filler = grpheight - (GROUP_TITLE_HEIGHT + listview->rowheight * grp->num_items); if (filler > 0) { gtk_paint_flat_box (treeview->style, listview->backbuf, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, treeview, "cell_even_ruled", x, grp_y - listview->scrollpos + GROUP_TITLE_HEIGHT + listview->rowheight * grp->num_items, w, filler); - ddb_listview_list_render_row_foreground (listview, NULL, 0, 0, grp->num_items * listview->rowheight, -listview->hscrollpos, grp_y - listview->scrollpos + GROUP_TITLE_HEIGHT + listview->rowheight * grp->num_items, listview->totalwidth, filler); + ddb_listview_list_render_row_foreground (listview, NULL, grp->head, 0, 0, grp->num_items * listview->rowheight, -listview->hscrollpos, grp_y - listview->scrollpos + GROUP_TITLE_HEIGHT + listview->rowheight * grp->num_items, listview->totalwidth, filler); } grp_y += grpheight; @@ -692,12 +707,12 @@ ddb_listview_vscroll_value_changed (GtkRange *widget, // redraw other part int start = height-d-1; ps->scrollpos = newscroll; - ddb_listview_list_render (ps, 0, start, ps->list->allocation.width, height); + ddb_listview_list_render (ps, 0, start, ps->list->allocation.width, widget->allocation.height-start); } else { // scroll up // copy scrolled part of buffer - draw_drawable (ps->backbuf, widget->style->black_gc, ps->backbuf, 0, 0, 0, d, widget->allocation.width, widget->allocation.height); + draw_drawable (ps->backbuf, widget->style->black_gc, ps->backbuf, 0, 0, 0, d, widget->allocation.width, widget->allocation.height-d); // redraw other part ps->scrollpos = newscroll; ddb_listview_list_render (ps, 0, 0, ps->list->allocation.width, d+1); @@ -1017,7 +1032,7 @@ ddb_listview_list_setup_hscroll (DdbListview *ps) { // returns -1 if row not found int -ddb_listview_list_get_drawinfo (DdbListview *listview, int row, int *even, int *cursor, int *group_y, int *x, int *y, int *w, int *h) { +ddb_listview_list_get_drawinfo (DdbListview *listview, int row, DdbListviewGroup **pgrp, int *even, int *cursor, int *group_y, int *x, int *y, int *w, int *h) { DdbListviewGroup *grp = listview->groups; int idx = 0; int idx2 = 0; @@ -1027,6 +1042,7 @@ ddb_listview_list_get_drawinfo (DdbListview *listview, int row, int *even, int * if (idx <= row && idx + grp->num_items > row) { // found int idx_in_group = row - idx; + *pgrp = grp; *even = (idx2 + 1 + idx_in_group) & 1; *cursor = (row == listview->binding->cursor ()) ? 1 : 0; *group_y = idx_in_group * listview->rowheight; @@ -1046,18 +1062,19 @@ ddb_listview_list_get_drawinfo (DdbListview *listview, int row, int *even, int * void ddb_listview_list_render_row (DdbListview *listview, int row, DdbListviewIter it, int expose) { + DdbListviewGroup *grp; int even; int cursor; int x, y, w, h; int group_y; - if (ddb_listview_list_get_drawinfo (listview, row, &even, &cursor, &group_y, &x, &y, &w, &h) == -1) { + if (ddb_listview_list_get_drawinfo (listview, row, &grp, &even, &cursor, &group_y, &x, &y, &w, &h) == -1) { return; } draw_begin ((uintptr_t)listview->backbuf); ddb_listview_list_render_row_background (listview, it, even, cursor, x, y, w, h); if (it) { - ddb_listview_list_render_row_foreground (listview, it, even, cursor, group_y, x, y, w, h); + ddb_listview_list_render_row_foreground (listview, it, grp->head, even, cursor, group_y, x, y, w, h); } draw_end (); if (expose) { @@ -1092,7 +1109,7 @@ ddb_listview_list_render_row_background (DdbListview *ps, DdbListviewIter it, in } void -ddb_listview_list_render_row_foreground (DdbListview *ps, DdbListviewIter it, int even, int cursor, int group_y, int x, int y, int w, int h) { +ddb_listview_list_render_row_foreground (DdbListview *ps, DdbListviewIter it, DdbListviewIter group_it, int even, int cursor, int group_y, int x, int y, int w, int h) { int width, height; draw_get_canvas_size ((uintptr_t)ps->backbuf, &width, &height); if (it && ps->binding->is_selected (it)) { @@ -1109,7 +1126,7 @@ ddb_listview_list_render_row_foreground (DdbListview *ps, DdbListviewIter it, in int cidx = 0; for (c = ps->columns; c; c = c->next, cidx++) { int cw = c->width; - ps->binding->draw_column_data (ps, ps->backbuf, it, cidx, group_y, x, y, cw, h); + ps->binding->draw_column_data (ps, ps->backbuf, it, GROUP_TITLE_HEIGHT > 0 ? group_it : NULL, cidx, group_y, x, y, cw, h); x += cw; } } @@ -2528,4 +2545,10 @@ ddb_listview_build_groups (DdbListview *listview) { listview->binding->unref (it); it = next; } + if (grp) { + if (grp->height - GROUP_TITLE_HEIGHT < min_height) { + grp->height = min_height + GROUP_TITLE_HEIGHT; + } + listview->fullheight += grp->height; + } } diff --git a/plugins/gtkui/ddblistview.h b/plugins/gtkui/ddblistview.h index a39e4fa7..c3e98141 100644 --- a/plugins/gtkui/ddblistview.h +++ b/plugins/gtkui/ddblistview.h @@ -73,7 +73,7 @@ typedef struct { // callbacks void (*draw_group_title) (DdbListview *listview, GdkDrawable *drawable, DdbListviewIter iter, int x, int y, int width, int height); - void (*draw_column_data) (DdbListview *listview, GdkDrawable *drawable, DdbListviewIter iter, int column, int group_y, int x, int y, int width, int height); + void (*draw_column_data) (DdbListview *listview, GdkDrawable *drawable, DdbListviewIter iter, DdbListviewIter group_iter, int column, int group_y, int x, int y, int width, int height); void (*list_context_menu) (DdbListview *listview, DdbListviewIter iter, int idx); void (*header_context_menu) (DdbListview *listview, int col); void (*handle_doubleclick) (DdbListview *listview, DdbListviewIter iter, int idx); diff --git a/plugins/gtkui/mainplaylist.c b/plugins/gtkui/mainplaylist.c index 61fbef50..7f4f6769 100644 --- a/plugins/gtkui/mainplaylist.c +++ b/plugins/gtkui/mainplaylist.c @@ -279,7 +279,7 @@ void main_selection_changed (DdbListviewIter it, int idx) { ddb_listview_draw_row (search, idx, it); } -void main_draw_column_data (DdbListview *listview, GdkDrawable *drawable, DdbListviewIter it, int column, int group_y, int x, int y, int width, int height) { +void main_draw_column_data (DdbListview *listview, GdkDrawable *drawable, DdbListviewIter it, DdbListviewIter group_it, int column, int group_y, int x, int y, int width, int height) { const char *ctitle; int cwidth; int calign_right; @@ -291,14 +291,25 @@ void main_draw_column_data (DdbListview *listview, GdkDrawable *drawable, DdbLis } if (cinf->id == DB_COLUMN_ALBUM_ART) { if (group_y < cwidth) { - int h = cwidth - group_y; - h = min (height, h); - gdk_draw_rectangle (drawable, GTK_WIDGET (listview)->style->white_gc, TRUE, x, y, width, h); -// GdkPixbuf *pixbuf = gdk_pixbuf_scale_simple ((GdkPixbuf *)play16_pixbuf, width, width, GDK_INTERP_BILINEAR); - if (it) { - GdkPixbuf *pixbuf = get_cover_art (it, width); - gdk_draw_pixbuf (drawable, GTK_WIDGET (listview)->style->white_gc, pixbuf, 0, group_y, x, y, width, h, GDK_RGB_DITHER_NONE, 0, 0); - g_object_unref (pixbuf); + if (group_it) { + int h = cwidth - group_y; + h = min (height, h); + gdk_draw_rectangle (drawable, GTK_WIDGET (listview)->style->white_gc, TRUE, x, y, width, h); + GdkPixbuf *pixbuf = get_cover_art (group_it, width); + if (pixbuf) { + int pw = gdk_pixbuf_get_width (pixbuf); + int ph = gdk_pixbuf_get_height (pixbuf); + if (group_y < ph) { + pw = min (width, pw); + if (group_y + h >= ph) { + ph = ph - group_y; + } + else { + ph = h; + } + gdk_draw_pixbuf (drawable, GTK_WIDGET (listview)->style->white_gc, pixbuf, 0, group_y, x, y, pw, ph, GDK_RGB_DITHER_NONE, 0, 0); + } + } } } } diff --git a/threading.h b/threading.h index f8767360..f0988574 100644 --- a/threading.h +++ b/threading.h @@ -29,6 +29,9 @@ thread_join (intptr_t tid); uintptr_t mutex_create (void); +uintptr_t +mutex_create_nonrecursive (void); + uintptr_t mutex_create_recursive (void); diff --git a/threading_pthread.c b/threading_pthread.c index c3e4e8fb..3b04e7c8 100644 --- a/threading_pthread.c +++ b/threading_pthread.c @@ -58,7 +58,7 @@ thread_join (intptr_t tid) { } uintptr_t -mutex_create (void) { +mutex_create_nonrecursive (void) { pthread_mutex_t *mtx = malloc (sizeof (pthread_mutex_t)); pthread_mutexattr_t attr = {0}; pthread_mutexattr_init (&attr); @@ -73,7 +73,7 @@ mutex_create (void) { } uintptr_t -mutex_create_recursive (void) { +mutex_create (void) { pthread_mutex_t *mtx = malloc (sizeof (pthread_mutex_t)); pthread_mutexattr_t attr = {0}; pthread_mutexattr_init (&attr); -- cgit v1.2.3