# HG changeset patch # User Tomasz Mon # Date 1215527810 -7200 # Node ID 6584bba8de632ede18a1f29df8193c308fa3fd37 # Parent a33facf195900de4a3b15ffd5be9ff1c898cf2f9 I don't think those files belong to legacy ui... diff -r a33facf19590 -r 6584bba8de63 src/audacious/Makefile --- a/src/audacious/Makefile Tue Jul 08 15:35:48 2008 +0200 +++ b/src/audacious/Makefile Tue Jul 08 16:36:50 2008 +0200 @@ -54,15 +54,15 @@ visualization.c \ volumecontrol.c \ sync-menu.c \ - legacy/ui_about.c \ - legacy/ui_albumart.c \ - legacy/ui_credits.c \ + ui_about.c \ + ui_albumart.c \ + ui_credits.c \ legacy/ui_dock.c \ legacy/ui_equalizer.c \ - legacy/ui_fileinfo.c \ + ui_fileinfo.c \ legacy/ui_hints.c \ - legacy/ui_jumptotrack.c \ - legacy/ui_jumptotrack_cache.c \ + ui_jumptotrack.c \ + ui_jumptotrack_cache.c \ legacy/ui_main.c \ legacy/ui_main_evlisteners.c \ legacy/ui_manager.c \ @@ -85,7 +85,7 @@ legacy/ui_skinned_playlist_slider.c \ legacy/ui_skinned_playlist.c \ legacy/ui_skinselector.c \ - legacy/ui_urlopener.c \ + ui_urlopener.c \ ifeq ($(USE_DBUS),yes) SRCS += dbus.c diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_about.c --- a/src/audacious/legacy/ui_about.c Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +0,0 @@ -/* - * Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2007 Audacious development team - * - * Based on BMP: - * Copyright (C) 2003-2004 BMP development team - * - * Based on XMMS: - * Copyright (C) 1998-2003 XMMS development team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "ui_credits.h" - -#include -#include -#include - -#include "platform/smartinclude.h" - -static GtkWidget *about_window = NULL; -static GdkPixbuf *about_pixbuf = NULL; -static GdkPixmap *mask_pixmap_window1 = NULL, - *mask_pixmap_window2 = NULL; -static GdkBitmap *mask_bitmap_window1 = NULL, - *mask_bitmap_window2 = NULL; - -static const gchar *audacious_brief = N_("Audacious %s\n\n" - "Copyright (C) 2005-2008 Audacious Development Team"); - -static gboolean -on_about_window_expose(GtkWidget *widget, GdkEventExpose *expose, gpointer data) -{ - g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE); - - gdk_window_set_back_pixmap(GDK_WINDOW(widget->window), mask_pixmap_window2, 0); - gdk_window_clear(GDK_WINDOW(widget->window)); - - return FALSE; -} - -static gboolean -on_about_window_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data) -{ - g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE); - - if (event->keyval == GDK_Escape) - { - gtk_widget_hide(widget); - } - - return FALSE; -} - -static gboolean -on_close_button_clicked (GtkWidget *widget, gpointer data) -{ - g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE); - - gtk_widget_hide(about_window); - - return FALSE; -} - -static gboolean -on_credits_button_clicked (GtkWidget *widget, gpointer data) -{ - g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE); - - show_credits_window(); - - return FALSE; -} - -void -show_about_window(void) -{ - GtkWidget *about_fixedbox; - GtkWidget *close_button; - GtkWidget *credits_button , *credits_button_hbox, *credits_button_image, *credits_button_label; - GtkWidget *brief_label; - gchar *filename = DATA_DIR G_DIR_SEPARATOR_S "images" G_DIR_SEPARATOR_S "about-logo.png"; - gchar *text; - PangoAttrList *brief_label_attrs; - PangoAttribute *brief_label_foreground; - - if (about_window != NULL) - { - gtk_window_present(GTK_WINDOW(about_window)); - return; - } - - about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - - g_signal_connect(about_window, "destroy", - G_CALLBACK(gtk_widget_destroyed), &about_window); - - gtk_widget_realize(about_window); - - about_pixbuf = gdk_pixbuf_new_from_file(filename, NULL); - - gtk_widget_set_size_request(GTK_WIDGET (about_window), - gdk_pixbuf_get_width (about_pixbuf), - gdk_pixbuf_get_height (about_pixbuf)); - - gtk_widget_set_app_paintable(about_window, TRUE); - gtk_window_set_title(GTK_WINDOW(about_window), _("About Audacious")); - gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(about_window), FALSE); - gtk_window_set_decorated(GTK_WINDOW(about_window), FALSE); - - gdk_pixbuf_render_pixmap_and_mask(about_pixbuf, - &mask_pixmap_window1, - &mask_bitmap_window1, - 0); - - gdk_pixbuf_render_pixmap_and_mask(about_pixbuf, - &mask_pixmap_window2, - &mask_bitmap_window2, - 128); - - gtk_widget_add_events(about_window, GDK_ALL_EVENTS_MASK); - - g_signal_connect(about_window, "expose-event", - G_CALLBACK(on_about_window_expose), &about_window); - - g_signal_connect(about_window, "key-press-event", - G_CALLBACK(on_about_window_key_press), &about_window); - - gtk_widget_shape_combine_mask(GTK_WIDGET(about_window), mask_bitmap_window2, 0, 0); - - /* GtkFixed hasn't got its GdkWindow, this means that it can be used to - display widgets while the logo below will be displayed anyway; - however fixed positions are not that great, cause the button sizes may (will) - vary depending on the gtk style used, so it's not possible to center - them unless a fixed width and heigth is forced (and this may bring to cutted - text if someone, i.e., uses a big font for gtk widgets); - other types of container most likely have their GdkWindow, this simply - means that the logo must be drawn on the container widget, instead of the - window; otherwise, it won't be displayed correctly */ - about_fixedbox = gtk_fixed_new(); - gtk_container_add( GTK_CONTAINER(about_window) , about_fixedbox ); - - close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); - - g_signal_connect(close_button, "clicked", - G_CALLBACK(on_close_button_clicked), NULL); - - gtk_fixed_put( GTK_FIXED(about_fixedbox) , close_button , 375 , 220 ); - gtk_widget_set_size_request( close_button , 100 , -1 ); - - credits_button = gtk_button_new(); - credits_button_hbox = gtk_hbox_new( FALSE , 0 ); - credits_button_image = gtk_image_new_from_stock( GTK_STOCK_DIALOG_INFO , GTK_ICON_SIZE_BUTTON ); - gtk_misc_set_alignment( GTK_MISC(credits_button_image) , 1 , 0.5 ); - credits_button_label = gtk_label_new( _("Credits") ); - gtk_misc_set_alignment( GTK_MISC(credits_button_label) , 0 , 0.5 ); - gtk_box_pack_start( GTK_BOX(credits_button_hbox) , credits_button_image , - TRUE , TRUE , 2 ); - gtk_box_pack_start( GTK_BOX(credits_button_hbox) , credits_button_label , - TRUE , TRUE , 2 ); - gtk_container_add( GTK_CONTAINER(credits_button) , credits_button_hbox ); - - g_signal_connect(credits_button, "clicked", - G_CALLBACK(on_credits_button_clicked), NULL); - - gtk_fixed_put( GTK_FIXED(about_fixedbox) , credits_button , 25 , 220 ); - gtk_widget_set_size_request( credits_button , 100 , -1 ); - - brief_label = gtk_label_new(NULL); - text = g_strdup_printf(_(audacious_brief), VERSION); - - brief_label_foreground = pango_attr_foreground_new(0, 0, 0); - brief_label_attrs = pango_attr_list_new(); - pango_attr_list_insert(brief_label_attrs, brief_label_foreground); - - gtk_label_set_markup(GTK_LABEL(brief_label), text); - gtk_label_set_justify(GTK_LABEL(brief_label), GTK_JUSTIFY_CENTER); - gtk_label_set_attributes(GTK_LABEL(brief_label), brief_label_attrs); - g_free(text); - - gtk_fixed_put(GTK_FIXED(about_fixedbox), brief_label, 20, 145); - gtk_widget_set_size_request( brief_label , 460 , -1 ); - - gtk_widget_show_all(about_window); - gtk_window_present(GTK_WINDOW(about_window)); -} - -void -hide_about_window(void) -{ - g_return_if_fail(about_window); - gtk_widget_hide(GTK_WIDGET(about_window)); -} diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_albumart.c --- a/src/audacious/legacy/ui_albumart.c Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,195 +0,0 @@ -/* - * Audacious: A cross-platform multimedia player - * Copyright (c) 2007 William Pitcock, Tony Vroon, George Averill, - * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include - -#include "ui_fileinfopopup.h" -#include "main.h" -#include "ui_main.h" -#include "playlist.h" -#include "playback.h" - -static gboolean -has_front_cover_extension(const gchar *name) -{ - char *ext; - - ext = strrchr(name, '.'); - if (!ext) { - /* No file extension */ - return FALSE; - } - - return g_strcasecmp(ext, ".jpg") == 0 || - g_strcasecmp(ext, ".jpeg") == 0 || - g_strcasecmp(ext, ".png") == 0; -} - -static gboolean -cover_name_filter(const gchar *name, const gchar *filter, const gboolean ret_on_empty) -{ - gboolean result = FALSE; - gchar **splitted; - gchar *current; - gchar *lname; - gint i; - - if (!filter || strlen(filter) == 0) { - return ret_on_empty; - } - - splitted = g_strsplit(filter, ",", 0); - - lname = g_strdup(name); - g_strdown(lname); - - for (i = 0; !result && (current = splitted[i]); i++) { - gchar *stripped = g_strstrip(g_strdup(current)); - g_strdown(stripped); - - result = result || strstr(lname, stripped); - - g_free(stripped); - } - - g_free(lname); - g_strfreev(splitted); - - return result; -} - -/* Check wether it's an image we want */ -static gboolean -is_front_cover_image(const gchar *imgfile) -{ - return cover_name_filter(imgfile, cfg.cover_name_include, TRUE) && - !cover_name_filter(imgfile, cfg.cover_name_exclude, FALSE); -} - -static gboolean -is_file_image(const gchar *imgfile, const gchar *file_name) -{ - char *imgfile_ext, *file_name_ext; - size_t imgfile_len, file_name_len; - - imgfile_ext = strrchr(imgfile, '.'); - if (!imgfile_ext) { - /* No file extension */ - return FALSE; - } - - file_name_ext = strrchr(file_name, '.'); - if (!file_name_ext) { - /* No file extension */ - return FALSE; - } - - imgfile_len = (imgfile_ext - imgfile); - file_name_len = (file_name_ext - file_name); - - if (imgfile_len == file_name_len) { - return (g_ascii_strncasecmp(imgfile, file_name, imgfile_len) == 0); - } else { - return FALSE; - } -} - -gchar* -fileinfo_recursive_get_image(const gchar* path, - const gchar* file_name, gint depth) -{ - GDir *d; - - if (cfg.recurse_for_cover && depth > cfg.recurse_for_cover_depth) - return NULL; - - d = g_dir_open(path, 0, NULL); - - if (d) { - const gchar *f; - - if (cfg.use_file_cover && file_name) { - /* Look for images matching file name */ - while((f = g_dir_read_name(d))) { - gchar *newpath = g_strconcat(path, "/", f, NULL); - - if (!g_file_test(newpath, G_FILE_TEST_IS_DIR) && - has_front_cover_extension(f) && - is_file_image(f, file_name)) { - g_dir_close(d); - return newpath; - } - - g_free(newpath); - } - g_dir_rewind(d); - } - - /* Search for files using filter */ - while ((f = g_dir_read_name(d))) { - gchar *newpath = g_strconcat(path, "/", f, NULL); - - if (!g_file_test(newpath, G_FILE_TEST_IS_DIR) && - has_front_cover_extension(f) && - is_front_cover_image(f)) { - g_dir_close(d); - return newpath; - } - - g_free(newpath); - } - g_dir_rewind(d); - - /* checks whether recursive or not. */ - if (!cfg.recurse_for_cover) { - g_dir_close(d); - return NULL; - } - - /* Descend into directories recursively. */ - while ((f = g_dir_read_name(d))) { - gchar *newpath = g_strconcat(path, "/", f, NULL); - - if(g_file_test(newpath, G_FILE_TEST_IS_DIR)) { - gchar *tmp = fileinfo_recursive_get_image(newpath, - NULL, depth + 1); - if(tmp) { - g_free(newpath); - g_dir_close(d); - return tmp; - } - } - - g_free(newpath); - } - - g_dir_close(d); - } - - return NULL; -} diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_credits.c --- a/src/audacious/legacy/ui_credits.c Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,434 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2007 Audacious Team - * - * Based on BMP: - * Copyright (C) 2003-2004 BMP development team - * - * Based on XMMS: - * Copyright (C) 1998-2003 XMMS development team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "ui_credits.h" - -#include -#include -#include - -#include "audacious_logo.xpm" - - -enum { - COL_LEFT, - COL_RIGHT, - N_COLS -}; - - -static const gchar *audacious_brief = - N_("Audacious %s\n" - "A skinned multimedia player for many platforms.\n" - "\n" - "Copyright (C) 2005-2008 Audacious Development Team\n"); - -static const gchar *credit_text[] = { - N_("Audacious core developers:"), - "George Averill", - "Daniel Barkalow", - "Christian Birchinger", - "Daniel Bradshaw", - "Adam Cecile", - "Michael Färber", - "Matti Hämäläinen", - "Troels Bang Jensen", - "Giacomo Lozito", - "Cristi Măgherușan", - "Tomasz Moń", - "William Pitcock", - "Derek Pomery", - "Jonathan Schleifer", - "Ben Tucker", - "Tony Vroon", - "Yoshiki Yazawa", - "Eugene Zagidullin", - NULL, - - N_("Graphics:"), - "George Averill", - "Stephan Sokolow", - NULL, - - N_("Default skin:"), - "George Averill", - "Michael Färber", - "William Pitcock", - NULL, - - N_("Plugin development:"), - "Kiyoshi Aman", - "Luca Barbato", - "Daniel Barkalow", - "Michael Färber", - "Shay Green", - "Matti Hämäläinen", - "Sascha Hlusiak", - "Giacomo Lozito", - "Cristi Măgherușan", - "Tomasz Moń", - "William Pitcock", - "Derek Pomery", - "Jonathan Schleifer", - "Tony Vroon", - "Yoshiki Yazawa", - NULL, - - N_("Patch authors:"), - "Massimo Cavalleri", - "Stefano D'Angelo", - "Laszlo Dvornik", - "Ralf Ertzinger", - "Mike Frysinger", - "Mark Glines", - "Teru KAMOGASHIRA", - "Chris Kehler", - "Alex Maclean", - "Michael Hanselmann", - "Joseph Jezak", - "Henrik Johansson", - "Rodrigo Martins de Matos Ventura", - "Diego Pettenò", - "Kazuki Shimura", - "Valentine Sinitsyn", - "Johan Tavelin", - "Tim Yamin", - "Ivan N. Zlatev", - NULL, - - N_("0.1.x developers:"), - "William Pitcock", - "Mohammed Sameer", - "Tony Vroon", - NULL, - - N_("BMP Developers:"), - "Artem Baguinski", - "Edward Brocklesby", - "Chong Kai Xiong", - "Milosz Derezynski", - "David Lau", - "Ole Andre Vadla Ravnaas", - "Michiel Sikkes", - "Andrei Badea", - "Peter Behroozi", - "Bernard Blackham", - "Oliver Blin", - "Tomas Bzatek", - "Liviu Danicel", - "Jon Dowland", - "Artur Frysiak", - "Sebastian Kapfer", - "Lukas Koberstein", - "Dan Korostelev", - "Jolan Luff", - "Michael Marineau", - "Tim-Philipp Muller", - "Julien Portalier", - "Andrew Ruder", - "Olivier Samyn", - "Martijn Vernooij", - NULL, - - NULL -}; - -static const gchar *translators[] = { - N_("Brazilian Portuguese:"), - "Fábio Antunes", - "Philipi Pinto", - NULL, - N_("Breton:"), - "Thierry Vignaud", - NULL, - N_("Bulgarian:"), - "Andrew Ivanov", - NULL, - N_("Catalan:"), - "Ernest Adrogu", - NULL, - N_("Croatian:"), - "Marin Glibic", - NULL, - N_("Czech:"), - "Petr Pisar", - NULL, - N_("Dutch:"), - "Laurens Buhler", - "Tony Vroon", - NULL, - N_("Estonian:"), - "Ivar Smolin", - NULL, - N_("Finnish:"), - "Pauli Virtanen", - "Matti Hämäläinen", - NULL, - N_("French:"), - "Adam Cecile", - "Stanislas Zeller", - "Stany Henry", - NULL, - N_("German:"), - "Michael Färber", - "Michael Hanselmann", - "Matthias Debus", - NULL, - N_("Georgian:"), - "George Machitidze", - NULL, - N_("Greek:"), - "Kouzinopoulos Haris", - "Stavros Giannouris", - "Stathis Kamperis", - NULL, - N_("Hindi:"), - "Dhananjaya Sharma", - NULL, - N_("Hungarian:"), - "Laszlo Dvornik", - NULL, - N_("Italian:"), - "Alessio D'Ascanio", - "Diego Pettenò", - NULL, - N_("Japanese:"), - "Dai", - NULL, - N_("Korean:"), - "DongCheon Park", - NULL, - N_("Lithuanian:"), - "Rimas Kudelis", - NULL, - N_("Macedonian:"), - "Arangel Angov", - NULL, - N_("Polish:"), - "Wojciech Myrda", - NULL, - N_("Romanian:"), - "Daniel Patriche", - "Cristi Măgherușan", - NULL, - N_("Russian:"), - "Alexandr Orlov", - NULL, - N_("Serbian (Latin):"), - "Strahinja Kustudić", - NULL, - N_("Serbian (Cyrillic):"), - "Strahinja Kustudić", - NULL, - N_("Simplified Chinese:"), - "Yang Zhang", - NULL, - N_("Slovak:"), - "Andrej Herceg", - NULL, - N_("Spanish:"), - "Gustavo D. Vranjes", - NULL, - N_("Swedish:"), - "Martin Persenius", - NULL, - N_("Traditional Chinese:"), - "Cheng-Wei Chien", - "Sylecn Song", - "Yang Zhang", - NULL, - N_("Turkish:"), - "Murat Şenel", - "Eren Turkay", - NULL, - N_("Ukrainian:"), - "Mykola Lynnyk", - NULL, - N_("Welsh:"), - "Edward Brocklesby", - "William Pitcock", - NULL, - - NULL -}; - - -static GtkWidget * -generate_credit_list(const gchar * text[], gboolean sec_space) -{ - GtkWidget *scrollwin; - GtkWidget *treeview; - GtkListStore *list_store; - GtkTreeIter iter; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - const gchar *const *item; - - list_store = gtk_list_store_new(N_COLS, G_TYPE_STRING, G_TYPE_STRING); - - item = text; - - while (*item) { - gtk_list_store_append(list_store, &iter); - gtk_list_store_set(list_store, &iter, - COL_LEFT, _(item[0]), COL_RIGHT, _(item[1]), -1); - item += 2; - - while (*item) { - gtk_list_store_append(list_store, &iter); - gtk_list_store_set(list_store, &iter, - COL_LEFT, "", COL_RIGHT, _(*item++), -1); - } - - ++item; - - if (*item && sec_space) { - gtk_list_store_append(list_store, &iter); - gtk_list_store_set(list_store, &iter, - COL_LEFT, "", COL_RIGHT, "", -1); - } - } - - treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)); - gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview), FALSE); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); - gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), - GTK_SELECTION_NONE); - - renderer = gtk_cell_renderer_text_new(); - g_object_set(renderer, "xalign", 1.0, NULL); - column = gtk_tree_view_column_new_with_attributes("Left", renderer, - "text", COL_LEFT, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); - - renderer = gtk_cell_renderer_text_new(); - g_object_set(renderer, "xalign", 0.0, NULL); - column = gtk_tree_view_column_new_with_attributes("Right", renderer, - "text", COL_RIGHT, - NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); - - scrollwin = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), - GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin), GTK_SHADOW_IN); - gtk_container_add(GTK_CONTAINER(scrollwin), treeview); - gtk_container_set_border_width(GTK_CONTAINER(scrollwin), 10); - - gtk_widget_show_all(scrollwin); - - return scrollwin; -} - -void -show_credits_window(void) -{ - static GtkWidget *about_window = NULL; - - GdkPixbuf *logo_pixbuf; - GtkWidget *about_vbox; - GtkWidget *about_credits_logo_box, *about_credits_logo_frame; - GtkWidget *about_credits_logo; - GtkWidget *about_notebook; - GtkWidget *list; - GtkWidget *bbox, *close_btn; - GtkWidget *label; - gchar *text; - - if (about_window) - return; - - about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_type_hint(GTK_WINDOW(about_window), - GDK_WINDOW_TYPE_HINT_DIALOG); - - gtk_window_set_default_size(GTK_WINDOW(about_window), -1, 512); - gtk_window_set_title(GTK_WINDOW(about_window), _("About Audacious")); - gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(about_window), TRUE); - gtk_container_set_border_width(GTK_CONTAINER(about_window), 10); - - g_signal_connect(about_window, "destroy", - G_CALLBACK(gtk_widget_destroyed), &about_window); - - gtk_widget_realize(about_window); - - about_vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(about_window), about_vbox); - - logo_pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)audacious_logo_xpm); - - about_credits_logo_box = gtk_hbox_new(TRUE, 0); - gtk_box_pack_start(GTK_BOX(about_vbox), about_credits_logo_box, - FALSE, FALSE, 0); - - about_credits_logo_frame = gtk_frame_new(NULL); - gtk_frame_set_shadow_type(GTK_FRAME(about_credits_logo_frame), - GTK_SHADOW_ETCHED_OUT); - gtk_box_pack_start(GTK_BOX(about_credits_logo_box), - about_credits_logo_frame, FALSE, FALSE, 0); - - about_credits_logo = gtk_image_new_from_pixbuf(logo_pixbuf); - gtk_container_add(GTK_CONTAINER(about_credits_logo_frame), - about_credits_logo); - g_object_unref(logo_pixbuf); - - label = gtk_label_new(NULL); - text = g_strdup_printf(_(audacious_brief), VERSION); - gtk_label_set_markup(GTK_LABEL(label), text); - gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); - g_free(text); - - gtk_box_pack_start(GTK_BOX(about_vbox), label, FALSE, FALSE, 0); - - about_notebook = gtk_notebook_new(); - gtk_box_pack_start(GTK_BOX(about_vbox), about_notebook, TRUE, TRUE, 0); - - list = generate_credit_list(credit_text, TRUE); - gtk_notebook_append_page(GTK_NOTEBOOK(about_notebook), list, - gtk_label_new(_("Credits"))); - - list = generate_credit_list(translators, FALSE); - gtk_notebook_append_page(GTK_NOTEBOOK(about_notebook), list, - gtk_label_new(_("Translators"))); - - bbox = gtk_hbutton_box_new(); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); - gtk_box_pack_start(GTK_BOX(about_vbox), bbox, FALSE, FALSE, 0); - - close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE); - g_signal_connect_swapped(close_btn, "clicked", - G_CALLBACK(gtk_widget_destroy), about_window); - GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT); - gtk_box_pack_start(GTK_BOX(bbox), close_btn, TRUE, TRUE, 0); - gtk_widget_grab_default(close_btn); - - gtk_widget_show_all(about_window); -} diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_credits.h --- a/src/audacious/legacy/ui_credits.h Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ - -#ifndef AUDACIOUS_UI_CREDITS_H -#define AUDACIOUS_UI_CREDITS_H - -void show_about_window(void); -void hide_about_window(void); -void show_credits_window(void); - -#endif /* AUDACIOUS_UI_CREDITS_H */ diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_fileinfo.c --- a/src/audacious/legacy/ui_fileinfo.c Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1019 +0,0 @@ -/* - * Audacious: A cross-platform multimedia player - * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill, - * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa. - * Copyright (c) 2008 Eugene Zagidullin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "plugin.h" -#include "pluginenum.h" -#include "input.h" -#include "effect.h" -#include "strings.h" -#include "general.h" -#include "output.h" -#include "visualization.h" - -#include "main.h" -#include "util.h" -#include "dnd.h" -#include "tuple.h" -#include "vfs.h" - -#include "playlist.h" - -#include "ui_main.h" -#include "ui_playlist.h" -#include "build_stamp.h" -#include "ui_fileinfo.h" -#include "ui_playlist.h" - -#define G_FREE_CLEAR(a) if(a != NULL) { g_free(a); a = NULL; } -#define STATUS_TIMEOUT 3*1000 - -GtkWidget *fileinfo_win = NULL; - -GtkWidget *entry_location; -GtkWidget *entry_title; -GtkWidget *entry_artist; -GtkWidget *entry_album; -GtkWidget *entry_comment; -GtkWidget *entry_year; -GtkWidget *entry_track; -GtkWidget *entry_genre; - -GtkWidget *image_artwork; - -GtkWidget *image_fileicon; -GtkWidget *label_format_name; -GtkWidget *label_quality; -GtkWidget *label_bitrate; -GtkWidget *btn_apply; -GtkWidget *label_mini_status; -GtkWidget *arrow_rawdata; -GtkWidget *treeview_rawdata; - -enum { - RAWDATA_KEY, - RAWDATA_VALUE, - RAWDATA_N_COLS -}; - -static gchar *current_file = NULL; -static InputPlugin *current_ip = NULL; -static gboolean something_changed = FALSE; - -/* stolen from Audacious 1.4 vorbis plugin. --nenolod */ -static const gchar *genre_table[] = { - N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"), - N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"), - N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"), - N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"), - N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"), - N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"), - N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"), - N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"), - N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"), - N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("AlternRock"), - N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"), - N_("Meditative"), N_("Instrumental Pop"), - N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"), - N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"), - N_("Pop-Folk"), N_("Eurodance"), N_("Dream"), - N_("Southern Rock"), N_("Comedy"), N_("Cult"), - N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"), - N_("Pop/Funk"), N_("Jungle"), N_("Native American"), - N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"), - N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"), - N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"), - N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"), - N_("Folk/Rock"), N_("National Folk"), N_("Swing"), - N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"), - N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"), - N_("Gothic Rock"), N_("Progressive Rock"), - N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"), - N_("Big Band"), N_("Chorus"), N_("Easy Listening"), - N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"), - N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"), - N_("Booty Bass"), N_("Primus"), N_("Porn Groove"), - N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"), - N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"), - N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"), - N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"), - N_("Euro-House"), N_("Dance Hall"), N_("Goa"), - N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"), - N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"), - N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"), - N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"), - N_("Contemporary Christian"), N_("Christian Rock"), - N_("Merengue"), N_("Salsa"), N_("Thrash Metal"), - N_("Anime"), N_("JPop"), N_("Synthpop") -}; - -static GList *genre_list = NULL; - -static void -fileinfo_entry_set_text(GtkWidget *widget, const char *text) -{ - if (widget == NULL) - return; - - gtk_entry_set_text(GTK_ENTRY(widget), text != NULL ? text : ""); -} - -static void -set_entry_str_from_field(GtkWidget *widget, Tuple *tuple, gint fieldn, gboolean editable) -{ - gchar *text; - - if(widget != NULL) { - text = (gchar*)tuple_get_string(tuple, fieldn, NULL); - gtk_entry_set_text(GTK_ENTRY(widget), text != NULL ? text : ""); - gtk_editable_set_editable(GTK_EDITABLE(widget), editable); - } -} - -static void -set_entry_int_from_field(GtkWidget *widget, Tuple *tuple, gint fieldn, gboolean editable) -{ - gchar *text; - - if(widget == NULL) return; - - if(tuple_get_value_type(tuple, fieldn, NULL) == TUPLE_INT) { - text = g_strdup_printf("%d", tuple_get_int(tuple, fieldn, NULL)); - gtk_entry_set_text(GTK_ENTRY(widget), text); - gtk_editable_set_editable(GTK_EDITABLE(widget), editable); - g_free(text); - } else { - gtk_entry_set_text(GTK_ENTRY(widget), ""); - gtk_editable_set_editable(GTK_EDITABLE(widget), editable); - } -} - -static void -set_field_str_from_entry(Tuple *tuple, gint fieldn, GtkWidget *widget) -{ - if(widget == NULL) return; - tuple_associate_string(tuple, fieldn, NULL, gtk_entry_get_text(GTK_ENTRY(widget))); -} - -static void -set_field_int_from_entry(Tuple *tuple, gint fieldn, GtkWidget *widget) -{ - gchar *tmp; - if(widget == NULL) return; - - tmp = (gchar*)gtk_entry_get_text(GTK_ENTRY(widget)); - if(*tmp != '\0') - tuple_associate_int(tuple, fieldn, NULL, atoi(tmp)); - else - tuple_associate_int(tuple, fieldn, NULL, -1); -} - -static void -fileinfo_label_set_text(GtkWidget *widget, const char *text) -{ - gchar *tmp; - - if (widget == NULL) - return; - - if (text) { - tmp = g_strdup_printf("%s", text); - gtk_label_set_text(GTK_LABEL(widget), tmp); - gtk_label_set_use_markup(GTK_LABEL(widget), TRUE); - g_free(tmp); - } else { - gtk_label_set_text(GTK_LABEL(widget), _("n/a")); - gtk_label_set_use_markup(GTK_LABEL(widget), TRUE); - } -} - -static void -fileinfo_entry_set_image(GtkWidget *widget, const char *text) -{ - GdkPixbuf *pixbuf; - int width, height; - double aspect; - GdkPixbuf *pixbuf2; - - if (widget == NULL) - return; - - pixbuf = gdk_pixbuf_new_from_file(text, NULL); - - if (pixbuf == NULL) - return; - - width = gdk_pixbuf_get_width(GDK_PIXBUF(pixbuf)); - height = gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf)); - - if (strcmp(DATA_DIR "/images/audio.png", text)) { - if (width == 0) - width = 1; - aspect = (double)height / (double)width; - - if (aspect > 1.0) { - height = (int)(cfg.filepopup_pixelsize * aspect); - width = cfg.filepopup_pixelsize; - } else { - height = cfg.filepopup_pixelsize; - width = (int)(cfg.filepopup_pixelsize / aspect); - } - - pixbuf2 = gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), width, height, GDK_INTERP_BILINEAR); - g_object_unref(G_OBJECT(pixbuf)); - pixbuf = pixbuf2; - } - - gtk_image_set_from_pixbuf(GTK_IMAGE(widget), GDK_PIXBUF(pixbuf)); - g_object_unref(G_OBJECT(pixbuf)); -} - -static void -fileinfo_hide(gpointer unused) -{ - if(GTK_WIDGET_VISIBLE(fileinfo_win)) gtk_widget_hide(fileinfo_win); - - /* Clear it out. */ - fileinfo_entry_set_text(entry_title, ""); - fileinfo_entry_set_text(entry_artist, ""); - fileinfo_entry_set_text(entry_album, ""); - fileinfo_entry_set_text(entry_comment, ""); - fileinfo_entry_set_text(gtk_bin_get_child(GTK_BIN(entry_genre)), ""); - fileinfo_entry_set_text(entry_year, ""); - fileinfo_entry_set_text(entry_track, ""); - fileinfo_entry_set_text(entry_location, ""); - - fileinfo_label_set_text(label_format_name, NULL); - fileinfo_label_set_text(label_quality, NULL); - fileinfo_label_set_text(label_bitrate, NULL); - - if (label_mini_status != NULL) { - gtk_label_set_text(GTK_LABEL(label_mini_status), ""); - gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); - } - - something_changed = FALSE; - gtk_widget_set_sensitive(btn_apply, FALSE); - - current_ip = NULL; - G_FREE_CLEAR(current_file); - - fileinfo_entry_set_image(image_artwork, DATA_DIR "/images/audio.png"); -} - -static void -entry_changed (GtkEditable *editable, gpointer user_data) -{ - if(current_file != NULL && current_ip != NULL && current_ip->update_song_tuple != NULL) { - something_changed = TRUE; - gtk_widget_set_sensitive(btn_apply, TRUE); - } -} - -static gboolean -ministatus_timeout_proc (gpointer data) -{ - GtkLabel *status = GTK_LABEL(data); - gtk_label_set_text(status, ""); - gtk_label_set_use_markup(status, TRUE); - - return FALSE; -} - -static void -ministatus_display_message(gchar *text) -{ - if(label_mini_status != NULL) { - gchar *tmp = g_strdup_printf("%s", text); - gtk_label_set_text(GTK_LABEL(label_mini_status), tmp); - g_free(tmp); - gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); - g_timeout_add (STATUS_TIMEOUT, (GSourceFunc) ministatus_timeout_proc, (gpointer) label_mini_status); - } -} - -static void -message_update_successfull() -{ - ministatus_display_message(_("Metadata updated successfully")); -} - -static void -message_update_failed() -{ - ministatus_display_message(_("Metadata updating failed")); -} - -static void -fileinfo_update_tuple(gpointer data) -{ - Tuple *tuple; - VFSFile *fd; - - if (current_file != NULL && current_ip != NULL && current_ip->update_song_tuple != NULL && something_changed) { - tuple = tuple_new(); - fd = vfs_fopen(current_file, "r+b"); - - if (fd != NULL) { - set_field_str_from_entry(tuple, FIELD_TITLE, entry_title); - set_field_str_from_entry(tuple, FIELD_ARTIST, entry_artist); - set_field_str_from_entry(tuple, FIELD_ALBUM, entry_album); - set_field_str_from_entry(tuple, FIELD_COMMENT, entry_comment); - set_field_str_from_entry(tuple, FIELD_GENRE, gtk_bin_get_child(GTK_BIN(entry_genre))); - - set_field_int_from_entry(tuple, FIELD_YEAR, entry_year); - set_field_int_from_entry(tuple, FIELD_TRACK_NUMBER, entry_track); - - plugin_set_current((Plugin *)current_ip); - if (current_ip->update_song_tuple(tuple, fd)) { - message_update_successfull(); - something_changed = FALSE; - gtk_widget_set_sensitive(btn_apply, FALSE); - } else - message_update_failed(); - - vfs_fclose(fd); - - } else - message_update_failed(); - - mowgli_object_unref(tuple); - } -} - -/** - * Looks up an icon from a NULL-terminated list of icon names. - * - * size: the requested size - * name: the default name - * ... : a NULL-terminated list of alternates - */ -GdkPixbuf * -themed_icon_lookup(gint size, const gchar *name, ...) -{ - GtkIconTheme *icon_theme; - GdkPixbuf *pixbuf; - GError *error = NULL; - gchar *n; - va_list par; - - icon_theme = gtk_icon_theme_get_default (); - pixbuf = gtk_icon_theme_load_icon (icon_theme, name, size, 0, &error); - - if (pixbuf != NULL) - return pixbuf; - - if (error != NULL) - g_error_free(error); - - /* fallback */ - va_start(par, name); - while((n = (gchar*)va_arg(par, gchar *)) != NULL) { - error = NULL; - pixbuf = gtk_icon_theme_load_icon (icon_theme, n, size, 0, &error); - - if (pixbuf) { - va_end(par); - return pixbuf; - } - - if (error != NULL) - g_error_free(error); - } - - return NULL; -} - -/** - * Intelligently looks up an icon for a mimetype. Supports - * HIDEOUSLY BROKEN gnome icon naming scheme too. - * - * size : the requested size - * mime_type: the mime type. - */ -GdkPixbuf * -mime_icon_lookup(gint size, const gchar *mime_type) /* smart icon resolving routine :) */ -{ - gchar *mime_as_is; /* audio-x-mp3 */ - gchar *mime_gnome; /* gnome-mime-audio-x-mp3 */ - gchar *mime_generic; /* audio-x-generic */ - gchar *mime_gnome_generic; /* gnome-mime-audio */ - - GdkPixbuf *icon = NULL; - - gchar **s = g_strsplit(mime_type, "/", 2); - if(s[1] != NULL) { - mime_as_is = g_strdup_printf("%s-%s", s[0], s[1]); - mime_gnome = g_strdup_printf("gnome-mime-%s-%s", s[0], s[1]); - mime_generic = g_strdup_printf("%s-x-generic", s[0]); - mime_gnome_generic = g_strdup_printf("gnome-mime-%s", s[0]); - icon = themed_icon_lookup(size, mime_as_is, mime_gnome, mime_generic, mime_gnome_generic, s[0], NULL); /* s[0] is category */ - g_free(mime_gnome_generic); - g_free(mime_generic); - g_free(mime_gnome); - g_free(mime_as_is); - } - g_strfreev(s); - - return icon; -} - -void -create_fileinfo_window(void) -{ - GtkWidget *hbox; - GtkWidget *hbox_status_and_bbox; - GtkWidget *vbox0; - GtkWidget *vbox1; - GtkWidget *vbox2; - GtkWidget *vbox3; - GtkWidget *label_title; - GtkWidget *label_artist; - GtkWidget *label_album; - GtkWidget *label_comment; - GtkWidget *label_genre; - GtkWidget *label_year; - GtkWidget *label_track; - GtkWidget *label_location; - GtkWidget *label_general; - GtkWidget *label_format; - GtkWidget *label_quality_label; - GtkWidget *label_bitrate_label; - GtkWidget *codec_hbox; - GtkWidget *codec_table; - GtkWidget *table1; - GtkWidget *bbox_close; - GtkWidget *btn_close; - GtkWidget *alignment; - GtkWidget *separator; - GtkWidget *scrolledwindow; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - gint i; - - fileinfo_win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(fileinfo_win), 6); - gtk_window_set_title(GTK_WINDOW(fileinfo_win), _("Track Information")); - gtk_window_set_position(GTK_WINDOW(fileinfo_win), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(fileinfo_win), FALSE); - gtk_window_set_type_hint(GTK_WINDOW(fileinfo_win), GDK_WINDOW_TYPE_HINT_DIALOG); - gtk_window_set_transient_for(GTK_WINDOW(fileinfo_win), GTK_WINDOW(mainwin)); - - vbox0 = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(fileinfo_win), vbox0); - - hbox = gtk_hbox_new(FALSE, 6); - gtk_box_pack_start(GTK_BOX(vbox0), hbox, TRUE, TRUE, 0); - - image_artwork = gtk_image_new(); - gtk_box_pack_start(GTK_BOX(hbox), image_artwork, FALSE, FALSE, 0); - gtk_misc_set_alignment(GTK_MISC(image_artwork), 0.5, 0); - gtk_image_set_from_file(GTK_IMAGE(image_artwork), DATA_DIR "/images/audio.png"); - separator = gtk_vseparator_new(); - gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, FALSE, 0); - - vbox1 = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), vbox1, TRUE, TRUE, 0); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox1), alignment, TRUE, TRUE, 0); - - vbox2 = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(alignment), vbox2); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox1), alignment, TRUE, TRUE, 0); - - vbox3 = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(alignment), vbox3); - - label_general = gtk_label_new(_("General")); - gtk_box_pack_start (GTK_BOX (vbox2), label_general, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_general), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_general), 0, 0.5); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 0, 0); - gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0); - - codec_hbox = gtk_hbox_new(FALSE, 6); - gtk_container_add (GTK_CONTAINER(alignment), codec_hbox); - - image_fileicon = gtk_image_new_from_stock (GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG); - gtk_box_pack_start (GTK_BOX (codec_hbox), image_fileicon, FALSE, FALSE, 0); - - codec_table = gtk_table_new(3, 2, FALSE); - gtk_table_set_row_spacings (GTK_TABLE(codec_table), 6); - gtk_table_set_col_spacings (GTK_TABLE(codec_table), 12); - gtk_box_pack_start (GTK_BOX (codec_hbox), codec_table, FALSE, FALSE, 0); - - label_format = gtk_label_new(_("Format:")); - gtk_label_set_use_markup(GTK_LABEL(label_format), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_format), 0, 0.5); - label_quality_label = gtk_label_new(_("Quality:")); - gtk_label_set_use_markup(GTK_LABEL(label_quality_label), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_quality_label), 0, 0.5); - label_bitrate_label = gtk_label_new(_("Bitrate:")); - gtk_label_set_use_markup(GTK_LABEL(label_bitrate_label), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_bitrate_label), 0, 0.5); - - label_format_name = gtk_label_new(_("n/a")); - gtk_label_set_use_markup(GTK_LABEL(label_format_name), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_format_name), 0, 0.5); - label_quality = gtk_label_new(_("n/a")); - gtk_label_set_use_markup(GTK_LABEL(label_quality), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_quality), 0, 0.5); - label_bitrate = gtk_label_new(_("n/a")); - gtk_label_set_use_markup(GTK_LABEL(label_bitrate), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_bitrate), 0, 0.5); - - gtk_table_attach(GTK_TABLE(codec_table), label_format, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_table_attach(GTK_TABLE(codec_table), label_format_name, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_table_attach(GTK_TABLE(codec_table), label_quality_label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_table_attach(GTK_TABLE(codec_table), label_quality, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_table_attach(GTK_TABLE(codec_table), label_bitrate_label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_table_attach(GTK_TABLE(codec_table), label_bitrate, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label_title = gtk_label_new(_("Title")); - gtk_box_pack_start(GTK_BOX(vbox2), label_title, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_title), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_title), 0, 0); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - entry_title = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(alignment), entry_title); - g_signal_connect(G_OBJECT(entry_title), "changed", (GCallback) entry_changed, NULL); - - label_artist = gtk_label_new(_("Artist")); - gtk_box_pack_start(GTK_BOX(vbox2), label_artist, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_artist), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_artist), 0, 0.5); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - entry_artist = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(alignment), entry_artist); - g_signal_connect(G_OBJECT(entry_artist), "changed", (GCallback) entry_changed, NULL); - - label_album = gtk_label_new(_("Album")); - gtk_box_pack_start(GTK_BOX(vbox2), label_album, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_album), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_album), 0, 0.5); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - entry_album = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(alignment), entry_album); - g_signal_connect(G_OBJECT(entry_album), "changed", (GCallback) entry_changed, NULL); - - label_comment = gtk_label_new(_("Comment")); - gtk_box_pack_start(GTK_BOX(vbox2), label_comment, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_comment), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_comment), 0, 0.5); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - entry_comment = gtk_entry_new(); - gtk_container_add (GTK_CONTAINER(alignment), entry_comment); - g_signal_connect(G_OBJECT(entry_comment), "changed", (GCallback) entry_changed, NULL); - - label_genre = gtk_label_new(_("Genre")); - gtk_box_pack_start(GTK_BOX(vbox2), label_genre, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_genre), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_genre), 0, 0.5); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - entry_genre = gtk_combo_box_entry_new_text(); - - if (!genre_list) { - GList *iter; - - for (i = 0; i < G_N_ELEMENTS(genre_table); i++) - genre_list = g_list_prepend(genre_list, _(genre_table[i])); - genre_list = g_list_sort(genre_list, (GCompareFunc) g_utf8_collate); - - MOWGLI_ITER_FOREACH(iter, genre_list) - gtk_combo_box_append_text(GTK_COMBO_BOX(entry_genre), iter->data); - } - - gtk_container_add(GTK_CONTAINER(alignment), entry_genre); - g_signal_connect(G_OBJECT(entry_genre), "changed", (GCallback) entry_changed, NULL); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - table1 = gtk_table_new(2, 2, FALSE); - gtk_container_add(GTK_CONTAINER(alignment), table1); - gtk_table_set_col_spacings(GTK_TABLE(table1), 6); - - label_year = gtk_label_new(_("Year")); - gtk_table_attach(GTK_TABLE(table1), label_year, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_label_set_use_markup(GTK_LABEL(label_year), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_year), 0, 0.5); - - entry_year = gtk_entry_new(); - gtk_table_attach(GTK_TABLE(table1), entry_year, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - g_signal_connect(G_OBJECT(entry_year), "changed", (GCallback) entry_changed, NULL); - - label_track = gtk_label_new(_("Track Number")); - gtk_table_attach(GTK_TABLE(table1), label_track, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_label_set_use_markup(GTK_LABEL(label_track), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_track), 0, 0.5); - - entry_track = gtk_entry_new(); - gtk_table_attach(GTK_TABLE(table1), entry_track, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - g_signal_connect(G_OBJECT(entry_track), "changed", (GCallback) entry_changed, NULL); - - label_location = gtk_label_new(_("Location")); - gtk_box_pack_start(GTK_BOX(vbox2), label_location, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_location), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_location), 0, 0.5); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 0, 0); - - entry_location = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(alignment), entry_location); - gtk_editable_set_editable(GTK_EDITABLE(entry_location), FALSE); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - hbox = gtk_hbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(alignment), hbox); - gtk_box_pack_start(GTK_BOX(vbox3), alignment, TRUE, TRUE, 0); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 0, 0); - arrow_rawdata = gtk_expander_new(_("Raw Metadata")); - gtk_expander_set_use_markup(GTK_EXPANDER(arrow_rawdata), TRUE); - gtk_container_add(GTK_CONTAINER(alignment), arrow_rawdata); - gtk_box_pack_start(GTK_BOX(hbox), alignment, TRUE, TRUE, 0); - - scrolledwindow = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN); - gtk_container_add(GTK_CONTAINER(arrow_rawdata), scrolledwindow); - - treeview_rawdata = gtk_tree_view_new(); - gtk_container_add(GTK_CONTAINER(scrolledwindow), treeview_rawdata); - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview_rawdata), TRUE); - gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview_rawdata), TRUE); - gtk_widget_set_size_request(treeview_rawdata, -1, 130); - - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(column, _("Key")); - gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); - gtk_tree_view_column_set_spacing(column, 4); - gtk_tree_view_column_set_resizable(column, FALSE); - gtk_tree_view_column_set_fixed_width(column, 50); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, FALSE); - gtk_tree_view_column_set_attributes(column, renderer, - "text", RAWDATA_KEY, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_rawdata), column); - - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(column, _("Value")); - gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); - gtk_tree_view_column_set_spacing(column, 4); - gtk_tree_view_column_set_resizable(column, FALSE); - gtk_tree_view_column_set_fixed_width(column, 50); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, FALSE); - gtk_tree_view_column_set_attributes(column, renderer, - "text", RAWDATA_VALUE, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_rawdata), column); - - hbox_status_and_bbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start (GTK_BOX (vbox0), hbox_status_and_bbox, FALSE, FALSE, 0); - - label_mini_status = gtk_label_new(""); - gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_mini_status), 0, 0.5); - gtk_box_pack_start (GTK_BOX (hbox_status_and_bbox), label_mini_status, TRUE, TRUE, 0); - - bbox_close = gtk_hbutton_box_new(); - gtk_box_set_spacing(GTK_BOX(bbox_close), 6); - gtk_box_pack_start(GTK_BOX(hbox_status_and_bbox), bbox_close, FALSE, FALSE, 0); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox_close), GTK_BUTTONBOX_END); - - btn_apply = gtk_button_new_from_stock("gtk-save"); - gtk_container_add(GTK_CONTAINER(bbox_close), btn_apply); - g_signal_connect(G_OBJECT(btn_apply), "clicked", (GCallback) fileinfo_update_tuple, NULL); - gtk_widget_set_sensitive(btn_apply, FALSE); - - btn_close = gtk_button_new_from_stock("gtk-close"); - gtk_container_add(GTK_CONTAINER(bbox_close), btn_close); - GTK_WIDGET_SET_FLAGS(btn_close, GTK_CAN_DEFAULT); - g_signal_connect(G_OBJECT(btn_close), "clicked", (GCallback) fileinfo_hide, NULL); - - gtk_widget_show_all (vbox0); -} - -static void -fileinfo_show_for_tuple(Tuple *tuple, gboolean updating_enabled) -{ - gchar *tmp = NULL; - GdkPixbuf *icon = NULL; - GtkTreeIter iter; - GtkListStore *store; - mowgli_dictionary_iteration_state_t state; - TupleValue *tvalue; - gint i; - - if (tuple == NULL) - return; - - if(!updating_enabled) { - current_ip = NULL; - G_FREE_CLEAR(current_file); - } - - something_changed = FALSE; - - if (fileinfo_win == NULL) - create_fileinfo_window(); - - if (!GTK_WIDGET_REALIZED(fileinfo_win)) - gtk_widget_realize(fileinfo_win); - - set_entry_str_from_field(entry_title, tuple, FIELD_TITLE, updating_enabled); - set_entry_str_from_field(entry_artist, tuple, FIELD_ARTIST, updating_enabled); - set_entry_str_from_field(entry_album, tuple, FIELD_ALBUM, updating_enabled); - set_entry_str_from_field(entry_comment, tuple, FIELD_COMMENT, updating_enabled); - set_entry_str_from_field(gtk_bin_get_child(GTK_BIN(entry_genre)), tuple, FIELD_GENRE, updating_enabled); - - tmp = g_strdup_printf("%s/%s", - tuple_get_string(tuple, FIELD_FILE_PATH, NULL), - tuple_get_string(tuple, FIELD_FILE_NAME, NULL)); - - if (tmp) { - fileinfo_entry_set_text(entry_location, tmp); - g_free(tmp); - } - - /* set empty string if field not availaible. --eugene */ - set_entry_int_from_field(entry_year, tuple, FIELD_YEAR, updating_enabled); - set_entry_int_from_field(entry_track, tuple, FIELD_TRACK_NUMBER, updating_enabled); - - fileinfo_label_set_text(label_format_name, tuple_get_string(tuple, FIELD_CODEC, NULL)); - fileinfo_label_set_text(label_quality, tuple_get_string(tuple, FIELD_QUALITY, NULL)); - - if (tuple_get_value_type(tuple, FIELD_BITRATE, NULL) == TUPLE_INT) { - tmp = g_strdup_printf(_("%d kb/s"), tuple_get_int(tuple, FIELD_BITRATE, NULL)); - fileinfo_label_set_text(label_bitrate, tmp); - g_free(tmp); - } else - fileinfo_label_set_text(label_bitrate, NULL); - - tmp = (gchar *)tuple_get_string(tuple, FIELD_MIMETYPE, NULL); - icon = mime_icon_lookup(48, tmp ? tmp : "audio/x-generic"); - if (icon) { - if (image_fileicon) gtk_image_set_from_pixbuf (GTK_IMAGE(image_fileicon), icon); - g_object_unref(icon); - } - - tmp = fileinfo_recursive_get_image( - tuple_get_string(tuple, FIELD_FILE_PATH, NULL), - tuple_get_string(tuple, FIELD_FILE_NAME, NULL), 0); - - if (tmp) { - fileinfo_entry_set_image(image_artwork, tmp); - g_free(tmp); - } - - gtk_widget_set_sensitive(btn_apply, FALSE); - - if (label_mini_status != NULL) { - gtk_label_set_text(GTK_LABEL(label_mini_status), ""); - gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); - } - - store = gtk_list_store_new(RAWDATA_N_COLS, G_TYPE_STRING, G_TYPE_STRING); - - for (i = 0; i < FIELD_LAST; i++) { - gchar *key, *value; - - if (!tuple->values[i]) - continue; - - if (tuple->values[i]->type != TUPLE_INT && tuple->values[i]->value.string) - value = g_strdup(tuple->values[i]->value.string); - else if (tuple->values[i]->type == TUPLE_INT) - value = g_strdup_printf("%d", tuple->values[i]->value.integer); - else - continue; - - key = g_strdup(tuple_fields[i].name); - - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - RAWDATA_KEY, key, - RAWDATA_VALUE, value, -1); - - g_free(key); - g_free(value); - } - - /* non-standard values are stored in a dictionary. */ - MOWGLI_DICTIONARY_FOREACH(tvalue, &state, tuple->dict) { - gchar *key, *value; - - if (tvalue->type != TUPLE_INT && tvalue->value.string) - value = g_strdup(tvalue->value.string); - else if (tvalue->type == TUPLE_INT) - value = g_strdup_printf("%d", tvalue->value.integer); - else - continue; - - key = g_strdup(state.cur->key); - - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - RAWDATA_KEY, key, - RAWDATA_VALUE, value, -1); - - g_free(key); - g_free(value); - } - - gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_rawdata), GTK_TREE_MODEL(store)); - g_object_unref(store); - - if (!GTK_WIDGET_VISIBLE(fileinfo_win)) - gtk_widget_show(fileinfo_win); -} - -static void -fileinfo_show_for_path(gchar *path) -{ - Tuple *tuple = input_get_song_tuple(path); - - if (tuple == NULL) { - input_file_info_box(path); - return; - } - - fileinfo_show_for_tuple(tuple, FALSE); - - mowgli_object_unref(tuple); -} - -static void -fileinfo_show_editor_for_path(gchar *path, InputPlugin *ip) -{ - G_FREE_CLEAR(current_file); - current_file = g_strdup(path); - current_ip = ip; - - Tuple *tuple = input_get_song_tuple(path); - - if (tuple == NULL) { - input_file_info_box(path); - return; - } - - fileinfo_show_for_tuple(tuple, TRUE); - - mowgli_object_unref(tuple); -} - -static void -ui_fileinfo_show_entry(Playlist *playlist, PlaylistEntry *entry) -{ - gchar *path = g_strdup(entry->filename); - Tuple *tuple = entry->tuple; - - /* plugin is capable of updating tags. we need to bypass tuple cache. --eugene */ - /* maybe code cleanup required... */ - if (entry != NULL && - entry->decoder != NULL && - entry->decoder->update_song_tuple != NULL && - entry->decoder->file_info_box == NULL && - path != NULL && !vfs_is_remote(path)) - { - fileinfo_show_editor_for_path(path, entry->decoder); - g_free(path); - } - else - { - if (tuple != NULL) - { - if (entry->decoder != NULL) - { - if (entry->decoder->file_info_box == NULL) - fileinfo_show_for_tuple(tuple, FALSE); - else - { - plugin_set_current((Plugin *)(entry->decoder)); - entry->decoder->file_info_box(path); - } - } - else - fileinfo_show_for_path(path); - g_free(path); - } - else if (path != NULL) - { - if (entry != NULL && - entry->decoder != NULL && - entry->decoder->file_info_box != NULL) - { - plugin_set_current((Plugin *)(entry->decoder)); - entry->decoder->file_info_box(path); - } - else - fileinfo_show_for_path(path); - g_free(path); - } - } -} - -void -ui_fileinfo_show(Playlist *playlist, guint pos) -{ - GList *node = NULL; - - PLAYLIST_LOCK(playlist); - - if ((node = g_list_nth(playlist->entries, pos))) - ui_fileinfo_show_entry(playlist, node->data); - - PLAYLIST_UNLOCK(playlist); -} - -void -ui_fileinfo_show_current(Playlist *playlist) -{ - PLAYLIST_LOCK(playlist); - - if (playlist->entries && playlist->position) - ui_fileinfo_show_entry(playlist, playlist->position); - - PLAYLIST_UNLOCK(playlist); -} diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_fileinfo.h --- a/src/audacious/legacy/ui_fileinfo.h Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Audacious: A cross-platform multimedia player - * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill, - * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ - -#ifndef AUDACIOUS_UI_FILEINFO_H -#define AUDACIOUS_UI_FILEINFO_H - -#include "tuple.h" -#include "plugin.h" -#include - -void create_fileinfo_window(void); -gchar* fileinfo_recursive_get_image(const gchar* path, const gchar* file_name, gint depth); - -void ui_fileinfo_show(Playlist *playlist, guint pos); -void ui_fileinfo_show_current(Playlist *playlist); - -#endif /* AUDACIOUS_UI_FILEINFO_H */ diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_jumptotrack.c --- a/src/audacious/legacy/ui_jumptotrack.c Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,623 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2006 Audacious development team. - * - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * - * Based on XMMS: - * Copyright (C) 1998-2003 XMMS development team. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - - -#include -#include -#include -#include -#include - -/* GDK including */ -#include "platform/smartinclude.h" - -#include -#include -#include - -#include - -#if defined(USE_REGEX_ONIGURUMA) - #include -#elif defined(USE_REGEX_PCRE) - #include -#else - #include -#endif - -#include "ui_main.h" -#include "icons-stock.h" - -#include "actions-mainwin.h" - -#include "main.h" - -#include "dnd.h" -#include "input.h" -#include "playback.h" -#include "playlist.h" -#include "pluginenum.h" -#include "ui_credits.h" -#include "ui_dock.h" -#include "ui_equalizer.h" -#include "ui_fileopener.h" -#include "ui_manager.h" -#include "ui_playlist.h" -#include "ui_preferences.h" -#include "ui_skinselector.h" -#include "ui_urlopener.h" -#include "strings.h" -#include "util.h" -#include "visualization.h" - -#include "ui_skinned_window.h" - -#include "ui_jumptotrack_cache.h" - -static GtkWidget *jump_to_track_win = NULL; -static gulong serial = 0; - -static JumpToTrackCache* cache = NULL; - -static void -change_song(guint pos) -{ - if (playback_get_playing()) - playback_stop(); - - playlist_set_position(playlist_get_active(), pos); - playback_initiate(); -} - -void -ui_jump_to_track_hide(void) -{ - g_return_if_fail(jump_to_track_win != NULL); - gtk_widget_hide(jump_to_track_win); -} - -static void -ui_jump_to_track_jump(GtkTreeView * treeview) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - guint pos; - - model = gtk_tree_view_get_model(treeview); - selection = gtk_tree_view_get_selection(treeview); - - if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) - return; - - gtk_tree_model_get(model, &iter, 0, &pos, -1); - - change_song(pos - 1); - - if(cfg.close_jtf_dialog) - ui_jump_to_track_hide(); -} - -static void -ui_jump_to_track_toggle_cb(GtkWidget * toggle) -{ - cfg.close_jtf_dialog = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)); -} - -static void -ui_jump_to_track_toggle2_cb(GtkWidget * toggle) -{ - cfg.remember_jtf_entry = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)); -} - -static void -ui_jump_to_track_jump_cb(GtkTreeView * treeview, - gpointer data) -{ - ui_jump_to_track_jump(treeview); -} - -static void -ui_jump_to_track_set_queue_button_label(GtkButton * button, - guint pos) -{ - if (playlist_is_position_queued(playlist_get_active(), pos)) - gtk_button_set_label(button, _("Un_queue")); - else - gtk_button_set_label(button, _("_Queue")); -} - -static void -ui_jump_to_track_queue_cb(GtkButton * button, - gpointer data) -{ - GtkTreeView *treeview; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - guint pos; - - treeview = GTK_TREE_VIEW(data); - model = gtk_tree_view_get_model(treeview); - selection = gtk_tree_view_get_selection(treeview); - - if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) - return; - - gtk_tree_model_get(model, &iter, 0, &pos, -1); - - playlist_queue_position(playlist_get_active(), (pos - 1)); - - ui_jump_to_track_set_queue_button_label(button, (pos - 1)); -} - -static void -ui_jump_to_track_selection_changed_cb(GtkTreeSelection *treesel, - gpointer data) -{ - GtkTreeView *treeview; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - guint pos; - - treeview = gtk_tree_selection_get_tree_view(treesel); - model = gtk_tree_view_get_model(treeview); - selection = gtk_tree_view_get_selection(treeview); - - if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) - return; - - gtk_tree_model_get(model, &iter, 0, &pos, -1); - - ui_jump_to_track_set_queue_button_label(GTK_BUTTON(data), (pos - 1)); -} - -static gboolean -ui_jump_to_track_edit_keypress_cb(GtkWidget * object, - GdkEventKey * event, - gpointer data) -{ - switch (event->keyval) { - case GDK_Return: - if (gtk_im_context_filter_keypress (GTK_ENTRY (object)->im_context, event)) { - GTK_ENTRY (object)->need_im_reset = TRUE; - return TRUE; - } else { - ui_jump_to_track_jump(GTK_TREE_VIEW(data)); - return TRUE; - } - default: - return FALSE; - } -} - -static gboolean -ui_jump_to_track_keypress_cb(GtkWidget * object, - GdkEventKey * event, - gpointer data) -{ - switch (event->keyval) { - case GDK_Escape: - ui_jump_to_track_hide(); - return TRUE; - case GDK_KP_Enter: - ui_jump_to_track_queue_cb(NULL, data); - return TRUE; - default: - return FALSE; - }; - - return FALSE; -} - -void -ui_jump_to_track_update(GtkWidget * widget, gpointer user_data) -{ - guint row; - GList *playlist_glist; - gchar *desc_buf = NULL; - GtkTreeIter iter; - GtkTreeSelection *selection; - Playlist *playlist; - - GtkTreeModel *store; - - GtkTreeView *tree = GTK_TREE_VIEW(g_object_get_data(user_data, "treeview")); - GtkEntry *edit = g_object_get_data(user_data, "edit"); - - if (!jump_to_track_win) - return; - - /* clear edit widget */ - if(edit){ - gtk_entry_set_text(edit, ""); - } - - store = gtk_tree_view_get_model(tree); - gtk_list_store_clear(GTK_LIST_STORE(store)); - - row = 1; - playlist = playlist_get_active(); - for (playlist_glist = playlist->entries; playlist_glist; - playlist_glist = g_list_next(playlist_glist)) { - PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data); - - if (entry->title) - desc_buf = g_strdup(entry->title); - else { - gchar *realfn = NULL; - realfn = g_filename_from_uri(entry->filename, NULL, NULL); - if (strchr(realfn ? realfn : entry->filename, '/')) - desc_buf = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1); - else - desc_buf = str_assert_utf8(realfn ? realfn : entry->filename); - g_free(realfn); realfn = NULL; - } - - gtk_list_store_append(GTK_LIST_STORE(store), &iter); - gtk_list_store_set(GTK_LIST_STORE(store), &iter, - 0, row, 1, desc_buf, -1); - row++; - - g_free(desc_buf); - desc_buf = NULL; - } - - gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); - selection = gtk_tree_view_get_selection(tree); - gtk_tree_selection_select_iter(selection, &iter); - serial = playlist->serial; // important. --yaz -} - -static void -ui_jump_to_track_edit_cb(GtkEntry * entry, gpointer user_data) -{ - GtkTreeView *treeview = GTK_TREE_VIEW(user_data); - GtkTreeSelection *selection; - GtkTreeIter iter; - - GtkListStore *store; - - const GArray *search_matches; - Playlist *playlist; - int i; - - if (cache == NULL) { - cache = ui_jump_to_track_cache_new(); - } - - /* FIXME: Remove the connected signals before clearing - * (row-selected will still eventually arrive once) */ - store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview)); - /* detach model from treeview */ - g_object_ref( store ); - gtk_tree_view_set_model( GTK_TREE_VIEW(treeview) , NULL ); - - gtk_list_store_clear(store); - - playlist = playlist_get_active(); - - PLAYLIST_LOCK(playlist); - - search_matches = ui_jump_to_track_cache_search(cache, - playlist, - gtk_entry_get_text(entry)); - - for (i = 0; i < search_matches->len; i++) - { - JumpToTrackEntry *jttentry = g_array_index(search_matches, JumpToTrackEntry*, i); - PlaylistEntry* entry = jttentry->entry; - gchar *title = NULL; - - if (entry->title) - title = g_strdup(entry->title); - else { - gchar *realfn = NULL; - realfn = g_filename_from_uri(entry->filename, NULL, NULL); - if (strchr(realfn ? realfn : entry->filename, '/')) - title = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1); - else - title = str_assert_utf8(realfn ? realfn : entry->filename); - g_free(realfn); realfn = NULL; - } - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, jttentry->playlist_position + 1 , 1, title, -1); - g_free(title); - } - - PLAYLIST_UNLOCK(playlist); - - /* attach the model again to the treeview */ - gtk_tree_view_set_model( GTK_TREE_VIEW(treeview) , GTK_TREE_MODEL(store) ); - g_object_unref( store ); - - if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { - selection = gtk_tree_view_get_selection(treeview); - gtk_tree_selection_select_iter(selection, &iter); - } -} - -static gboolean -ui_jump_to_track_fill(gpointer treeview) -{ - GList *playlist_glist; - Playlist *playlist; - gchar *desc_buf = NULL; - guint row; - GtkTreeIter iter; - GtkListStore *jtf_store = (GtkListStore*)gtk_tree_view_get_model( GTK_TREE_VIEW(treeview) ); - - /* detach model from treeview before fill */ - g_object_ref(jtf_store); - gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), NULL ); - - gtk_list_store_clear(jtf_store); - - row = 1; - playlist = playlist_get_active(); - - PLAYLIST_LOCK(playlist); - for (playlist_glist = playlist->entries; playlist_glist; - playlist_glist = g_list_next(playlist_glist)) { - - PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data); - - if (entry->title) - desc_buf = g_strdup(entry->title); - else { - gchar *realfn = NULL; - realfn = g_filename_from_uri(entry->filename, NULL, NULL); - if (strchr(realfn ? realfn : entry->filename, '/')) - desc_buf = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1); - else - desc_buf = str_assert_utf8(realfn ? realfn : entry->filename); - g_free(realfn); realfn = NULL; - } - - gtk_list_store_append(GTK_LIST_STORE(jtf_store), &iter); - gtk_list_store_set(GTK_LIST_STORE(jtf_store), &iter, - 0, row, 1, desc_buf, -1); - row++; - - g_free(desc_buf); - desc_buf = NULL; - } - PLAYLIST_UNLOCK(playlist); - - /* attach liststore to treeview */ - gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(jtf_store)); - g_object_unref(jtf_store); - serial = playlist->serial; - return FALSE; -} - -static gboolean -watchdog(gpointer storage) -{ - GtkWidget *widget; - Playlist *playlist = playlist_get_active(); - - if(serial == playlist->serial) - return TRUE; - - widget = g_object_get_data(storage, "widget"); - ui_jump_to_track_update(widget, storage); - return TRUE; -} - -void -ui_jump_to_track(void) -{ - GtkWidget *scrollwin; - GtkWidget *vbox, *bbox, *sep; - GtkWidget *toggle, *toggle2; - GtkWidget *jump, *queue, *close; - GtkWidget *rescan; - GtkWidget *search_label, *hbox; - static GtkWidget *edit; - - GtkWidget *treeview = NULL; - GtkListStore *jtf_store; - - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - gpointer storage; - - if (jump_to_track_win) { - gtk_window_present(GTK_WINDOW(jump_to_track_win)); - - if(!cfg.remember_jtf_entry) - gtk_entry_set_text(GTK_ENTRY(edit), ""); - - gtk_widget_grab_focus(edit); - gtk_editable_select_region(GTK_EDITABLE(edit), 0, -1); - return; - } - - #if defined(USE_REGEX_ONIGURUMA) - /* set encoding for Oniguruma regex to UTF-8 */ - reg_set_encoding( REG_POSIX_ENCODING_UTF8 ); - onig_set_default_syntax( ONIG_SYNTAX_POSIX_BASIC ); - #endif - - jump_to_track_win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_type_hint(GTK_WINDOW(jump_to_track_win), - GDK_WINDOW_TYPE_HINT_DIALOG); - - gtk_window_set_title(GTK_WINDOW(jump_to_track_win), _("Jump to Track")); - - gtk_window_set_position(GTK_WINDOW(jump_to_track_win), GTK_WIN_POS_CENTER); - g_signal_connect(jump_to_track_win, "destroy", - G_CALLBACK(gtk_widget_destroyed), &jump_to_track_win); - - gtk_container_border_width(GTK_CONTAINER(jump_to_track_win), 10); - gtk_window_set_default_size(GTK_WINDOW(jump_to_track_win), 600, 500); - - vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(jump_to_track_win), vbox); - - jtf_store = gtk_list_store_new(2, G_TYPE_UINT, G_TYPE_STRING); - treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(jtf_store)); - g_object_unref(jtf_store); - - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); - - column = gtk_tree_view_column_new(); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); - gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, FALSE); - gtk_tree_view_column_set_attributes(column, renderer, "text", 0, NULL); - gtk_tree_view_column_set_spacing(column, 4); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, FALSE); - gtk_tree_view_column_set_attributes(column, renderer, "text", 1, NULL); - gtk_tree_view_column_set_spacing(column, 4); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); - - gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), 1); - - g_signal_connect(treeview, "row-activated", - G_CALLBACK(ui_jump_to_track_jump), NULL); - - hbox = gtk_hbox_new(FALSE, 3); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); - - - /* filter box */ - search_label = gtk_label_new(_("Filter: ")); - gtk_label_set_markup_with_mnemonic(GTK_LABEL(search_label), _("_Filter:")); - gtk_box_pack_start(GTK_BOX(hbox), search_label, FALSE, FALSE, 0); - - edit = gtk_entry_new(); - gtk_entry_set_editable(GTK_ENTRY(edit), TRUE); - gtk_label_set_mnemonic_widget(GTK_LABEL(search_label), edit); - g_signal_connect(edit, "changed", - G_CALLBACK(ui_jump_to_track_edit_cb), treeview); - - g_signal_connect(edit, "key_press_event", - G_CALLBACK(ui_jump_to_track_edit_keypress_cb), treeview); - - g_signal_connect(jump_to_track_win, "key_press_event", - G_CALLBACK(ui_jump_to_track_keypress_cb), treeview); - - gtk_box_pack_start(GTK_BOX(hbox), edit, TRUE, TRUE, 3); - - /* remember text entry */ - toggle2 = gtk_check_button_new_with_label(_("Remember")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle2), - cfg.remember_jtf_entry ? TRUE : FALSE); - gtk_box_pack_start(GTK_BOX(hbox), toggle2, FALSE, FALSE, 0); - g_signal_connect(toggle2, "clicked", - G_CALLBACK(ui_jump_to_track_toggle2_cb), - toggle2); - - /* clear button */ - rescan = gtk_button_new_from_stock(GTK_STOCK_CLEAR); - gtk_box_pack_start(GTK_BOX(hbox), rescan, FALSE, FALSE, 0); - - - /* pack to container */ - storage = g_object_new(G_TYPE_OBJECT, NULL); - g_object_set_data(storage, "widget", rescan); - g_object_set_data(storage, "treeview", treeview); - g_object_set_data(storage, "edit", edit); - - g_signal_connect(rescan, "clicked", - G_CALLBACK(ui_jump_to_track_update), storage); - - GTK_WIDGET_SET_FLAGS(rescan, GTK_CAN_DEFAULT); - gtk_widget_grab_default(rescan); - - scrollwin = gtk_scrolled_window_new(NULL, NULL); - gtk_container_add(GTK_CONTAINER(scrollwin), treeview); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin), - GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0); - - sep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); - - bbox = gtk_hbutton_box_new(); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 4); - gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); - - /* close dialog toggle */ - toggle = gtk_check_button_new_with_label(_("Close on Jump")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), - cfg.close_jtf_dialog ? TRUE : FALSE); - gtk_box_pack_start(GTK_BOX(bbox), toggle, FALSE, FALSE, 0); - g_signal_connect(toggle, "clicked", - G_CALLBACK(ui_jump_to_track_toggle_cb), - toggle); - - queue = gtk_button_new_with_mnemonic(_("_Queue")); - gtk_button_set_image(GTK_BUTTON(queue), - gtk_image_new_from_stock(AUD_STOCK_QUEUETOGGLE, GTK_ICON_SIZE_BUTTON)); - gtk_box_pack_start(GTK_BOX(bbox), queue, FALSE, FALSE, 0); - GTK_WIDGET_SET_FLAGS(queue, GTK_CAN_DEFAULT); - g_signal_connect(queue, "clicked", - G_CALLBACK(ui_jump_to_track_queue_cb), - treeview); - g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), "changed", - G_CALLBACK(ui_jump_to_track_selection_changed_cb), - queue); - - jump = gtk_button_new_from_stock(GTK_STOCK_JUMP_TO); - gtk_box_pack_start(GTK_BOX(bbox), jump, FALSE, FALSE, 0); - - g_signal_connect_swapped(jump, "clicked", - G_CALLBACK(ui_jump_to_track_jump_cb), - treeview); - - GTK_WIDGET_SET_FLAGS(jump, GTK_CAN_DEFAULT); - gtk_widget_grab_default(jump); - - close = gtk_button_new_from_stock(GTK_STOCK_CLOSE); - gtk_box_pack_start(GTK_BOX(bbox), close, FALSE, FALSE, 0); - g_signal_connect_swapped(close, "clicked", - G_CALLBACK(gtk_widget_hide), - jump_to_track_win); // just hide --yaz - GTK_WIDGET_SET_FLAGS(close, GTK_CAN_DEFAULT); - - g_timeout_add(100, (GSourceFunc)ui_jump_to_track_fill, treeview); - g_timeout_add(500, (GSourceFunc)watchdog, storage); - - gtk_widget_show_all(jump_to_track_win); - gtk_widget_grab_focus(edit); -} diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_jumptotrack_cache.c --- a/src/audacious/legacy/ui_jumptotrack_cache.c Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,431 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2008 Audacious development team. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#include -#include -#include - -#if defined(USE_REGEX_ONIGURUMA) - #include -#elif defined(USE_REGEX_PCRE) - #include -#else - #include -#endif - -#include "playlist.h" -#include "strings.h" - -#include "ui_jumptotrack_cache.h" - -// Struct to keep information about matches from searches. -typedef struct -{ - GArray* track_entries; // JumpToTrackEntry* - GArray* normalized_titles; // gchar* -} KeywordMatches; - -/** - * Creates an regular expression list usable in searches from search keyword. - * - * In searches, every regular expression on this list is matched against - * the search title and if they all match, the title is declared as - * matching one. - * - * Regular expressions in list are formed by splitting the 'keyword' to words - * by splitting the keyword string with space character. - */ -static GSList* -ui_jump_to_track_cache_regex_list_create(const GString* keyword) -{ - GSList *regex_list = NULL; - gchar **words = NULL; - int i = -1; - /* Chop the key string into ' '-separated key regex-pattern strings */ - words = g_strsplit(keyword->str, " ", 0); - - /* create a list of regex using the regex-pattern strings */ - while ( words[++i] != NULL ) - { - // Ignore empty words. - if (words[i][0] == 0) { - continue; - } - regex_t *regex = g_malloc(sizeof(regex_t)); - #if defined(USE_REGEX_PCRE) - if ( regcomp( regex , words[i] , REG_NOSUB | REG_UTF8 ) == 0 ) - #else - if ( regcomp( regex , words[i] , REG_NOSUB ) == 0 ) - #endif - regex_list = g_slist_append( regex_list , regex ); - else - g_free( regex ); - } - - g_strfreev(words); - - return regex_list; -} - -/** - * Frees the regular expression list used in searches. - */ -static void -ui_jump_to_track_cache_regex_list_free(GSList* regex_list) -{ - if ( regex_list != NULL ) - { - GSList* regex_list_tmp = regex_list; - while ( regex_list != NULL ) - { - regex_t *regex = regex_list->data; - regfree( regex ); - g_free( regex ); - regex_list = g_slist_next(regex_list); - } - g_slist_free( regex_list_tmp ); - } -} - -/** - * Checks if 'song' matches all regular expressions in 'regex_list'. - */ -static gboolean -ui_jump_to_track_match(const gchar * song, GSList *regex_list) -{ - if ( song == NULL ) - return FALSE; - - for ( ; regex_list ; regex_list = g_slist_next(regex_list) ) - { - regex_t *regex = regex_list->data; - if ( regexec( regex , song , 0 , NULL , 0 ) != 0 ) - return FALSE; - } - - return TRUE; -} - -/** - * Returns all songs that match 'keyword'. - * - * Searches are conducted against entries in 'search_space' variable - * and after the search, search result is added to 'cache'. - * - * @param cache The result of this search is added to cache. - * @param search_space Entries inside which the search is conducted. - * @param keyword Normalized string for searches. - */ -static GArray* -ui_jump_to_track_cache_match_keyword(JumpToTrackCache* cache, - const KeywordMatches* search_space, - const GString* keyword) -{ - GSList* regex_list = ui_jump_to_track_cache_regex_list_create(keyword); - GArray* track_entries = g_array_new(FALSE, FALSE, sizeof(JumpToTrackEntry*)); - GArray* normalized_titles = g_array_new(FALSE, FALSE, sizeof(gchar*)); - gboolean match = FALSE; - int i = 0; - - for (i = 0; i < search_space->normalized_titles->len; i++) - { - gchar* title = g_array_index(search_space->normalized_titles, gchar*, i); - - if (regex_list != NULL) - match = ui_jump_to_track_match(title, regex_list); - else - match = TRUE; - - if (match) { - JumpToTrackEntry* entry = g_array_index(search_space->track_entries, - JumpToTrackEntry*, i); - g_array_append_val(track_entries, entry); - g_array_append_val(normalized_titles, title); - } - } - - KeywordMatches* keyword_matches = g_new(KeywordMatches, 1); - keyword_matches->track_entries = track_entries; - keyword_matches->normalized_titles = normalized_titles; - - g_hash_table_insert(cache->keywords, - GINT_TO_POINTER(g_string_hash(keyword)), - keyword_matches); - - ui_jump_to_track_cache_regex_list_free(regex_list); - return track_entries; -} - -/** - * Normalizes the search string to be more suitable for searches. - * - * Basically this does Unicode NFKD normalization to for example match - * half-width and full-width characters and case folding mainly to match - * upper- and lowercase letters. - * - * String returned by this function should be freed manually. - */ -static gchar * -normalize_search_string(const gchar* string) -{ - gchar* normalized_string = g_utf8_normalize(string, -1, G_NORMALIZE_NFKD); - gchar* folded_string = g_utf8_casefold(normalized_string, -1); - g_free(normalized_string); - return folded_string; -} - -/** - * Frees the possibly allocated data in KeywordMatches. - */ -static void -ui_jump_to_track_cache_free_keywordmatch_data(KeywordMatches* match_entry) -{ - int i = 0; - assert(match_entry->normalized_titles->len == match_entry->track_entries->len); - for (i = 0; i < match_entry->normalized_titles->len; i++) - { - g_free(g_array_index(match_entry->normalized_titles, gchar*, i)); - g_free(g_array_index(match_entry->track_entries, PlaylistEntry*, i)); - } -} - -/** - * Frees the memory reserved for an search result. - */ -static void -ui_jump_to_track_cache_free_cache_entry(gpointer entry) -{ - KeywordMatches* match_entry = (KeywordMatches*)entry; - g_array_free(match_entry->track_entries, TRUE); - g_array_free(match_entry->normalized_titles, TRUE); -} - -/** - * Creates a new song search cache. - * - * Returned value should be freed with ui_jump_to_track_cache_free() function. - */ -JumpToTrackCache* -ui_jump_to_track_cache_new() -{ - JumpToTrackCache* cache = g_new(JumpToTrackCache, 1); - cache->playlist_serial = -1; - cache->keywords = g_hash_table_new_full(NULL, NULL, NULL, - ui_jump_to_track_cache_free_cache_entry); - return cache; -} - -/** - * Clears the search cache. - */ -static void -ui_jump_to_track_cache_clear(JumpToTrackCache* cache) -{ - GString* empty_keyword = g_string_new(""); - gpointer found_keyword = NULL; - - cache->playlist_serial = -1; - - // All normalized titles reside in an empty key "" so we'll free them - // first. - found_keyword = g_hash_table_lookup(cache->keywords, - GINT_TO_POINTER(g_string_hash(empty_keyword))); - g_string_free(empty_keyword, - TRUE); - if (found_keyword != NULL) - { - KeywordMatches* all_titles = (KeywordMatches*)found_keyword; - ui_jump_to_track_cache_free_keywordmatch_data(all_titles); - } - // Now when all normalized strings are freed, no need to worry about - // double frees or memory leaks. - g_hash_table_remove_all(cache->keywords); -} - -/** - * Initializes the search cache if cache is empty or has wrong playlist. - */ -static void -ui_jump_to_track_cache_init(JumpToTrackCache* cache, - const Playlist* playlist) -{ - if (cache->playlist_serial != playlist->serial) - { - GList* playlist_entries = NULL; - GArray* track_entries = g_array_new(FALSE, FALSE, sizeof(JumpToTrackEntry*)); - GArray* normalized_titles = g_array_new(FALSE, FALSE, sizeof(gchar*)); - GString* empty_keyword = g_string_new(""); - gulong song_index = 0; - - // Reset cache state - ui_jump_to_track_cache_clear(cache); - - cache->playlist_serial = playlist->serial; - - // Initialize cache with playlist data - for (playlist_entries = playlist->entries; - playlist_entries; - playlist_entries = g_list_next(playlist_entries)) - { - PlaylistEntry* playlist_entry = PLAYLIST_ENTRY(playlist_entries->data); - - gchar *title = NULL; - /*we are matching all the path not just the filename or title*/ - - /* - * FIXME: The search string should be adapted to the - * current display setting, e.g. if the user has set it to - * "%p - %t" then build the match string like that too, or - * even better, search for each of the tags seperatly. - * - * In any case the string to match should _never_ contain - * something the user can't actually see in the playlist. - */ - if (playlist_entry->title) { - title = normalize_search_string(playlist_entry->title); - } else { - gchar *realfn = NULL; - realfn = g_filename_from_uri(playlist_entry->filename, NULL, NULL); - gchar *tmp_title = str_assert_utf8(realfn ? realfn : playlist_entry->filename); - title = normalize_search_string(tmp_title); - g_free(tmp_title); - g_free(realfn); realfn = NULL; - } - - JumpToTrackEntry* search_entry = g_new(JumpToTrackEntry, 1); - search_entry->entry = playlist_entry; - search_entry->playlist_position = song_index; - g_array_append_val(track_entries, search_entry); - g_array_append_val(normalized_titles, title); - // We need to manually keep track of the current playlist index. - song_index++; - } - // Finally insert all titles into cache into an empty key "" so that - // the matchable data has specified place to be. - KeywordMatches* keyword_data = g_new(KeywordMatches, 1); - keyword_data->track_entries = track_entries; - keyword_data->normalized_titles = normalized_titles; - g_hash_table_insert(cache->keywords, - GINT_TO_POINTER(g_string_hash(empty_keyword)), - keyword_data); - g_string_free(empty_keyword, - TRUE); - } -} - -/** - * Searches 'keyword' inside 'playlist' by using 'cache' to speed up searching. - * - * Searches are basically conducted as follows: - * - * Cache is checked if it has the information about right playlist and - * initialized with playlist data if needed. - * - * Keyword is normalized for searching (Unicode NFKD, case folding) - * - * Cache is checked if it has keyword and if it has, we can immediately get - * the search results and return. If not, searching goes as follows: - * - * Search for the longest word that is in cache that matches the beginning - * of keyword and use the cached matches as base for the current search. - * The shortest word that can be matched against is the empty string "", so - * there should always be matches in cache. - * - * After that conduct the search by splitting keyword into words separated - * by space and using regular expressions. - * - * When the keyword is searched, search result is added to cache to - * corresponding keyword that can be used as base for new searches. - * - * The motivation for caching is that to search word 'some cool song' one - * has to type following strings that are all searched individually: - * - * s - * so - * som - * some - * some - * some c - * some co - * some coo - * some cool - * some cool - * some cool s - * some cool so - * some cool son - * some cool song - * - * If the search results are cached in every phase and the result of - * the maximum length matching string is used as base for concurrent - * searches, we can probably get the matches reduced to some hundreds - * after a few letters typed on playlists with thousands of songs and - * reduce useless iteration quite a lot. - * - * Return: GArray of JumpToTrackEntry* - */ -const GArray* -ui_jump_to_track_cache_search(JumpToTrackCache* cache, - const Playlist* playlist, - const gchar* keyword) -{ - gchar* normalized_keyword = normalize_search_string(keyword); - GString* keyword_string = g_string_new(normalized_keyword); - GString* match_string = g_string_new(normalized_keyword); - gsize match_string_length = keyword_string->len; - - ui_jump_to_track_cache_init(cache, playlist); - - while (match_string_length >= 0) - { - gpointer string_ptr = GINT_TO_POINTER(g_string_hash(match_string)); - gpointer result_entries = g_hash_table_lookup(cache->keywords, - string_ptr); - if (result_entries != NULL) - { - KeywordMatches* matched_entries = (KeywordMatches*)result_entries; - // if keyword matches something we have, we'll just return the list - // of matches that the keyword has. - if (match_string_length == keyword_string->len) { - g_string_free(keyword_string, TRUE); - g_string_free(match_string, TRUE); - g_free(normalized_keyword); - return matched_entries->track_entries; - } - - // Do normal search by using the result of previous search - // as search space. - GArray* result = ui_jump_to_track_cache_match_keyword(cache, - matched_entries, - keyword_string); - g_string_free(keyword_string, TRUE); - g_string_free(match_string, TRUE); - g_free(normalized_keyword); - return result; - } - match_string_length--; - g_string_set_size(match_string, match_string_length); - } - // This should never, ever get to this point because there is _always_ - // the empty string to match against. - AUDDBG("One should never get to this point. Something is really wrong with \ -cache->keywords hash table."); - assert(FALSE); - g_return_val_if_fail(FALSE, (GArray*)-1); -} - diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_jumptotrack_cache.h --- a/src/audacious/legacy/ui_jumptotrack_cache.h Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2008 Audacious development team. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#ifndef AUDACIOUS_UI_JUMPTOTRACK_CACHE_H -#define AUDACIOUS_UI_JUMPTOTRACK_CACHE_H - -#include - -#include "playlist.h" - -typedef struct _JumpToTrackCache JumpToTrackCache; -typedef struct _JumpToTrackEntry JumpToTrackEntry; - -struct _JumpToTrackCache -{ - gulong playlist_serial; - GHashTable* keywords; -}; - -struct _JumpToTrackEntry -{ - PlaylistEntry* entry; - // We need to manually keep information about current playlist position. - gulong playlist_position; -}; - -extern JumpToTrackCache* ui_jump_to_track_cache_new(void); -extern const GArray* ui_jump_to_track_cache_search(JumpToTrackCache* cache, const Playlist* playlist, const gchar* keyword); -extern void ui_jump_to_track_cache_free(JumpToTrackCache* cache); - -#endif /* AUDACIOUS_UI_JUMPTOTRACK_CACHE_H */ diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_urlopener.c --- a/src/audacious/legacy/ui_urlopener.c Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2007 Audacious development team - * - * Based on BMP: - * Copyright (C) 2003-2004 BMP development team. - * - * Based on XMMS: - * Copyright (C) 1998-2003 XMMS development team. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#define NEED_GLADE -#include "util.h" - -#include -#include -#include -#include -#include -#include - -#include "platform/smartinclude.h" -#include - -#include "input.h" -#include "main.h" -#include "playback.h" -#include "strings.h" -#include "ui_playlist.h" - -#ifdef USE_CHARDET -#include "../libguess/libguess.h" -# ifdef HAVE_UDET -# include -# endif -#endif - -#define URL_HISTORY_MAX_SIZE 30 - -static void -util_add_url_callback(GtkWidget * widget, - GtkEntry * entry) -{ - const gchar *text; - - text = gtk_entry_get_text(entry); - if (g_list_find_custom(cfg.url_history, text, (GCompareFunc) strcasecmp)) - return; - - cfg.url_history = g_list_prepend(cfg.url_history, g_strdup(text)); - - while (g_list_length(cfg.url_history) > URL_HISTORY_MAX_SIZE) { - GList *node = g_list_last(cfg.url_history); - g_free(node->data); - cfg.url_history = g_list_delete_link(cfg.url_history, node); - } -} - -GtkWidget * -util_add_url_dialog_new(const gchar * caption, GCallback ok_func, - GCallback enqueue_func) -{ - GtkWidget *win, *vbox, *bbox, *cancel, *enqueue, *ok, *combo, *entry, - *label; - GList *url; - - win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(win), _("Add/Open URL Dialog")); - gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DIALOG); - gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER); - gtk_window_set_default_size(GTK_WINDOW(win), 400, -1); - gtk_container_set_border_width(GTK_CONTAINER(win), 12); - - vbox = gtk_vbox_new(FALSE, 10); - gtk_container_add(GTK_CONTAINER(win), vbox); - - label = gtk_label_new(caption); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - combo = gtk_combo_box_entry_new_text(); - gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0); - - entry = gtk_bin_get_child(GTK_BIN(combo)); - gtk_window_set_focus(GTK_WINDOW(win), entry); - gtk_entry_set_text(GTK_ENTRY(entry), ""); - - for (url = cfg.url_history; url; url = g_list_next(url)) - gtk_combo_box_append_text(GTK_COMBO_BOX(combo), - (const gchar *) url->data); - - g_signal_connect(entry, "activate", - G_CALLBACK(util_add_url_callback), - entry); - g_signal_connect(entry, "activate", - G_CALLBACK(ok_func), - entry); - g_signal_connect_swapped(entry, "activate", - G_CALLBACK(gtk_widget_destroy), - win); - - bbox = gtk_hbutton_box_new(); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); - gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); - - cancel = gtk_button_new_from_stock(GTK_STOCK_CLOSE); - gtk_box_pack_start(GTK_BOX(bbox), cancel, FALSE, FALSE, 0); - gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(bbox), cancel, TRUE); - - g_signal_connect_swapped(cancel, "clicked", - G_CALLBACK(gtk_widget_destroy), - win); - - enqueue = gtk_button_new_from_stock(GTK_STOCK_ADD); - gtk_box_pack_start(GTK_BOX(bbox), enqueue, FALSE, FALSE, 0); - - g_signal_connect(enqueue, "clicked", - G_CALLBACK(util_add_url_callback), - entry); - g_signal_connect(enqueue, "clicked", - G_CALLBACK(enqueue_func), - entry); - g_signal_connect_swapped(enqueue, "clicked", - G_CALLBACK(gtk_widget_destroy), - win); - - ok = gtk_button_new_from_stock(GTK_STOCK_OPEN); - g_signal_connect(ok, "clicked", - G_CALLBACK(util_add_url_callback), entry); - g_signal_connect(ok, "clicked", - G_CALLBACK(ok_func), entry); - g_signal_connect_swapped(ok, "clicked", - G_CALLBACK(gtk_widget_destroy), - win); - gtk_box_pack_start(GTK_BOX(bbox), ok, FALSE, FALSE, 0); - - gtk_widget_show_all(vbox); - - return win; -} diff -r a33facf19590 -r 6584bba8de63 src/audacious/legacy/ui_urlopener.h --- a/src/audacious/legacy/ui_urlopener.h Tue Jul 08 15:35:48 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2007 Audacious development team - * - * Based on BMP: - * Copyright (C) 2003-2004 BMP development team - * - * Based on XMMS: - * Copyright (C) 1998-2003 XMMS development team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#ifndef AUDACIOUS_UI_URLOPENER_H -#define AUDACIOUS_UI_URLOPENER_H - -#ifdef _AUDACIOUS_CORE -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif -#endif - -#include -#include - -G_BEGIN_DECLS - -GtkWidget *util_add_url_dialog_new(const gchar * caption, GCallback ok_func, - GCallback enqueue_func); - -G_END_DECLS - -#endif /* AUDACIOUS_UI_URLOPENER_H */ diff -r a33facf19590 -r 6584bba8de63 src/audacious/pluginenum.c --- a/src/audacious/pluginenum.c Tue Jul 08 15:35:48 2008 +0200 +++ b/src/audacious/pluginenum.c Tue Jul 08 16:36:50 2008 +0200 @@ -56,7 +56,7 @@ #include "volumecontrol.h" #include "equalizer_preset.h" -#include "legacy/ui_fileinfo.h" +#include "ui_fileinfo.h" #include "ui_fileinfopopup.h" #include "ui_plugin_menu.h" #include "ui_preferences.h" diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_about.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_about.c Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,212 @@ +/* + * Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui_credits.h" + +#include +#include +#include + +#include "platform/smartinclude.h" + +static GtkWidget *about_window = NULL; +static GdkPixbuf *about_pixbuf = NULL; +static GdkPixmap *mask_pixmap_window1 = NULL, + *mask_pixmap_window2 = NULL; +static GdkBitmap *mask_bitmap_window1 = NULL, + *mask_bitmap_window2 = NULL; + +static const gchar *audacious_brief = N_("Audacious %s\n\n" + "Copyright (C) 2005-2008 Audacious Development Team"); + +static gboolean +on_about_window_expose(GtkWidget *widget, GdkEventExpose *expose, gpointer data) +{ + g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE); + + gdk_window_set_back_pixmap(GDK_WINDOW(widget->window), mask_pixmap_window2, 0); + gdk_window_clear(GDK_WINDOW(widget->window)); + + return FALSE; +} + +static gboolean +on_about_window_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE); + + if (event->keyval == GDK_Escape) + { + gtk_widget_hide(widget); + } + + return FALSE; +} + +static gboolean +on_close_button_clicked (GtkWidget *widget, gpointer data) +{ + g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE); + + gtk_widget_hide(about_window); + + return FALSE; +} + +static gboolean +on_credits_button_clicked (GtkWidget *widget, gpointer data) +{ + g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE); + + show_credits_window(); + + return FALSE; +} + +void +show_about_window(void) +{ + GtkWidget *about_fixedbox; + GtkWidget *close_button; + GtkWidget *credits_button , *credits_button_hbox, *credits_button_image, *credits_button_label; + GtkWidget *brief_label; + gchar *filename = DATA_DIR G_DIR_SEPARATOR_S "images" G_DIR_SEPARATOR_S "about-logo.png"; + gchar *text; + PangoAttrList *brief_label_attrs; + PangoAttribute *brief_label_foreground; + + if (about_window != NULL) + { + gtk_window_present(GTK_WINDOW(about_window)); + return; + } + + about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + g_signal_connect(about_window, "destroy", + G_CALLBACK(gtk_widget_destroyed), &about_window); + + gtk_widget_realize(about_window); + + about_pixbuf = gdk_pixbuf_new_from_file(filename, NULL); + + gtk_widget_set_size_request(GTK_WIDGET (about_window), + gdk_pixbuf_get_width (about_pixbuf), + gdk_pixbuf_get_height (about_pixbuf)); + + gtk_widget_set_app_paintable(about_window, TRUE); + gtk_window_set_title(GTK_WINDOW(about_window), _("About Audacious")); + gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_CENTER); + gtk_window_set_resizable(GTK_WINDOW(about_window), FALSE); + gtk_window_set_decorated(GTK_WINDOW(about_window), FALSE); + + gdk_pixbuf_render_pixmap_and_mask(about_pixbuf, + &mask_pixmap_window1, + &mask_bitmap_window1, + 0); + + gdk_pixbuf_render_pixmap_and_mask(about_pixbuf, + &mask_pixmap_window2, + &mask_bitmap_window2, + 128); + + gtk_widget_add_events(about_window, GDK_ALL_EVENTS_MASK); + + g_signal_connect(about_window, "expose-event", + G_CALLBACK(on_about_window_expose), &about_window); + + g_signal_connect(about_window, "key-press-event", + G_CALLBACK(on_about_window_key_press), &about_window); + + gtk_widget_shape_combine_mask(GTK_WIDGET(about_window), mask_bitmap_window2, 0, 0); + + /* GtkFixed hasn't got its GdkWindow, this means that it can be used to + display widgets while the logo below will be displayed anyway; + however fixed positions are not that great, cause the button sizes may (will) + vary depending on the gtk style used, so it's not possible to center + them unless a fixed width and heigth is forced (and this may bring to cutted + text if someone, i.e., uses a big font for gtk widgets); + other types of container most likely have their GdkWindow, this simply + means that the logo must be drawn on the container widget, instead of the + window; otherwise, it won't be displayed correctly */ + about_fixedbox = gtk_fixed_new(); + gtk_container_add( GTK_CONTAINER(about_window) , about_fixedbox ); + + close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + + g_signal_connect(close_button, "clicked", + G_CALLBACK(on_close_button_clicked), NULL); + + gtk_fixed_put( GTK_FIXED(about_fixedbox) , close_button , 375 , 220 ); + gtk_widget_set_size_request( close_button , 100 , -1 ); + + credits_button = gtk_button_new(); + credits_button_hbox = gtk_hbox_new( FALSE , 0 ); + credits_button_image = gtk_image_new_from_stock( GTK_STOCK_DIALOG_INFO , GTK_ICON_SIZE_BUTTON ); + gtk_misc_set_alignment( GTK_MISC(credits_button_image) , 1 , 0.5 ); + credits_button_label = gtk_label_new( _("Credits") ); + gtk_misc_set_alignment( GTK_MISC(credits_button_label) , 0 , 0.5 ); + gtk_box_pack_start( GTK_BOX(credits_button_hbox) , credits_button_image , + TRUE , TRUE , 2 ); + gtk_box_pack_start( GTK_BOX(credits_button_hbox) , credits_button_label , + TRUE , TRUE , 2 ); + gtk_container_add( GTK_CONTAINER(credits_button) , credits_button_hbox ); + + g_signal_connect(credits_button, "clicked", + G_CALLBACK(on_credits_button_clicked), NULL); + + gtk_fixed_put( GTK_FIXED(about_fixedbox) , credits_button , 25 , 220 ); + gtk_widget_set_size_request( credits_button , 100 , -1 ); + + brief_label = gtk_label_new(NULL); + text = g_strdup_printf(_(audacious_brief), VERSION); + + brief_label_foreground = pango_attr_foreground_new(0, 0, 0); + brief_label_attrs = pango_attr_list_new(); + pango_attr_list_insert(brief_label_attrs, brief_label_foreground); + + gtk_label_set_markup(GTK_LABEL(brief_label), text); + gtk_label_set_justify(GTK_LABEL(brief_label), GTK_JUSTIFY_CENTER); + gtk_label_set_attributes(GTK_LABEL(brief_label), brief_label_attrs); + g_free(text); + + gtk_fixed_put(GTK_FIXED(about_fixedbox), brief_label, 20, 145); + gtk_widget_set_size_request( brief_label , 460 , -1 ); + + gtk_widget_show_all(about_window); + gtk_window_present(GTK_WINDOW(about_window)); +} + +void +hide_about_window(void) +{ + g_return_if_fail(about_window); + gtk_widget_hide(GTK_WIDGET(about_window)); +} diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_albumart.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_albumart.c Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,194 @@ +/* + * Audacious: A cross-platform multimedia player + * Copyright (c) 2007 William Pitcock, Tony Vroon, George Averill, + * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include + +#include "ui_fileinfopopup.h" +#include "main.h" +#include "playlist.h" +#include "playback.h" + +static gboolean +has_front_cover_extension(const gchar *name) +{ + char *ext; + + ext = strrchr(name, '.'); + if (!ext) { + /* No file extension */ + return FALSE; + } + + return g_strcasecmp(ext, ".jpg") == 0 || + g_strcasecmp(ext, ".jpeg") == 0 || + g_strcasecmp(ext, ".png") == 0; +} + +static gboolean +cover_name_filter(const gchar *name, const gchar *filter, const gboolean ret_on_empty) +{ + gboolean result = FALSE; + gchar **splitted; + gchar *current; + gchar *lname; + gint i; + + if (!filter || strlen(filter) == 0) { + return ret_on_empty; + } + + splitted = g_strsplit(filter, ",", 0); + + lname = g_strdup(name); + g_strdown(lname); + + for (i = 0; !result && (current = splitted[i]); i++) { + gchar *stripped = g_strstrip(g_strdup(current)); + g_strdown(stripped); + + result = result || strstr(lname, stripped); + + g_free(stripped); + } + + g_free(lname); + g_strfreev(splitted); + + return result; +} + +/* Check wether it's an image we want */ +static gboolean +is_front_cover_image(const gchar *imgfile) +{ + return cover_name_filter(imgfile, cfg.cover_name_include, TRUE) && + !cover_name_filter(imgfile, cfg.cover_name_exclude, FALSE); +} + +static gboolean +is_file_image(const gchar *imgfile, const gchar *file_name) +{ + char *imgfile_ext, *file_name_ext; + size_t imgfile_len, file_name_len; + + imgfile_ext = strrchr(imgfile, '.'); + if (!imgfile_ext) { + /* No file extension */ + return FALSE; + } + + file_name_ext = strrchr(file_name, '.'); + if (!file_name_ext) { + /* No file extension */ + return FALSE; + } + + imgfile_len = (imgfile_ext - imgfile); + file_name_len = (file_name_ext - file_name); + + if (imgfile_len == file_name_len) { + return (g_ascii_strncasecmp(imgfile, file_name, imgfile_len) == 0); + } else { + return FALSE; + } +} + +gchar* +fileinfo_recursive_get_image(const gchar* path, + const gchar* file_name, gint depth) +{ + GDir *d; + + if (cfg.recurse_for_cover && depth > cfg.recurse_for_cover_depth) + return NULL; + + d = g_dir_open(path, 0, NULL); + + if (d) { + const gchar *f; + + if (cfg.use_file_cover && file_name) { + /* Look for images matching file name */ + while((f = g_dir_read_name(d))) { + gchar *newpath = g_strconcat(path, "/", f, NULL); + + if (!g_file_test(newpath, G_FILE_TEST_IS_DIR) && + has_front_cover_extension(f) && + is_file_image(f, file_name)) { + g_dir_close(d); + return newpath; + } + + g_free(newpath); + } + g_dir_rewind(d); + } + + /* Search for files using filter */ + while ((f = g_dir_read_name(d))) { + gchar *newpath = g_strconcat(path, "/", f, NULL); + + if (!g_file_test(newpath, G_FILE_TEST_IS_DIR) && + has_front_cover_extension(f) && + is_front_cover_image(f)) { + g_dir_close(d); + return newpath; + } + + g_free(newpath); + } + g_dir_rewind(d); + + /* checks whether recursive or not. */ + if (!cfg.recurse_for_cover) { + g_dir_close(d); + return NULL; + } + + /* Descend into directories recursively. */ + while ((f = g_dir_read_name(d))) { + gchar *newpath = g_strconcat(path, "/", f, NULL); + + if(g_file_test(newpath, G_FILE_TEST_IS_DIR)) { + gchar *tmp = fileinfo_recursive_get_image(newpath, + NULL, depth + 1); + if(tmp) { + g_free(newpath); + g_dir_close(d); + return tmp; + } + } + + g_free(newpath); + } + + g_dir_close(d); + } + + return NULL; +} diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_credits.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_credits.c Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,434 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious Team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui_credits.h" + +#include +#include +#include + +#include "audacious_logo.xpm" + + +enum { + COL_LEFT, + COL_RIGHT, + N_COLS +}; + + +static const gchar *audacious_brief = + N_("Audacious %s\n" + "A skinned multimedia player for many platforms.\n" + "\n" + "Copyright (C) 2005-2008 Audacious Development Team\n"); + +static const gchar *credit_text[] = { + N_("Audacious core developers:"), + "George Averill", + "Daniel Barkalow", + "Christian Birchinger", + "Daniel Bradshaw", + "Adam Cecile", + "Michael Färber", + "Matti Hämäläinen", + "Troels Bang Jensen", + "Giacomo Lozito", + "Cristi Măgherușan", + "Tomasz Moń", + "William Pitcock", + "Derek Pomery", + "Jonathan Schleifer", + "Ben Tucker", + "Tony Vroon", + "Yoshiki Yazawa", + "Eugene Zagidullin", + NULL, + + N_("Graphics:"), + "George Averill", + "Stephan Sokolow", + NULL, + + N_("Default skin:"), + "George Averill", + "Michael Färber", + "William Pitcock", + NULL, + + N_("Plugin development:"), + "Kiyoshi Aman", + "Luca Barbato", + "Daniel Barkalow", + "Michael Färber", + "Shay Green", + "Matti Hämäläinen", + "Sascha Hlusiak", + "Giacomo Lozito", + "Cristi Măgherușan", + "Tomasz Moń", + "William Pitcock", + "Derek Pomery", + "Jonathan Schleifer", + "Tony Vroon", + "Yoshiki Yazawa", + NULL, + + N_("Patch authors:"), + "Massimo Cavalleri", + "Stefano D'Angelo", + "Laszlo Dvornik", + "Ralf Ertzinger", + "Mike Frysinger", + "Mark Glines", + "Teru KAMOGASHIRA", + "Chris Kehler", + "Alex Maclean", + "Michael Hanselmann", + "Joseph Jezak", + "Henrik Johansson", + "Rodrigo Martins de Matos Ventura", + "Diego Pettenò", + "Kazuki Shimura", + "Valentine Sinitsyn", + "Johan Tavelin", + "Tim Yamin", + "Ivan N. Zlatev", + NULL, + + N_("0.1.x developers:"), + "William Pitcock", + "Mohammed Sameer", + "Tony Vroon", + NULL, + + N_("BMP Developers:"), + "Artem Baguinski", + "Edward Brocklesby", + "Chong Kai Xiong", + "Milosz Derezynski", + "David Lau", + "Ole Andre Vadla Ravnaas", + "Michiel Sikkes", + "Andrei Badea", + "Peter Behroozi", + "Bernard Blackham", + "Oliver Blin", + "Tomas Bzatek", + "Liviu Danicel", + "Jon Dowland", + "Artur Frysiak", + "Sebastian Kapfer", + "Lukas Koberstein", + "Dan Korostelev", + "Jolan Luff", + "Michael Marineau", + "Tim-Philipp Muller", + "Julien Portalier", + "Andrew Ruder", + "Olivier Samyn", + "Martijn Vernooij", + NULL, + + NULL +}; + +static const gchar *translators[] = { + N_("Brazilian Portuguese:"), + "Fábio Antunes", + "Philipi Pinto", + NULL, + N_("Breton:"), + "Thierry Vignaud", + NULL, + N_("Bulgarian:"), + "Andrew Ivanov", + NULL, + N_("Catalan:"), + "Ernest Adrogu", + NULL, + N_("Croatian:"), + "Marin Glibic", + NULL, + N_("Czech:"), + "Petr Pisar", + NULL, + N_("Dutch:"), + "Laurens Buhler", + "Tony Vroon", + NULL, + N_("Estonian:"), + "Ivar Smolin", + NULL, + N_("Finnish:"), + "Pauli Virtanen", + "Matti Hämäläinen", + NULL, + N_("French:"), + "Adam Cecile", + "Stanislas Zeller", + "Stany Henry", + NULL, + N_("German:"), + "Michael Färber", + "Michael Hanselmann", + "Matthias Debus", + NULL, + N_("Georgian:"), + "George Machitidze", + NULL, + N_("Greek:"), + "Kouzinopoulos Haris", + "Stavros Giannouris", + "Stathis Kamperis", + NULL, + N_("Hindi:"), + "Dhananjaya Sharma", + NULL, + N_("Hungarian:"), + "Laszlo Dvornik", + NULL, + N_("Italian:"), + "Alessio D'Ascanio", + "Diego Pettenò", + NULL, + N_("Japanese:"), + "Dai", + NULL, + N_("Korean:"), + "DongCheon Park", + NULL, + N_("Lithuanian:"), + "Rimas Kudelis", + NULL, + N_("Macedonian:"), + "Arangel Angov", + NULL, + N_("Polish:"), + "Wojciech Myrda", + NULL, + N_("Romanian:"), + "Daniel Patriche", + "Cristi Măgherușan", + NULL, + N_("Russian:"), + "Alexandr Orlov", + NULL, + N_("Serbian (Latin):"), + "Strahinja Kustudić", + NULL, + N_("Serbian (Cyrillic):"), + "Strahinja Kustudić", + NULL, + N_("Simplified Chinese:"), + "Yang Zhang", + NULL, + N_("Slovak:"), + "Andrej Herceg", + NULL, + N_("Spanish:"), + "Gustavo D. Vranjes", + NULL, + N_("Swedish:"), + "Martin Persenius", + NULL, + N_("Traditional Chinese:"), + "Cheng-Wei Chien", + "Sylecn Song", + "Yang Zhang", + NULL, + N_("Turkish:"), + "Murat Şenel", + "Eren Turkay", + NULL, + N_("Ukrainian:"), + "Mykola Lynnyk", + NULL, + N_("Welsh:"), + "Edward Brocklesby", + "William Pitcock", + NULL, + + NULL +}; + + +static GtkWidget * +generate_credit_list(const gchar * text[], gboolean sec_space) +{ + GtkWidget *scrollwin; + GtkWidget *treeview; + GtkListStore *list_store; + GtkTreeIter iter; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + const gchar *const *item; + + list_store = gtk_list_store_new(N_COLS, G_TYPE_STRING, G_TYPE_STRING); + + item = text; + + while (*item) { + gtk_list_store_append(list_store, &iter); + gtk_list_store_set(list_store, &iter, + COL_LEFT, _(item[0]), COL_RIGHT, _(item[1]), -1); + item += 2; + + while (*item) { + gtk_list_store_append(list_store, &iter); + gtk_list_store_set(list_store, &iter, + COL_LEFT, "", COL_RIGHT, _(*item++), -1); + } + + ++item; + + if (*item && sec_space) { + gtk_list_store_append(list_store, &iter); + gtk_list_store_set(list_store, &iter, + COL_LEFT, "", COL_RIGHT, "", -1); + } + } + + treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)); + gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview), FALSE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); + gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), + GTK_SELECTION_NONE); + + renderer = gtk_cell_renderer_text_new(); + g_object_set(renderer, "xalign", 1.0, NULL); + column = gtk_tree_view_column_new_with_attributes("Left", renderer, + "text", COL_LEFT, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); + + renderer = gtk_cell_renderer_text_new(); + g_object_set(renderer, "xalign", 0.0, NULL); + column = gtk_tree_view_column_new_with_attributes("Right", renderer, + "text", COL_RIGHT, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); + + scrollwin = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), + GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin), GTK_SHADOW_IN); + gtk_container_add(GTK_CONTAINER(scrollwin), treeview); + gtk_container_set_border_width(GTK_CONTAINER(scrollwin), 10); + + gtk_widget_show_all(scrollwin); + + return scrollwin; +} + +void +show_credits_window(void) +{ + static GtkWidget *about_window = NULL; + + GdkPixbuf *logo_pixbuf; + GtkWidget *about_vbox; + GtkWidget *about_credits_logo_box, *about_credits_logo_frame; + GtkWidget *about_credits_logo; + GtkWidget *about_notebook; + GtkWidget *list; + GtkWidget *bbox, *close_btn; + GtkWidget *label; + gchar *text; + + if (about_window) + return; + + about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_type_hint(GTK_WINDOW(about_window), + GDK_WINDOW_TYPE_HINT_DIALOG); + + gtk_window_set_default_size(GTK_WINDOW(about_window), -1, 512); + gtk_window_set_title(GTK_WINDOW(about_window), _("About Audacious")); + gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_CENTER); + gtk_window_set_resizable(GTK_WINDOW(about_window), TRUE); + gtk_container_set_border_width(GTK_CONTAINER(about_window), 10); + + g_signal_connect(about_window, "destroy", + G_CALLBACK(gtk_widget_destroyed), &about_window); + + gtk_widget_realize(about_window); + + about_vbox = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(about_window), about_vbox); + + logo_pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)audacious_logo_xpm); + + about_credits_logo_box = gtk_hbox_new(TRUE, 0); + gtk_box_pack_start(GTK_BOX(about_vbox), about_credits_logo_box, + FALSE, FALSE, 0); + + about_credits_logo_frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(about_credits_logo_frame), + GTK_SHADOW_ETCHED_OUT); + gtk_box_pack_start(GTK_BOX(about_credits_logo_box), + about_credits_logo_frame, FALSE, FALSE, 0); + + about_credits_logo = gtk_image_new_from_pixbuf(logo_pixbuf); + gtk_container_add(GTK_CONTAINER(about_credits_logo_frame), + about_credits_logo); + g_object_unref(logo_pixbuf); + + label = gtk_label_new(NULL); + text = g_strdup_printf(_(audacious_brief), VERSION); + gtk_label_set_markup(GTK_LABEL(label), text); + gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); + g_free(text); + + gtk_box_pack_start(GTK_BOX(about_vbox), label, FALSE, FALSE, 0); + + about_notebook = gtk_notebook_new(); + gtk_box_pack_start(GTK_BOX(about_vbox), about_notebook, TRUE, TRUE, 0); + + list = generate_credit_list(credit_text, TRUE); + gtk_notebook_append_page(GTK_NOTEBOOK(about_notebook), list, + gtk_label_new(_("Credits"))); + + list = generate_credit_list(translators, FALSE); + gtk_notebook_append_page(GTK_NOTEBOOK(about_notebook), list, + gtk_label_new(_("Translators"))); + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(about_vbox), bbox, FALSE, FALSE, 0); + + close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + g_signal_connect_swapped(close_btn, "clicked", + G_CALLBACK(gtk_widget_destroy), about_window); + GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), close_btn, TRUE, TRUE, 0); + gtk_widget_grab_default(close_btn); + + gtk_widget_show_all(about_window); +} diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_credits.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_credits.h Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,9 @@ + +#ifndef AUDACIOUS_UI_CREDITS_H +#define AUDACIOUS_UI_CREDITS_H + +void show_about_window(void); +void hide_about_window(void); +void show_credits_window(void); + +#endif /* AUDACIOUS_UI_CREDITS_H */ diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_fileinfo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_fileinfo.c Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,1016 @@ +/* + * Audacious: A cross-platform multimedia player + * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill, + * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa. + * Copyright (c) 2008 Eugene Zagidullin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "plugin.h" +#include "pluginenum.h" +#include "input.h" +#include "effect.h" +#include "strings.h" +#include "general.h" +#include "output.h" +#include "visualization.h" + +#include "main.h" +#include "util.h" +#include "dnd.h" +#include "tuple.h" +#include "vfs.h" + +#include "playlist.h" + +#include "build_stamp.h" +#include "ui_fileinfo.h" + +#define G_FREE_CLEAR(a) if(a != NULL) { g_free(a); a = NULL; } +#define STATUS_TIMEOUT 3*1000 + +GtkWidget *fileinfo_win = NULL; + +GtkWidget *entry_location; +GtkWidget *entry_title; +GtkWidget *entry_artist; +GtkWidget *entry_album; +GtkWidget *entry_comment; +GtkWidget *entry_year; +GtkWidget *entry_track; +GtkWidget *entry_genre; + +GtkWidget *image_artwork; + +GtkWidget *image_fileicon; +GtkWidget *label_format_name; +GtkWidget *label_quality; +GtkWidget *label_bitrate; +GtkWidget *btn_apply; +GtkWidget *label_mini_status; +GtkWidget *arrow_rawdata; +GtkWidget *treeview_rawdata; + +enum { + RAWDATA_KEY, + RAWDATA_VALUE, + RAWDATA_N_COLS +}; + +static gchar *current_file = NULL; +static InputPlugin *current_ip = NULL; +static gboolean something_changed = FALSE; + +/* stolen from Audacious 1.4 vorbis plugin. --nenolod */ +static const gchar *genre_table[] = { + N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"), + N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"), + N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"), + N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"), + N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"), + N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"), + N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"), + N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"), + N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"), + N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("AlternRock"), + N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"), + N_("Meditative"), N_("Instrumental Pop"), + N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"), + N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"), + N_("Pop-Folk"), N_("Eurodance"), N_("Dream"), + N_("Southern Rock"), N_("Comedy"), N_("Cult"), + N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"), + N_("Pop/Funk"), N_("Jungle"), N_("Native American"), + N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"), + N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"), + N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"), + N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"), + N_("Folk/Rock"), N_("National Folk"), N_("Swing"), + N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"), + N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"), + N_("Gothic Rock"), N_("Progressive Rock"), + N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"), + N_("Big Band"), N_("Chorus"), N_("Easy Listening"), + N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"), + N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"), + N_("Booty Bass"), N_("Primus"), N_("Porn Groove"), + N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"), + N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"), + N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"), + N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"), + N_("Euro-House"), N_("Dance Hall"), N_("Goa"), + N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"), + N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"), + N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"), + N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"), + N_("Contemporary Christian"), N_("Christian Rock"), + N_("Merengue"), N_("Salsa"), N_("Thrash Metal"), + N_("Anime"), N_("JPop"), N_("Synthpop") +}; + +static GList *genre_list = NULL; + +static void +fileinfo_entry_set_text(GtkWidget *widget, const char *text) +{ + if (widget == NULL) + return; + + gtk_entry_set_text(GTK_ENTRY(widget), text != NULL ? text : ""); +} + +static void +set_entry_str_from_field(GtkWidget *widget, Tuple *tuple, gint fieldn, gboolean editable) +{ + gchar *text; + + if(widget != NULL) { + text = (gchar*)tuple_get_string(tuple, fieldn, NULL); + gtk_entry_set_text(GTK_ENTRY(widget), text != NULL ? text : ""); + gtk_editable_set_editable(GTK_EDITABLE(widget), editable); + } +} + +static void +set_entry_int_from_field(GtkWidget *widget, Tuple *tuple, gint fieldn, gboolean editable) +{ + gchar *text; + + if(widget == NULL) return; + + if(tuple_get_value_type(tuple, fieldn, NULL) == TUPLE_INT) { + text = g_strdup_printf("%d", tuple_get_int(tuple, fieldn, NULL)); + gtk_entry_set_text(GTK_ENTRY(widget), text); + gtk_editable_set_editable(GTK_EDITABLE(widget), editable); + g_free(text); + } else { + gtk_entry_set_text(GTK_ENTRY(widget), ""); + gtk_editable_set_editable(GTK_EDITABLE(widget), editable); + } +} + +static void +set_field_str_from_entry(Tuple *tuple, gint fieldn, GtkWidget *widget) +{ + if(widget == NULL) return; + tuple_associate_string(tuple, fieldn, NULL, gtk_entry_get_text(GTK_ENTRY(widget))); +} + +static void +set_field_int_from_entry(Tuple *tuple, gint fieldn, GtkWidget *widget) +{ + gchar *tmp; + if(widget == NULL) return; + + tmp = (gchar*)gtk_entry_get_text(GTK_ENTRY(widget)); + if(*tmp != '\0') + tuple_associate_int(tuple, fieldn, NULL, atoi(tmp)); + else + tuple_associate_int(tuple, fieldn, NULL, -1); +} + +static void +fileinfo_label_set_text(GtkWidget *widget, const char *text) +{ + gchar *tmp; + + if (widget == NULL) + return; + + if (text) { + tmp = g_strdup_printf("%s", text); + gtk_label_set_text(GTK_LABEL(widget), tmp); + gtk_label_set_use_markup(GTK_LABEL(widget), TRUE); + g_free(tmp); + } else { + gtk_label_set_text(GTK_LABEL(widget), _("n/a")); + gtk_label_set_use_markup(GTK_LABEL(widget), TRUE); + } +} + +static void +fileinfo_entry_set_image(GtkWidget *widget, const char *text) +{ + GdkPixbuf *pixbuf; + int width, height; + double aspect; + GdkPixbuf *pixbuf2; + + if (widget == NULL) + return; + + pixbuf = gdk_pixbuf_new_from_file(text, NULL); + + if (pixbuf == NULL) + return; + + width = gdk_pixbuf_get_width(GDK_PIXBUF(pixbuf)); + height = gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf)); + + if (strcmp(DATA_DIR "/images/audio.png", text)) { + if (width == 0) + width = 1; + aspect = (double)height / (double)width; + + if (aspect > 1.0) { + height = (int)(cfg.filepopup_pixelsize * aspect); + width = cfg.filepopup_pixelsize; + } else { + height = cfg.filepopup_pixelsize; + width = (int)(cfg.filepopup_pixelsize / aspect); + } + + pixbuf2 = gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), width, height, GDK_INTERP_BILINEAR); + g_object_unref(G_OBJECT(pixbuf)); + pixbuf = pixbuf2; + } + + gtk_image_set_from_pixbuf(GTK_IMAGE(widget), GDK_PIXBUF(pixbuf)); + g_object_unref(G_OBJECT(pixbuf)); +} + +static void +fileinfo_hide(gpointer unused) +{ + if(GTK_WIDGET_VISIBLE(fileinfo_win)) gtk_widget_hide(fileinfo_win); + + /* Clear it out. */ + fileinfo_entry_set_text(entry_title, ""); + fileinfo_entry_set_text(entry_artist, ""); + fileinfo_entry_set_text(entry_album, ""); + fileinfo_entry_set_text(entry_comment, ""); + fileinfo_entry_set_text(gtk_bin_get_child(GTK_BIN(entry_genre)), ""); + fileinfo_entry_set_text(entry_year, ""); + fileinfo_entry_set_text(entry_track, ""); + fileinfo_entry_set_text(entry_location, ""); + + fileinfo_label_set_text(label_format_name, NULL); + fileinfo_label_set_text(label_quality, NULL); + fileinfo_label_set_text(label_bitrate, NULL); + + if (label_mini_status != NULL) { + gtk_label_set_text(GTK_LABEL(label_mini_status), ""); + gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); + } + + something_changed = FALSE; + gtk_widget_set_sensitive(btn_apply, FALSE); + + current_ip = NULL; + G_FREE_CLEAR(current_file); + + fileinfo_entry_set_image(image_artwork, DATA_DIR "/images/audio.png"); +} + +static void +entry_changed (GtkEditable *editable, gpointer user_data) +{ + if(current_file != NULL && current_ip != NULL && current_ip->update_song_tuple != NULL) { + something_changed = TRUE; + gtk_widget_set_sensitive(btn_apply, TRUE); + } +} + +static gboolean +ministatus_timeout_proc (gpointer data) +{ + GtkLabel *status = GTK_LABEL(data); + gtk_label_set_text(status, ""); + gtk_label_set_use_markup(status, TRUE); + + return FALSE; +} + +static void +ministatus_display_message(gchar *text) +{ + if(label_mini_status != NULL) { + gchar *tmp = g_strdup_printf("%s", text); + gtk_label_set_text(GTK_LABEL(label_mini_status), tmp); + g_free(tmp); + gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); + g_timeout_add (STATUS_TIMEOUT, (GSourceFunc) ministatus_timeout_proc, (gpointer) label_mini_status); + } +} + +static void +message_update_successfull() +{ + ministatus_display_message(_("Metadata updated successfully")); +} + +static void +message_update_failed() +{ + ministatus_display_message(_("Metadata updating failed")); +} + +static void +fileinfo_update_tuple(gpointer data) +{ + Tuple *tuple; + VFSFile *fd; + + if (current_file != NULL && current_ip != NULL && current_ip->update_song_tuple != NULL && something_changed) { + tuple = tuple_new(); + fd = vfs_fopen(current_file, "r+b"); + + if (fd != NULL) { + set_field_str_from_entry(tuple, FIELD_TITLE, entry_title); + set_field_str_from_entry(tuple, FIELD_ARTIST, entry_artist); + set_field_str_from_entry(tuple, FIELD_ALBUM, entry_album); + set_field_str_from_entry(tuple, FIELD_COMMENT, entry_comment); + set_field_str_from_entry(tuple, FIELD_GENRE, gtk_bin_get_child(GTK_BIN(entry_genre))); + + set_field_int_from_entry(tuple, FIELD_YEAR, entry_year); + set_field_int_from_entry(tuple, FIELD_TRACK_NUMBER, entry_track); + + plugin_set_current((Plugin *)current_ip); + if (current_ip->update_song_tuple(tuple, fd)) { + message_update_successfull(); + something_changed = FALSE; + gtk_widget_set_sensitive(btn_apply, FALSE); + } else + message_update_failed(); + + vfs_fclose(fd); + + } else + message_update_failed(); + + mowgli_object_unref(tuple); + } +} + +/** + * Looks up an icon from a NULL-terminated list of icon names. + * + * size: the requested size + * name: the default name + * ... : a NULL-terminated list of alternates + */ +GdkPixbuf * +themed_icon_lookup(gint size, const gchar *name, ...) +{ + GtkIconTheme *icon_theme; + GdkPixbuf *pixbuf; + GError *error = NULL; + gchar *n; + va_list par; + + icon_theme = gtk_icon_theme_get_default (); + pixbuf = gtk_icon_theme_load_icon (icon_theme, name, size, 0, &error); + + if (pixbuf != NULL) + return pixbuf; + + if (error != NULL) + g_error_free(error); + + /* fallback */ + va_start(par, name); + while((n = (gchar*)va_arg(par, gchar *)) != NULL) { + error = NULL; + pixbuf = gtk_icon_theme_load_icon (icon_theme, n, size, 0, &error); + + if (pixbuf) { + va_end(par); + return pixbuf; + } + + if (error != NULL) + g_error_free(error); + } + + return NULL; +} + +/** + * Intelligently looks up an icon for a mimetype. Supports + * HIDEOUSLY BROKEN gnome icon naming scheme too. + * + * size : the requested size + * mime_type: the mime type. + */ +GdkPixbuf * +mime_icon_lookup(gint size, const gchar *mime_type) /* smart icon resolving routine :) */ +{ + gchar *mime_as_is; /* audio-x-mp3 */ + gchar *mime_gnome; /* gnome-mime-audio-x-mp3 */ + gchar *mime_generic; /* audio-x-generic */ + gchar *mime_gnome_generic; /* gnome-mime-audio */ + + GdkPixbuf *icon = NULL; + + gchar **s = g_strsplit(mime_type, "/", 2); + if(s[1] != NULL) { + mime_as_is = g_strdup_printf("%s-%s", s[0], s[1]); + mime_gnome = g_strdup_printf("gnome-mime-%s-%s", s[0], s[1]); + mime_generic = g_strdup_printf("%s-x-generic", s[0]); + mime_gnome_generic = g_strdup_printf("gnome-mime-%s", s[0]); + icon = themed_icon_lookup(size, mime_as_is, mime_gnome, mime_generic, mime_gnome_generic, s[0], NULL); /* s[0] is category */ + g_free(mime_gnome_generic); + g_free(mime_generic); + g_free(mime_gnome); + g_free(mime_as_is); + } + g_strfreev(s); + + return icon; +} + +void +create_fileinfo_window(void) +{ + GtkWidget *hbox; + GtkWidget *hbox_status_and_bbox; + GtkWidget *vbox0; + GtkWidget *vbox1; + GtkWidget *vbox2; + GtkWidget *vbox3; + GtkWidget *label_title; + GtkWidget *label_artist; + GtkWidget *label_album; + GtkWidget *label_comment; + GtkWidget *label_genre; + GtkWidget *label_year; + GtkWidget *label_track; + GtkWidget *label_location; + GtkWidget *label_general; + GtkWidget *label_format; + GtkWidget *label_quality_label; + GtkWidget *label_bitrate_label; + GtkWidget *codec_hbox; + GtkWidget *codec_table; + GtkWidget *table1; + GtkWidget *bbox_close; + GtkWidget *btn_close; + GtkWidget *alignment; + GtkWidget *separator; + GtkWidget *scrolledwindow; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + gint i; + + fileinfo_win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(fileinfo_win), 6); + gtk_window_set_title(GTK_WINDOW(fileinfo_win), _("Track Information")); + gtk_window_set_position(GTK_WINDOW(fileinfo_win), GTK_WIN_POS_CENTER); + gtk_window_set_resizable(GTK_WINDOW(fileinfo_win), FALSE); + gtk_window_set_type_hint(GTK_WINDOW(fileinfo_win), GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_window_set_transient_for(GTK_WINDOW(fileinfo_win), GTK_WINDOW(mainwin)); + + vbox0 = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(fileinfo_win), vbox0); + + hbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(vbox0), hbox, TRUE, TRUE, 0); + + image_artwork = gtk_image_new(); + gtk_box_pack_start(GTK_BOX(hbox), image_artwork, FALSE, FALSE, 0); + gtk_misc_set_alignment(GTK_MISC(image_artwork), 0.5, 0); + gtk_image_set_from_file(GTK_IMAGE(image_artwork), DATA_DIR "/images/audio.png"); + separator = gtk_vseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, FALSE, 0); + + vbox1 = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), vbox1, TRUE, TRUE, 0); + + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + gtk_box_pack_start(GTK_BOX(vbox1), alignment, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(alignment), vbox2); + + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + gtk_box_pack_start(GTK_BOX(vbox1), alignment, TRUE, TRUE, 0); + + vbox3 = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(alignment), vbox3); + + label_general = gtk_label_new(_("General")); + gtk_box_pack_start (GTK_BOX (vbox2), label_general, FALSE, FALSE, 0); + gtk_label_set_use_markup(GTK_LABEL(label_general), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_general), 0, 0.5); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 0, 0); + gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0); + + codec_hbox = gtk_hbox_new(FALSE, 6); + gtk_container_add (GTK_CONTAINER(alignment), codec_hbox); + + image_fileicon = gtk_image_new_from_stock (GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG); + gtk_box_pack_start (GTK_BOX (codec_hbox), image_fileicon, FALSE, FALSE, 0); + + codec_table = gtk_table_new(3, 2, FALSE); + gtk_table_set_row_spacings (GTK_TABLE(codec_table), 6); + gtk_table_set_col_spacings (GTK_TABLE(codec_table), 12); + gtk_box_pack_start (GTK_BOX (codec_hbox), codec_table, FALSE, FALSE, 0); + + label_format = gtk_label_new(_("Format:")); + gtk_label_set_use_markup(GTK_LABEL(label_format), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_format), 0, 0.5); + label_quality_label = gtk_label_new(_("Quality:")); + gtk_label_set_use_markup(GTK_LABEL(label_quality_label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_quality_label), 0, 0.5); + label_bitrate_label = gtk_label_new(_("Bitrate:")); + gtk_label_set_use_markup(GTK_LABEL(label_bitrate_label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_bitrate_label), 0, 0.5); + + label_format_name = gtk_label_new(_("n/a")); + gtk_label_set_use_markup(GTK_LABEL(label_format_name), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_format_name), 0, 0.5); + label_quality = gtk_label_new(_("n/a")); + gtk_label_set_use_markup(GTK_LABEL(label_quality), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_quality), 0, 0.5); + label_bitrate = gtk_label_new(_("n/a")); + gtk_label_set_use_markup(GTK_LABEL(label_bitrate), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_bitrate), 0, 0.5); + + gtk_table_attach(GTK_TABLE(codec_table), label_format, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_table_attach(GTK_TABLE(codec_table), label_format_name, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_table_attach(GTK_TABLE(codec_table), label_quality_label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_table_attach(GTK_TABLE(codec_table), label_quality, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_table_attach(GTK_TABLE(codec_table), label_bitrate_label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_table_attach(GTK_TABLE(codec_table), label_bitrate, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label_title = gtk_label_new(_("Title")); + gtk_box_pack_start(GTK_BOX(vbox2), label_title, FALSE, FALSE, 0); + gtk_label_set_use_markup(GTK_LABEL(label_title), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_title), 0, 0); + + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); + entry_title = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(alignment), entry_title); + g_signal_connect(G_OBJECT(entry_title), "changed", (GCallback) entry_changed, NULL); + + label_artist = gtk_label_new(_("Artist")); + gtk_box_pack_start(GTK_BOX(vbox2), label_artist, FALSE, FALSE, 0); + gtk_label_set_use_markup(GTK_LABEL(label_artist), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_artist), 0, 0.5); + + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); + entry_artist = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(alignment), entry_artist); + g_signal_connect(G_OBJECT(entry_artist), "changed", (GCallback) entry_changed, NULL); + + label_album = gtk_label_new(_("Album")); + gtk_box_pack_start(GTK_BOX(vbox2), label_album, FALSE, FALSE, 0); + gtk_label_set_use_markup(GTK_LABEL(label_album), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_album), 0, 0.5); + + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); + entry_album = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(alignment), entry_album); + g_signal_connect(G_OBJECT(entry_album), "changed", (GCallback) entry_changed, NULL); + + label_comment = gtk_label_new(_("Comment")); + gtk_box_pack_start(GTK_BOX(vbox2), label_comment, FALSE, FALSE, 0); + gtk_label_set_use_markup(GTK_LABEL(label_comment), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_comment), 0, 0.5); + + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); + entry_comment = gtk_entry_new(); + gtk_container_add (GTK_CONTAINER(alignment), entry_comment); + g_signal_connect(G_OBJECT(entry_comment), "changed", (GCallback) entry_changed, NULL); + + label_genre = gtk_label_new(_("Genre")); + gtk_box_pack_start(GTK_BOX(vbox2), label_genre, FALSE, FALSE, 0); + gtk_label_set_use_markup(GTK_LABEL(label_genre), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_genre), 0, 0.5); + + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); + entry_genre = gtk_combo_box_entry_new_text(); + + if (!genre_list) { + GList *iter; + + for (i = 0; i < G_N_ELEMENTS(genre_table); i++) + genre_list = g_list_prepend(genre_list, _(genre_table[i])); + genre_list = g_list_sort(genre_list, (GCompareFunc) g_utf8_collate); + + MOWGLI_ITER_FOREACH(iter, genre_list) + gtk_combo_box_append_text(GTK_COMBO_BOX(entry_genre), iter->data); + } + + gtk_container_add(GTK_CONTAINER(alignment), entry_genre); + g_signal_connect(G_OBJECT(entry_genre), "changed", (GCallback) entry_changed, NULL); + + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); + table1 = gtk_table_new(2, 2, FALSE); + gtk_container_add(GTK_CONTAINER(alignment), table1); + gtk_table_set_col_spacings(GTK_TABLE(table1), 6); + + label_year = gtk_label_new(_("Year")); + gtk_table_attach(GTK_TABLE(table1), label_year, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_use_markup(GTK_LABEL(label_year), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_year), 0, 0.5); + + entry_year = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table1), entry_year, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + g_signal_connect(G_OBJECT(entry_year), "changed", (GCallback) entry_changed, NULL); + + label_track = gtk_label_new(_("Track Number")); + gtk_table_attach(GTK_TABLE(table1), label_track, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_use_markup(GTK_LABEL(label_track), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_track), 0, 0.5); + + entry_track = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table1), entry_track, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + g_signal_connect(G_OBJECT(entry_track), "changed", (GCallback) entry_changed, NULL); + + label_location = gtk_label_new(_("Location")); + gtk_box_pack_start(GTK_BOX(vbox2), label_location, FALSE, FALSE, 0); + gtk_label_set_use_markup(GTK_LABEL(label_location), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_location), 0, 0.5); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 0, 0); + + entry_location = gtk_entry_new(); + gtk_container_add(GTK_CONTAINER(alignment), entry_location); + gtk_editable_set_editable(GTK_EDITABLE(entry_location), FALSE); + + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + hbox = gtk_hbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(alignment), hbox); + gtk_box_pack_start(GTK_BOX(vbox3), alignment, TRUE, TRUE, 0); + + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 0, 0); + arrow_rawdata = gtk_expander_new(_("Raw Metadata")); + gtk_expander_set_use_markup(GTK_EXPANDER(arrow_rawdata), TRUE); + gtk_container_add(GTK_CONTAINER(alignment), arrow_rawdata); + gtk_box_pack_start(GTK_BOX(hbox), alignment, TRUE, TRUE, 0); + + scrolledwindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN); + gtk_container_add(GTK_CONTAINER(arrow_rawdata), scrolledwindow); + + treeview_rawdata = gtk_tree_view_new(); + gtk_container_add(GTK_CONTAINER(scrolledwindow), treeview_rawdata); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview_rawdata), TRUE); + gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview_rawdata), TRUE); + gtk_widget_set_size_request(treeview_rawdata, -1, 130); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Key")); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_spacing(column, 4); + gtk_tree_view_column_set_resizable(column, FALSE); + gtk_tree_view_column_set_fixed_width(column, 50); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_set_attributes(column, renderer, + "text", RAWDATA_KEY, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_rawdata), column); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Value")); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_spacing(column, 4); + gtk_tree_view_column_set_resizable(column, FALSE); + gtk_tree_view_column_set_fixed_width(column, 50); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_set_attributes(column, renderer, + "text", RAWDATA_VALUE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_rawdata), column); + + hbox_status_and_bbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox0), hbox_status_and_bbox, FALSE, FALSE, 0); + + label_mini_status = gtk_label_new(""); + gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); + gtk_misc_set_alignment(GTK_MISC(label_mini_status), 0, 0.5); + gtk_box_pack_start (GTK_BOX (hbox_status_and_bbox), label_mini_status, TRUE, TRUE, 0); + + bbox_close = gtk_hbutton_box_new(); + gtk_box_set_spacing(GTK_BOX(bbox_close), 6); + gtk_box_pack_start(GTK_BOX(hbox_status_and_bbox), bbox_close, FALSE, FALSE, 0); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox_close), GTK_BUTTONBOX_END); + + btn_apply = gtk_button_new_from_stock("gtk-save"); + gtk_container_add(GTK_CONTAINER(bbox_close), btn_apply); + g_signal_connect(G_OBJECT(btn_apply), "clicked", (GCallback) fileinfo_update_tuple, NULL); + gtk_widget_set_sensitive(btn_apply, FALSE); + + btn_close = gtk_button_new_from_stock("gtk-close"); + gtk_container_add(GTK_CONTAINER(bbox_close), btn_close); + GTK_WIDGET_SET_FLAGS(btn_close, GTK_CAN_DEFAULT); + g_signal_connect(G_OBJECT(btn_close), "clicked", (GCallback) fileinfo_hide, NULL); + + gtk_widget_show_all (vbox0); +} + +static void +fileinfo_show_for_tuple(Tuple *tuple, gboolean updating_enabled) +{ + gchar *tmp = NULL; + GdkPixbuf *icon = NULL; + GtkTreeIter iter; + GtkListStore *store; + mowgli_dictionary_iteration_state_t state; + TupleValue *tvalue; + gint i; + + if (tuple == NULL) + return; + + if(!updating_enabled) { + current_ip = NULL; + G_FREE_CLEAR(current_file); + } + + something_changed = FALSE; + + if (fileinfo_win == NULL) + create_fileinfo_window(); + + if (!GTK_WIDGET_REALIZED(fileinfo_win)) + gtk_widget_realize(fileinfo_win); + + set_entry_str_from_field(entry_title, tuple, FIELD_TITLE, updating_enabled); + set_entry_str_from_field(entry_artist, tuple, FIELD_ARTIST, updating_enabled); + set_entry_str_from_field(entry_album, tuple, FIELD_ALBUM, updating_enabled); + set_entry_str_from_field(entry_comment, tuple, FIELD_COMMENT, updating_enabled); + set_entry_str_from_field(gtk_bin_get_child(GTK_BIN(entry_genre)), tuple, FIELD_GENRE, updating_enabled); + + tmp = g_strdup_printf("%s/%s", + tuple_get_string(tuple, FIELD_FILE_PATH, NULL), + tuple_get_string(tuple, FIELD_FILE_NAME, NULL)); + + if (tmp) { + fileinfo_entry_set_text(entry_location, tmp); + g_free(tmp); + } + + /* set empty string if field not availaible. --eugene */ + set_entry_int_from_field(entry_year, tuple, FIELD_YEAR, updating_enabled); + set_entry_int_from_field(entry_track, tuple, FIELD_TRACK_NUMBER, updating_enabled); + + fileinfo_label_set_text(label_format_name, tuple_get_string(tuple, FIELD_CODEC, NULL)); + fileinfo_label_set_text(label_quality, tuple_get_string(tuple, FIELD_QUALITY, NULL)); + + if (tuple_get_value_type(tuple, FIELD_BITRATE, NULL) == TUPLE_INT) { + tmp = g_strdup_printf(_("%d kb/s"), tuple_get_int(tuple, FIELD_BITRATE, NULL)); + fileinfo_label_set_text(label_bitrate, tmp); + g_free(tmp); + } else + fileinfo_label_set_text(label_bitrate, NULL); + + tmp = (gchar *)tuple_get_string(tuple, FIELD_MIMETYPE, NULL); + icon = mime_icon_lookup(48, tmp ? tmp : "audio/x-generic"); + if (icon) { + if (image_fileicon) gtk_image_set_from_pixbuf (GTK_IMAGE(image_fileicon), icon); + g_object_unref(icon); + } + + tmp = fileinfo_recursive_get_image( + tuple_get_string(tuple, FIELD_FILE_PATH, NULL), + tuple_get_string(tuple, FIELD_FILE_NAME, NULL), 0); + + if (tmp) { + fileinfo_entry_set_image(image_artwork, tmp); + g_free(tmp); + } + + gtk_widget_set_sensitive(btn_apply, FALSE); + + if (label_mini_status != NULL) { + gtk_label_set_text(GTK_LABEL(label_mini_status), ""); + gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); + } + + store = gtk_list_store_new(RAWDATA_N_COLS, G_TYPE_STRING, G_TYPE_STRING); + + for (i = 0; i < FIELD_LAST; i++) { + gchar *key, *value; + + if (!tuple->values[i]) + continue; + + if (tuple->values[i]->type != TUPLE_INT && tuple->values[i]->value.string) + value = g_strdup(tuple->values[i]->value.string); + else if (tuple->values[i]->type == TUPLE_INT) + value = g_strdup_printf("%d", tuple->values[i]->value.integer); + else + continue; + + key = g_strdup(tuple_fields[i].name); + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + RAWDATA_KEY, key, + RAWDATA_VALUE, value, -1); + + g_free(key); + g_free(value); + } + + /* non-standard values are stored in a dictionary. */ + MOWGLI_DICTIONARY_FOREACH(tvalue, &state, tuple->dict) { + gchar *key, *value; + + if (tvalue->type != TUPLE_INT && tvalue->value.string) + value = g_strdup(tvalue->value.string); + else if (tvalue->type == TUPLE_INT) + value = g_strdup_printf("%d", tvalue->value.integer); + else + continue; + + key = g_strdup(state.cur->key); + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + RAWDATA_KEY, key, + RAWDATA_VALUE, value, -1); + + g_free(key); + g_free(value); + } + + gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_rawdata), GTK_TREE_MODEL(store)); + g_object_unref(store); + + if (!GTK_WIDGET_VISIBLE(fileinfo_win)) + gtk_widget_show(fileinfo_win); +} + +static void +fileinfo_show_for_path(gchar *path) +{ + Tuple *tuple = input_get_song_tuple(path); + + if (tuple == NULL) { + input_file_info_box(path); + return; + } + + fileinfo_show_for_tuple(tuple, FALSE); + + mowgli_object_unref(tuple); +} + +static void +fileinfo_show_editor_for_path(gchar *path, InputPlugin *ip) +{ + G_FREE_CLEAR(current_file); + current_file = g_strdup(path); + current_ip = ip; + + Tuple *tuple = input_get_song_tuple(path); + + if (tuple == NULL) { + input_file_info_box(path); + return; + } + + fileinfo_show_for_tuple(tuple, TRUE); + + mowgli_object_unref(tuple); +} + +static void +ui_fileinfo_show_entry(Playlist *playlist, PlaylistEntry *entry) +{ + gchar *path = g_strdup(entry->filename); + Tuple *tuple = entry->tuple; + + /* plugin is capable of updating tags. we need to bypass tuple cache. --eugene */ + /* maybe code cleanup required... */ + if (entry != NULL && + entry->decoder != NULL && + entry->decoder->update_song_tuple != NULL && + entry->decoder->file_info_box == NULL && + path != NULL && !vfs_is_remote(path)) + { + fileinfo_show_editor_for_path(path, entry->decoder); + g_free(path); + } + else + { + if (tuple != NULL) + { + if (entry->decoder != NULL) + { + if (entry->decoder->file_info_box == NULL) + fileinfo_show_for_tuple(tuple, FALSE); + else + { + plugin_set_current((Plugin *)(entry->decoder)); + entry->decoder->file_info_box(path); + } + } + else + fileinfo_show_for_path(path); + g_free(path); + } + else if (path != NULL) + { + if (entry != NULL && + entry->decoder != NULL && + entry->decoder->file_info_box != NULL) + { + plugin_set_current((Plugin *)(entry->decoder)); + entry->decoder->file_info_box(path); + } + else + fileinfo_show_for_path(path); + g_free(path); + } + } +} + +void +ui_fileinfo_show(Playlist *playlist, guint pos) +{ + GList *node = NULL; + + PLAYLIST_LOCK(playlist); + + if ((node = g_list_nth(playlist->entries, pos))) + ui_fileinfo_show_entry(playlist, node->data); + + PLAYLIST_UNLOCK(playlist); +} + +void +ui_fileinfo_show_current(Playlist *playlist) +{ + PLAYLIST_LOCK(playlist); + + if (playlist->entries && playlist->position) + ui_fileinfo_show_entry(playlist, playlist->position); + + PLAYLIST_UNLOCK(playlist); +} diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_fileinfo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_fileinfo.h Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,32 @@ +/* + * Audacious: A cross-platform multimedia player + * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill, + * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#ifndef AUDACIOUS_UI_FILEINFO_H +#define AUDACIOUS_UI_FILEINFO_H + +#include "tuple.h" +#include "plugin.h" +#include + +void create_fileinfo_window(void); +gchar* fileinfo_recursive_get_image(const gchar* path, const gchar* file_name, gint depth); + +void ui_fileinfo_show(Playlist *playlist, guint pos); +void ui_fileinfo_show_current(Playlist *playlist); + +#endif /* AUDACIOUS_UI_FILEINFO_H */ diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_fileinfopopup.c --- a/src/audacious/ui_fileinfopopup.c Tue Jul 08 15:35:48 2008 +0200 +++ b/src/audacious/ui_fileinfopopup.c Tue Jul 08 16:36:50 2008 +0200 @@ -33,7 +33,7 @@ #include "playback.h" #include "strings.h" #include "ui_fileinfopopup.h" -#include "legacy/ui_fileinfo.h" +#include "ui_fileinfo.h" static void filepopup_entry_set_text(GtkWidget *filepopup_win, const gchar *entry_name, diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_jumptotrack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_jumptotrack.c Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,614 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2006 Audacious development team. + * + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +#include +#include +#include +#include +#include + +/* GDK including */ +#include "platform/smartinclude.h" + +#include +#include +#include + +#include + +#if defined(USE_REGEX_ONIGURUMA) + #include +#elif defined(USE_REGEX_PCRE) + #include +#else + #include +#endif + +#include "icons-stock.h" + +#include "actions-mainwin.h" + +#include "main.h" + +#include "dnd.h" +#include "input.h" +#include "playback.h" +#include "playlist.h" +#include "pluginenum.h" +#include "ui_credits.h" +#include "ui_fileopener.h" +#include "ui_preferences.h" +#include "strings.h" +#include "util.h" +#include "visualization.h" + +#include "ui_jumptotrack_cache.h" + +static GtkWidget *jump_to_track_win = NULL; +static gulong serial = 0; + +static JumpToTrackCache* cache = NULL; + +static void +change_song(guint pos) +{ + if (playback_get_playing()) + playback_stop(); + + playlist_set_position(playlist_get_active(), pos); + playback_initiate(); +} + +void +ui_jump_to_track_hide(void) +{ + g_return_if_fail(jump_to_track_win != NULL); + gtk_widget_hide(jump_to_track_win); +} + +static void +ui_jump_to_track_jump(GtkTreeView * treeview) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + guint pos; + + model = gtk_tree_view_get_model(treeview); + selection = gtk_tree_view_get_selection(treeview); + + if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) + return; + + gtk_tree_model_get(model, &iter, 0, &pos, -1); + + change_song(pos - 1); + + if(cfg.close_jtf_dialog) + ui_jump_to_track_hide(); +} + +static void +ui_jump_to_track_toggle_cb(GtkWidget * toggle) +{ + cfg.close_jtf_dialog = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)); +} + +static void +ui_jump_to_track_toggle2_cb(GtkWidget * toggle) +{ + cfg.remember_jtf_entry = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)); +} + +static void +ui_jump_to_track_jump_cb(GtkTreeView * treeview, + gpointer data) +{ + ui_jump_to_track_jump(treeview); +} + +static void +ui_jump_to_track_set_queue_button_label(GtkButton * button, + guint pos) +{ + if (playlist_is_position_queued(playlist_get_active(), pos)) + gtk_button_set_label(button, _("Un_queue")); + else + gtk_button_set_label(button, _("_Queue")); +} + +static void +ui_jump_to_track_queue_cb(GtkButton * button, + gpointer data) +{ + GtkTreeView *treeview; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + guint pos; + + treeview = GTK_TREE_VIEW(data); + model = gtk_tree_view_get_model(treeview); + selection = gtk_tree_view_get_selection(treeview); + + if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) + return; + + gtk_tree_model_get(model, &iter, 0, &pos, -1); + + playlist_queue_position(playlist_get_active(), (pos - 1)); + + ui_jump_to_track_set_queue_button_label(button, (pos - 1)); +} + +static void +ui_jump_to_track_selection_changed_cb(GtkTreeSelection *treesel, + gpointer data) +{ + GtkTreeView *treeview; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + guint pos; + + treeview = gtk_tree_selection_get_tree_view(treesel); + model = gtk_tree_view_get_model(treeview); + selection = gtk_tree_view_get_selection(treeview); + + if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) + return; + + gtk_tree_model_get(model, &iter, 0, &pos, -1); + + ui_jump_to_track_set_queue_button_label(GTK_BUTTON(data), (pos - 1)); +} + +static gboolean +ui_jump_to_track_edit_keypress_cb(GtkWidget * object, + GdkEventKey * event, + gpointer data) +{ + switch (event->keyval) { + case GDK_Return: + if (gtk_im_context_filter_keypress (GTK_ENTRY (object)->im_context, event)) { + GTK_ENTRY (object)->need_im_reset = TRUE; + return TRUE; + } else { + ui_jump_to_track_jump(GTK_TREE_VIEW(data)); + return TRUE; + } + default: + return FALSE; + } +} + +static gboolean +ui_jump_to_track_keypress_cb(GtkWidget * object, + GdkEventKey * event, + gpointer data) +{ + switch (event->keyval) { + case GDK_Escape: + ui_jump_to_track_hide(); + return TRUE; + case GDK_KP_Enter: + ui_jump_to_track_queue_cb(NULL, data); + return TRUE; + default: + return FALSE; + }; + + return FALSE; +} + +void +ui_jump_to_track_update(GtkWidget * widget, gpointer user_data) +{ + guint row; + GList *playlist_glist; + gchar *desc_buf = NULL; + GtkTreeIter iter; + GtkTreeSelection *selection; + Playlist *playlist; + + GtkTreeModel *store; + + GtkTreeView *tree = GTK_TREE_VIEW(g_object_get_data(user_data, "treeview")); + GtkEntry *edit = g_object_get_data(user_data, "edit"); + + if (!jump_to_track_win) + return; + + /* clear edit widget */ + if(edit){ + gtk_entry_set_text(edit, ""); + } + + store = gtk_tree_view_get_model(tree); + gtk_list_store_clear(GTK_LIST_STORE(store)); + + row = 1; + playlist = playlist_get_active(); + for (playlist_glist = playlist->entries; playlist_glist; + playlist_glist = g_list_next(playlist_glist)) { + PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data); + + if (entry->title) + desc_buf = g_strdup(entry->title); + else { + gchar *realfn = NULL; + realfn = g_filename_from_uri(entry->filename, NULL, NULL); + if (strchr(realfn ? realfn : entry->filename, '/')) + desc_buf = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1); + else + desc_buf = str_assert_utf8(realfn ? realfn : entry->filename); + g_free(realfn); realfn = NULL; + } + + gtk_list_store_append(GTK_LIST_STORE(store), &iter); + gtk_list_store_set(GTK_LIST_STORE(store), &iter, + 0, row, 1, desc_buf, -1); + row++; + + g_free(desc_buf); + desc_buf = NULL; + } + + gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); + selection = gtk_tree_view_get_selection(tree); + gtk_tree_selection_select_iter(selection, &iter); + serial = playlist->serial; // important. --yaz +} + +static void +ui_jump_to_track_edit_cb(GtkEntry * entry, gpointer user_data) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(user_data); + GtkTreeSelection *selection; + GtkTreeIter iter; + + GtkListStore *store; + + const GArray *search_matches; + Playlist *playlist; + int i; + + if (cache == NULL) { + cache = ui_jump_to_track_cache_new(); + } + + /* FIXME: Remove the connected signals before clearing + * (row-selected will still eventually arrive once) */ + store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview)); + /* detach model from treeview */ + g_object_ref( store ); + gtk_tree_view_set_model( GTK_TREE_VIEW(treeview) , NULL ); + + gtk_list_store_clear(store); + + playlist = playlist_get_active(); + + PLAYLIST_LOCK(playlist); + + search_matches = ui_jump_to_track_cache_search(cache, + playlist, + gtk_entry_get_text(entry)); + + for (i = 0; i < search_matches->len; i++) + { + JumpToTrackEntry *jttentry = g_array_index(search_matches, JumpToTrackEntry*, i); + PlaylistEntry* entry = jttentry->entry; + gchar *title = NULL; + + if (entry->title) + title = g_strdup(entry->title); + else { + gchar *realfn = NULL; + realfn = g_filename_from_uri(entry->filename, NULL, NULL); + if (strchr(realfn ? realfn : entry->filename, '/')) + title = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1); + else + title = str_assert_utf8(realfn ? realfn : entry->filename); + g_free(realfn); realfn = NULL; + } + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, jttentry->playlist_position + 1 , 1, title, -1); + g_free(title); + } + + PLAYLIST_UNLOCK(playlist); + + /* attach the model again to the treeview */ + gtk_tree_view_set_model( GTK_TREE_VIEW(treeview) , GTK_TREE_MODEL(store) ); + g_object_unref( store ); + + if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { + selection = gtk_tree_view_get_selection(treeview); + gtk_tree_selection_select_iter(selection, &iter); + } +} + +static gboolean +ui_jump_to_track_fill(gpointer treeview) +{ + GList *playlist_glist; + Playlist *playlist; + gchar *desc_buf = NULL; + guint row; + GtkTreeIter iter; + GtkListStore *jtf_store = (GtkListStore*)gtk_tree_view_get_model( GTK_TREE_VIEW(treeview) ); + + /* detach model from treeview before fill */ + g_object_ref(jtf_store); + gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), NULL ); + + gtk_list_store_clear(jtf_store); + + row = 1; + playlist = playlist_get_active(); + + PLAYLIST_LOCK(playlist); + for (playlist_glist = playlist->entries; playlist_glist; + playlist_glist = g_list_next(playlist_glist)) { + + PlaylistEntry *entry = PLAYLIST_ENTRY(playlist_glist->data); + + if (entry->title) + desc_buf = g_strdup(entry->title); + else { + gchar *realfn = NULL; + realfn = g_filename_from_uri(entry->filename, NULL, NULL); + if (strchr(realfn ? realfn : entry->filename, '/')) + desc_buf = str_assert_utf8(strrchr(realfn ? realfn : entry->filename, '/') + 1); + else + desc_buf = str_assert_utf8(realfn ? realfn : entry->filename); + g_free(realfn); realfn = NULL; + } + + gtk_list_store_append(GTK_LIST_STORE(jtf_store), &iter); + gtk_list_store_set(GTK_LIST_STORE(jtf_store), &iter, + 0, row, 1, desc_buf, -1); + row++; + + g_free(desc_buf); + desc_buf = NULL; + } + PLAYLIST_UNLOCK(playlist); + + /* attach liststore to treeview */ + gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(jtf_store)); + g_object_unref(jtf_store); + serial = playlist->serial; + return FALSE; +} + +static gboolean +watchdog(gpointer storage) +{ + GtkWidget *widget; + Playlist *playlist = playlist_get_active(); + + if(serial == playlist->serial) + return TRUE; + + widget = g_object_get_data(storage, "widget"); + ui_jump_to_track_update(widget, storage); + return TRUE; +} + +void +ui_jump_to_track(void) +{ + GtkWidget *scrollwin; + GtkWidget *vbox, *bbox, *sep; + GtkWidget *toggle, *toggle2; + GtkWidget *jump, *queue, *close; + GtkWidget *rescan; + GtkWidget *search_label, *hbox; + static GtkWidget *edit; + + GtkWidget *treeview = NULL; + GtkListStore *jtf_store; + + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + gpointer storage; + + if (jump_to_track_win) { + gtk_window_present(GTK_WINDOW(jump_to_track_win)); + + if(!cfg.remember_jtf_entry) + gtk_entry_set_text(GTK_ENTRY(edit), ""); + + gtk_widget_grab_focus(edit); + gtk_editable_select_region(GTK_EDITABLE(edit), 0, -1); + return; + } + + #if defined(USE_REGEX_ONIGURUMA) + /* set encoding for Oniguruma regex to UTF-8 */ + reg_set_encoding( REG_POSIX_ENCODING_UTF8 ); + onig_set_default_syntax( ONIG_SYNTAX_POSIX_BASIC ); + #endif + + jump_to_track_win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_type_hint(GTK_WINDOW(jump_to_track_win), + GDK_WINDOW_TYPE_HINT_DIALOG); + + gtk_window_set_title(GTK_WINDOW(jump_to_track_win), _("Jump to Track")); + + gtk_window_set_position(GTK_WINDOW(jump_to_track_win), GTK_WIN_POS_CENTER); + g_signal_connect(jump_to_track_win, "destroy", + G_CALLBACK(gtk_widget_destroyed), &jump_to_track_win); + + gtk_container_border_width(GTK_CONTAINER(jump_to_track_win), 10); + gtk_window_set_default_size(GTK_WINDOW(jump_to_track_win), 600, 500); + + vbox = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(jump_to_track_win), vbox); + + jtf_store = gtk_list_store_new(2, G_TYPE_UINT, G_TYPE_STRING); + treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(jtf_store)); + g_object_unref(jtf_store); + + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); + + column = gtk_tree_view_column_new(); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_set_attributes(column, renderer, "text", 0, NULL); + gtk_tree_view_column_set_spacing(column, 4); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_set_attributes(column, renderer, "text", 1, NULL); + gtk_tree_view_column_set_spacing(column, 4); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); + + gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), 1); + + g_signal_connect(treeview, "row-activated", + G_CALLBACK(ui_jump_to_track_jump), NULL); + + hbox = gtk_hbox_new(FALSE, 3); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); + + + /* filter box */ + search_label = gtk_label_new(_("Filter: ")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(search_label), _("_Filter:")); + gtk_box_pack_start(GTK_BOX(hbox), search_label, FALSE, FALSE, 0); + + edit = gtk_entry_new(); + gtk_entry_set_editable(GTK_ENTRY(edit), TRUE); + gtk_label_set_mnemonic_widget(GTK_LABEL(search_label), edit); + g_signal_connect(edit, "changed", + G_CALLBACK(ui_jump_to_track_edit_cb), treeview); + + g_signal_connect(edit, "key_press_event", + G_CALLBACK(ui_jump_to_track_edit_keypress_cb), treeview); + + g_signal_connect(jump_to_track_win, "key_press_event", + G_CALLBACK(ui_jump_to_track_keypress_cb), treeview); + + gtk_box_pack_start(GTK_BOX(hbox), edit, TRUE, TRUE, 3); + + /* remember text entry */ + toggle2 = gtk_check_button_new_with_label(_("Remember")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle2), + cfg.remember_jtf_entry ? TRUE : FALSE); + gtk_box_pack_start(GTK_BOX(hbox), toggle2, FALSE, FALSE, 0); + g_signal_connect(toggle2, "clicked", + G_CALLBACK(ui_jump_to_track_toggle2_cb), + toggle2); + + /* clear button */ + rescan = gtk_button_new_from_stock(GTK_STOCK_CLEAR); + gtk_box_pack_start(GTK_BOX(hbox), rescan, FALSE, FALSE, 0); + + + /* pack to container */ + storage = g_object_new(G_TYPE_OBJECT, NULL); + g_object_set_data(storage, "widget", rescan); + g_object_set_data(storage, "treeview", treeview); + g_object_set_data(storage, "edit", edit); + + g_signal_connect(rescan, "clicked", + G_CALLBACK(ui_jump_to_track_update), storage); + + GTK_WIDGET_SET_FLAGS(rescan, GTK_CAN_DEFAULT); + gtk_widget_grab_default(rescan); + + scrollwin = gtk_scrolled_window_new(NULL, NULL); + gtk_container_add(GTK_CONTAINER(scrollwin), treeview); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin), + GTK_SHADOW_IN); + gtk_box_pack_start(GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0); + + sep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 4); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + /* close dialog toggle */ + toggle = gtk_check_button_new_with_label(_("Close on Jump")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), + cfg.close_jtf_dialog ? TRUE : FALSE); + gtk_box_pack_start(GTK_BOX(bbox), toggle, FALSE, FALSE, 0); + g_signal_connect(toggle, "clicked", + G_CALLBACK(ui_jump_to_track_toggle_cb), + toggle); + + queue = gtk_button_new_with_mnemonic(_("_Queue")); + gtk_button_set_image(GTK_BUTTON(queue), + gtk_image_new_from_stock(AUD_STOCK_QUEUETOGGLE, GTK_ICON_SIZE_BUTTON)); + gtk_box_pack_start(GTK_BOX(bbox), queue, FALSE, FALSE, 0); + GTK_WIDGET_SET_FLAGS(queue, GTK_CAN_DEFAULT); + g_signal_connect(queue, "clicked", + G_CALLBACK(ui_jump_to_track_queue_cb), + treeview); + g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), "changed", + G_CALLBACK(ui_jump_to_track_selection_changed_cb), + queue); + + jump = gtk_button_new_from_stock(GTK_STOCK_JUMP_TO); + gtk_box_pack_start(GTK_BOX(bbox), jump, FALSE, FALSE, 0); + + g_signal_connect_swapped(jump, "clicked", + G_CALLBACK(ui_jump_to_track_jump_cb), + treeview); + + GTK_WIDGET_SET_FLAGS(jump, GTK_CAN_DEFAULT); + gtk_widget_grab_default(jump); + + close = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + gtk_box_pack_start(GTK_BOX(bbox), close, FALSE, FALSE, 0); + g_signal_connect_swapped(close, "clicked", + G_CALLBACK(gtk_widget_hide), + jump_to_track_win); // just hide --yaz + GTK_WIDGET_SET_FLAGS(close, GTK_CAN_DEFAULT); + + g_timeout_add(100, (GSourceFunc)ui_jump_to_track_fill, treeview); + g_timeout_add(500, (GSourceFunc)watchdog, storage); + + gtk_widget_show_all(jump_to_track_win); + gtk_widget_grab_focus(edit); +} diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_jumptotrack_cache.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_jumptotrack_cache.c Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,431 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2008 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include +#include +#include + +#if defined(USE_REGEX_ONIGURUMA) + #include +#elif defined(USE_REGEX_PCRE) + #include +#else + #include +#endif + +#include "playlist.h" +#include "strings.h" + +#include "ui_jumptotrack_cache.h" + +// Struct to keep information about matches from searches. +typedef struct +{ + GArray* track_entries; // JumpToTrackEntry* + GArray* normalized_titles; // gchar* +} KeywordMatches; + +/** + * Creates an regular expression list usable in searches from search keyword. + * + * In searches, every regular expression on this list is matched against + * the search title and if they all match, the title is declared as + * matching one. + * + * Regular expressions in list are formed by splitting the 'keyword' to words + * by splitting the keyword string with space character. + */ +static GSList* +ui_jump_to_track_cache_regex_list_create(const GString* keyword) +{ + GSList *regex_list = NULL; + gchar **words = NULL; + int i = -1; + /* Chop the key string into ' '-separated key regex-pattern strings */ + words = g_strsplit(keyword->str, " ", 0); + + /* create a list of regex using the regex-pattern strings */ + while ( words[++i] != NULL ) + { + // Ignore empty words. + if (words[i][0] == 0) { + continue; + } + regex_t *regex = g_malloc(sizeof(regex_t)); + #if defined(USE_REGEX_PCRE) + if ( regcomp( regex , words[i] , REG_NOSUB | REG_UTF8 ) == 0 ) + #else + if ( regcomp( regex , words[i] , REG_NOSUB ) == 0 ) + #endif + regex_list = g_slist_append( regex_list , regex ); + else + g_free( regex ); + } + + g_strfreev(words); + + return regex_list; +} + +/** + * Frees the regular expression list used in searches. + */ +static void +ui_jump_to_track_cache_regex_list_free(GSList* regex_list) +{ + if ( regex_list != NULL ) + { + GSList* regex_list_tmp = regex_list; + while ( regex_list != NULL ) + { + regex_t *regex = regex_list->data; + regfree( regex ); + g_free( regex ); + regex_list = g_slist_next(regex_list); + } + g_slist_free( regex_list_tmp ); + } +} + +/** + * Checks if 'song' matches all regular expressions in 'regex_list'. + */ +static gboolean +ui_jump_to_track_match(const gchar * song, GSList *regex_list) +{ + if ( song == NULL ) + return FALSE; + + for ( ; regex_list ; regex_list = g_slist_next(regex_list) ) + { + regex_t *regex = regex_list->data; + if ( regexec( regex , song , 0 , NULL , 0 ) != 0 ) + return FALSE; + } + + return TRUE; +} + +/** + * Returns all songs that match 'keyword'. + * + * Searches are conducted against entries in 'search_space' variable + * and after the search, search result is added to 'cache'. + * + * @param cache The result of this search is added to cache. + * @param search_space Entries inside which the search is conducted. + * @param keyword Normalized string for searches. + */ +static GArray* +ui_jump_to_track_cache_match_keyword(JumpToTrackCache* cache, + const KeywordMatches* search_space, + const GString* keyword) +{ + GSList* regex_list = ui_jump_to_track_cache_regex_list_create(keyword); + GArray* track_entries = g_array_new(FALSE, FALSE, sizeof(JumpToTrackEntry*)); + GArray* normalized_titles = g_array_new(FALSE, FALSE, sizeof(gchar*)); + gboolean match = FALSE; + int i = 0; + + for (i = 0; i < search_space->normalized_titles->len; i++) + { + gchar* title = g_array_index(search_space->normalized_titles, gchar*, i); + + if (regex_list != NULL) + match = ui_jump_to_track_match(title, regex_list); + else + match = TRUE; + + if (match) { + JumpToTrackEntry* entry = g_array_index(search_space->track_entries, + JumpToTrackEntry*, i); + g_array_append_val(track_entries, entry); + g_array_append_val(normalized_titles, title); + } + } + + KeywordMatches* keyword_matches = g_new(KeywordMatches, 1); + keyword_matches->track_entries = track_entries; + keyword_matches->normalized_titles = normalized_titles; + + g_hash_table_insert(cache->keywords, + GINT_TO_POINTER(g_string_hash(keyword)), + keyword_matches); + + ui_jump_to_track_cache_regex_list_free(regex_list); + return track_entries; +} + +/** + * Normalizes the search string to be more suitable for searches. + * + * Basically this does Unicode NFKD normalization to for example match + * half-width and full-width characters and case folding mainly to match + * upper- and lowercase letters. + * + * String returned by this function should be freed manually. + */ +static gchar * +normalize_search_string(const gchar* string) +{ + gchar* normalized_string = g_utf8_normalize(string, -1, G_NORMALIZE_NFKD); + gchar* folded_string = g_utf8_casefold(normalized_string, -1); + g_free(normalized_string); + return folded_string; +} + +/** + * Frees the possibly allocated data in KeywordMatches. + */ +static void +ui_jump_to_track_cache_free_keywordmatch_data(KeywordMatches* match_entry) +{ + int i = 0; + assert(match_entry->normalized_titles->len == match_entry->track_entries->len); + for (i = 0; i < match_entry->normalized_titles->len; i++) + { + g_free(g_array_index(match_entry->normalized_titles, gchar*, i)); + g_free(g_array_index(match_entry->track_entries, PlaylistEntry*, i)); + } +} + +/** + * Frees the memory reserved for an search result. + */ +static void +ui_jump_to_track_cache_free_cache_entry(gpointer entry) +{ + KeywordMatches* match_entry = (KeywordMatches*)entry; + g_array_free(match_entry->track_entries, TRUE); + g_array_free(match_entry->normalized_titles, TRUE); +} + +/** + * Creates a new song search cache. + * + * Returned value should be freed with ui_jump_to_track_cache_free() function. + */ +JumpToTrackCache* +ui_jump_to_track_cache_new() +{ + JumpToTrackCache* cache = g_new(JumpToTrackCache, 1); + cache->playlist_serial = -1; + cache->keywords = g_hash_table_new_full(NULL, NULL, NULL, + ui_jump_to_track_cache_free_cache_entry); + return cache; +} + +/** + * Clears the search cache. + */ +static void +ui_jump_to_track_cache_clear(JumpToTrackCache* cache) +{ + GString* empty_keyword = g_string_new(""); + gpointer found_keyword = NULL; + + cache->playlist_serial = -1; + + // All normalized titles reside in an empty key "" so we'll free them + // first. + found_keyword = g_hash_table_lookup(cache->keywords, + GINT_TO_POINTER(g_string_hash(empty_keyword))); + g_string_free(empty_keyword, + TRUE); + if (found_keyword != NULL) + { + KeywordMatches* all_titles = (KeywordMatches*)found_keyword; + ui_jump_to_track_cache_free_keywordmatch_data(all_titles); + } + // Now when all normalized strings are freed, no need to worry about + // double frees or memory leaks. + g_hash_table_remove_all(cache->keywords); +} + +/** + * Initializes the search cache if cache is empty or has wrong playlist. + */ +static void +ui_jump_to_track_cache_init(JumpToTrackCache* cache, + const Playlist* playlist) +{ + if (cache->playlist_serial != playlist->serial) + { + GList* playlist_entries = NULL; + GArray* track_entries = g_array_new(FALSE, FALSE, sizeof(JumpToTrackEntry*)); + GArray* normalized_titles = g_array_new(FALSE, FALSE, sizeof(gchar*)); + GString* empty_keyword = g_string_new(""); + gulong song_index = 0; + + // Reset cache state + ui_jump_to_track_cache_clear(cache); + + cache->playlist_serial = playlist->serial; + + // Initialize cache with playlist data + for (playlist_entries = playlist->entries; + playlist_entries; + playlist_entries = g_list_next(playlist_entries)) + { + PlaylistEntry* playlist_entry = PLAYLIST_ENTRY(playlist_entries->data); + + gchar *title = NULL; + /*we are matching all the path not just the filename or title*/ + + /* + * FIXME: The search string should be adapted to the + * current display setting, e.g. if the user has set it to + * "%p - %t" then build the match string like that too, or + * even better, search for each of the tags seperatly. + * + * In any case the string to match should _never_ contain + * something the user can't actually see in the playlist. + */ + if (playlist_entry->title) { + title = normalize_search_string(playlist_entry->title); + } else { + gchar *realfn = NULL; + realfn = g_filename_from_uri(playlist_entry->filename, NULL, NULL); + gchar *tmp_title = str_assert_utf8(realfn ? realfn : playlist_entry->filename); + title = normalize_search_string(tmp_title); + g_free(tmp_title); + g_free(realfn); realfn = NULL; + } + + JumpToTrackEntry* search_entry = g_new(JumpToTrackEntry, 1); + search_entry->entry = playlist_entry; + search_entry->playlist_position = song_index; + g_array_append_val(track_entries, search_entry); + g_array_append_val(normalized_titles, title); + // We need to manually keep track of the current playlist index. + song_index++; + } + // Finally insert all titles into cache into an empty key "" so that + // the matchable data has specified place to be. + KeywordMatches* keyword_data = g_new(KeywordMatches, 1); + keyword_data->track_entries = track_entries; + keyword_data->normalized_titles = normalized_titles; + g_hash_table_insert(cache->keywords, + GINT_TO_POINTER(g_string_hash(empty_keyword)), + keyword_data); + g_string_free(empty_keyword, + TRUE); + } +} + +/** + * Searches 'keyword' inside 'playlist' by using 'cache' to speed up searching. + * + * Searches are basically conducted as follows: + * + * Cache is checked if it has the information about right playlist and + * initialized with playlist data if needed. + * + * Keyword is normalized for searching (Unicode NFKD, case folding) + * + * Cache is checked if it has keyword and if it has, we can immediately get + * the search results and return. If not, searching goes as follows: + * + * Search for the longest word that is in cache that matches the beginning + * of keyword and use the cached matches as base for the current search. + * The shortest word that can be matched against is the empty string "", so + * there should always be matches in cache. + * + * After that conduct the search by splitting keyword into words separated + * by space and using regular expressions. + * + * When the keyword is searched, search result is added to cache to + * corresponding keyword that can be used as base for new searches. + * + * The motivation for caching is that to search word 'some cool song' one + * has to type following strings that are all searched individually: + * + * s + * so + * som + * some + * some + * some c + * some co + * some coo + * some cool + * some cool + * some cool s + * some cool so + * some cool son + * some cool song + * + * If the search results are cached in every phase and the result of + * the maximum length matching string is used as base for concurrent + * searches, we can probably get the matches reduced to some hundreds + * after a few letters typed on playlists with thousands of songs and + * reduce useless iteration quite a lot. + * + * Return: GArray of JumpToTrackEntry* + */ +const GArray* +ui_jump_to_track_cache_search(JumpToTrackCache* cache, + const Playlist* playlist, + const gchar* keyword) +{ + gchar* normalized_keyword = normalize_search_string(keyword); + GString* keyword_string = g_string_new(normalized_keyword); + GString* match_string = g_string_new(normalized_keyword); + gsize match_string_length = keyword_string->len; + + ui_jump_to_track_cache_init(cache, playlist); + + while (match_string_length >= 0) + { + gpointer string_ptr = GINT_TO_POINTER(g_string_hash(match_string)); + gpointer result_entries = g_hash_table_lookup(cache->keywords, + string_ptr); + if (result_entries != NULL) + { + KeywordMatches* matched_entries = (KeywordMatches*)result_entries; + // if keyword matches something we have, we'll just return the list + // of matches that the keyword has. + if (match_string_length == keyword_string->len) { + g_string_free(keyword_string, TRUE); + g_string_free(match_string, TRUE); + g_free(normalized_keyword); + return matched_entries->track_entries; + } + + // Do normal search by using the result of previous search + // as search space. + GArray* result = ui_jump_to_track_cache_match_keyword(cache, + matched_entries, + keyword_string); + g_string_free(keyword_string, TRUE); + g_string_free(match_string, TRUE); + g_free(normalized_keyword); + return result; + } + match_string_length--; + g_string_set_size(match_string, match_string_length); + } + // This should never, ever get to this point because there is _always_ + // the empty string to match against. + AUDDBG("One should never get to this point. Something is really wrong with \ +cache->keywords hash table."); + assert(FALSE); + g_return_val_if_fail(FALSE, (GArray*)-1); +} + diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_jumptotrack_cache.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_jumptotrack_cache.h Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,47 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2008 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_JUMPTOTRACK_CACHE_H +#define AUDACIOUS_UI_JUMPTOTRACK_CACHE_H + +#include + +#include "playlist.h" + +typedef struct _JumpToTrackCache JumpToTrackCache; +typedef struct _JumpToTrackEntry JumpToTrackEntry; + +struct _JumpToTrackCache +{ + gulong playlist_serial; + GHashTable* keywords; +}; + +struct _JumpToTrackEntry +{ + PlaylistEntry* entry; + // We need to manually keep information about current playlist position. + gulong playlist_position; +}; + +extern JumpToTrackCache* ui_jump_to_track_cache_new(void); +extern const GArray* ui_jump_to_track_cache_search(JumpToTrackCache* cache, const Playlist* playlist, const gchar* keyword); +extern void ui_jump_to_track_cache_free(JumpToTrackCache* cache); + +#endif /* AUDACIOUS_UI_JUMPTOTRACK_CACHE_H */ diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_legacy.c --- a/src/audacious/ui_legacy.c Tue Jul 08 15:35:48 2008 +0200 +++ b/src/audacious/ui_legacy.c Tue Jul 08 16:36:50 2008 +0200 @@ -66,7 +66,7 @@ #include "signals.h" #include "legacy/ui_skin.h" #include "legacy/ui_equalizer.h" -#include "legacy/ui_fileinfo.h" +#include "ui_fileinfo.h" #include "legacy/ui_hints.h" #include "legacy/ui_main.h" #include "legacy/ui_manager.h" diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_urlopener.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_urlopener.c Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,158 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team. + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define NEED_GLADE +#include "util.h" + +#include +#include +#include +#include +#include +#include + +#include "platform/smartinclude.h" +#include + +#include "input.h" +#include "main.h" +#include "playback.h" +#include "strings.h" + +#ifdef USE_CHARDET +#include "../libguess/libguess.h" +# ifdef HAVE_UDET +# include +# endif +#endif + +#define URL_HISTORY_MAX_SIZE 30 + +static void +util_add_url_callback(GtkWidget * widget, + GtkEntry * entry) +{ + const gchar *text; + + text = gtk_entry_get_text(entry); + if (g_list_find_custom(cfg.url_history, text, (GCompareFunc) strcasecmp)) + return; + + cfg.url_history = g_list_prepend(cfg.url_history, g_strdup(text)); + + while (g_list_length(cfg.url_history) > URL_HISTORY_MAX_SIZE) { + GList *node = g_list_last(cfg.url_history); + g_free(node->data); + cfg.url_history = g_list_delete_link(cfg.url_history, node); + } +} + +GtkWidget * +util_add_url_dialog_new(const gchar * caption, GCallback ok_func, + GCallback enqueue_func) +{ + GtkWidget *win, *vbox, *bbox, *cancel, *enqueue, *ok, *combo, *entry, + *label; + GList *url; + + win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(win), _("Add/Open URL Dialog")); + gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER); + gtk_window_set_default_size(GTK_WINDOW(win), 400, -1); + gtk_container_set_border_width(GTK_CONTAINER(win), 12); + + vbox = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(win), vbox); + + label = gtk_label_new(caption); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + combo = gtk_combo_box_entry_new_text(); + gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0); + + entry = gtk_bin_get_child(GTK_BIN(combo)); + gtk_window_set_focus(GTK_WINDOW(win), entry); + gtk_entry_set_text(GTK_ENTRY(entry), ""); + + for (url = cfg.url_history; url; url = g_list_next(url)) + gtk_combo_box_append_text(GTK_COMBO_BOX(combo), + (const gchar *) url->data); + + g_signal_connect(entry, "activate", + G_CALLBACK(util_add_url_callback), + entry); + g_signal_connect(entry, "activate", + G_CALLBACK(ok_func), + entry); + g_signal_connect_swapped(entry, "activate", + G_CALLBACK(gtk_widget_destroy), + win); + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + cancel = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + gtk_box_pack_start(GTK_BOX(bbox), cancel, FALSE, FALSE, 0); + gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(bbox), cancel, TRUE); + + g_signal_connect_swapped(cancel, "clicked", + G_CALLBACK(gtk_widget_destroy), + win); + + enqueue = gtk_button_new_from_stock(GTK_STOCK_ADD); + gtk_box_pack_start(GTK_BOX(bbox), enqueue, FALSE, FALSE, 0); + + g_signal_connect(enqueue, "clicked", + G_CALLBACK(util_add_url_callback), + entry); + g_signal_connect(enqueue, "clicked", + G_CALLBACK(enqueue_func), + entry); + g_signal_connect_swapped(enqueue, "clicked", + G_CALLBACK(gtk_widget_destroy), + win); + + ok = gtk_button_new_from_stock(GTK_STOCK_OPEN); + g_signal_connect(ok, "clicked", + G_CALLBACK(util_add_url_callback), entry); + g_signal_connect(ok, "clicked", + G_CALLBACK(ok_func), entry); + g_signal_connect_swapped(ok, "clicked", + G_CALLBACK(gtk_widget_destroy), + win); + gtk_box_pack_start(GTK_BOX(bbox), ok, FALSE, FALSE, 0); + + gtk_widget_show_all(vbox); + + return win; +} diff -r a33facf19590 -r 6584bba8de63 src/audacious/ui_urlopener.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/ui_urlopener.h Tue Jul 08 16:36:50 2008 +0200 @@ -0,0 +1,45 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 Audacious development team + * + * Based on BMP: + * Copyright (C) 2003-2004 BMP development team + * + * Based on XMMS: + * Copyright (C) 1998-2003 XMMS development team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#ifndef AUDACIOUS_UI_URLOPENER_H +#define AUDACIOUS_UI_URLOPENER_H + +#ifdef _AUDACIOUS_CORE +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +#endif + +#include +#include + +G_BEGIN_DECLS + +GtkWidget *util_add_url_dialog_new(const gchar * caption, GCallback ok_func, + GCallback enqueue_func); + +G_END_DECLS + +#endif /* AUDACIOUS_UI_URLOPENER_H */