diff options
-rw-r--r-- | junklib.c | 8 | ||||
-rw-r--r-- | main.c | 61 | ||||
-rw-r--r-- | plugins/aac/aac.c | 7 | ||||
-rw-r--r-- | plugins/dca/Makefile.am | 24 | ||||
-rw-r--r-- | plugins/dca/extract_dca.c | 23 | ||||
-rw-r--r-- | plugins/dca/parse.c | 11 | ||||
-rw-r--r-- | plugins/flac/flac.c | 3 | ||||
-rw-r--r-- | plugins/gtkui/callbacks.c | 22 | ||||
-rw-r--r-- | plugins/gtkui/callbacks.h | 4 | ||||
-rw-r--r-- | plugins/gtkui/ddbtabstrip.c | 269 | ||||
-rw-r--r-- | plugins/gtkui/ddbtabstrip.h | 2 | ||||
-rw-r--r-- | plugins/gtkui/deadbeef.glade | 63 | ||||
-rw-r--r-- | plugins/gtkui/gtkui.c | 13 | ||||
-rw-r--r-- | plugins/gtkui/gtkui.h | 3 | ||||
-rw-r--r-- | plugins/gtkui/interface.c | 111 | ||||
-rw-r--r-- | plugins/gtkui/plcommon.c | 5 | ||||
-rw-r--r-- | plugins/lastfm/lastfm.c | 2 | ||||
-rw-r--r-- | plugins/mpgmad/mpgmad.c | 38 | ||||
-rw-r--r-- | plugins/shellexec/shellexec.c | 47 | ||||
-rw-r--r-- | plugins/vorbis/vorbis.c | 3 | ||||
-rw-r--r-- | streamer.c | 35 |
21 files changed, 530 insertions, 224 deletions
@@ -62,7 +62,7 @@ enum { static const char *frame_mapping[] = { "artist", "TPE1", "TPE1", "TP1", "Artist", - "band", "TPE2", "TPE2", "TP2", "Band", + "band", "TPE2", "TPE2", "TP2", "Album artist", "disc", "TPOS", "TPOS", "TPA", "Media", "title", "TIT2", "TIT2", "TT2", "Title", "album", "TALB", "TALB", "TAL", "Album", @@ -76,7 +76,7 @@ static const char *frame_mapping[] = { "comment", NULL, NULL, NULL, "Comment", "cuesheet", NULL, NULL, NULL, "Cuesheet", // "<performer>", "TXXX", "TXXX", "TXX", "Performer", // fb2k only -// "<albumartist>", "TXXX", "TXXX", "TXX", "Album artist", // fb2k only +// "band", "TXXX", "TXXX", "TXX", "Album artist", // fb2k only // "date", "TXXX", "TXXX", "TXX", "Date", // fb2k only NULL }; @@ -2505,10 +2505,10 @@ junk_id3v2_load_txx (int version_major, playItem_t *it, uint8_t *readptr, int sy it->replaygain_track_peak = atof (val); } else if (!strcasecmp (txx, "performer")) { - pl_append_meta (it, "performer", val); + pl_replace_meta (it, "performer", val); } else if (!strcasecmp (txx, "album artist")) { - pl_append_meta (it, "albumartist", val); + pl_replace_meta (it, "band", val); } else if (!strcasecmp (txx, "date")) { pl_replace_meta (it, "year", val); @@ -481,6 +481,41 @@ sigsegv_handler (int sig) { } #endif +void +save_resume_state (void) { + playItem_t *trk = streamer_get_playing_track (); + float playpos = -1; + int playtrack = -1; + int playlist = streamer_get_current_playlist (); + int paused = (p_get_state () == OUTPUT_STATE_PAUSED); + if (trk && playlist >= 0) { + playtrack = str_get_idx_of (trk); + playpos = streamer_get_playpos (); + pl_item_unref (trk); + } + + conf_set_float ("resume.position", playpos); + conf_set_int ("resume.track", playtrack); + conf_set_int ("resume.playlist", playlist); + conf_set_int ("resume.paused", paused); +} + +void +restore_resume_state (void) { + if (conf_get_int ("resume_last_session", 0) && p_isstopped ()) { + int plt = conf_get_int ("resume.playlist", -1); + int track = conf_get_int ("resume.track", -1); + float pos = conf_get_float ("resume.position", -1); + int paused = conf_get_int ("resume.paused", 0); + trace ("resume: track %d pos %f playlist %d\n", track, pos, plt); + if (plt >= 0 && track >= 0 && pos >= 0) { + streamer_set_current_playlist (plt); + streamer_set_seek (pos); + streamer_set_nextsong (track, paused ? 2 : 3); + } + } +} + int main (int argc, char *argv[]) { #ifdef __linux__ @@ -676,34 +711,12 @@ main (int argc, char *argv[]) { streamer_init (); - if (conf_get_int ("resume_last_session", 0) && p_isstopped ()) { - int plt = conf_get_int ("resume.playlist", -1); - int track = conf_get_int ("resume.track", -1); - float pos = conf_get_float ("resume.position", -1); - trace ("resume: track %d pos %f playlist %d\n", track, pos, plt); - if (plt >= 0 && track >= 0 && pos >= 0) { - streamer_set_current_playlist (plt); - streamer_set_seek (pos); - streamer_set_nextsong (track, 3); - } - } + restore_resume_state (); // this runs in main thread (blocks right here) player_mainloop (); - playItem_t *trk = streamer_get_playing_track (); - float playpos = -1; - int playtrack = -1; - int playlist = streamer_get_current_playlist (); - if (trk && playlist >= 0) { - playtrack = str_get_idx_of (trk); - playpos = streamer_get_playpos (); - pl_item_unref (trk); - } - - conf_set_float ("resume.position", playpos); - conf_set_int ("resume.track", playtrack); - conf_set_int ("resume.playlist", playlist); + save_resume_state (); // save config pl_save_all (); diff --git a/plugins/aac/aac.c b/plugins/aac/aac.c index fd152498..f278147a 100644 --- a/plugins/aac/aac.c +++ b/plugins/aac/aac.c @@ -378,7 +378,10 @@ aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) { if (skip >= 0) { deadbeef->fseek (info->file, skip, SEEK_SET); } - offs =deadbeef->ftell (info->file); + offs = deadbeef->ftell (info->file); + } + else { + deadbeef->fset_track (info->file, it); } info->mp4track = -1; @@ -869,7 +872,7 @@ static const char *metainfo[] = { "genre", "genre", "comment", "comment", "performer", "performer", - "albumartist", "band", + "album_artist", "band", "writer", "composer", "vendor", "vendor", "disc", "disc", diff --git a/plugins/dca/Makefile.am b/plugins/dca/Makefile.am index 3d0aabb4..d6429b84 100644 --- a/plugins/dca/Makefile.am +++ b/plugins/dca/Makefile.am @@ -9,18 +9,18 @@ parse.c\ bitstream.c\ downmix.c\ convert2s16.c\ -plugins/dca/audio_out.h\ -plugins/dca/dca.h\ -plugins/dca/dts.h\ -plugins/dca/gettimeofday.h\ -plugins/dca/tendra.h\ -plugins/dca/dca_internal.h\ -plugins/dca/tables_adpcm.h\ -plugins/dca/tables_fir.h\ -plugins/dca/tables.h\ -plugins/dca/tables_huffman.h\ -plugins/dca/tables_quantization.h\ -plugins/dca/tables_vq.h +audio_out.h\ +dca.h\ +dts.h\ +gettimeofday.h\ +tendra.h\ +dca_internal.h\ +tables_adpcm.h\ +tables_fir.h\ +tables.h\ +tables_huffman.h\ +tables_quantization.h\ +tables_vq.h dca_la_LDFLAGS = -module diff --git a/plugins/dca/extract_dca.c b/plugins/dca/extract_dca.c index 81534409..58fb105b 100644 --- a/plugins/dca/extract_dca.c +++ b/plugins/dca/extract_dca.c @@ -35,6 +35,9 @@ #endif #include <inttypes.h> +//#define trace(...) { fprintf (stderr, __VA_ARGS__); } +#define trace(fmt,...) + #define BUFFER_SIZE 4096 static uint8_t buffer[BUFFER_SIZE]; static FILE * in_file; @@ -44,7 +47,7 @@ static int demux_pes = 0; static void print_usage (char ** argv) { - fprintf (stderr, "usage: %s [-h] [-s <track>] [-t <pid>] <file>\n" + trace ( "usage: %s [-h] [-s <track>] [-t <pid>] <file>\n" "\t-h\tdisplay help\n" "\t-s\tset track number (0-7 or 0x80-0x87)\n" "\t-t\tuse transport stream demultiplexer, pid 0x10-0x1ffe\n" @@ -66,7 +69,7 @@ static void handle_args (int argc, char ** argv) if (demux_track < 0x80) demux_track += 0x80; if (demux_track < 0x80 || demux_track > 0x87 || *s) { - fprintf (stderr, "Invalid track number: %s\n", optarg); + trace ( "Invalid track number: %s\n", optarg); print_usage (argv); } break; @@ -74,7 +77,7 @@ static void handle_args (int argc, char ** argv) case 't': demux_pid = strtol (optarg, &s, 0); if (demux_pid < 0x10 || demux_pid > 0x1ffe || *s) { - fprintf (stderr, "Invalid pid: %s\n", optarg); + trace ( "Invalid pid: %s\n", optarg); print_usage (argv); } break; @@ -90,7 +93,7 @@ static void handle_args (int argc, char ** argv) if (optind < argc) { in_file = fopen (argv[optind], "rb"); if (!in_file) { - fprintf (stderr, "%s - could not open file %s\n", strerror (errno), + trace ( "%s - could not open file %s\n", strerror (errno), argv[optind]); exit (1); } @@ -218,12 +221,12 @@ static int demux (uint8_t * buf, uint8_t * end, int flags) } if (demux_pid || demux_pes) { if (header[3] != 0xbd) { - fprintf (stderr, "bad stream id %x\n", header[3]); + trace ( "bad stream id %x\n", header[3]); exit (1); } NEEDBYTES (9); if ((header[6] & 0xc0) != 0x80) { /* not mpeg2 */ - fprintf (stderr, "bad multiplex - not mpeg2\n"); + trace ( "bad multiplex - not mpeg2\n"); exit (1); } len = 9 + header[8]; @@ -257,7 +260,7 @@ static int demux (uint8_t * buf, uint8_t * end, int flags) DONEBYTES (12); /* header points to the mpeg1 pack header */ } else { - fprintf (stderr, "weird pack header\n"); + trace ( "weird pack header\n"); DONEBYTES (5); } break; @@ -274,7 +277,7 @@ static int demux (uint8_t * buf, uint8_t * end, int flags) len++; NEEDBYTES (len); if (len == 23) { - fprintf (stderr, "too much stuffing\n"); + trace ( "too much stuffing\n"); break; } } @@ -309,7 +312,7 @@ static int demux (uint8_t * buf, uint8_t * end, int flags) break; default: if (header[3] < 0xb9) { - fprintf (stderr, + trace ( "looks like a video stream, not system stream\n"); exit (1); } else { @@ -353,7 +356,7 @@ static void ts_loop (void) buf = buffer; for (; (nextbuf = buf + 188) <= end; buf = nextbuf) { if (*buf != 0x47) { - fprintf (stderr, "bad sync byte\n"); + trace ( "bad sync byte\n"); nextbuf = buf + 1; continue; } diff --git a/plugins/dca/parse.c b/plugins/dca/parse.c index c66a64ff..6a9225b0 100644 --- a/plugins/dca/parse.c +++ b/plugins/dca/parse.c @@ -46,6 +46,9 @@ #include "tables_fir.h" #include "tables_vq.h" +//#define trace(...) { fprintf (stderr, __VA_ARGS__); } +#define trace(fmt,...) + /* #define DEBUG */ #if defined(HAVE_MEMALIGN) && !defined(__cplusplus) @@ -520,7 +523,7 @@ static int dca_subframe_header (dca_state_t * state) if (state->bitalloc[j][k] > 26) { - fprintf (stderr, "bitalloc index [%i][%i] too big (%i)\n", + trace ("bitalloc index [%i][%i] too big (%i)\n", j, k, state->bitalloc[j][k]); return -1; } @@ -950,7 +953,7 @@ static int dca_subsubframe (dca_state_t * state) if (!state->debug_flag & 0x01) { - fprintf (stderr, "Stream with high frequencies VQ coding\n"); + trace ("Stream with high frequencies VQ coding\n"); state->debug_flag |= 0x01; } @@ -974,7 +977,7 @@ static int dca_subsubframe (dca_state_t * state) } else { - fprintf( stderr, "Didn't get subframe DSYNC\n" ); + trace( "Didn't get subframe DSYNC\n" ); } } @@ -1125,7 +1128,7 @@ int decode_blockcode( int code, int levels, int *values ) return 1; else { - fprintf (stderr, "ERROR: block code look-up failed\n"); + trace ("ERROR: block code look-up failed\n"); return 0; } } diff --git a/plugins/flac/flac.c b/plugins/flac/flac.c index ab35b8a0..defa013c 100644 --- a/plugins/flac/flac.c +++ b/plugins/flac/flac.c @@ -487,12 +487,13 @@ static const char *metainfo[] = { "GENRE", "genre", "COMMENT", "comment", "PERFORMER", "performer", - "ENSEMBLE", "band", +// "ENSEMBLE", "band", "COMPOSER", "composer", "ENCODED-BY", "vendor", "DISCNUMBER", "disc", "COPYRIGHT", "copyright", "TRACKTOTAL", "numtracks", + "ALBUM ARTIST", "band", NULL }; diff --git a/plugins/gtkui/callbacks.c b/plugins/gtkui/callbacks.c index a152aef5..c13ee248 100644 --- a/plugins/gtkui/callbacks.c +++ b/plugins/gtkui/callbacks.c @@ -302,17 +302,6 @@ on_playrand_clicked (GtkButton *button, deadbeef->sendmessage (M_PLAYRANDOM, 0, 0, 0); } -void -focus_on_playing_track (void) { - DB_playItem_t *it = deadbeef->streamer_get_playing_track (); - if (it) { - int idx = deadbeef->pl_get_idx_of (it); - ddb_listview_scroll_to (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), idx); - ddb_listview_set_cursor (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), idx); - deadbeef->pl_item_unref (it); - } -} - gboolean on_mainwin_key_press_event (GtkWidget *widget, GdkEventKey *event, @@ -330,9 +319,6 @@ on_mainwin_key_press_event (GtkWidget *widget, deadbeef->conf_set_int ("playlist.current", pl); } } - else if (event->state == GDK_CONTROL_MASK && event->keyval == GDK_j) { - focus_on_playing_track (); - } else { ddb_listview_handle_keypress (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), event->keyval, event->state); } @@ -1071,3 +1057,11 @@ create_seekbar (gchar *widget_name, gchar *string1, gchar *string2, return GTK_WIDGET (ddb_seekbar_new ()); } + +void +on_jump_to_current_track1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + gtkui_focus_on_playing_track (); +} + diff --git a/plugins/gtkui/callbacks.h b/plugins/gtkui/callbacks.h index 62d79f38..0a54f314 100644 --- a/plugins/gtkui/callbacks.h +++ b/plugins/gtkui/callbacks.h @@ -975,3 +975,7 @@ on_statusbar_button_press_event (GtkWidget *widget, void on_resume_last_session_toggled (GtkToggleButton *togglebutton, gpointer user_data); + +void +on_jump_to_current_track1_activate (GtkMenuItem *menuitem, + gpointer user_data); diff --git a/plugins/gtkui/ddbtabstrip.c b/plugins/gtkui/ddbtabstrip.c index 3d56f38e..d28efd58 100644 --- a/plugins/gtkui/ddbtabstrip.c +++ b/plugins/gtkui/ddbtabstrip.c @@ -37,6 +37,10 @@ G_DEFINE_TYPE (DdbTabStrip, ddb_tabstrip, GTK_TYPE_WIDGET); +extern GtkWidget *theme_button; +#define arrow_sz 10 +#define arrow_widget_width (arrow_sz+4) + void plt_get_title_wrapper (int plt, char *buffer, int len) { deadbeef->plt_get_title (plt, buffer, len); @@ -184,7 +188,7 @@ on_tabstrip_drag_end (GtkWidget *widget, GdkDragContext *drag_context); static int -get_tab_under_cursor (int x); +get_tab_under_cursor (DdbTabStrip *ts, int x); static void ddb_tabstrip_destroy(GtkObject *object) @@ -366,11 +370,103 @@ ddb_tabstrip_get_tab_width (DdbTabStrip *ts, int tab) { return width; } +int +tabstrip_need_arrows (DdbTabStrip *ts) { + GtkWidget *widget = GTK_WIDGET (ts); + int cnt = deadbeef->plt_get_count (); + int w = 0; + for (int idx = 0; idx < cnt; idx++) { + w += ddb_tabstrip_get_tab_width (ts, idx) - tab_overlap_size; + if (w >= widget->allocation.width) { + return 1; + } + } + w += tab_overlap_size + 3; + if (w >= widget->allocation.width) { + return 1; + } + return 0; +} + +static void +tabstrip_scroll_to_tab_int (DdbTabStrip *ts, int tab, int redraw) { + GtkWidget *widget = GTK_WIDGET (ts); + int w = 0; + int cnt = deadbeef->plt_get_count (); + int boundary = widget->allocation.width - arrow_widget_width*2 + ts->hscrollpos; + for (int idx = 0; idx < cnt; idx++) { + int tab_w = ddb_tabstrip_get_tab_width (ts, idx); + if (idx == cnt-1) { + tab_w += 3; + } + if (idx == tab) { + if (w < ts->hscrollpos) { + ts->hscrollpos = w; + deadbeef->conf_set_int ("gtkui.tabscroll", ts->hscrollpos); + if (redraw) { + gtk_widget_queue_draw (widget); + } + } + else if (w + tab_w >= boundary) { + ts->hscrollpos += (w+tab_w) - boundary; + deadbeef->conf_set_int ("gtkui.tabscroll", ts->hscrollpos); + if (redraw) { + gtk_widget_queue_draw (widget); + } + } + break; + } + w += tab_w - tab_overlap_size; + } +} + +static void +tabstrip_scroll_to_tab (DdbTabStrip *ts, int tab) { + tabstrip_scroll_to_tab_int (ts, tab, 1); +} + +void +tabstrip_adjust_hscroll (DdbTabStrip *ts) { + GtkWidget *widget = GTK_WIDGET (ts); + ts->hscrollpos = deadbeef->conf_get_int ("gtkui.tabscroll", 0); + if (deadbeef->plt_get_count () > 0) { + int need_arrows = tabstrip_need_arrows (ts); + if (need_arrows) { + int w = 0; + int cnt = deadbeef->plt_get_count (); + for (int idx = 0; idx < cnt; idx++) { + w += ddb_tabstrip_get_tab_width (ts, idx) - tab_overlap_size; + } + w += tab_overlap_size + 3; + if (ts->hscrollpos > w - (widget->allocation.width - arrow_widget_width*2)) { + ts->hscrollpos = w - (widget->allocation.width - arrow_widget_width*2); + deadbeef->conf_set_int ("gtkui.tabscroll", ts->hscrollpos); + } + tabstrip_scroll_to_tab_int (ts, deadbeef->plt_get_curr (), 0); + } + else { + ts->hscrollpos = 0; + deadbeef->conf_set_int ("gtkui.tabscroll", ts->hscrollpos); + } + } +} + void tabstrip_render (DdbTabStrip *ts) { GtkWidget *widget = GTK_WIDGET (ts); GdkDrawable *backbuf = gtk_widget_get_window (widget); - int x = -ts->hscrollpos; + + tabstrip_adjust_hscroll (ts); + + int cnt = deadbeef->plt_get_count (); + int hscroll = ts->hscrollpos; + + int need_arrows = tabstrip_need_arrows (ts); + if (need_arrows) { + hscroll -= arrow_widget_width; + } + + int x = -hscroll; int w = 0; int h = draw_get_font_size (); h = widget->allocation.height; @@ -378,7 +474,6 @@ tabstrip_render (DdbTabStrip *ts) { text_right_padding = h - 3; const char *detail = "button"; - int cnt = deadbeef->plt_get_count (); int tab_selected = deadbeef->plt_get_curr (); GdkGC *gc = gdk_gc_new (backbuf); @@ -395,7 +490,6 @@ tabstrip_render (DdbTabStrip *ts) { int need_draw_moving = 0; int idx; int widths[cnt]; - int fullwidth = 0; for (idx = 0; idx < cnt; idx++) { char title[100]; plt_get_title_wrapper (idx, title, sizeof (title)); @@ -405,11 +499,9 @@ tabstrip_render (DdbTabStrip *ts) { if (widths[idx] < min_tab_size) { widths[idx] = min_tab_size; } - fullwidth += widths[idx] - tab_overlap_size; } - fullwidth += tab_overlap_size; - x = -ts->hscrollpos + tabs_left_margin; + x = -hscroll + tabs_left_margin; for (idx = 0; idx < cnt; idx++) { w = widths[idx]; @@ -419,7 +511,6 @@ tabstrip_render (DdbTabStrip *ts) { area.width = w; area.height = 24; if (idx != tab_selected) { -// gtk_paint_box (widget->style, widget->window, idx == tab_selected ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, GTK_SHADOW_OUT, &area, widget, "button", x, idx == tab_selected ? 0 : 1, w+margin_size, 32); ddb_tabstrip_draw_tab (widget, backbuf, idx == tab_selected, x, y, w, h); char tab_title[100]; plt_get_title_wrapper (idx, tab_title, sizeof (tab_title)); @@ -433,7 +524,7 @@ tabstrip_render (DdbTabStrip *ts) { gdk_draw_line (backbuf, widget->style->dark_gc[GTK_STATE_NORMAL], 0, widget->allocation.height-2, widget->allocation.width, widget->allocation.height-2); gdk_draw_line (backbuf, widget->style->light_gc[GTK_STATE_NORMAL], 0, widget->allocation.height-1, widget->allocation.width, widget->allocation.height-1); // calc position for drawin selected tab - x = -ts->hscrollpos; + x = -hscroll; for (idx = 0; idx < tab_selected; idx++) { x += widths[idx] - tab_overlap_size; } @@ -447,7 +538,6 @@ tabstrip_render (DdbTabStrip *ts) { area.y = 0; area.width = w; area.height = 24; -// gtk_paint_box (widget->style, widget->window, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, &area, widget, "button", x, idx == tab_selected ? 0 : 1, w, 32); ddb_tabstrip_draw_tab (widget, backbuf, 1, x, y, w, h); char tab_title[100]; plt_get_title_wrapper (idx, tab_title, sizeof (tab_title)); @@ -460,22 +550,15 @@ tabstrip_render (DdbTabStrip *ts) { need_draw_moving = 1; } if (need_draw_moving) { - x = -ts->hscrollpos + tabs_left_margin; + x = -hscroll + tabs_left_margin; for (idx = 0; idx < cnt; idx++) { w = widths[idx]; if (idx == ts->dragging) { -#if 0 - // draw empty slot - if (x < widget->allocation.width) { - gtk_paint_box (widget->style, backbuf, GTK_STATE_ACTIVE, GTK_SHADOW_ETCHED_IN, NULL, widget, "button", x, 0, w, h); - } -#endif x = ts->movepos; if (x >= widget->allocation.width) { break; } if (w > 0) { - //gtk_paint_box (widget->style, backbuf, GTK_STATE_SELECTED, GTK_SHADOW_OUT, NULL, widget, "button", x, 0, w, h); ddb_tabstrip_draw_tab (widget, backbuf, 1, x, y, w, h); char tab_title[100]; plt_get_title_wrapper (idx, tab_title, sizeof (tab_title)); @@ -489,15 +572,31 @@ tabstrip_render (DdbTabStrip *ts) { x += w - tab_overlap_size; } } + + if (need_arrows) { + int sz = widget->allocation.height-3; + GdkColor clr; + gdk_gc_set_rgb_fg_color (gc, (gtkui_get_tabstrip_mid_color (&clr), &clr)); + gdk_draw_rectangle (backbuf, gc, TRUE, 0, 1, arrow_widget_width, sz); + gtk_paint_arrow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, widget, NULL, GTK_ARROW_LEFT, TRUE, 2, sz/2-arrow_sz/2, arrow_sz, arrow_sz); + gdk_draw_rectangle (backbuf, gc, TRUE, widget->allocation.width-arrow_widget_width, 1, arrow_widget_width, sz); + gtk_paint_arrow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, widget, NULL, GTK_ARROW_RIGHT, TRUE, widget->allocation.width-arrow_sz-2, 1+sz/2-arrow_sz/2, arrow_sz, arrow_sz); + } + draw_end (); g_object_unref (gc); } static int -get_tab_under_cursor (int x) { +get_tab_under_cursor (DdbTabStrip *ts, int x) { + int hscroll = ts->hscrollpos; + int need_arrows = tabstrip_need_arrows (ts); + if (need_arrows) { + hscroll -= arrow_widget_width; + } int idx; int cnt = deadbeef->plt_get_count (); - int fw = tabs_left_margin; + int fw = tabs_left_margin - hscroll; int tab_selected = deadbeef->plt_get_curr (); for (idx = 0; idx < cnt; idx++) { char title[100]; @@ -666,14 +765,115 @@ create_plmenu (void) return plmenu; } +static void +tabstrip_scroll_left (DdbTabStrip *ts) { +#if 0 + // scroll to leftmost border-spanning tab + int scrollsize = 0; + int w = 0; + int cnt = deadbeef->plt_get_count (); + for (int idx = 0; idx < cnt; idx++) { + int tab_w = ddb_tabstrip_get_tab_width (ts, idx); + if (w < ts->hscrollpos && w + tab_w >= ts->hscrollpos) { + scrollsize = ts->hscrollpos - w; + break; + } + w += tab_w - tab_overlap_size; + } + w += tab_overlap_size + 3; + + ts->hscrollpos -= scrollsize; + if (ts->hscrollpos < 0) { + ts->hscrollpos = 0; + } + deadbeef->conf_set_int ("gtkui.tabscroll", ts->hscrollpos); + gtk_widget_queue_draw (GTK_WIDGET (ts)); +#endif + int tab = deadbeef->plt_get_curr (); + if (tab > 0) { + tab--; + deadbeef->plt_set_curr (tab); + deadbeef->conf_set_int ("playlist.current", tab); + } + tabstrip_scroll_to_tab (ts, tab); +} + +static void +tabstrip_scroll_right (DdbTabStrip *ts) { +#if 0 + // scroll to rightmost border-spanning tab + GtkWidget *widget = GTK_WIDGET (ts); + int scrollsize = 0; + int w = 0; + int cnt = deadbeef->plt_get_count (); + int boundary = widget->allocation.width - arrow_widget_width*2 + ts->hscrollpos; + for (int idx = 0; idx < cnt; idx++) { + int tab_w = ddb_tabstrip_get_tab_width (ts, idx); + + if (scrollsize == 0 && w < boundary && w + tab_w >= boundary) { + scrollsize = (w + tab_w) - boundary; + } + w += tab_w - tab_overlap_size; + } + w += tab_overlap_size + 3; + ts->hscrollpos += scrollsize; + if (ts->hscrollpos > w - (widget->allocation.width - arrow_widget_width*2)) { + ts->hscrollpos = w - (widget->allocation.width - arrow_widget_width*2); + } + deadbeef->conf_set_int ("gtkui.tabscroll", ts->hscrollpos); + gtk_widget_queue_draw (widget); +#endif + int tab = deadbeef->plt_get_curr (); + if (tab < deadbeef->plt_get_count ()-1) { + tab++; + deadbeef->plt_set_curr (tab); + deadbeef->conf_set_int ("playlist.current", tab); + } + tabstrip_scroll_to_tab (ts, tab); +} + +gboolean +tabstrip_scroll_cb (gpointer data) { + DdbTabStrip *ts = DDB_TABSTRIP (data); + if (ts->scroll_direction < 0) { + tabstrip_scroll_left (ts); + } + else if (ts->scroll_direction > 0) { + tabstrip_scroll_right (ts); + } + else { + return FALSE; + } + return TRUE; +} + gboolean on_tabstrip_button_press_event (GtkWidget *widget, GdkEventButton *event) { DdbTabStrip *ts = DDB_TABSTRIP (widget); - tab_clicked = get_tab_under_cursor (event->x); + tab_clicked = get_tab_under_cursor (ts, event->x); if (event->button == 1) { + int need_arrows = tabstrip_need_arrows (ts); + if (need_arrows) { + if (event->x < arrow_widget_width) { + if (event->type == GDK_BUTTON_PRESS) { + tabstrip_scroll_left (ts); + ts->scroll_direction = -1; + ts->scroll_timer = g_timeout_add (300, tabstrip_scroll_cb, ts); + } + return FALSE; + } + else if (event->x >= widget->allocation.width - arrow_widget_width) { + if (event->type == GDK_BUTTON_PRESS) { + tabstrip_scroll_right (ts); + ts->scroll_direction = 1; + ts->scroll_timer = g_timeout_add (300, tabstrip_scroll_cb, ts); + } + return FALSE; + } + } if (tab_clicked != -1) { deadbeef->plt_set_curr (tab_clicked); deadbeef->conf_set_int ("playlist.current", tab_clicked); @@ -691,7 +891,16 @@ on_tabstrip_button_press_event (GtkWidget *widget, return FALSE; } - int x = -ts->hscrollpos + tabs_left_margin; + // adjust scroll if clicked tab spans border + if (need_arrows) { + tabstrip_scroll_to_tab (ts, tab_clicked); + } + + int hscroll = ts->hscrollpos; + if (need_arrows) { + hscroll -= arrow_widget_width; + } + int x = -hscroll + tabs_left_margin; int idx; for (idx = 0; idx < tab_clicked; idx++) { int width = ddb_tabstrip_get_tab_width (ts, idx); @@ -736,6 +945,10 @@ on_tabstrip_button_release_event (GtkWidget *widget, { DdbTabStrip *ts = DDB_TABSTRIP (widget); if (event->button == 1) { + if (ts->scroll_timer > 0) { + ts->scroll_direction = 0; + ts->scroll_timer = 0; + } if (ts->prepare || ts->dragging >= 0) { ts->dragging = -1; ts->prepare = 0; @@ -745,12 +958,13 @@ on_tabstrip_button_release_event (GtkWidget *widget, return FALSE; } - gboolean on_tabstrip_configure_event (GtkWidget *widget, GdkEventConfigure *event) { draw_init_font (widget->style); + DdbTabStrip *ts = DDB_TABSTRIP (widget); + tabstrip_adjust_hscroll (ts); int height = draw_get_font_size () + 13; if (height != widget->allocation.height) { gtk_widget_set_size_request (widget, -1, height); @@ -789,7 +1003,12 @@ on_tabstrip_motion_notify_event (GtkWidget *widget, // find closest tab to the left int idx; - int x = -ts->hscrollpos + tabs_left_margin; + int hscroll = ts->hscrollpos; + int need_arrows = tabstrip_need_arrows (ts); + if (need_arrows) { + hscroll -= arrow_widget_width; + } + int x = -hscroll + tabs_left_margin; int inspos = -1; int cnt = deadbeef->plt_get_count (); for (idx = 0; idx < cnt; idx++) { @@ -840,7 +1059,7 @@ on_tabstrip_drag_motion_event (GtkWidget *widget, gint y, guint time) { - int tab = get_tab_under_cursor (x); + int tab = get_tab_under_cursor (DDB_TABSTRIP (widget), x); int prev = deadbeef->plt_get_curr (); if (tab != -1 && tab != prev) { deadbeef->plt_set_curr (tab); diff --git a/plugins/gtkui/ddbtabstrip.h b/plugins/gtkui/ddbtabstrip.h index 10639aa9..7f530e2f 100644 --- a/plugins/gtkui/ddbtabstrip.h +++ b/plugins/gtkui/ddbtabstrip.h @@ -44,6 +44,8 @@ struct _DdbTabStrip { int dragpt[2]; int prev_x; int movepos; + guint scroll_timer; + int scroll_direction; }; struct _DdbTabStripClass { diff --git a/plugins/gtkui/deadbeef.glade b/plugins/gtkui/deadbeef.glade index c2dd31f0..e0aceb88 100644 --- a/plugins/gtkui/deadbeef.glade +++ b/plugins/gtkui/deadbeef.glade @@ -62,7 +62,7 @@ <accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image423"> + <widget class="GtkImage" id="image430"> <property name="visible">True</property> <property name="stock">gtk-open</property> <property name="icon_size">1</property> @@ -89,7 +89,7 @@ <signal name="activate" handler="on_add_files_activate" last_modification_time="Sat, 04 Jul 2009 13:04:01 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image424"> + <widget class="GtkImage" id="image431"> <property name="visible">True</property> <property name="stock">gtk-add</property> <property name="icon_size">1</property> @@ -110,7 +110,7 @@ <signal name="activate" handler="on_add_folders_activate" last_modification_time="Sun, 06 Sep 2009 17:51:40 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image425"> + <widget class="GtkImage" id="image432"> <property name="visible">True</property> <property name="stock">gtk-add</property> <property name="icon_size">1</property> @@ -190,7 +190,7 @@ <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image426"> + <widget class="GtkImage" id="image433"> <property name="visible">True</property> <property name="stock">gtk-quit</property> <property name="icon_size">1</property> @@ -224,7 +224,7 @@ <signal name="activate" handler="on_clear1_activate" last_modification_time="Sun, 06 Sep 2009 18:30:03 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image427"> + <widget class="GtkImage" id="image434"> <property name="visible">True</property> <property name="stock">gtk-clear</property> <property name="icon_size">1</property> @@ -283,7 +283,7 @@ <signal name="activate" handler="on_remove1_activate" last_modification_time="Sun, 06 Sep 2009 18:30:03 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image428"> + <widget class="GtkImage" id="image435"> <property name="visible">True</property> <property name="stock">gtk-remove</property> <property name="icon_size">1</property> @@ -520,6 +520,22 @@ <accelerator key="M" modifiers="GDK_CONTROL_MASK" signal="activate"/> </widget> </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator11"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="jump_to_current_track1"> + <property name="visible">True</property> + <property name="label" translatable="yes">Jump to current track</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_jump_to_current_track1_activate" last_modification_time="Wed, 01 Sep 2010 19:11:01 GMT"/> + <accelerator key="J" modifiers="GDK_CONTROL_MASK" signal="activate"/> + </widget> + </child> </widget> </child> </widget> @@ -542,7 +558,7 @@ <signal name="activate" handler="on_help1_activate" last_modification_time="Tue, 08 Sep 2009 17:32:06 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image429"> + <widget class="GtkImage" id="image436"> <property name="visible">True</property> <property name="stock">gtk-help</property> <property name="icon_size">1</property> @@ -573,7 +589,7 @@ <child> <widget class="GtkMenuItem" id="gpl1"> <property name="visible">True</property> - <property name="label">_GPLv2</property> + <property name="label" translatable="yes">_GPLv2</property> <property name="use_underline">True</property> <signal name="activate" handler="on_gpl1_activate" last_modification_time="Wed, 06 Jan 2010 20:30:20 GMT"/> </widget> @@ -582,7 +598,7 @@ <child> <widget class="GtkMenuItem" id="lgpl1"> <property name="visible">True</property> - <property name="label">_LGPLv2.1</property> + <property name="label" translatable="yes">_LGPLv2.1</property> <property name="use_underline">True</property> <signal name="activate" handler="on_lgpl1_activate" last_modification_time="Wed, 06 Jan 2010 20:30:20 GMT"/> </widget> @@ -602,7 +618,7 @@ <signal name="activate" handler="on_about1_activate" last_modification_time="Sat, 04 Jul 2009 12:57:58 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image430"> + <widget class="GtkImage" id="image437"> <property name="visible">True</property> <property name="stock">gtk-about</property> <property name="icon_size">1</property> @@ -784,6 +800,7 @@ <child> <widget class="Custom" id="seekbar"> + <property name="width_request">20</property> <property name="visible">True</property> <property name="creation_function">create_seekbar</property> <property name="int1">0</property> @@ -1422,32 +1439,6 @@ </child> <child> - <widget class="GtkLabel" id="label99"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>WARNING</b>: tag writing feature is still in development. -<b>Make backup copies</b> before using.</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - - <child> <widget class="GtkHButtonBox" id="hbuttonbox1"> <property name="visible">True</property> <property name="layout_style">GTK_BUTTONBOX_END</property> diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c index 9c7eb63b..f740bacb 100644 --- a/plugins/gtkui/gtkui.c +++ b/plugins/gtkui/gtkui.c @@ -992,7 +992,9 @@ gtkui_thread (void *ctx) { deadbeef->pl_format_title (NULL, -1, str, sizeof (str), -1, deadbeef->conf_get_str ("gtkui.titlebar_stopped", "DeaDBeeF-%V")); gtk_window_set_title (GTK_WINDOW (mainwin), str); gtk_initialized = 1; + gtk_main (); + cover_art_free (); eq_window_destroy (); trkproperties_destroy (); @@ -1062,6 +1064,17 @@ gtkui_pl_add_files_end (void) { gtkui_original_pl_add_files_end (); } +void +gtkui_focus_on_playing_track (void) { + DB_playItem_t *it = deadbeef->streamer_get_playing_track (); + if (it) { + int idx = deadbeef->pl_get_idx_of (it); + ddb_listview_scroll_to (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), idx); + ddb_listview_set_cursor (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), idx); + deadbeef->pl_item_unref (it); + } +} + static int gtkui_start (void) { // gtk must be running in separate thread diff --git a/plugins/gtkui/gtkui.h b/plugins/gtkui/gtkui.h index 5ab30376..c333b322 100644 --- a/plugins/gtkui/gtkui.h +++ b/plugins/gtkui/gtkui.h @@ -154,4 +154,7 @@ gtkui_add_file_info_cb (DB_playItem_t *it, void *data); extern int (*gtkui_original_pl_add_dir) (const char *dirname, int (*cb)(DB_playItem_t *it, void *data), void *user_data); extern int (*gtkui_original_pl_add_file) (const char *fname, int (*cb)(DB_playItem_t *it, void *data), void *user_data); +void +gtkui_focus_on_playing_track (void); + #endif diff --git a/plugins/gtkui/interface.c b/plugins/gtkui/interface.c index e6f59396..b1a9a3e3 100644 --- a/plugins/gtkui/interface.c +++ b/plugins/gtkui/interface.c @@ -35,12 +35,12 @@ create_mainwin (void) GtkWidget *File; GtkWidget *File_menu; GtkWidget *open; - GtkWidget *image423; + GtkWidget *image430; GtkWidget *separator2; GtkWidget *add_files; - GtkWidget *image424; + GtkWidget *image431; GtkWidget *add_folders; - GtkWidget *image425; + GtkWidget *image432; GtkWidget *add_location1; GtkWidget *separatormenuitem1; GtkWidget *new_playlist1; @@ -49,18 +49,18 @@ create_mainwin (void) GtkWidget *playlist_save_as; GtkWidget *separator8; GtkWidget *quit; - GtkWidget *image426; + GtkWidget *image433; GtkWidget *Edit; GtkWidget *Edit_menu; GtkWidget *clear1; - GtkWidget *image427; + GtkWidget *image434; GtkWidget *select_all1; GtkWidget *deselect_all1; GtkWidget *invert_selection1; GtkWidget *Selection; GtkWidget *Selection_menu; GtkWidget *remove1; - GtkWidget *image428; + GtkWidget *image435; GtkWidget *crop1; GtkWidget *find1; GtkWidget *separator5; @@ -88,17 +88,19 @@ create_mainwin (void) GtkWidget *scroll_follows_playback; GtkWidget *cursor_follows_playback; GtkWidget *stop_after_current; + GtkWidget *separator11; + GtkWidget *jump_to_current_track1; GtkWidget *Help; GtkWidget *Help_menu; GtkWidget *help1; - GtkWidget *image429; + GtkWidget *image436; GtkWidget *changelog1; GtkWidget *separator10; GtkWidget *gpl1; GtkWidget *lgpl1; GtkWidget *separator9; GtkWidget *about1; - GtkWidget *image430; + GtkWidget *image437; GtkWidget *hbox2; GtkWidget *hbox3; GtkWidget *stopbtn; @@ -149,9 +151,9 @@ create_mainwin (void) GDK_O, (GdkModifierType) GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); - image423 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU); - gtk_widget_show (image423); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (open), image423); + image430 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU); + gtk_widget_show (image430); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (open), image430); separator2 = gtk_separator_menu_item_new (); gtk_widget_show (separator2); @@ -162,17 +164,17 @@ create_mainwin (void) gtk_widget_show (add_files); gtk_container_add (GTK_CONTAINER (File_menu), add_files); - image424 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU); - gtk_widget_show (image424); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_files), image424); + image431 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU); + gtk_widget_show (image431); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_files), image431); add_folders = gtk_image_menu_item_new_with_mnemonic (_("Add folder(s)")); gtk_widget_show (add_folders); gtk_container_add (GTK_CONTAINER (File_menu), add_folders); - image425 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU); - gtk_widget_show (image425); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_folders), image425); + image432 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU); + gtk_widget_show (image432); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_folders), image432); add_location1 = gtk_menu_item_new_with_mnemonic (_("Add location")); gtk_widget_show (add_location1); @@ -214,9 +216,9 @@ create_mainwin (void) GDK_Q, (GdkModifierType) GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); - image426 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU); - gtk_widget_show (image426); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (quit), image426); + image433 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU); + gtk_widget_show (image433); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (quit), image433); Edit = gtk_menu_item_new_with_mnemonic (_("_Edit")); gtk_widget_show (Edit); @@ -229,9 +231,9 @@ create_mainwin (void) gtk_widget_show (clear1); gtk_container_add (GTK_CONTAINER (Edit_menu), clear1); - image427 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_MENU); - gtk_widget_show (image427); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (clear1), image427); + image434 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_MENU); + gtk_widget_show (image434); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (clear1), image434); select_all1 = gtk_menu_item_new_with_mnemonic (_("Select all")); gtk_widget_show (select_all1); @@ -262,9 +264,9 @@ create_mainwin (void) gtk_widget_show (remove1); gtk_container_add (GTK_CONTAINER (Selection_menu), remove1); - image428 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU); - gtk_widget_show (image428); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (remove1), image428); + image435 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU); + gtk_widget_show (image435); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (remove1), image435); crop1 = gtk_menu_item_new_with_mnemonic (_("Crop")); gtk_widget_show (crop1); @@ -382,6 +384,18 @@ create_mainwin (void) GDK_M, (GdkModifierType) GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); + separator11 = gtk_separator_menu_item_new (); + gtk_widget_show (separator11); + gtk_container_add (GTK_CONTAINER (Playback_menu), separator11); + gtk_widget_set_sensitive (separator11, FALSE); + + jump_to_current_track1 = gtk_menu_item_new_with_mnemonic (_("Jump to current track")); + gtk_widget_show (jump_to_current_track1); + gtk_container_add (GTK_CONTAINER (Playback_menu), jump_to_current_track1); + gtk_widget_add_accelerator (jump_to_current_track1, "activate", accel_group, + GDK_J, (GdkModifierType) GDK_CONTROL_MASK, + GTK_ACCEL_VISIBLE); + Help = gtk_menu_item_new_with_mnemonic (_("_Help")); gtk_widget_show (Help); gtk_container_add (GTK_CONTAINER (menubar1), Help); @@ -393,9 +407,9 @@ create_mainwin (void) gtk_widget_show (help1); gtk_container_add (GTK_CONTAINER (Help_menu), help1); - image429 = gtk_image_new_from_stock ("gtk-help", GTK_ICON_SIZE_MENU); - gtk_widget_show (image429); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (help1), image429); + image436 = gtk_image_new_from_stock ("gtk-help", GTK_ICON_SIZE_MENU); + gtk_widget_show (image436); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (help1), image436); changelog1 = gtk_menu_item_new_with_mnemonic (_("_ChangeLog")); gtk_widget_show (changelog1); @@ -406,11 +420,11 @@ create_mainwin (void) gtk_container_add (GTK_CONTAINER (Help_menu), separator10); gtk_widget_set_sensitive (separator10, FALSE); - gpl1 = gtk_menu_item_new_with_mnemonic ("_GPLv2"); + gpl1 = gtk_menu_item_new_with_mnemonic (_("_GPLv2")); gtk_widget_show (gpl1); gtk_container_add (GTK_CONTAINER (Help_menu), gpl1); - lgpl1 = gtk_menu_item_new_with_mnemonic ("_LGPLv2.1"); + lgpl1 = gtk_menu_item_new_with_mnemonic (_("_LGPLv2.1")); gtk_widget_show (lgpl1); gtk_container_add (GTK_CONTAINER (Help_menu), lgpl1); @@ -423,9 +437,9 @@ create_mainwin (void) gtk_widget_show (about1); gtk_container_add (GTK_CONTAINER (Help_menu), about1); - image430 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU); - gtk_widget_show (image430); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (about1), image430); + image437 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU); + gtk_widget_show (image437); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (about1), image437); hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); @@ -509,6 +523,7 @@ create_mainwin (void) seekbar = create_seekbar ("seekbar", "", "", 0, 0); gtk_widget_show (seekbar); gtk_box_pack_start (GTK_BOX (hbox2), seekbar, TRUE, TRUE, 2); + gtk_widget_set_size_request (seekbar, 20, -1); GTK_WIDGET_UNSET_FLAGS (seekbar, GTK_CAN_FOCUS); GTK_WIDGET_UNSET_FLAGS (seekbar, GTK_CAN_DEFAULT); @@ -662,6 +677,9 @@ create_mainwin (void) g_signal_connect ((gpointer) stop_after_current, "activate", G_CALLBACK (on_stop_after_current_activate), NULL); + g_signal_connect ((gpointer) jump_to_current_track1, "activate", + G_CALLBACK (on_jump_to_current_track1_activate), + NULL); g_signal_connect ((gpointer) help1, "activate", G_CALLBACK (on_help1_activate), NULL); @@ -700,12 +718,12 @@ create_mainwin (void) GLADE_HOOKUP_OBJECT (mainwin, File, "File"); GLADE_HOOKUP_OBJECT (mainwin, File_menu, "File_menu"); GLADE_HOOKUP_OBJECT (mainwin, open, "open"); - GLADE_HOOKUP_OBJECT (mainwin, image423, "image423"); + GLADE_HOOKUP_OBJECT (mainwin, image430, "image430"); GLADE_HOOKUP_OBJECT (mainwin, separator2, "separator2"); GLADE_HOOKUP_OBJECT (mainwin, add_files, "add_files"); - GLADE_HOOKUP_OBJECT (mainwin, image424, "image424"); + GLADE_HOOKUP_OBJECT (mainwin, image431, "image431"); GLADE_HOOKUP_OBJECT (mainwin, add_folders, "add_folders"); - GLADE_HOOKUP_OBJECT (mainwin, image425, "image425"); + GLADE_HOOKUP_OBJECT (mainwin, image432, "image432"); GLADE_HOOKUP_OBJECT (mainwin, add_location1, "add_location1"); GLADE_HOOKUP_OBJECT (mainwin, separatormenuitem1, "separatormenuitem1"); GLADE_HOOKUP_OBJECT (mainwin, new_playlist1, "new_playlist1"); @@ -714,18 +732,18 @@ create_mainwin (void) GLADE_HOOKUP_OBJECT (mainwin, playlist_save_as, "playlist_save_as"); GLADE_HOOKUP_OBJECT (mainwin, separator8, "separator8"); GLADE_HOOKUP_OBJECT (mainwin, quit, "quit"); - GLADE_HOOKUP_OBJECT (mainwin, image426, "image426"); + GLADE_HOOKUP_OBJECT (mainwin, image433, "image433"); GLADE_HOOKUP_OBJECT (mainwin, Edit, "Edit"); GLADE_HOOKUP_OBJECT (mainwin, Edit_menu, "Edit_menu"); GLADE_HOOKUP_OBJECT (mainwin, clear1, "clear1"); - GLADE_HOOKUP_OBJECT (mainwin, image427, "image427"); + GLADE_HOOKUP_OBJECT (mainwin, image434, "image434"); GLADE_HOOKUP_OBJECT (mainwin, select_all1, "select_all1"); GLADE_HOOKUP_OBJECT (mainwin, deselect_all1, "deselect_all1"); GLADE_HOOKUP_OBJECT (mainwin, invert_selection1, "invert_selection1"); GLADE_HOOKUP_OBJECT (mainwin, Selection, "Selection"); GLADE_HOOKUP_OBJECT (mainwin, Selection_menu, "Selection_menu"); GLADE_HOOKUP_OBJECT (mainwin, remove1, "remove1"); - GLADE_HOOKUP_OBJECT (mainwin, image428, "image428"); + GLADE_HOOKUP_OBJECT (mainwin, image435, "image435"); GLADE_HOOKUP_OBJECT (mainwin, crop1, "crop1"); GLADE_HOOKUP_OBJECT (mainwin, find1, "find1"); GLADE_HOOKUP_OBJECT (mainwin, separator5, "separator5"); @@ -751,17 +769,19 @@ create_mainwin (void) GLADE_HOOKUP_OBJECT (mainwin, scroll_follows_playback, "scroll_follows_playback"); GLADE_HOOKUP_OBJECT (mainwin, cursor_follows_playback, "cursor_follows_playback"); GLADE_HOOKUP_OBJECT (mainwin, stop_after_current, "stop_after_current"); + GLADE_HOOKUP_OBJECT (mainwin, separator11, "separator11"); + GLADE_HOOKUP_OBJECT (mainwin, jump_to_current_track1, "jump_to_current_track1"); GLADE_HOOKUP_OBJECT (mainwin, Help, "Help"); GLADE_HOOKUP_OBJECT (mainwin, Help_menu, "Help_menu"); GLADE_HOOKUP_OBJECT (mainwin, help1, "help1"); - GLADE_HOOKUP_OBJECT (mainwin, image429, "image429"); + GLADE_HOOKUP_OBJECT (mainwin, image436, "image436"); GLADE_HOOKUP_OBJECT (mainwin, changelog1, "changelog1"); GLADE_HOOKUP_OBJECT (mainwin, separator10, "separator10"); GLADE_HOOKUP_OBJECT (mainwin, gpl1, "gpl1"); GLADE_HOOKUP_OBJECT (mainwin, lgpl1, "lgpl1"); GLADE_HOOKUP_OBJECT (mainwin, separator9, "separator9"); GLADE_HOOKUP_OBJECT (mainwin, about1, "about1"); - GLADE_HOOKUP_OBJECT (mainwin, image430, "image430"); + GLADE_HOOKUP_OBJECT (mainwin, image437, "image437"); GLADE_HOOKUP_OBJECT (mainwin, hbox2, "hbox2"); GLADE_HOOKUP_OBJECT (mainwin, hbox3, "hbox3"); GLADE_HOOKUP_OBJECT (mainwin, stopbtn, "stopbtn"); @@ -1126,7 +1146,6 @@ create_trackproperties (void) GtkWidget *vbox16; GtkWidget *scrolledwindow5; GtkWidget *metalist; - GtkWidget *label99; GtkWidget *hbuttonbox1; GtkWidget *write_tags; GtkWidget *alignment11; @@ -1176,11 +1195,6 @@ create_trackproperties (void) gtk_container_add (GTK_CONTAINER (scrolledwindow5), metalist); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (metalist), TRUE); - label99 = gtk_label_new (_("<b>WARNING</b>: tag writing feature is still in development.\n<b>Make backup copies</b> before using.")); - gtk_widget_show (label99); - gtk_box_pack_start (GTK_BOX (vbox16), label99, FALSE, FALSE, 0); - gtk_label_set_use_markup (GTK_LABEL (label99), TRUE); - hbuttonbox1 = gtk_hbutton_box_new (); gtk_widget_show (hbuttonbox1); gtk_box_pack_start (GTK_BOX (vbox16), hbuttonbox1, FALSE, FALSE, 0); @@ -1300,7 +1314,6 @@ create_trackproperties (void) GLADE_HOOKUP_OBJECT (trackproperties, vbox16, "vbox16"); GLADE_HOOKUP_OBJECT (trackproperties, scrolledwindow5, "scrolledwindow5"); GLADE_HOOKUP_OBJECT (trackproperties, metalist, "metalist"); - GLADE_HOOKUP_OBJECT (trackproperties, label99, "label99"); GLADE_HOOKUP_OBJECT (trackproperties, hbuttonbox1, "hbuttonbox1"); GLADE_HOOKUP_OBJECT (trackproperties, write_tags, "write_tags"); GLADE_HOOKUP_OBJECT (trackproperties, alignment11, "alignment11"); diff --git a/plugins/gtkui/plcommon.c b/plugins/gtkui/plcommon.c index 02b41a87..61fdc925 100644 --- a/plugins/gtkui/plcommon.c +++ b/plugins/gtkui/plcommon.c @@ -19,6 +19,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <gdk/gdkkeysyms.h> #include "gtkui.h" #include "plcommon.h" #include "coverart.h" @@ -41,6 +42,8 @@ extern GdkPixbuf *play16_pixbuf; extern GdkPixbuf *pause16_pixbuf; extern GdkPixbuf *buffering16_pixbuf; +static int clicked_idx = -1; + void write_column_config (const char *name, int idx, const char *title, int width, int align_right, int id, const char *format) { char key[128]; @@ -259,8 +262,6 @@ main_reload_metadata_activate trkproperties_fill_metadata (); } -int clicked_idx = -1; - void main_properties_activate (GtkMenuItem *menuitem, gpointer user_data) diff --git a/plugins/lastfm/lastfm.c b/plugins/lastfm/lastfm.c index f71bc2dc..27c6f6f0 100644 --- a/plugins/lastfm/lastfm.c +++ b/plugins/lastfm/lastfm.c @@ -843,7 +843,7 @@ lfm_action_lookup (DB_plugin_action_t *action, DB_playItem_t *it) return 0; char *command = NULL; - if (-1 == asprintf (&command, "xdg-open 'http://www.last.fm/music/%s/_/%s'", eartist, etitle)) + if (-1 == asprintf (&command, "xdg-open 'http://www.last.fm/music/%s/_/%s' &", eartist, etitle)) return 0; printf ("executing %s\n", command); system (command); diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 5f74b111..abdf117e 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -27,6 +27,12 @@ //#define trace(...) { fprintf(stderr, __VA_ARGS__); } #define trace(fmt,...) +//#define WRITE_DUMP 1 + +#if WRITE_DUMP +FILE *out; +#endif + #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) @@ -170,7 +176,7 @@ static int cmp3_scan_stream (buffer_t *buffer, int sample) { trace ("cmp3_scan_stream %d\n", sample); int initpos = deadbeef->ftell (buffer->file); - trace ("filepos: %d\n", initpos); + trace ("initpos: %d\n", initpos); // if (sample == 0) { // sample = -1; // } @@ -189,11 +195,12 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { buffer->totalsamples = 0; fsize = deadbeef->fgetlength (buffer->file) - initpos; } - if (sample == 0 && buffer->avg_packetlength == 0) { + if (sample <= 0 && buffer->avg_packetlength == 0) { buffer->avg_packetlength = 0; buffer->avg_samplerate = 0; buffer->avg_samples_per_frame = 0; buffer->nframes = 0; + trace ("setting startoffset to %d\n", initpos); buffer->startoffset = initpos; } @@ -357,7 +364,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { buffer->frameduration = dur; buffer->channels = nchannels; buffer->bitspersample = 16; - //trace ("frame %d(@%d) mpeg v%d layer %d bitrate %d samplerate %d packetlength %d framedur %f channels %d\n", nframe, pos, ver, layer, bitrate, samplerate, packetlength, dur, nchannels); + //trace ("frame %d mpeg v%d layer %d bitrate %d samplerate %d packetlength %d framedur %f channels %d\n", nframe, ver, layer, bitrate, samplerate, packetlength, dur, nchannels); } // try to read xing/info tag (only on initial scans) if (sample <= 0 && !got_xing_header) @@ -377,11 +384,6 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { trace ("cmp3_scan_stream: EOF while checking for Xing header\n"); return -1; // EOF } - // add information to skip this frame - int startoffset = deadbeef->ftell (buffer->file) + packetlength; - if (startoffset > buffer->startoffset) { - buffer->startoffset = startoffset; - } // trace ("xing magic: %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]); @@ -584,7 +586,7 @@ cmp3_init (DB_fileinfo_t *_info, DB_playItem_t *it) { if (!info->buffer.file->vfs->streaming) { int skip = deadbeef->junk_get_leading_size (info->buffer.file); if (skip > 0) { - trace ("mpgmad: skipping %d bytes of junk\n", skip); + trace ("mpgmad: skipping %d(%xH) bytes of junk\n", skip, skip); deadbeef->fseek (info->buffer.file, skip, SEEK_SET); } cmp3_scan_stream (&info->buffer, -1); // scan entire stream, calc duration @@ -600,6 +602,7 @@ cmp3_init (DB_fileinfo_t *_info, DB_playItem_t *it) { info->buffer.endsample = info->buffer.totalsamples-1; info->buffer.skipsamples = info->buffer.startdelay; info->buffer.currentsample = info->buffer.startdelay; + trace ("mpgmad: seeking to %d(%xH) start offset\n", info->buffer.startoffset, info->buffer.startoffset); deadbeef->fseek (info->buffer.file, info->buffer.startoffset, SEEK_SET); } } @@ -822,6 +825,9 @@ cmp3_stream_frame (mpgmad_info_t *info) { if (bytes[0] != 0xff || (bytes[1]&(3<<5)) != (3<<5)) { trace ("mpgmad: read didn't start at frame boundary!\ncmp3_scan_stream is broken\n"); } + else { + trace ("mpgmad: streambuffer=NULL\n"); + } } } info->stream.error=0; @@ -830,16 +836,14 @@ cmp3_stream_frame (mpgmad_info_t *info) { { if(MAD_RECOVERABLE(info->stream.error)) { -#if 0 if(info->stream.error!=MAD_ERROR_LOSTSYNC) { trace ("mpgmad: recoverable frame level error (%s)\n", MadErrorString(&info->stream)); } -#endif continue; } else { if(info->stream.error==MAD_ERROR_BUFLEN) { -// trace ("mpgmad: recoverable frame level error (%s)\n", MadErrorString(&info->stream)); + trace ("mpgmad: recoverable frame level error (%s)\n", MadErrorString(&info->stream)); continue; } else @@ -931,12 +935,22 @@ cmp3_free (DB_fileinfo_t *_info) { static int cmp3_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) { +#if WRITE_DUMP + if (!out) { + out = fopen ("out.raw", "w+b"); + } +#endif mpgmad_info_t *info = (mpgmad_info_t *)_info; info->buffer.readsize = size; info->buffer.out = bytes; cmp3_decode_int16 (info); info->buffer.currentsample += (size - info->buffer.readsize) / 4; _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate; +#if WRITE_DUMP + if (size - info->buffer.readsize > 0) { + fwrite (bytes, 1, size - info->buffer.readsize, out); + } +#endif return size - info->buffer.readsize; } diff --git a/plugins/shellexec/shellexec.c b/plugins/shellexec/shellexec.c index 35c8a2eb..e8298cab 100644 --- a/plugins/shellexec/shellexec.c +++ b/plugins/shellexec/shellexec.c @@ -130,44 +130,37 @@ shx_start () strcpy (tmp, item->value); trace ("Shellexec: %s\n", tmp); - const char *command; - const char *title; - const char *name; - const char *flags; + char *args[4] = {0}; - char *semicolon; int idx = 0; - tmpptr = tmp; - do - { - semicolon = strchr (tmpptr, ':'); - if (semicolon) - *semicolon = 0; - - trace ("Shellexec: idx: %d, tmp: %s\n", idx, tmpptr); - switch (idx) - { - case 0: command = trim (tmpptr); break; - case 1: title = trim (tmpptr); break; - case 2: name = trim (tmpptr); break; - case 3: flags = trim (tmpptr); break; + char *p = tmp; + while (idx < 4 && p) { + char *e = strchr (p, ':'); + args[idx++] = p; + if (!e) { + break; } - if (semicolon) - tmpptr = semicolon + 1; - idx++; + *e = 0; + p = e+1; } - while (semicolon); if (idx < 2) { fprintf (stderr, "Shellexec: need at least command and title (%s)\n", item->value); continue; } - if (idx > 4) - { - fprintf (stderr, "Shellexec: too many parameters in configuration line (%s)\n", item->value); - continue; + + const char *command = args[0]; + const char *title = args[1]; + const char *name = args[2]; + const char *flags = args[3]; + if (!name) { + name = "noname"; + } + if (!flags) { + flags = "local"; } + if (strstr (flags, "disabled")) continue; diff --git a/plugins/vorbis/vorbis.c b/plugins/vorbis/vorbis.c index 390e614e..ae1e8832 100644 --- a/plugins/vorbis/vorbis.c +++ b/plugins/vorbis/vorbis.c @@ -82,12 +82,13 @@ static const char *metainfo[] = { "GENRE", "genre", "COMMENT", "comment", "PERFORMER", "performer", - "ENSEMBLE", "band", +// "ENSEMBLE", "band", "COMPOSER", "composer", "ENCODER", "vendor", "DISCNUMBER", "disc", "COPYRIGHT", "copyright", "TRACKTOTAL", "numtracks", + "ALBUM ARTIST", "band", NULL }; @@ -40,6 +40,12 @@ //#define trace(...) { fprintf(stderr, __VA_ARGS__); } #define trace(fmt,...) +// #define WRITE_DUMP 1 + +#if WRITE_DUMP +FILE *out; +#endif + static intptr_t streamer_tid; static int src_quality; static SRC_STATE *src; @@ -500,7 +506,14 @@ streamer_move_to_randomsong (void) { trace ("empty playlist\n"); return -1; } + int curr = str_get_idx_of (playing_track); int r = rand () / (float)RAND_MAX * cnt; + if (r == curr) { + r++; + if (r >= cnt) { + r = 0; + } + } streamer_set_nextsong (r, 1); return 0; } @@ -805,6 +818,19 @@ streamer_start_new_song (void) { } } else if (pstate == 2) { + if (p_get_state () == OUTPUT_STATE_STOPPED) { + last_bitrate = -1; + avg_bitrate = -1; + streamer_reset (1); + if (fileinfo) { + plug_get_output ()->change_rate (fileinfo->samplerate); + } + if (p_play () < 0) { + fprintf (stderr, "streamer: failed to start playback; output plugin doesn't work\n"); + streamer_set_nextsong (-2, 0); + return; + } + } p_pause (); } } @@ -1083,6 +1109,9 @@ streamer_thread (void *ctx) { int streamer_init (void) { +#if WRITE_DUMP + out = fopen ("out.raw", "w+b"); +#endif mutex = mutex_create (); decodemutex = mutex_create (); srcmutex = mutex_create (); @@ -1099,6 +1128,9 @@ streamer_init (void) { void streamer_free (void) { +#if WRITE_DUMP + fclose (out); +#endif streamer_abort_files (); streaming_terminate = 1; thread_join (streamer_tid); @@ -1616,6 +1648,9 @@ streamer_read (char *bytes, int size) { int ms = (tm2.tv_sec*1000+tm2.tv_usec/1000) - (tm1.tv_sec*1000+tm1.tv_usec/1000); printf ("streamer_read took %d ms\n", ms); #endif +#if WRITE_DUMP + fwrite (bytes, 1, sz, out); +#endif return sz; } |