comparison src/audacious/ui_main.c @ 2500:04642d2d0941 trunk

[svn] - split out jump to track
author nenolod
date Sat, 10 Feb 2007 20:47:46 -0800
parents 204d1bab71f9
children 319b10203d7c
comparison
equal deleted inserted replaced
2499:15a1f5ee4d1c 2500:04642d2d0941
81 #include "strings.h" 81 #include "strings.h"
82 #include "util.h" 82 #include "util.h"
83 #include "visualization.h" 83 #include "visualization.h"
84 84
85 #include "ui_skinned_window.h" 85 #include "ui_skinned_window.h"
86 #include "ui_jumptotrack.h"
86 87
87 static GTimeVal cb_time; /* click delay for tristate is defined by TRISTATE_THRESHOLD */ 88 static GTimeVal cb_time; /* click delay for tristate is defined by TRISTATE_THRESHOLD */
88 89
89 #define ITEM_SEPARATOR {"/-", NULL, NULL, 0, "<Separator>"} 90 #define ITEM_SEPARATOR {"/-", NULL, NULL, 0, "<Separator>"}
90 #define TRISTATE_THRESHOLD 200 91 #define TRISTATE_THRESHOLD 200
117 GtkWidget *err = NULL; /* an error dialog for miscellaneous error messages */ 118 GtkWidget *err = NULL; /* an error dialog for miscellaneous error messages */
118 119
119 static GdkBitmap *nullmask; 120 static GdkBitmap *nullmask;
120 static gint balance; 121 static gint balance;
121 122
122 GtkWidget *mainwin_jtf = NULL;
123 static GtkWidget *mainwin_jtt = NULL; 123 static GtkWidget *mainwin_jtt = NULL;
124 124
125 gint seek_state = MAINWIN_SEEK_NIL; 125 gint seek_state = MAINWIN_SEEK_NIL;
126 gint seek_initial_pos = 0; 126 gint seek_initial_pos = 0;
127 127
1260 break; 1260 break;
1261 case GDK_KP_6: 1261 case GDK_KP_6:
1262 playlist_next(playlist); 1262 playlist_next(playlist);
1263 break; 1263 break;
1264 case GDK_KP_Insert: 1264 case GDK_KP_Insert:
1265 mainwin_jump_to_file(); 1265 ui_jump_to_track();
1266 break; 1266 break;
1267 case GDK_KP_5: 1267 case GDK_KP_5:
1268 mainwin_play_pushed(); 1268 mainwin_play_pushed();
1269 break; 1269 break;
1270 case GDK_Escape: 1270 case GDK_Escape:
1392 1392
1393 gtk_widget_show_all(mainwin_jtt); 1393 gtk_widget_show_all(mainwin_jtt);
1394 1394
1395 gtk_widget_grab_focus(time_entry); 1395 gtk_widget_grab_focus(time_entry);
1396 gtk_widget_grab_default(jump); 1396 gtk_widget_grab_default(jump);
1397 }
1398
1399 static void
1400 change_song(guint pos)
1401 {
1402 if (playback_get_playing())
1403 playback_stop();
1404
1405 playlist_set_position(playlist_get_active(), pos);
1406 playback_initiate();
1407 }
1408
1409 static void
1410 mainwin_jump_to_file_jump(GtkTreeView * treeview)
1411 {
1412 GtkTreeModel *model;
1413 GtkTreeSelection *selection;
1414 GtkTreeIter iter;
1415 guint pos;
1416
1417 model = gtk_tree_view_get_model(treeview);
1418 selection = gtk_tree_view_get_selection(treeview);
1419
1420 if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
1421 return;
1422
1423 gtk_tree_model_get(model, &iter, 0, &pos, -1);
1424
1425 change_song(pos - 1);
1426
1427 /* FIXME: should only hide window */
1428 gtk_widget_destroy(mainwin_jtf);
1429 mainwin_jtf = NULL;
1430 }
1431
1432 static void
1433 mainwin_jump_to_file_jump_cb(GtkTreeView * treeview,
1434 gpointer data)
1435 {
1436 mainwin_jump_to_file_jump(treeview);
1437 }
1438
1439 static void
1440 mainwin_jump_to_file_set_queue_button_label(GtkButton * button,
1441 guint pos)
1442 {
1443 if (playlist_is_position_queued(playlist_get_active(), pos))
1444 gtk_button_set_label(button, _("Un_queue"));
1445 else
1446 gtk_button_set_label(button, _("_Queue"));
1447 }
1448
1449 static void
1450 mainwin_jump_to_file_queue_cb(GtkButton * button,
1451 gpointer data)
1452 {
1453 GtkTreeView *treeview;
1454 GtkTreeModel *model;
1455 GtkTreeSelection *selection;
1456 GtkTreeIter iter;
1457 guint pos;
1458
1459 treeview = GTK_TREE_VIEW(data);
1460 model = gtk_tree_view_get_model(treeview);
1461 selection = gtk_tree_view_get_selection(treeview);
1462
1463 if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
1464 return;
1465
1466 gtk_tree_model_get(model, &iter, 0, &pos, -1);
1467
1468 playlist_queue_position(playlist_get_active(), (pos - 1));
1469
1470 mainwin_jump_to_file_set_queue_button_label(button, (pos - 1));
1471 }
1472
1473 static void
1474 mainwin_jump_to_file_selection_changed_cb(GtkTreeSelection *treesel,
1475 gpointer data)
1476 {
1477 GtkTreeView *treeview;
1478 GtkTreeModel *model;
1479 GtkTreeSelection *selection;
1480 GtkTreeIter iter;
1481 guint pos;
1482
1483 treeview = gtk_tree_selection_get_tree_view(treesel);
1484 model = gtk_tree_view_get_model(treeview);
1485 selection = gtk_tree_view_get_selection(treeview);
1486
1487 if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
1488 return;
1489
1490 gtk_tree_model_get(model, &iter, 0, &pos, -1);
1491
1492 mainwin_jump_to_file_set_queue_button_label(GTK_BUTTON(data), (pos - 1));
1493 }
1494
1495 static gboolean
1496 mainwin_jump_to_file_edit_keypress_cb(GtkWidget * object,
1497 GdkEventKey * event,
1498 gpointer data)
1499 {
1500 switch (event->keyval) {
1501 case GDK_Return:
1502 if (gtk_im_context_filter_keypress (GTK_ENTRY (object)->im_context, event)) {
1503 GTK_ENTRY (object)->need_im_reset = TRUE;
1504 return TRUE;
1505 } else {
1506 mainwin_jump_to_file_jump(GTK_TREE_VIEW(data));
1507 return TRUE;
1508 }
1509 default:
1510 return FALSE;
1511 }
1512 }
1513
1514 static gboolean
1515 mainwin_jump_to_file_keypress_cb(GtkWidget * object,
1516 GdkEventKey * event,
1517 gpointer data)
1518 {
1519 switch (event->keyval) {
1520 case GDK_Escape:
1521 /* FIXME: show only hide window */
1522 gtk_widget_destroy(mainwin_jtf);
1523 mainwin_jtf = NULL;
1524 return TRUE;
1525 case GDK_KP_Enter:
1526 mainwin_jump_to_file_queue_cb(NULL, data);
1527 return TRUE;
1528 default:
1529 return FALSE;
1530 };
1531
1532 return FALSE;
1533 }
1534
1535 static gboolean
1536 mainwin_jump_to_file_match(const gchar * song, GSList *regex_list)
1537 {
1538 gboolean rv = TRUE;
1539
1540 if ( song == NULL )
1541 return FALSE;
1542
1543 for ( ; regex_list ; regex_list = g_slist_next(regex_list) )
1544 {
1545 regex_t *regex = regex_list->data;
1546 if ( regexec( regex , song , 0 , NULL , 0 ) != 0 )
1547 {
1548 rv = FALSE;
1549 break;
1550 }
1551 }
1552
1553 return rv;
1554 }
1555
1556 /* FIXME: Clear the entry when the list gets updated */
1557 static void
1558 mainwin_update_jtf(GtkWidget * widget, gpointer user_data)
1559 {
1560 /* FIXME: Is not in sync with playlist due to delayed extinfo
1561 * reading */
1562 guint row;
1563 GList *playlist_glist;
1564 gchar *desc_buf = NULL;
1565 GtkTreeIter iter;
1566 GtkTreeSelection *selection;
1567 Playlist *playlist;
1568
1569 GtkTreeModel *store;
1570
1571 if (!mainwin_jtf)
1572 return;
1573
1574 store = gtk_tree_view_get_model(GTK_TREE_VIEW(user_data));
1575 gtk_list_store_clear(GTK_LIST_STORE(store));
1576
1577 row = 1;
1578 playlist = playlist_get_active();
1579 for (playlist_glist = playlist->entries; playlist_glist;
1580 playlist_glist = g_list_next(playlist_glist)) {
1581 PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data);
1582
1583 if (entry->title)
1584 desc_buf = g_strdup(entry->title);
1585 else if (strchr(entry->filename, '/'))
1586 desc_buf = str_to_utf8(strrchr(entry->filename, '/') + 1);
1587 else
1588 desc_buf = str_to_utf8(entry->filename);
1589
1590 gtk_list_store_append(GTK_LIST_STORE(store), &iter);
1591 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
1592 0, row, 1, desc_buf, -1);
1593 row++;
1594
1595 if(desc_buf) {
1596 g_free(desc_buf);
1597 desc_buf = NULL;
1598 }
1599 }
1600
1601 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
1602 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(user_data));
1603 gtk_tree_selection_select_iter(selection, &iter);
1604 }
1605
1606 static void
1607 mainwin_jump_to_file_edit_cb(GtkEntry * entry, gpointer user_data)
1608 {
1609 GtkTreeView *treeview = GTK_TREE_VIEW(user_data);
1610 GtkTreeSelection *selection;
1611 GtkTreeIter iter;
1612
1613 GtkListStore *store;
1614
1615 guint song_index = 0;
1616 gchar **words;
1617 GList *playlist_glist;
1618 Playlist *playlist;
1619
1620 gboolean match = FALSE;
1621
1622 GSList *regex_list = NULL, *regex_list_tmp = NULL;
1623 gint i = -1;
1624
1625 /* Chop the key string into ' '-separated key regex-pattern strings */
1626 words = g_strsplit(gtk_entry_get_text(entry), " ", 0);
1627
1628 /* create a list of regex using the regex-pattern strings */
1629 while ( words[++i] != NULL )
1630 {
1631 regex_t *regex = g_malloc(sizeof(regex_t));
1632 #if defined(USE_REGEX_PCRE)
1633 if ( regcomp( regex , words[i] , REG_NOSUB | REG_ICASE | REG_UTF8 ) == 0 )
1634 #else
1635 if ( regcomp( regex , words[i] , REG_NOSUB | REG_ICASE ) == 0 )
1636 #endif
1637 regex_list = g_slist_append( regex_list , regex );
1638 }
1639
1640 /* FIXME: Remove the connected signals before clearing
1641 * (row-selected will still eventually arrive once) */
1642 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
1643 /* detach model from treeview */
1644 g_object_ref( store );
1645 gtk_tree_view_set_model( GTK_TREE_VIEW(treeview) , NULL );
1646
1647 gtk_list_store_clear(store);
1648
1649 playlist = playlist_get_active();
1650
1651 PLAYLIST_LOCK(playlist->mutex);
1652
1653 for (playlist_glist = playlist->entries; playlist_glist;
1654 playlist_glist = g_list_next(playlist_glist)) {
1655
1656 PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data);
1657 const gchar *title;
1658 gchar *filename = NULL;
1659
1660 title = entry->title;
1661 if (!title) {
1662 filename = str_to_utf8(entry->filename);
1663
1664 if (strchr(filename, '/'))
1665 title = strrchr(filename, '/') + 1;
1666 else
1667 title = filename;
1668 }
1669
1670 /* Compare the reg.expressions to the string - if all the
1671 regexp in regex_list match, add to the ListStore */
1672
1673 /*
1674 * FIXME: The search string should be adapted to the
1675 * current display setting, e.g. if the user has set it to
1676 * "%p - %t" then build the match string like that too, or
1677 * even better, search for each of the tags seperatly.
1678 *
1679 * In any case the string to match should _never_ contain
1680 * something the user can't actually see in the playlist.
1681 */
1682 if (regex_list != NULL)
1683 match = mainwin_jump_to_file_match(title, regex_list);
1684 else
1685 match = TRUE;
1686
1687 if (match) {
1688 gtk_list_store_append(store, &iter);
1689 gtk_list_store_set(store, &iter, 0, song_index + 1 , 1, title, -1);
1690 }
1691
1692 song_index++;
1693
1694 if (filename) {
1695 g_free(filename);
1696 filename = NULL;
1697 }
1698 }
1699
1700 PLAYLIST_UNLOCK(playlist->mutex);
1701
1702 /* attach the model again to the treeview */
1703 gtk_tree_view_set_model( GTK_TREE_VIEW(treeview) , GTK_TREE_MODEL(store) );
1704 g_object_unref( store );
1705
1706 if ( regex_list != NULL )
1707 {
1708 regex_list_tmp = regex_list;
1709 while ( regex_list != NULL )
1710 {
1711 regex_t *regex = regex_list->data;
1712 regfree( regex );
1713 regex_list = g_slist_next(regex_list);
1714 }
1715 g_slist_free( regex_list_tmp );
1716 }
1717 g_strfreev(words);
1718
1719 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
1720 selection = gtk_tree_view_get_selection(treeview);
1721 gtk_tree_selection_select_iter(selection, &iter);
1722 }
1723 }
1724
1725 void
1726 mainwin_jump_to_file(void)
1727 {
1728 GtkWidget *scrollwin;
1729 GtkWidget *vbox, *bbox, *sep;
1730 GtkWidget *jump, *queue, *cancel;
1731 GtkWidget *rescan, *edit;
1732 GtkWidget *search_label, *hbox;
1733 GList *playlist_glist;
1734 Playlist *playlist;
1735 gchar *desc_buf = NULL;
1736 guint row;
1737
1738 GtkWidget *treeview;
1739 GtkListStore *jtf_store;
1740
1741 GtkTreeIter iter;
1742 GtkCellRenderer *renderer;
1743 GtkTreeViewColumn *column;
1744
1745 if (mainwin_jtf) {
1746 gtk_window_present(GTK_WINDOW(mainwin_jtf));
1747 return;
1748 }
1749
1750 #if defined(USE_REGEX_ONIGURUMA)
1751 /* set encoding for Oniguruma regex to UTF-8 */
1752 reg_set_encoding( REG_POSIX_ENCODING_UTF8 );
1753 onig_set_default_syntax( ONIG_SYNTAX_POSIX_BASIC );
1754 #endif
1755
1756 mainwin_jtf = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1757 gtk_window_set_type_hint(GTK_WINDOW(mainwin_jtf),
1758 GDK_WINDOW_TYPE_HINT_DIALOG);
1759
1760 gtk_window_set_title(GTK_WINDOW(mainwin_jtf), _("Jump to Track"));
1761
1762 gtk_window_set_position(GTK_WINDOW(mainwin_jtf), GTK_WIN_POS_CENTER);
1763 g_signal_connect(mainwin_jtf, "destroy",
1764 G_CALLBACK(gtk_widget_destroyed), &mainwin_jtf);
1765
1766 gtk_container_border_width(GTK_CONTAINER(mainwin_jtf), 10);
1767 gtk_window_set_default_size(GTK_WINDOW(mainwin_jtf), 550, 350);
1768
1769 vbox = gtk_vbox_new(FALSE, 5);
1770 gtk_container_add(GTK_CONTAINER(mainwin_jtf), vbox);
1771
1772 jtf_store = gtk_list_store_new(2, G_TYPE_UINT, G_TYPE_STRING);
1773 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(jtf_store));
1774 g_object_unref(jtf_store);
1775
1776 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
1777
1778 column = gtk_tree_view_column_new();
1779 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
1780 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1781
1782 renderer = gtk_cell_renderer_text_new();
1783 gtk_tree_view_column_pack_start(column, renderer, FALSE);
1784 gtk_tree_view_column_set_attributes(column, renderer, "text", 0, NULL);
1785 gtk_tree_view_column_set_spacing(column, 4);
1786
1787 renderer = gtk_cell_renderer_text_new();
1788 gtk_tree_view_column_pack_start(column, renderer, FALSE);
1789 gtk_tree_view_column_set_attributes(column, renderer, "text", 1, NULL);
1790 gtk_tree_view_column_set_spacing(column, 4);
1791 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
1792
1793 gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), 1);
1794
1795 g_signal_connect(treeview, "row-activated",
1796 G_CALLBACK(mainwin_jump_to_file_jump), NULL);
1797
1798 hbox = gtk_hbox_new(FALSE, 3);
1799 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
1800
1801 search_label = gtk_label_new(_("Filter: "));
1802 gtk_label_set_markup_with_mnemonic(GTK_LABEL(search_label), _("_Filter:"));
1803 gtk_box_pack_start(GTK_BOX(hbox), search_label, FALSE, FALSE, 0);
1804
1805 edit = gtk_entry_new();
1806 gtk_entry_set_editable(GTK_ENTRY(edit), TRUE);
1807 gtk_label_set_mnemonic_widget(GTK_LABEL(search_label), edit);
1808 g_signal_connect(edit, "changed",
1809 G_CALLBACK(mainwin_jump_to_file_edit_cb), treeview);
1810
1811 g_signal_connect(edit, "key_press_event",
1812 G_CALLBACK(mainwin_jump_to_file_edit_keypress_cb), treeview);
1813
1814 g_signal_connect(mainwin_jtf, "key_press_event",
1815 G_CALLBACK(mainwin_jump_to_file_keypress_cb), treeview);
1816
1817 gtk_box_pack_start(GTK_BOX(hbox), edit, TRUE, TRUE, 3);
1818
1819 scrollwin = gtk_scrolled_window_new(NULL, NULL);
1820 gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
1821 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
1822 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1823 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin),
1824 GTK_SHADOW_IN);
1825 gtk_box_pack_start(GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0);
1826
1827 sep = gtk_hseparator_new();
1828 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
1829
1830 bbox = gtk_hbutton_box_new();
1831 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1832 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
1833 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
1834
1835 queue = gtk_button_new_with_mnemonic(_("_Queue"));
1836 gtk_box_pack_start(GTK_BOX(bbox), queue, FALSE, FALSE, 0);
1837 GTK_WIDGET_SET_FLAGS(queue, GTK_CAN_DEFAULT);
1838 g_signal_connect(queue, "clicked",
1839 G_CALLBACK(mainwin_jump_to_file_queue_cb),
1840 treeview);
1841 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), "changed",
1842 G_CALLBACK(mainwin_jump_to_file_selection_changed_cb),
1843 queue);
1844
1845 rescan = gtk_button_new_from_stock(GTK_STOCK_REFRESH);
1846 gtk_box_pack_start(GTK_BOX(bbox), rescan, FALSE, FALSE, 0);
1847 g_signal_connect(rescan, "clicked",
1848 G_CALLBACK(mainwin_update_jtf), treeview);
1849 GTK_WIDGET_SET_FLAGS(rescan, GTK_CAN_DEFAULT);
1850 gtk_widget_grab_default(rescan);
1851
1852 jump = gtk_button_new_from_stock(GTK_STOCK_JUMP_TO);
1853 gtk_box_pack_start(GTK_BOX(bbox), jump, FALSE, FALSE, 0);
1854
1855 g_signal_connect_swapped(jump, "clicked",
1856 G_CALLBACK(mainwin_jump_to_file_jump_cb),
1857 treeview);
1858
1859 GTK_WIDGET_SET_FLAGS(jump, GTK_CAN_DEFAULT);
1860 gtk_widget_grab_default(jump);
1861
1862 cancel = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1863 gtk_box_pack_start(GTK_BOX(bbox), cancel, FALSE, FALSE, 0);
1864 g_signal_connect_swapped(cancel, "clicked",
1865 G_CALLBACK(gtk_widget_destroy),
1866 mainwin_jtf);
1867 GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
1868
1869 gtk_list_store_clear(jtf_store);
1870
1871 row = 1;
1872
1873 playlist = playlist_get_active();
1874
1875 PLAYLIST_LOCK(playlist->mutex);
1876
1877 for (playlist_glist = playlist->entries; playlist_glist;
1878 playlist_glist = g_list_next(playlist_glist)) {
1879
1880 PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data);
1881
1882 if (entry->title)
1883 desc_buf = g_strdup(entry->title);
1884 else if (strchr(entry->filename, '/'))
1885 desc_buf = str_to_utf8(strrchr(entry->filename, '/') + 1);
1886 else
1887 desc_buf = str_to_utf8(entry->filename);
1888
1889 gtk_list_store_append(GTK_LIST_STORE(jtf_store), &iter);
1890 gtk_list_store_set(GTK_LIST_STORE(jtf_store), &iter,
1891 0, row, 1, desc_buf, -1);
1892 row++;
1893
1894 if (desc_buf) {
1895 g_free(desc_buf);
1896 desc_buf = NULL;
1897 }
1898 }
1899
1900 PLAYLIST_UNLOCK(playlist->mutex);
1901
1902 gtk_widget_show_all(mainwin_jtf);
1903 } 1397 }
1904 1398
1905 static gboolean 1399 static gboolean
1906 mainwin_configure(GtkWidget * window, 1400 mainwin_configure(GtkWidget * window,
1907 GdkEventConfigure * event, 1401 GdkEventConfigure * event,
2585 break; 2079 break;
2586 case MAINWIN_GENERAL_JTT: 2080 case MAINWIN_GENERAL_JTT:
2587 mainwin_jump_to_time(); 2081 mainwin_jump_to_time();
2588 break; 2082 break;
2589 case MAINWIN_GENERAL_JTF: 2083 case MAINWIN_GENERAL_JTF:
2590 mainwin_jump_to_file(); 2084 ui_jump_to_track();
2591 break; 2085 break;
2592 case MAINWIN_GENERAL_EXIT: 2086 case MAINWIN_GENERAL_EXIT:
2593 mainwin_quit_cb(); 2087 mainwin_quit_cb();
2594 break; 2088 break;
2595 case MAINWIN_GENERAL_SETAB: 2089 case MAINWIN_GENERAL_SETAB:
3905 } 3399 }
3906 3400
3907 void 3401 void
3908 action_jump_to_file( void ) 3402 action_jump_to_file( void )
3909 { 3403 {
3910 mainwin_jump_to_file(); 3404 ui_jump_to_track();
3911 } 3405 }
3912 3406
3913 void 3407 void
3914 action_jump_to_playlist_start( void ) 3408 action_jump_to_playlist_start( void )
3915 { 3409 {