# HG changeset patch # User mf0102 <0102@gmx.at> # Date 1215359740 -7200 # Node ID 3a56d27860634c72f8c636b8573296eda439eebb # Parent cfc8d1e0c78bb27c5b1b4a7544a5970687d7ccce move all files belonging to the legacy UI to legacy/ diff -r cfc8d1e0c78b -r 3a56d2786063 acinclude.m4 --- a/acinclude.m4 Sun Jul 06 13:55:23 2008 +0200 +++ b/acinclude.m4 Sun Jul 06 17:55:40 2008 +0200 @@ -206,6 +206,7 @@ int main() { _mm_setzero_pd(); + asm volatile("xorpd %xmm0,%xmm0\n\t"); return 0; } ],[ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/Makefile --- a/src/audacious/Makefile Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/Makefile Sun Jul 06 17:55:40 2008 +0200 @@ -3,87 +3,87 @@ SUBDIRS = ${INTL_OBJECTIVE} PROG = audacious${PROG_SUFFIX} -SRCS = af_equalizer.c \ - auddrct.c \ - audconfig.c \ - build_stamp.c \ - configdb.c \ - custom_uri.c \ - discovery.c \ - dnd.c \ - effect.c \ - equalizer_flow.c \ - eventqueue.c \ - fft.c \ - flow.c \ - general.c \ - hook.c \ - icons-stock.c \ - interface.c \ - input.c \ - logger.c \ - main.c \ - mime.c \ - output.c \ - pixbuf_effects.c \ - playback.c \ - playback_evlisteners.c \ - playlist.c \ - playlist_container.c \ - pluginenum.c \ - rcfile.c \ - signals.c \ - src_flow.c \ - strings.c \ - tuple.c \ - tuple_formatter.c \ - tuple_compiler.c \ - ui_about.c \ - ui_albumart.c \ - ui_credits.c \ - ui_dock.c \ - ui_equalizer.c \ - ui_fileinfo.c \ - ui_fileinfopopup.c \ - ui_fileopener.c \ - ui_headless.c \ - ui_hints.c \ - ui_jumptotrack.c \ - ui_jumptotrack_cache.c \ - ui_legacy.c \ - ui_main.c \ - ui_main_evlisteners.c \ - ui_manager.c \ - ui_new.c \ - ui_playlist.c \ - ui_playlist_evlisteners.c \ - ui_playlist_manager.c \ - ui_preferences.c \ - ui_skin.c \ - ui_skinned_window.c \ - ui_skinned_button.c \ - ui_skinned_textbox.c \ - ui_skinned_number.c \ - ui_skinned_horizontal_slider.c \ - ui_vis.c \ - ui_svis.c \ - ui_skinned_menurow.c \ - ui_skinned_playstatus.c \ - ui_skinned_monostereo.c \ - ui_skinned_equalizer_slider.c \ - ui_skinned_equalizer_graph.c \ - ui_skinned_playlist_slider.c \ - ui_skinned_playlist.c \ - ui_skinselector.c \ - ui_urlopener.c \ - util.c \ - vfs.c \ - vfs_buffer.c \ - vfs_buffered_file.c \ - vfs_common.c \ - visualization.c \ - volumecontrol.c \ - sync-menu.c +SRCS = af_equalizer.c \ + auddrct.c \ + audconfig.c \ + build_stamp.c \ + configdb.c \ + custom_uri.c \ + discovery.c \ + dnd.c \ + effect.c \ + equalizer_flow.c \ + eventqueue.c \ + fft.c \ + flow.c \ + general.c \ + hook.c \ + icons-stock.c \ + interface.c \ + input.c \ + logger.c \ + main.c \ + mime.c \ + output.c \ + pixbuf_effects.c \ + playback.c \ + playback_evlisteners.c \ + playlist.c \ + playlist_container.c \ + pluginenum.c \ + rcfile.c \ + signals.c \ + src_flow.c \ + strings.c \ + tuple.c \ + tuple_formatter.c \ + tuple_compiler.c \ + ui_fileinfopopup.c \ + ui_fileopener.c \ + ui_headless.c \ + ui_legacy.c \ + ui_new.c \ + ui_preferences.c \ + util.c \ + vfs.c \ + vfs_buffer.c \ + vfs_buffered_file.c \ + vfs_common.c \ + visualization.c \ + volumecontrol.c \ + sync-menu.c \ + legacy/ui_about.c \ + legacy/ui_albumart.c \ + legacy/ui_credits.c \ + legacy/ui_dock.c \ + legacy/ui_equalizer.c \ + legacy/ui_fileinfo.c \ + legacy/ui_hints.c \ + legacy/ui_jumptotrack.c \ + legacy/ui_jumptotrack_cache.c \ + legacy/ui_main.c \ + legacy/ui_main_evlisteners.c \ + legacy/ui_manager.c \ + legacy/ui_playlist.c \ + legacy/ui_playlist_evlisteners.c \ + legacy/ui_playlist_manager.c \ + legacy/ui_skin.c \ + legacy/ui_skinned_window.c \ + legacy/ui_skinned_button.c \ + legacy/ui_skinned_textbox.c \ + legacy/ui_skinned_number.c \ + legacy/ui_skinned_horizontal_slider.c \ + legacy/ui_vis.c \ + legacy/ui_svis.c \ + legacy/ui_skinned_menurow.c \ + legacy/ui_skinned_playstatus.c \ + legacy/ui_skinned_monostereo.c \ + legacy/ui_skinned_equalizer_slider.c \ + legacy/ui_skinned_equalizer_graph.c \ + legacy/ui_skinned_playlist_slider.c \ + legacy/ui_skinned_playlist.c \ + legacy/ui_skinselector.c \ + legacy/ui_urlopener.c \ ifeq ($(USE_DBUS),yes) SRCS += dbus.c @@ -102,7 +102,7 @@ i18n.h \ input.h \ hook.h \ - interface.h \ + interface.h \ main.h \ mime.h \ output.h \ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/audconfig.c --- a/src/audacious/audconfig.c Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/audconfig.c Sun Jul 06 17:55:40 2008 +0200 @@ -37,11 +37,11 @@ #include "general.h" #include "playback.h" #include "pluginenum.h" -#include "ui_equalizer.h" -#include "ui_playlist.h" -#include "ui_skin.h" -#include "ui_skinned_window.h" -#include "ui_vis.h" +#include "legacy/ui_equalizer.h" +#include "legacy/ui_playlist.h" +#include "legacy/ui_skin.h" +#include "legacy/ui_skinned_window.h" +#include "legacy/ui_vis.h" #include "util.h" #include "visualization.h" diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/dbus.c --- a/src/audacious/dbus.c Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/dbus.c Sun Jul 06 17:55:40 2008 +0200 @@ -39,8 +39,8 @@ #include "tuple.h" #include "strings.h" -#include "ui_equalizer.h" -#include "ui_skin.h" +#include "legacy/ui_equalizer.h" +#include "legacy/ui_skin.h" static DBusGConnection *dbus_conn = NULL; static guint signals[LAST_SIG] = { 0 }; diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_about.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_about.c Sun Jul 06 17:55:40 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_albumart.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_albumart.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,195 @@ +/* + * 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_credits.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_credits.c Sun Jul 06 17:55:40 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_credits.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_credits.h Sun Jul 06 17:55:40 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_dock.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_dock.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,531 @@ +/* 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. + */ + +#include "ui_dock.h" + +#include +#include +#include "main.h" +#include "ui_skinned_window.h" + +#include "platform/smartinclude.h" + +static GList *dock_window_list = NULL; + +struct _DockedWindow { + GtkWindow *w; + gint offset_x, offset_y; +}; + +typedef struct _DockedWindow DockedWindow; + + +static gint +docked_list_compare(DockedWindow * a, DockedWindow * b) +{ + if (a->w == b->w) + return 0; + return 1; +} + +static void +snap_edge(gint * x, gint * y, gint w, gint h, gint bx, gint by, + gint bw, gint bh) +{ + gint sd = cfg.snap_distance; + + if ((*x + w > bx - sd) && (*x + w < bx + sd) && + (*y > by - h - sd) && (*y < by + bh + sd)) { + *x = bx - w; + if ((*y > by - sd) && (*y < by + sd)) + *y = by; + if ((*y + h > by + bh - sd) && (*y + h < by + bh + sd)) + *y = by + bh - h; + } + if ((*x > bx + bw - sd) && (*x < bx + bw + sd) && + (*y > by - h - sd) && (*y < by + bh + sd)) { + *x = bx + bw; + if ((*y > by - sd) && (*y < by + sd)) + *y = by; + if ((*y + h > by + bh - sd) && (*y + h < by + bh + sd)) + *y = by + bh - h; + } +} + +static void +snap(gint * x, gint * y, gint w, gint h, gint bx, gint by, gint bw, gint bh) +{ + snap_edge(x, y, w, h, bx, by, bw, bh); + snap_edge(y, x, h, w, by, bx, bh, bw); +} + +static void +calc_snap_offset(GList * dlist, GList * wlist, gint x, gint y, + gint * off_x, gint * off_y) +{ + gint nx, ny, nw, nh, sx, sy, sw, sh; + GtkWindow *w; + GList *dnode, *wnode; + DockedWindow temp, *dw; + + + *off_x = 0; + *off_y = 0; + + if (!cfg.snap_windows) + return; + + /* + * FIXME: Why not break out of the loop when we find someting + * to snap to? + */ + for (dnode = dlist; dnode; dnode = g_list_next(dnode)) { + dw = dnode->data; + gtk_window_get_size(dw->w, &nw, &nh); + + nx = dw->offset_x + *off_x + x; + ny = dw->offset_y + *off_y + y; + + /* Snap to screen edges */ + if (abs(nx) < cfg.snap_distance) + *off_x -= nx; + if (abs(ny) < cfg.snap_distance) + *off_y -= ny; + if (abs(nx + nw - gdk_screen_width()) < cfg.snap_distance) + *off_x -= nx + nw - gdk_screen_width(); + if (abs(ny + nh - gdk_screen_height()) < cfg.snap_distance) + *off_y -= ny + nh - gdk_screen_height(); + + /* Snap to other windows */ + for (wnode = wlist; wnode; wnode = g_list_next(wnode)) { + temp.w = wnode->data; + if (g_list_find_custom + (dlist, &temp, (GCompareFunc) docked_list_compare)) + /* These windows are already docked */ + continue; + + w = GTK_WINDOW(wnode->data); + gtk_window_get_position(w, &sx, &sy); + gtk_window_get_size(w, &sw, &sh); + + nx = dw->offset_x + *off_x + x; + ny = dw->offset_y + *off_y + y; + + snap(&nx, &ny, nw, nh, sx, sy, sw, sh); + + *off_x += nx - (dw->offset_x + *off_x + x); + *off_y += ny - (dw->offset_y + *off_y + y); + } + } +} + + +static gboolean +is_docked(gint a_x, gint a_y, gint a_w, gint a_h, + gint b_x, gint b_y, gint b_w, gint b_h) +{ + if (((a_x == b_x + b_w) || (a_x + a_w == b_x)) && + (b_y + b_h >= a_y) && (b_y <= a_y + a_h)) + return TRUE; + + if (((a_y == b_y + b_h) || (a_y + a_h == b_y)) && + (b_x >= a_x - b_w) && (b_x <= a_x + a_w)) + return TRUE; + + return FALSE; +} + +/* + * Builds a list of all windows that are docked to the window "w". + * Recursively adds all windows that are docked to the windows that are + * docked to "w" and so on... + * FIXME: init_off_? ? + */ + +static GList * +get_docked_list(GList * dlist, GList * wlist, GtkWindow * w, + gint init_off_x, gint init_off_y) +{ + GList *node; + DockedWindow *dwin, temp; + gint w_x, w_y, w_width, w_height; + gint t_x, t_y, t_width, t_height; + + + gtk_window_get_position(w, &w_x, &w_y); + gtk_window_get_size(w, &w_width, &w_height); + if (!dlist) { + dwin = g_new0(DockedWindow, 1); + dwin->w = w; + dlist = g_list_append(dlist, dwin); + } + + for (node = wlist; node; node = g_list_next(node)) { + temp.w = node->data; + if (g_list_find_custom + (dlist, &temp, (GCompareFunc) docked_list_compare)) + continue; + + gtk_window_get_position(GTK_WINDOW(node->data), &t_x, &t_y); + gtk_window_get_size(GTK_WINDOW(node->data), &t_width, &t_height); + if (is_docked + (w_x, w_y, w_width, w_height, t_x, t_y, t_width, t_height)) { + dwin = g_new0(DockedWindow, 1); + dwin->w = node->data; + + dwin->offset_x = t_x - w_x + init_off_x; + dwin->offset_y = t_y - w_y + init_off_y; + + dlist = g_list_append(dlist, dwin); + + dlist = + get_docked_list(dlist, wlist, dwin->w, dwin->offset_x, + dwin->offset_y); + } + } + return dlist; +} + +static void +free_docked_list(GList * dlist) +{ + GList *node; + + for (node = dlist; node; node = g_list_next(node)) + g_free(node->data); + g_list_free(dlist); +} + +static void +docked_list_move(GList * list, gint x, gint y) +{ + GList *node; + DockedWindow *dw; + + for (node = list; node; node = g_list_next(node)) { + dw = node->data; + gtk_window_move(dw->w, x + dw->offset_x, y + dw->offset_y); + + SkinnedWindow *window = SKINNED_WINDOW(dw->w); + if (window) { + switch(window->type) { + + case WINDOW_MAIN: + cfg.player_x = x + dw->offset_x; + cfg.player_y = y + dw->offset_y; + break; + case WINDOW_EQ: + cfg.equalizer_x = x + dw->offset_x; + cfg.equalizer_y = y + dw->offset_y; + break; + case WINDOW_PLAYLIST: + cfg.playlist_x = x + dw->offset_x; + cfg.playlist_y = y + dw->offset_y; + break; + } + + window->x = x + dw->offset_x; + window->y = y + dw->offset_y; + } + } +} + +static GList * +shade_move_list(GList * list, GtkWindow * widget, gint offset) +{ + gint x, y, w, h; + GList *node; + DockedWindow *dw; + + gtk_window_get_position(widget, &x, &y); + gtk_window_get_size(widget, &w, &h); + + + for (node = list; node;) { + gint dx, dy, dwidth, dheight; + + dw = node->data; + gtk_window_get_position(dw->w, &dx, &dy); + gtk_window_get_size(dw->w, &dwidth, &dheight); + if (is_docked(x, y, w, h, dx, dy, dwidth, dheight) && + ((dx + dwidth) > x && dx < (x + w))) { + list = g_list_remove_link(list, node); + g_list_free_1(node); + + node = list = shade_move_list(list, dw->w, offset); + } + else + node = g_list_next(node); + } + gtk_window_move(widget, x, y + offset); + return list; +} + +/* + * Builds a list of the windows in the list of DockedWindows "winlist" + * that are docked to the top or bottom of the window, and recursively + * adds all windows that are docked to the top or bottom of that window, + * and so on... + * Note: The data in "winlist" is not copied. + */ +static GList * +find_shade_list(GtkWindow * widget, GList * winlist, GList * shade_list) +{ + gint x, y, w, h; + gint dx, dy, dwidth, dheight; + GList *node; + + gtk_window_get_position(widget, &x, &y); + gtk_window_get_size(widget, &w, &h); + for (node = winlist; node; node = g_list_next(node)) { + DockedWindow *dw = node->data; + if (g_list_find_custom + (shade_list, dw, (GCompareFunc) docked_list_compare)) + continue; + gtk_window_get_position(dw->w, &dx, &dy); + gtk_window_get_size(dw->w, &dwidth, &dheight); + + /* FIXME. Is the is_docked() necessary? */ + if (is_docked(x, y, w, h, dx, dy, dwidth, dheight) && + ((dx + dwidth) > x && dx < (x + w))) { + shade_list = g_list_append(shade_list, dw); + shade_list = find_shade_list(dw->w, winlist, shade_list); + } + } + return shade_list; +} + +void +dock_window_resize(GtkWindow * widget, gint new_w, gint new_h, gint w, gint h) +{ + gdk_window_set_hints(GTK_WIDGET(widget)->window, 0, 0, MIN(w, new_w), + MIN(h, new_h), MAX(w, new_w), MAX(h, new_h), + GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); + gdk_window_resize(GTK_WIDGET(widget)->window, new_w, new_h); + gdk_window_set_hints(GTK_WIDGET(widget)->window, 0, 0, new_w, new_h, + new_w, new_h, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); +} + +void +dock_shade(GList * window_list, GtkWindow * widget, gint new_h) +{ + gint x, y, w, h, off_y, orig_off_y; + GList *node, *docked_list, *slist; + DockedWindow *dw; + + gtk_window_get_position(widget, &x, &y); + gtk_window_get_size(widget, &w, &h); + + if (cfg.show_wm_decorations) { + dock_window_resize(widget, w, new_h, w, h); + return; + } + + docked_list = get_docked_list(NULL, window_list, widget, 0, 0); + slist = find_shade_list(widget, docked_list, NULL); + + off_y = new_h - h; + do { + orig_off_y = off_y; + for (node = slist; node; node = g_list_next(node)) { + gint dx, dy, dwidth, dheight; + + dw = node->data; + if (dw->w == widget) + continue; + gtk_window_get_position(dw->w, &dx, &dy); + gtk_window_get_size(dw->w, &dwidth, &dheight); + if ((dy >= y) && ((dy + off_y + dheight) > gdk_screen_height())) + off_y -= (dy + off_y + dheight) - gdk_screen_height(); + else if ((dy >= y) && ((dy + dheight) == gdk_screen_height())) + off_y = 0; + + if (((dy >= y) && ((dy + off_y) < 0))) + off_y -= dy + off_y; + if ((dy < y) && ((dy + (off_y - (new_h - h))) < 0)) + off_y -= dy + (off_y - (new_h - h)); + } + } while (orig_off_y != off_y); + if (slist) { + GList *mlist = g_list_copy(slist); + + /* Remove this widget from the list */ + for (node = mlist; node; node = g_list_next(node)) { + dw = node->data; + if (dw->w == widget) { + mlist = g_list_remove_link(mlist, node); + g_list_free_1(node); + break; + } + } + for (node = mlist; node;) { + GList *temp; + gint dx, dy, dwidth, dheight; + + dw = node->data; + + gtk_window_get_position(dw->w, &dx, &dy); + gtk_window_get_size(dw->w, &dwidth, &dheight); + /* + * Find windows that are directly docked to this window, + * move it, and any windows docked to that window again + */ + if (is_docked(x, y, w, h, dx, dy, dwidth, dheight) && + ((dx + dwidth) > x && dx < (x + w))) { + mlist = g_list_remove_link(mlist, node); + g_list_free_1(node); + if (dy > y) + temp = shade_move_list(mlist, dw->w, off_y); + else if (off_y - (new_h - h) != 0) + temp = shade_move_list(mlist, dw->w, off_y - (new_h - h)); + else + temp = mlist; + node = mlist = temp; + } + else + node = g_list_next(node); + } + g_list_free(mlist); + } + g_list_free(slist); + free_docked_list(docked_list); + gtk_window_move(widget, x, y + off_y - (new_h - h)); + dock_window_resize(widget, w, new_h, w, h); +} + +void +dock_move_press(GList * window_list, GtkWindow * w, + GdkEventButton * event, gboolean move_list) +{ + gint mx, my; + DockedWindow *dwin; + + if (cfg.show_wm_decorations) + return; + + gtk_window_present(w); + mx = event->x; + my = event->y; + gtk_object_set_data(GTK_OBJECT(w), "move_offset_x", GINT_TO_POINTER(mx)); + gtk_object_set_data(GTK_OBJECT(w), "move_offset_y", GINT_TO_POINTER(my)); + if (move_list) + gtk_object_set_data(GTK_OBJECT(w), "docked_list", + get_docked_list(NULL, window_list, w, 0, 0)); + else { + dwin = g_new0(DockedWindow, 1); + dwin->w = w; + gtk_object_set_data(GTK_OBJECT(w), "docked_list", + g_list_append(NULL, dwin)); + } + gtk_object_set_data(GTK_OBJECT(w), "window_list", window_list); + gtk_object_set_data(GTK_OBJECT(w), "is_moving", GINT_TO_POINTER(1)); +} + +void +dock_move_motion(GtkWindow * w, GdkEventMotion * event) +{ + gint offset_x, offset_y, x, y; + GList *dlist; + GList *window_list; + + if (!gtk_object_get_data(GTK_OBJECT(w), "is_moving")) + return; + + offset_x = + GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(w), "move_offset_x")); + offset_y = + GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(w), "move_offset_y")); + dlist = gtk_object_get_data(GTK_OBJECT(w), "docked_list"); + window_list = gtk_object_get_data(GTK_OBJECT(w), "window_list"); + + x = event->x_root - offset_x; + y = event->y_root - offset_y; + + calc_snap_offset(dlist, window_list, x, y, &offset_x, &offset_y); + x += offset_x; + y += offset_y; + + docked_list_move(dlist, x, y); +} + +void +dock_move_release(GtkWindow * w) +{ + GList *dlist; + gtk_object_remove_data(GTK_OBJECT(w), "is_moving"); + gtk_object_remove_data(GTK_OBJECT(w), "move_offset_x"); + gtk_object_remove_data(GTK_OBJECT(w), "move_offset_y"); + if ((dlist = gtk_object_get_data(GTK_OBJECT(w), "docked_list")) != NULL) + free_docked_list(dlist); + gtk_object_remove_data(GTK_OBJECT(w), "docked_list"); + gtk_object_remove_data(GTK_OBJECT(w), "window_list"); +} + +gboolean +dock_is_moving(GtkWindow * w) +{ + if (gtk_object_get_data(GTK_OBJECT(w), "is_moving")) + return TRUE; + return FALSE; +} + +GList * +dock_add_window(GList * list, GtkWindow * window) +{ + return g_list_append(list, window); +} + +GList * +dock_remove_window(GList * list, GtkWindow * window) +{ + return g_list_remove(list, window); +} + +GList * +dock_window_set_decorated(GList * list, GtkWindow * window, + gboolean decorated) +{ + if (gtk_window_get_decorated(window) == decorated) + return list; + + if (decorated) + list = dock_remove_window(list, window); + else + list = dock_add_window(list, window); + + gtk_window_set_decorated(window, decorated); + + return list; +} + +GList * +get_dock_window_list() { + return dock_window_list; +} + +void +set_dock_window_list(GList * list) { + dock_window_list = list; +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_dock.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_dock.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,50 @@ +/* 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_DOCK_H +#define AUDACIOUS_UI_DOCK_H + +#include +#include + +void dock_set_uposition(GtkWindow * widget, gint x, gint y); +GList *dock_add_window(GList * window_list, GtkWindow * window); +GList *dock_remove_window(GList * window_list, GtkWindow * window); +void dock_move_press(GList * window_list, GtkWindow * w, + GdkEventButton * event, gboolean move_list); +void dock_move_motion(GtkWindow * w, GdkEventMotion * event); +void dock_move_release(GtkWindow * w); +void dock_get_widget_pos(GtkWindow * w, gint * x, gint * y); +gboolean dock_is_moving(GtkWindow * w); +void dock_shade(GList * window_list, GtkWindow * widget, gint new_h); + +GList *dock_window_set_decorated(GList * list, GtkWindow * window, + gboolean decorated); +void dock_window_resize(GtkWindow * widget, gint new_w, gint new_h, gint w, gint h); + +GList *get_dock_window_list(); +void set_dock_window_list(GList * list); + +#endif /* AUDACIOUS_UI_DOCK_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_equalizer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_equalizer.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,1521 @@ +/* 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. + */ + +/*#define AUD_DEBUG*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui_equalizer.h" + +#include +#include +#include +#include +#include +#include + +#include "platform/smartinclude.h" +#include "ui_skin.h" +#include "input.h" +#include "main.h" +#include "ui_manager.h" +#include "actions-equalizer.h" +#include "playlist.h" +#include "ui_playlist.h" +#include "util.h" +#include "output.h" +#include "equalizer_flow.h" + +#include "rcfile.h" +#include "vfs.h" + +#include "images/audacious_eq.xpm" + +#include "ui_dock.h" +#include "ui_skinned_window.h" +#include "ui_skinned_button.h" +#include "ui_skinned_horizontal_slider.h" +#include "ui_skinned_equalizer_slider.h" +#include "ui_skinned_equalizer_graph.h" + +enum PresetViewCols { + PRESET_VIEW_COL_NAME, + PRESET_VIEW_N_COLS +}; + +struct _EqualizerPreset { + gchar *name; + gfloat preamp, bands[AUD_EQUALIZER_NBANDS]; +}; + +typedef struct _EqualizerPreset EqualizerPreset; + + +GtkWidget *equalizerwin; +GtkWidget *equalizerwin_graph; + +static GtkWidget *equalizerwin_load_window = NULL; +static GtkWidget *equalizerwin_load_auto_window = NULL; +static GtkWidget *equalizerwin_save_window = NULL; +static GtkWidget *equalizerwin_save_entry = NULL; +static GtkWidget *equalizerwin_save_auto_window = NULL; +static GtkWidget *equalizerwin_save_auto_entry = NULL; +static GtkWidget *equalizerwin_delete_window = NULL; +static GtkWidget *equalizerwin_delete_auto_window = NULL; + +static GtkWidget *equalizerwin_on, *equalizerwin_auto; + +static GtkWidget *equalizerwin_close, *equalizerwin_presets, *equalizerwin_shade; +static GtkWidget *equalizerwin_preamp,*equalizerwin_bands[AUD_EQUALIZER_NBANDS]; +static GtkWidget *equalizerwin_volume, *equalizerwin_balance; + +static GList *equalizer_presets = NULL, *equalizer_auto_presets = NULL; + +EqualizerPreset * +equalizer_preset_new(const gchar * name) +{ + EqualizerPreset *preset = g_new0(EqualizerPreset, 1); + preset->name = g_strdup(name); + return preset; +} + +void +equalizer_preset_free(EqualizerPreset * preset) +{ + if (!preset) + return; + + g_free(preset->name); + g_free(preset); +} + +void +equalizerwin_set_scaled(gboolean ds) +{ + gint height; + + if (cfg.equalizer_shaded) + height = 14; + else + height = 116; + + if (cfg.scaled) { + dock_window_resize(GTK_WINDOW(equalizerwin), 275 * cfg.scale_factor, + height * cfg.scale_factor, 275 * cfg.scale_factor, height * cfg.scale_factor); + } else { + dock_window_resize(GTK_WINDOW(equalizerwin), 275, height, 275, height); + } + + GList *iter; + for (iter = GTK_FIXED (SKINNED_WINDOW(equalizerwin)->fixed)->children; iter; iter = g_list_next (iter)) { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + GtkWidget *child = child_data->widget; + g_signal_emit_by_name(child, "toggle-scaled"); + } + gtk_widget_shape_combine_mask(equalizerwin, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + cfg.equalizer_shaded), 0, 0); +} + +void +equalizerwin_set_shade_menu_cb(gboolean shaded) +{ + cfg.equalizer_shaded = shaded; + + if (shaded) { + dock_shade(get_dock_window_list(), GTK_WINDOW(equalizerwin), + 14 * EQUALIZER_SCALE_FACTOR); + ui_skinned_set_push_button_data(equalizerwin_shade, -1, 3, -1, 47); + ui_skinned_button_set_skin_index1(equalizerwin_shade, SKIN_EQ_EX); + ui_skinned_set_push_button_data(equalizerwin_close, 11, 38, 11, 47); + ui_skinned_button_set_skin_index(equalizerwin_close, SKIN_EQ_EX); + gtk_widget_show(equalizerwin_volume); + gtk_widget_show(equalizerwin_balance); + } + else { + dock_shade(get_dock_window_list(), GTK_WINDOW(equalizerwin), + 116 * EQUALIZER_SCALE_FACTOR); + ui_skinned_set_push_button_data(equalizerwin_shade, -1, 137, -1, 38); + ui_skinned_button_set_skin_index1(equalizerwin_shade, SKIN_EQMAIN); + ui_skinned_set_push_button_data(equalizerwin_close, 0, 116, 0, 125); + ui_skinned_button_set_skin_index(equalizerwin_close, SKIN_EQMAIN); + gtk_widget_hide(equalizerwin_volume); + gtk_widget_hide(equalizerwin_balance); + } + + gtk_widget_shape_combine_mask(equalizerwin, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + cfg.equalizer_shaded), 0, 0); +} + +static void +equalizerwin_set_shade(gboolean shaded) +{ + GtkAction *action = gtk_action_group_get_action( + toggleaction_group_others , "roll up equalizer" ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , shaded ); +} + +static void +equalizerwin_shade_toggle(void) +{ + equalizerwin_set_shade(!cfg.equalizer_shaded); +} + +void +equalizerwin_eq_changed(void) +{ + gint i; + + cfg.equalizer_preamp = ui_skinned_equalizer_slider_get_position(equalizerwin_preamp); + for (i = 0; i < AUD_EQUALIZER_NBANDS; i++) + cfg.equalizer_bands[i] = ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i]); + + output_set_eq(cfg.equalizer_active, cfg.equalizer_preamp, + cfg.equalizer_bands); + + gtk_widget_queue_draw(equalizerwin_graph); +} + +static void +equalizerwin_on_pushed(void) +{ + cfg.equalizer_active = UI_SKINNED_BUTTON(equalizerwin_on)->inside; + equalizerwin_eq_changed(); +} + +static void +equalizerwin_presets_pushed(void) +{ + GdkModifierType modmask; + gint x, y; + + gdk_window_get_pointer(NULL, &x, &y, &modmask); + ui_manager_popup_menu_show(GTK_MENU(equalizerwin_presets_menu), x, y, 1, GDK_CURRENT_TIME); +} + +static void +equalizerwin_auto_pushed(void) +{ + cfg.equalizer_autoload = UI_SKINNED_BUTTON(equalizerwin_auto)->inside; +} + +gboolean +equalizerwin_press(GtkWidget * widget, GdkEventButton * event, + gpointer callback_data) +{ + if (event->button == 1 && event->type == GDK_2BUTTON_PRESS + && event->y < 14) { + equalizerwin_set_shade(!cfg.equalizer_shaded); + if (dock_is_moving(GTK_WINDOW(equalizerwin))) + dock_move_release(GTK_WINDOW(equalizerwin)); + return TRUE; + } + if (event->button == 3) { + /* + * Pop up the main menu a few pixels down to avoid + * anything to be selected initially. + */ + ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), event->x_root, + event->y_root + 2, 3, event->time); + return TRUE; + } + + return FALSE; +} + +static gboolean +equalizerwin_keypress(GtkWidget * widget, + GdkEventKey * event, + gpointer data) +{ + if (event->keyval == GDK_Tab && event->state & GDK_CONTROL_MASK) { + if (cfg.playlist_visible) + gtk_window_present(GTK_WINDOW(playlistwin)); + else if (cfg.player_visible) + gtk_window_present(GTK_WINDOW(mainwin)); + return TRUE; + } + + if (!cfg.equalizer_shaded) { + gtk_widget_event(mainwin, (GdkEvent *) event); + return TRUE; + } + + switch (event->keyval) { + case GDK_Left: + case GDK_KP_Left: + mainwin_set_balance_diff(-4); + break; + case GDK_Right: + case GDK_KP_Right: + mainwin_set_balance_diff(4); + break; + default: + gtk_widget_event(mainwin, (GdkEvent *) event); + break; + } + + return FALSE; +} + +static void +equalizerwin_close_cb(void) +{ + equalizerwin_show(FALSE); +} + +static gboolean +equalizerwin_delete(GtkWidget * widget, + gpointer data) +{ + equalizerwin_show(FALSE); + return TRUE; +} + +static GList * +equalizerwin_read_presets(const gchar * basename) +{ + gchar *filename, *name; + RcFile *rcfile; + GList *list = NULL; + gint i, p = 0; + EqualizerPreset *preset; + + /* START mod: add check for the default presets locate in system path ({prefix}/share/audacious) + by Massimo Cavalleri (submax) */ + + filename = g_build_filename(aud_paths[BMP_PATH_USER_DIR], basename, NULL); + + if ((rcfile = aud_rcfile_open(filename)) == NULL) { + g_free(filename); + // DATA_DIR = "{prefix}/share/audacious" ; example is "/usr/share/audacious" + filename = g_build_filename(DATA_DIR, basename, NULL); + if ((rcfile = aud_rcfile_open(filename)) == NULL) { + g_free(filename); + return NULL; + } + } + + // END mod + + g_free(filename); + + for (;;) { + gchar section[32]; + + g_snprintf(section, sizeof(section), "Preset%d", p++); + if (aud_rcfile_read_string(rcfile, "Presets", section, &name)) { + preset = g_new0(EqualizerPreset, 1); + preset->name = name; + aud_rcfile_read_float(rcfile, name, "Preamp", &preset->preamp); + for (i = 0; i < AUD_EQUALIZER_NBANDS; i++) { + gchar band[16]; + g_snprintf(band, sizeof(band), "Band%d", i); + aud_rcfile_read_float(rcfile, name, band, &preset->bands[i]); + } + list = g_list_prepend(list, preset); + } + else + break; + } + list = g_list_reverse(list); + aud_rcfile_free(rcfile); + return list; +} + +gint +equalizerwin_volume_frame_cb(gint pos) +{ + if (equalizerwin_volume) { + gint x; + if (pos < 32) + x = 1; + else if (pos < 63) + x = 4; + else + x = 7; + + UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_volume)->knob_nx = x; + UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_volume)->knob_px = x; + } + return 1; +} + +static void +equalizerwin_volume_motion_cb(GtkWidget *widget, gint pos) +{ + gint v = (gint) rint(pos * 100 / 94.0); + mainwin_adjust_volume_motion(v); + mainwin_set_volume_slider(v); +} + +static void +equalizerwin_volume_release_cb(GtkWidget *widget, gint pos) +{ + mainwin_adjust_volume_release(); +} + +static gint +equalizerwin_balance_frame_cb(gint pos) +{ + if (equalizerwin_balance) { + gint x; + if (pos < 13) + x = 11; + else if (pos < 26) + x = 14; + else + x = 17; + + UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_balance)->knob_nx = x; + UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_balance)->knob_px = x; + } + + return 1; +} + +static void +equalizerwin_balance_motion_cb(GtkWidget *widget, gint pos) +{ + gint b; + pos = MIN(pos, 38); /* The skin uses a even number of pixels + for the balance-slider *sigh* */ + b = (gint) rint((pos - 19) * 100 / 19.0); + mainwin_adjust_balance_motion(b); + mainwin_set_balance_slider(b); +} + +static void +equalizerwin_balance_release_cb(GtkWidget *widget, gint pos) +{ + mainwin_adjust_balance_release(); +} + +void +equalizerwin_set_balance_slider(gint percent) +{ + ui_skinned_horizontal_slider_set_position(equalizerwin_balance, + (gint) rint((percent * 19 / 100.0) + 19)); +} + +void +equalizerwin_set_volume_slider(gint percent) +{ + ui_skinned_horizontal_slider_set_position(equalizerwin_volume, + (gint) rint(percent * 94 / 100.0)); +} + +static void +equalizerwin_create_widgets(void) +{ + gint i; + + equalizerwin_on = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(equalizerwin_on, SKINNED_WINDOW(equalizerwin)->fixed, + 14, 18, 25, 12, 10, 119, 128, 119, 69, 119, 187, 119, SKIN_EQMAIN); + g_signal_connect(equalizerwin_on, "clicked", equalizerwin_on_pushed, NULL); + UI_SKINNED_BUTTON(equalizerwin_on)->inside = cfg.equalizer_active; + + equalizerwin_auto = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(equalizerwin_auto, SKINNED_WINDOW(equalizerwin)->fixed, + 39, 18, 33, 12, 35, 119, 153, 119, 94, 119, 212, 119, SKIN_EQMAIN); + g_signal_connect(equalizerwin_auto, "clicked", equalizerwin_auto_pushed, NULL); + UI_SKINNED_BUTTON(equalizerwin_auto)->inside = cfg.equalizer_autoload; + + equalizerwin_presets = ui_skinned_button_new(); + ui_skinned_push_button_setup(equalizerwin_presets, SKINNED_WINDOW(equalizerwin)->fixed, + 217, 18, 44, 12, 224, 164, 224, 176, SKIN_EQMAIN); + g_signal_connect(equalizerwin_presets, "clicked", equalizerwin_presets_pushed, NULL ); + + equalizerwin_close = ui_skinned_button_new(); + ui_skinned_push_button_setup(equalizerwin_close, SKINNED_WINDOW(equalizerwin)->fixed, + 264, 3, 9, 9, 0, 116, 0, 125, SKIN_EQMAIN); + g_signal_connect(equalizerwin_close, "clicked", equalizerwin_close_cb, NULL ); + + equalizerwin_shade = ui_skinned_button_new(); + ui_skinned_push_button_setup(equalizerwin_shade, SKINNED_WINDOW(equalizerwin)->fixed, + 254, 3, 9, 9, 254, 137, 1, 38, SKIN_EQMAIN); + ui_skinned_button_set_skin_index2(equalizerwin_shade, SKIN_EQ_EX); + g_signal_connect(equalizerwin_shade, "clicked", equalizerwin_shade_toggle, NULL ); + + equalizerwin_graph = ui_skinned_equalizer_graph_new(SKINNED_WINDOW(equalizerwin)->fixed, 86, 17); + + equalizerwin_preamp = ui_skinned_equalizer_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, 21, 38); + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, cfg.equalizer_preamp); + + for (i = 0; i < AUD_EQUALIZER_NBANDS; i++) { + equalizerwin_bands[i] = + ui_skinned_equalizer_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, 78 + (i * 18), 38); + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], cfg.equalizer_bands[i]); + } + + equalizerwin_volume = + ui_skinned_horizontal_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, + 61, 4, 97, 8, 1, 30, 1, 30, 3, 7, 4, 61, 0, 94, + equalizerwin_volume_frame_cb, SKIN_EQ_EX); + g_signal_connect(equalizerwin_volume, "motion", G_CALLBACK(equalizerwin_volume_motion_cb), NULL); + g_signal_connect(equalizerwin_volume, "release", G_CALLBACK(equalizerwin_volume_release_cb), NULL); + + + equalizerwin_balance = + ui_skinned_horizontal_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, + 164, 4, 42, 8, 11, 30, 11, 30, 3, 7, 4, 164, 0, 39, + equalizerwin_balance_frame_cb, SKIN_EQ_EX); + g_signal_connect(equalizerwin_balance, "motion", G_CALLBACK(equalizerwin_balance_motion_cb), NULL); + g_signal_connect(equalizerwin_balance, "release", G_CALLBACK(equalizerwin_balance_release_cb), NULL); +} + + +static void +equalizerwin_create_window(void) +{ + GdkPixbuf *icon; + gint width, height; + + width = 275; + height = cfg.equalizer_shaded ? 14 : 116; + + equalizerwin = ui_skinned_window_new("equalizer"); + gtk_window_set_title(GTK_WINDOW(equalizerwin), _("Audacious Equalizer")); + gtk_window_set_role(GTK_WINDOW(equalizerwin), "equalizer"); + gtk_window_set_resizable(GTK_WINDOW(equalizerwin), FALSE); + + if (cfg.scaled && cfg.eq_scaled_linked) { + width *= cfg.scale_factor; + height *= cfg.scale_factor; + } + + gtk_widget_set_size_request(equalizerwin, width, height); + + /* this will hide only mainwin. it's annoying! yaz */ + gtk_window_set_transient_for(GTK_WINDOW(equalizerwin), + GTK_WINDOW(mainwin)); + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(equalizerwin), TRUE); + + icon = gdk_pixbuf_new_from_xpm_data((const gchar **) audacious_eq_icon); + gtk_window_set_icon(GTK_WINDOW(equalizerwin), icon); + g_object_unref(icon); + + gtk_widget_set_app_paintable(equalizerwin, TRUE); + + if (cfg.equalizer_x != -1 && cfg.save_window_position) + gtk_window_move(GTK_WINDOW(equalizerwin), + cfg.equalizer_x, cfg.equalizer_y); + + g_signal_connect(equalizerwin, "delete_event", + G_CALLBACK(equalizerwin_delete), NULL); + g_signal_connect(equalizerwin, "button_press_event", + G_CALLBACK(equalizerwin_press), NULL); + g_signal_connect(equalizerwin, "key_press_event", + G_CALLBACK(equalizerwin_keypress), NULL); +} + +void +equalizerwin_create(void) +{ + equalizer_presets = equalizerwin_read_presets("eq.preset"); + equalizer_auto_presets = equalizerwin_read_presets("eq.auto_preset"); + + equalizerwin_create_window(); + + gtk_window_add_accel_group( GTK_WINDOW(equalizerwin) , ui_manager_get_accel_group() ); + + equalizerwin_create_widgets(); +} + + +void +equalizerwin_show(gboolean show) +{ + GtkAction *action = gtk_action_group_get_action( + toggleaction_group_others , "show equalizer" ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , show ); + + if (show) + equalizerwin_real_show(); + else + equalizerwin_real_hide(); +} + +void +equalizerwin_real_show(void) +{ + gtk_window_move(GTK_WINDOW(equalizerwin), cfg.equalizer_x, cfg.equalizer_y); + if (cfg.scaled && cfg.eq_scaled_linked) + gtk_widget_set_size_request(equalizerwin, 275 * cfg.scale_factor, + ((cfg.equalizer_shaded ? 14 : 116) * cfg.scale_factor)); + else + gtk_widget_set_size_request(equalizerwin, 275, + (cfg.equalizer_shaded ? 14 : 116)); + cfg.equalizer_visible = TRUE; + UI_SKINNED_BUTTON(mainwin_eq)->inside = TRUE; + gtk_widget_show_all(equalizerwin); + + if (!cfg.equalizer_shaded) { + gtk_widget_hide(equalizerwin_volume); + gtk_widget_hide(equalizerwin_balance); + } + else { + ui_skinned_set_push_button_data(equalizerwin_shade, -1, 3, -1, 47); + ui_skinned_button_set_skin_index1(equalizerwin_shade, SKIN_EQ_EX); + ui_skinned_set_push_button_data(equalizerwin_close, 11, 38, 11, 47); + ui_skinned_button_set_skin_index(equalizerwin_close, SKIN_EQ_EX); + } + + gtk_window_present(GTK_WINDOW(equalizerwin)); +} + +void +equalizerwin_real_hide(void) +{ + /* + * This function should only be called from the + * main menu signal handler + */ + gtk_widget_hide(equalizerwin); + cfg.equalizer_visible = FALSE; + UI_SKINNED_BUTTON(mainwin_eq)->inside = FALSE; + gtk_widget_queue_draw(mainwin_eq); +} + +static EqualizerPreset * +equalizerwin_find_preset(GList * list, const gchar * name) +{ + GList *node = list; + EqualizerPreset *preset; + + while (node) { + preset = node->data; + if (!strcasecmp(preset->name, name)) + return preset; + node = g_list_next(node); + } + return NULL; +} + +static void +equalizerwin_write_preset_file(GList * list, const gchar * basename) +{ + gchar *filename, *tmp; + gint i, p; + EqualizerPreset *preset; + RcFile *rcfile; + GList *node; + + rcfile = aud_rcfile_new(); + p = 0; + for (node = list; node; node = g_list_next(node)) { + preset = node->data; + tmp = g_strdup_printf("Preset%d", p++); + aud_rcfile_write_string(rcfile, "Presets", tmp, preset->name); + g_free(tmp); + aud_rcfile_write_float(rcfile, preset->name, "Preamp", + preset->preamp); + for (i = 0; i < 10; i++) { + tmp = g_strdup_printf("Band%d\n", i); + aud_rcfile_write_float(rcfile, preset->name, tmp, + preset->bands[i]); + g_free(tmp); + } + } + + filename = g_build_filename(aud_paths[BMP_PATH_USER_DIR], basename, NULL); + aud_rcfile_write(rcfile, filename); + aud_rcfile_free(rcfile); + g_free(filename); +} + +static gboolean +equalizerwin_load_preset(GList * list, const gchar * name) +{ + EqualizerPreset *preset; + gint i; + + if ((preset = equalizerwin_find_preset(list, name)) != NULL) { + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, preset->preamp); + for (i = 0; i < 10; i++) + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], preset->bands[i]); + equalizerwin_eq_changed(); + return TRUE; + } + return FALSE; +} + +static GList * +equalizerwin_save_preset(GList * list, const gchar * name, + const gchar * filename) +{ + gint i; + EqualizerPreset *preset; + + if (!(preset = equalizerwin_find_preset(list, name))) { + preset = g_new0(EqualizerPreset, 1); + preset->name = g_strdup(name); + list = g_list_append(list, preset); + } + + preset->preamp = ui_skinned_equalizer_slider_get_position(equalizerwin_preamp); + for (i = 0; i < 10; i++) + preset->bands[i] = ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i]); + + equalizerwin_write_preset_file(list, filename); + + return list; +} + +static GList * +equalizerwin_delete_preset(GList * list, gchar * name, gchar * filename) +{ + EqualizerPreset *preset; + GList *node; + + if (!(preset = equalizerwin_find_preset(list, name))) + return list; + + if (!(node = g_list_find(list, preset))) + return list; + + list = g_list_remove_link(list, node); + equalizer_preset_free(preset); + g_list_free_1(node); + + equalizerwin_write_preset_file(list, filename); + + return list; +} + +static void +equalizerwin_delete_selected_presets(GtkTreeView *view, gchar *filename) +{ + gchar *text; + + GtkTreeSelection *selection = gtk_tree_view_get_selection(view); + GtkTreeModel *model = gtk_tree_view_get_model(view); + + /* + * first we are making a list of the selected rows, then we convert this + * list into a list of GtkTreeRowReferences, so that when you delete an + * item you can still access the other items + * finally we iterate through all GtkTreeRowReferences, convert them to + * GtkTreeIters and delete those one after the other + */ + + GList *list = gtk_tree_selection_get_selected_rows(selection, &model); + GList *rrefs = NULL; + GList *litr; + + for (litr = list; litr; litr = litr->next) + { + GtkTreePath *path = litr->data; + rrefs = g_list_append(rrefs, gtk_tree_row_reference_new(model, path)); + } + + for (litr = rrefs; litr; litr = litr->next) + { + GtkTreeRowReference *ref = litr->data; + GtkTreePath *path = gtk_tree_row_reference_get_path(ref); + GtkTreeIter iter; + gtk_tree_model_get_iter(model, &iter, path); + + gtk_tree_model_get(model, &iter, 0, &text, -1); + + if (!strcmp(filename, "eq.preset")) + equalizer_presets = equalizerwin_delete_preset(equalizer_presets, text, filename); + else if (!strcmp(filename, "eq.auto_preset")) + equalizer_auto_presets = equalizerwin_delete_preset(equalizer_auto_presets, text, filename); + + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + } +} + +static GList * +import_winamp_eqf(VFSFile * file) +{ + gchar header[31]; + gchar bands[11]; + gint i = 0; + EqualizerPreset *preset = NULL; + GList *list = NULL; + GtkWidget *dialog; + gchar *realfn; + gchar preset_name[0xb4]; + + vfs_fread(header, 1, 31, file); + if (strncmp(header, "Winamp EQ library file v1.1", 27)) goto error; + + AUDDBG("The EQF header is OK\n"); + + if (vfs_fseek(file, 0x1f, SEEK_SET) == -1) goto error; + + while (vfs_fread(preset_name, 1, 0xb4, file) == 0xb4) { + AUDDBG("The preset name is '%s'\n", preset_name); + vfs_fseek(file, 0x4d, SEEK_CUR); /* unknown crap --asphyx */ + if (vfs_fread(bands, 1, 11, file) != 11) break; + + preset = equalizer_preset_new(preset_name); + /*this was divided by 63, but shouldn't it be 64? --majeru*/ + preset->preamp = EQUALIZER_MAX_GAIN - ((bands[10] * EQUALIZER_MAX_GAIN * 2) / 64.0); + + for (i = 0; i < 10; i++) + preset->bands[i] = EQUALIZER_MAX_GAIN - ((bands[i] * EQUALIZER_MAX_GAIN * 2) / 64.0); + + list = g_list_prepend(list, preset); + } + + list = g_list_reverse(list); + if (list == NULL) goto error; + + return list; + +error: + realfn = g_filename_from_uri(file->uri, NULL, NULL); + dialog = gtk_message_dialog_new (GTK_WINDOW(mainwin), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error importing Winamp EQF file '%s'"), + realfn); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + g_free(realfn); + return NULL; +} + +static void +free_cb (gpointer data, gpointer user_data) +{ + equalizer_preset_free((EqualizerPreset*)data); +} + +static void +equalizerwin_read_winamp_eqf(VFSFile * file) +{ + GList *presets; + gint i; + + if ((presets = import_winamp_eqf(file)) == NULL) + return; + + /* just get the first preset --asphyx */ + EqualizerPreset *preset = (EqualizerPreset*)presets->data; + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, + preset->preamp); + + for (i = 0; i < 10; i++) + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], + preset->bands[i]); + + g_list_foreach(presets, free_cb, NULL); + g_list_free(presets); + + equalizerwin_eq_changed(); +} + +static void +equalizerwin_read_aud_preset(RcFile * rcfile) +{ + gfloat val; + gint i; + + if (aud_rcfile_read_float(rcfile, "Equalizer preset", "Preamp", &val)) + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, val); + for (i = 0; i < 10; i++) { + gchar tmp[7]; + g_snprintf(tmp, sizeof(tmp), "Band%d", i); + if (aud_rcfile_read_float(rcfile, "Equalizer preset", tmp, &val)) + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], val); + } + equalizerwin_eq_changed(); +} + +static void +equalizerwin_save_ok(GtkWidget * widget, gpointer data) +{ + const gchar *text; + + text = gtk_entry_get_text(GTK_ENTRY(equalizerwin_save_entry)); + if (strlen(text) != 0) + equalizer_presets = + equalizerwin_save_preset(equalizer_presets, text, "eq.preset"); + gtk_widget_destroy(equalizerwin_save_window); +} + +static void +equalizerwin_save_select(GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer data) +{ + gchar *text; + + GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); + GtkTreeModel *model; + GtkTreeIter iter; + + if (selection) + { + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gtk_tree_model_get(model, &iter, 0, &text, -1); + gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_entry), text); + equalizerwin_save_ok(NULL, NULL); + + g_free(text); + } + } +} + +static void +equalizerwin_load_ok(GtkWidget *widget, gpointer data) +{ + gchar *text; + + GtkTreeView* view = GTK_TREE_VIEW(data); + GtkTreeSelection *selection = gtk_tree_view_get_selection(view); + GtkTreeModel *model; + GtkTreeIter iter; + + if (selection) + { + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gtk_tree_model_get(model, &iter, 0, &text, -1); + equalizerwin_load_preset(equalizer_presets, text); + + g_free(text); + } + } + gtk_widget_destroy(equalizerwin_load_window); +} + +static void +equalizerwin_load_select(GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer data) +{ + equalizerwin_load_ok(NULL, treeview); +} + +static void +equalizerwin_delete_delete(GtkWidget *widget, gpointer data) +{ + equalizerwin_delete_selected_presets(GTK_TREE_VIEW(data), "eq.preset"); +} + +static void +equalizerwin_save_auto_ok(GtkWidget *widget, gpointer data) +{ + const gchar *text; + + text = gtk_entry_get_text(GTK_ENTRY(equalizerwin_save_auto_entry)); + if (strlen(text) != 0) + equalizer_auto_presets = + equalizerwin_save_preset(equalizer_auto_presets, text, + "eq.auto_preset"); + gtk_widget_destroy(equalizerwin_save_auto_window); +} + +static void +equalizerwin_save_auto_select(GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer data) +{ + gchar *text; + + GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); + GtkTreeModel *model; + GtkTreeIter iter; + + if (selection) + { + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gtk_tree_model_get(model, &iter, 0, &text, -1); + gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_auto_entry), text); + equalizerwin_save_auto_ok(NULL, NULL); + + g_free(text); + } + } +} + +static void +equalizerwin_load_auto_ok(GtkWidget *widget, gpointer data) +{ + gchar *text; + + GtkTreeView *view = GTK_TREE_VIEW(data); + GtkTreeSelection *selection = gtk_tree_view_get_selection(view); + GtkTreeModel *model; + GtkTreeIter iter; + + if (selection) + { + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gtk_tree_model_get(model, &iter, 0, &text, -1); + equalizerwin_load_preset(equalizer_auto_presets, text); + + g_free(text); + } + } + gtk_widget_destroy(equalizerwin_load_auto_window); +} + +static void +equalizerwin_load_auto_select(GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer data) +{ + equalizerwin_load_auto_ok(NULL, treeview); +} + +static void +equalizerwin_delete_auto_delete(GtkWidget *widget, gpointer data) +{ + equalizerwin_delete_selected_presets(GTK_TREE_VIEW(data), "eq.auto_preset"); +} + + +static void +load_preset_file(const gchar *filename) +{ + RcFile *rcfile; + + if ((rcfile = aud_rcfile_open(filename)) != NULL) { + equalizerwin_read_aud_preset(rcfile); + aud_rcfile_free(rcfile); + } +} + +static VFSFile * +open_vfs_file(const gchar *filename, const gchar *mode) +{ + VFSFile *file; + GtkWidget *dialog; + + if (!(file = vfs_fopen(filename, mode))) { + dialog = gtk_message_dialog_new (GTK_WINDOW (mainwin), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "Error loading file '%s'", + filename); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + + return file; +} + +static void +load_winamp_file(const gchar * filename) +{ + VFSFile *file; + + if (!(file = open_vfs_file(filename, "rb"))) + return; + + equalizerwin_read_winamp_eqf(file); + vfs_fclose(file); +} + +static void +import_winamp_file(const gchar * filename) +{ + VFSFile *file; + GList *list; + + if (!(file = open_vfs_file(filename, "rb")) || + !(list = import_winamp_eqf(file))) + return; + + equalizer_presets = g_list_concat(equalizer_presets, list); + equalizerwin_write_preset_file(equalizer_presets, "eq.preset"); + + vfs_fclose(file); +} + +static void +save_preset_file(const gchar * filename) +{ + RcFile *rcfile; + gint i; + + rcfile = aud_rcfile_new(); + aud_rcfile_write_float(rcfile, "Equalizer preset", "Preamp", + ui_skinned_equalizer_slider_get_position(equalizerwin_preamp)); + + for (i = 0; i < 10; i++) { + gchar tmp[7]; + g_snprintf(tmp, sizeof(tmp), "Band%d", i); + aud_rcfile_write_float(rcfile, "Equalizer preset", tmp, + ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i])); + } + + aud_rcfile_write(rcfile, filename); + aud_rcfile_free(rcfile); +} + +static void +save_winamp_file(const gchar * filename) +{ + VFSFile *file; + + gchar name[257]; + gint i; + guchar bands[11]; + + if (!(file = open_vfs_file(filename, "wb"))) + return; + + vfs_fwrite("Winamp EQ library file v1.1\x1a!--", 1, 31, file); + + memset(name, 0, 257); + g_strlcpy(name, "Entry1", 257); + vfs_fwrite(name, 1, 257, file); + + for (i = 0; i < 10; i++) + bands[i] = 63 - (((ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i]) + EQUALIZER_MAX_GAIN) * 63) / EQUALIZER_MAX_GAIN / 2); + bands[10] = 63 - (((ui_skinned_equalizer_slider_get_position(equalizerwin_preamp) + EQUALIZER_MAX_GAIN) * 63) / EQUALIZER_MAX_GAIN / 2); + vfs_fwrite(bands, 1, 11, file); + + vfs_fclose(file); +} + +static GtkWidget * +equalizerwin_create_list_window(GList *preset_list, + const gchar *title, + GtkWidget **window, + GtkSelectionMode sel_mode, + GtkWidget **entry, + const gchar *action_name, + GCallback action_func, + GCallback select_row_func) +{ + GtkWidget *vbox, *scrolled_window, *bbox, *view; + GtkWidget *button_cancel, *button_action; + GList *node; + + GtkListStore *store; + GtkTreeIter iter; + GtkTreeModel *model; + GtkCellRenderer *renderer; + GtkTreeSelection *selection; + GtkTreeSortable *sortable; + + + + *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(*window), title); + gtk_window_set_type_hint(GTK_WINDOW(*window), GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_window_set_default_size(GTK_WINDOW(*window), 350, 300); + gtk_window_set_position(GTK_WINDOW(*window), GTK_WIN_POS_CENTER); + gtk_container_set_border_width(GTK_CONTAINER(*window), 10); + gtk_window_set_transient_for(GTK_WINDOW(*window), + GTK_WINDOW(equalizerwin)); + g_signal_connect(*window, "destroy", + G_CALLBACK(gtk_widget_destroyed), window); + + vbox = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(*window), vbox); + + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + + + /* fill the store with the names of all available presets */ + store = gtk_list_store_new(1, G_TYPE_STRING); + for (node = preset_list; node; node = g_list_next(node)) + { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, ((EqualizerPreset*)node->data)->name, + -1); + } + model = GTK_TREE_MODEL(store); + + + sortable = GTK_TREE_SORTABLE(store); + gtk_tree_sortable_set_sort_column_id(sortable, 0, GTK_SORT_ASCENDING); + + + view = gtk_tree_view_new(); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, + _("Presets"), renderer, + "text", 0, NULL); + gtk_tree_view_set_model(GTK_TREE_VIEW(view), model); + g_object_unref(model); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + gtk_tree_selection_set_mode(selection, sel_mode); + + + + + gtk_container_add(GTK_CONTAINER(scrolled_window), view); + gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0); + + if (entry) { + *entry = gtk_entry_new(); + g_signal_connect(*entry, "activate", action_func, NULL); + gtk_box_pack_start(GTK_BOX(vbox), *entry, 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), 5); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + button_cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + g_signal_connect_swapped(button_cancel, "clicked", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(*window)); + gtk_box_pack_start(GTK_BOX(bbox), button_cancel, TRUE, TRUE, 0); + + button_action = gtk_button_new_from_stock(action_name); + g_signal_connect(button_action, "clicked", G_CALLBACK(action_func), view); + GTK_WIDGET_SET_FLAGS(button_action, GTK_CAN_DEFAULT); + + if (select_row_func) + g_signal_connect(view, "row-activated", G_CALLBACK(select_row_func), NULL); + + + gtk_box_pack_start(GTK_BOX(bbox), button_action, TRUE, TRUE, 0); + + gtk_widget_grab_default(button_action); + + + gtk_widget_show_all(*window); + + return *window; +} + +void +equalizerwin_load_auto_preset(const gchar * filename) +{ + gchar *presetfilename, *directory; + RcFile *rcfile; + + g_return_if_fail(filename != NULL); + + if (!cfg.equalizer_autoload) + return; + + presetfilename = g_strconcat(filename, ".", cfg.eqpreset_extension, NULL); + + /* First try to find a per file preset file */ + if (strlen(cfg.eqpreset_extension) > 0 && + (rcfile = aud_rcfile_open(presetfilename)) != NULL) { + g_free(presetfilename); + equalizerwin_read_aud_preset(rcfile); + aud_rcfile_free(rcfile); + return; + } + + g_free(presetfilename); + + directory = g_path_get_dirname(filename); + presetfilename = g_build_filename(directory, cfg.eqpreset_default_file, + NULL); + g_free(directory); + + /* Try to find a per directory preset file */ + if (strlen(cfg.eqpreset_default_file) > 0 && + (rcfile = aud_rcfile_open(presetfilename)) != NULL) { + equalizerwin_read_aud_preset(rcfile); + aud_rcfile_free(rcfile); + } + else if (!equalizerwin_load_preset + (equalizer_auto_presets, g_basename(filename))) { + /* Fall back to the oldstyle auto presets */ + equalizerwin_load_preset(equalizer_presets, "Default"); + } + + g_free(presetfilename); +} + +void +equalizerwin_set_preamp(gfloat preamp) +{ + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, preamp); + equalizerwin_eq_changed(); +} + +void +equalizerwin_set_band(gint band, gfloat value) +{ + g_return_if_fail(band >= 0 && band < 10); + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[band], value); +} + +gfloat +equalizerwin_get_preamp(void) +{ + return ui_skinned_equalizer_slider_get_position(equalizerwin_preamp); +} + +gfloat +equalizerwin_get_band(gint band) +{ + g_return_val_if_fail(band >= 0 && band < 10, 0.0); + return ui_skinned_equalizer_slider_get_position(equalizerwin_bands[band]); +} + +void +action_equ_load_preset(void) +{ + if (equalizerwin_load_window) { + gtk_window_present(GTK_WINDOW(equalizerwin_load_window)); + return; + } + + equalizerwin_create_list_window(equalizer_presets, + Q_("Load preset"), + &equalizerwin_load_window, + GTK_SELECTION_SINGLE, NULL, + GTK_STOCK_OK, + G_CALLBACK(equalizerwin_load_ok), + G_CALLBACK(equalizerwin_load_select)); +} + +void +action_equ_load_auto_preset(void) +{ + if (equalizerwin_load_auto_window) { + gtk_window_present(GTK_WINDOW(equalizerwin_load_auto_window)); + return; + } + + equalizerwin_create_list_window(equalizer_auto_presets, + Q_("Load auto-preset"), + &equalizerwin_load_auto_window, + GTK_SELECTION_SINGLE, NULL, + GTK_STOCK_OK, + G_CALLBACK(equalizerwin_load_auto_ok), + G_CALLBACK(equalizerwin_load_auto_select)); +} + +void +action_equ_load_default_preset(void) +{ + equalizerwin_load_preset(equalizer_presets, "Default"); +} + +void +action_equ_zero_preset(void) +{ + gint i; + + ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, 0); + for (i = 0; i < 10; i++) + ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], 0); + + equalizerwin_eq_changed(); +} + +void +action_equ_load_preset_file(void) +{ + GtkWidget *dialog; + gchar *file_uri; + + dialog = make_filebrowser(Q_("Load equalizer preset"), FALSE); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); + load_preset_file(file_uri); + g_free(file_uri); + } + gtk_widget_destroy(dialog); +} + +void +action_equ_load_preset_eqf(void) +{ + GtkWidget *dialog; + gchar *file_uri; + + dialog = make_filebrowser(Q_("Load equalizer preset"), FALSE); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); + load_winamp_file(file_uri); + g_free(file_uri); + } + gtk_widget_destroy(dialog); +} + +void +action_equ_import_winamp_presets(void) +{ + GtkWidget *dialog; + gchar *file_uri; + + dialog = make_filebrowser(Q_("Load equalizer preset"), FALSE); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); + import_winamp_file(file_uri); + g_free(file_uri); + } + gtk_widget_destroy(dialog); +} + +void +action_equ_save_preset(void) +{ + if (equalizerwin_save_window) { + gtk_window_present(GTK_WINDOW(equalizerwin_save_window)); + return; + } + + equalizerwin_create_list_window(equalizer_presets, + Q_("Save preset"), + &equalizerwin_save_window, + GTK_SELECTION_SINGLE, + &equalizerwin_save_entry, + GTK_STOCK_OK, + G_CALLBACK(equalizerwin_save_ok), + G_CALLBACK(equalizerwin_save_select)); +} + +void +action_equ_save_auto_preset(void) +{ + gchar *name; + Playlist *playlist = playlist_get_active(); + + if (equalizerwin_save_auto_window) + gtk_window_present(GTK_WINDOW(equalizerwin_save_auto_window)); + else + equalizerwin_create_list_window(equalizer_auto_presets, + Q_("Save auto-preset"), + &equalizerwin_save_auto_window, + GTK_SELECTION_SINGLE, + &equalizerwin_save_auto_entry, + GTK_STOCK_OK, + G_CALLBACK(equalizerwin_save_auto_ok), + G_CALLBACK(equalizerwin_save_auto_select)); + + name = playlist_get_filename(playlist, playlist_get_position(playlist)); + if (name) { + gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_auto_entry), + g_basename(name)); + g_free(name); + } +} + +void +action_equ_save_default_preset(void) +{ + equalizer_presets = + equalizerwin_save_preset(equalizer_presets, Q_("Default"), "eq.preset"); +} + +void +action_equ_save_preset_file(void) +{ + GtkWidget *dialog; + gchar *file_uri; + gchar *songname; + Playlist *playlist = playlist_get_active(); + + dialog = make_filebrowser(Q_("Save equalizer preset"), TRUE); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); + save_preset_file(file_uri); + g_free(file_uri); + } + + songname = playlist_get_filename(playlist, playlist_get_position(playlist)); + if (songname) { + gchar *eqname = g_strdup_printf("%s.%s", songname, + cfg.eqpreset_extension); + g_free(songname); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), + eqname); + g_free(eqname); + } + + gtk_widget_destroy(dialog); +} + +void +action_equ_save_preset_eqf(void) +{ + GtkWidget *dialog; + gchar *file_uri; + + dialog = make_filebrowser(Q_("Save equalizer preset"), TRUE); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); + save_winamp_file(file_uri); + g_free(file_uri); + } + gtk_widget_destroy(dialog); +} + +void +action_equ_delete_preset(void) +{ + if (equalizerwin_delete_window) { + gtk_window_present(GTK_WINDOW(equalizerwin_delete_window)); + return; + } + + equalizerwin_create_list_window(equalizer_presets, + Q_("Delete preset"), + &equalizerwin_delete_window, + GTK_SELECTION_EXTENDED, NULL, + GTK_STOCK_DELETE, + G_CALLBACK(equalizerwin_delete_delete), + NULL); +} + +void +action_equ_delete_auto_preset(void) +{ + if (equalizerwin_delete_auto_window) { + gtk_window_present(GTK_WINDOW(equalizerwin_delete_auto_window)); + return; + } + + equalizerwin_create_list_window(equalizer_auto_presets, + Q_("Delete auto-preset"), + &equalizerwin_delete_auto_window, + GTK_SELECTION_EXTENDED, NULL, + GTK_STOCK_DELETE, + G_CALLBACK(equalizerwin_delete_auto_delete), + NULL); +} + +void +equalizer_activate(gboolean active) +{ + cfg.equalizer_active = active; + UI_SKINNED_BUTTON(equalizerwin_on)->inside = active; + gtk_widget_queue_draw(equalizerwin_on); + + equalizerwin_eq_changed(); +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_equalizer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_equalizer.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,68 @@ +/* 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_EQUALIZER_H +#define AUDACIOUS_UI_EQUALIZER_H + +#include +#include + +#define EQUALIZER_SCALED (cfg.scaled && cfg.eq_scaled_linked) +#define EQUALIZER_SCALE_FACTOR (EQUALIZER_SCALED ? cfg.scale_factor : 1) + +#define EQUALIZER_HEIGHT ((cfg.equalizer_shaded ? 14 : 116) * (EQUALIZER_SCALE_FACTOR)) +#define EQUALIZER_WIDTH (275 * EQUALIZER_SCALE_FACTOR) + +#define EQUALIZER_DEFAULT_POS_X 20 +#define EQUALIZER_DEFAULT_POS_Y 136 + +#define EQUALIZER_DEFAULT_DIR_PRESET "dir_default.preset" +#define EQUALIZER_DEFAULT_PRESET_EXT "preset" + +void equalizerwin_set_scaled(gboolean ds); +void equalizerwin_set_shade_menu_cb(gboolean shaded); +void draw_equalizer_window(gboolean force); +void equalizerwin_create(void); +void equalizerwin_show(gboolean show); +void equalizerwin_real_show(void); +void equalizerwin_real_hide(void); +void equalizerwin_load_auto_preset(const gchar * filename); +void equalizerwin_set_volume_slider(gint percent); +void equalizerwin_set_balance_slider(gint percent); +void equalizerwin_eq_changed(void); +void equalizerwin_set_preamp(gfloat preamp); +void equalizerwin_set_band(gint band, gfloat value); +gfloat equalizerwin_get_preamp(void); +gfloat equalizerwin_get_band(gint band); + +gboolean equalizerwin_has_focus(void); + +extern GtkWidget *equalizerwin; +extern GtkWidget *equalizerwin_graph; +extern gboolean equalizerwin_focus; + +void equalizer_activate(gboolean active); + +#endif /* AUDACIOUS_UI_EQUALIZER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_fileinfo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_fileinfo.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,1019 @@ +/* + * 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_fileinfo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_fileinfo.h Sun Jul 06 17:55:40 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_hints.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_hints.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,59 @@ +/* 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. + */ + +#include "ui_hints.h" + +#include +#include + +#include "ui_equalizer.h" +#include "ui_main.h" +#include "ui_playlist.h" + +#include "platform/smartinclude.h" + +void +hint_set_always(gboolean always) +{ + gtk_window_set_keep_above(GTK_WINDOW(mainwin), always); + gtk_window_set_keep_above(GTK_WINDOW(equalizerwin), always); + gtk_window_set_keep_above(GTK_WINDOW(playlistwin), always); +} + +void +hint_set_sticky(gboolean sticky) +{ + if (sticky) { + gtk_window_stick(GTK_WINDOW(mainwin)); + gtk_window_stick(GTK_WINDOW(equalizerwin)); + gtk_window_stick(GTK_WINDOW(playlistwin)); + } + else { + gtk_window_unstick(GTK_WINDOW(mainwin)); + gtk_window_unstick(GTK_WINDOW(equalizerwin)); + gtk_window_unstick(GTK_WINDOW(playlistwin)); + } +} + diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_hints.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_hints.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,35 @@ +/* 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_HINTS_H +#define AUDACIOUS_UI_HINTS_H + +#include +#include + +void hint_set_always(gboolean always); +void hint_set_sticky(gboolean sticky); + +#endif /* AUDACIOUS_UI_HINTS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_jumptotrack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_jumptotrack.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,623 @@ +/* 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_jumptotrack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_jumptotrack.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,33 @@ +/* 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. + */ + +#ifndef AUDACIOUS_UI_JUMPTOTRACK_H +#define AUDACIOUS_UI_JUMPTOTRACK_H + +extern void ui_jump_to_track_update(GtkWidget * widget, gpointer user_data); +extern void ui_jump_to_track(void); +extern void ui_jump_to_track_hide(void); + +#endif /* AUDACIOUS_UI_JUMPTOTRACK_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_jumptotrack_cache.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_jumptotrack_cache.c Sun Jul 06 17:55:40 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_jumptotrack_cache.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_jumptotrack_cache.h Sun Jul 06 17:55:40 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_main.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,2850 @@ +/* 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 +#include +#include +#include +#include + +/* GDK including */ +#include "platform/smartinclude.h" + +#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 "configdb.h" +#include "dnd.h" +#include "input.h" +#include "main.h" +#include "playback.h" +#include "playlist.h" +#include "pluginenum.h" +#include "strings.h" +#include "ui_credits.h" +#include "ui_dock.h" +#include "ui_equalizer.h" +#include "ui_fileinfo.h" +#include "ui_fileopener.h" +#include "ui_hints.h" +#include "ui_jumptotrack.h" +#include "ui_main_evlisteners.h" +#include "ui_manager.h" +#include "ui_playlist.h" +#include "ui_preferences.h" +#include "ui_skinselector.h" +#include "ui_urlopener.h" +#include "util.h" +#include "visualization.h" + +#include "ui_skinned_window.h" +#include "ui_skinned_button.h" +#include "ui_skinned_textbox.h" +#include "ui_skinned_number.h" +#include "ui_skinned_horizontal_slider.h" +#include "ui_skinned_menurow.h" +#include "ui_skinned_playstatus.h" +#include "ui_skinned_monostereo.h" +#include "ui_skinned_playlist.h" + +static GTimeVal cb_time; +static const int TRISTATE_THRESHOLD = 200; + +enum { + MAINWIN_SEEK_REV = -1, + MAINWIN_SEEK_NIL, + MAINWIN_SEEK_FWD +}; + +GtkWidget *mainwin = NULL; + +static gint balance; + +static GtkWidget *mainwin_jtt = NULL; + +static gint seek_state = MAINWIN_SEEK_NIL; +static gint seek_initial_pos = 0; + +static GtkWidget *mainwin_menubtn; +static GtkWidget *mainwin_minimize, *mainwin_shade, *mainwin_close; + +static GtkWidget *mainwin_rew, *mainwin_fwd; +static GtkWidget *mainwin_eject; +static GtkWidget *mainwin_play, *mainwin_pause, *mainwin_stop; + +static GtkWidget *mainwin_shuffle, *mainwin_repeat; +GtkWidget *mainwin_eq, *mainwin_pl; + +GtkWidget *mainwin_info; +GtkWidget *mainwin_stime_min, *mainwin_stime_sec; + +static GtkWidget *mainwin_rate_text, *mainwin_freq_text, *mainwin_othertext; + +GtkWidget *mainwin_playstatus; + +GtkWidget *mainwin_minus_num, *mainwin_10min_num, *mainwin_min_num; +GtkWidget *mainwin_10sec_num, *mainwin_sec_num; + +GtkWidget *mainwin_vis; +GtkWidget *mainwin_svis; + +GtkWidget *mainwin_sposition = NULL; + +static GtkWidget *mainwin_menurow; +static GtkWidget *mainwin_volume, *mainwin_balance; +GtkWidget *mainwin_position; + +static GtkWidget *mainwin_monostereo; +static GtkWidget *mainwin_srew, *mainwin_splay, *mainwin_spause; +static GtkWidget *mainwin_sstop, *mainwin_sfwd, *mainwin_seject, *mainwin_about; + +static gint mainwin_timeout_id; + +static gboolean mainwin_info_text_locked = FALSE; +static guint mainwin_volume_release_timeout = 0; + +static int ab_position_a = -1; +static int ab_position_b = -1; + +static void mainwin_refresh_visible(void); +static gint mainwin_idle_func(gpointer data); + +static void set_timer_mode_menu_cb(TimerMode mode); +static void set_timer_mode(TimerMode mode); +static void change_timer_mode(void); + +static void mainwin_position_motion_cb(GtkWidget *widget, gint pos); +static void mainwin_position_release_cb(GtkWidget *widget, gint pos); + +static void set_scaled(gboolean scaled); +static void mainwin_eq_pushed(gboolean toggled); +static void mainwin_pl_pushed(gboolean toggled); + +static void +mainwin_set_title_scroll(gboolean scroll) +{ + cfg.autoscroll = scroll; + ui_skinned_textbox_set_scroll(mainwin_info, cfg.autoscroll); +} + + +void +mainwin_set_always_on_top(gboolean always) +{ + GtkAction *action = gtk_action_group_get_action(toggleaction_group_others, + "view always on top"); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , always ); +} + +static void +mainwin_set_shade(gboolean shaded) +{ + GtkAction *action = gtk_action_group_get_action(toggleaction_group_others, + "roll up player"); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , shaded ); +} + +static void +mainwin_set_shade_menu_cb(gboolean shaded) +{ + cfg.player_shaded = shaded; + + if (shaded) { + dock_shade(get_dock_window_list(), GTK_WINDOW(mainwin), + MAINWIN_SHADED_HEIGHT * MAINWIN_SCALE_FACTOR); + } else { + gint height = !aud_active_skin->properties.mainwin_height ? MAINWIN_HEIGHT : + aud_active_skin->properties.mainwin_height; + + dock_shade(get_dock_window_list(), GTK_WINDOW(mainwin), height * MAINWIN_SCALE_FACTOR); + } + + mainwin_refresh_hints(); + ui_skinned_set_push_button_data(mainwin_shade, 0, cfg.player_shaded ? 27 : 18, 9, cfg.player_shaded ? 27 : 18); + gtk_widget_shape_combine_mask(mainwin, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + cfg.player_shaded), 0, 0); +} + +static void +mainwin_vis_set_refresh(RefreshRate rate) +{ + cfg.vis_refresh = rate; +} + +static void +mainwin_vis_set_afalloff(FalloffSpeed speed) +{ + cfg.analyzer_falloff = speed; +} + +static void +mainwin_vis_set_pfalloff(FalloffSpeed speed) +{ + cfg.peaks_falloff = speed; +} + +static void +mainwin_vis_set_analyzer_mode(AnalyzerMode mode) +{ + cfg.analyzer_mode = mode; +} + +static void +mainwin_vis_set_analyzer_type(AnalyzerType mode) +{ + cfg.analyzer_type = mode; +} + +void +mainwin_vis_set_type(VisType mode) +{ + GtkAction *action; + + switch ( mode ) + { + case VIS_ANALYZER: + action = gtk_action_group_get_action(radioaction_group_vismode, + "vismode analyzer"); + break; + case VIS_SCOPE: + action = gtk_action_group_get_action(radioaction_group_vismode, + "vismode scope"); + break; + case VIS_VOICEPRINT: + action = gtk_action_group_get_action(radioaction_group_vismode, + "vismode voiceprint"); + break; + case VIS_OFF: + default: + action = gtk_action_group_get_action(radioaction_group_vismode, + "vismode off"); + break; + } + + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , TRUE ); +} + +static void +mainwin_vis_set_type_menu_cb(VisType mode) +{ + cfg.vis_type = mode; + + if (mode == VIS_OFF) { + if (cfg.player_shaded) { + ui_svis_set_visible(mainwin_svis, FALSE); + ui_vis_set_visible(mainwin_vis, TRUE); + } else { + ui_svis_set_visible(mainwin_svis, TRUE); + ui_vis_set_visible(mainwin_vis, FALSE); + } + } + if (mode == VIS_ANALYZER || mode == VIS_SCOPE || mode == VIS_VOICEPRINT) { + if (cfg.player_shaded) { + ui_svis_clear_data(mainwin_svis); + ui_svis_set_visible(mainwin_svis, TRUE); + ui_vis_clear_data(mainwin_vis); + ui_vis_set_visible(mainwin_vis, FALSE); + } else { + ui_svis_clear_data(mainwin_svis); + ui_svis_set_visible(mainwin_svis, FALSE); + ui_vis_clear_data(mainwin_vis); + ui_vis_set_visible(mainwin_vis, TRUE); + } + } +} + +static void +mainwin_menubtn_cb(void) +{ + gint x, y; + gtk_window_get_position(GTK_WINDOW(mainwin), &x, &y); + ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), + x + 6 * MAINWIN_SCALE_FACTOR , + y + MAINWIN_SHADED_HEIGHT * MAINWIN_SCALE_FACTOR, + 1, GDK_CURRENT_TIME); +} + +void +mainwin_minimize_cb(void) +{ + if (!mainwin) + return; + + gtk_window_iconify(GTK_WINDOW(mainwin)); +} + +static void +mainwin_shade_toggle(void) +{ + mainwin_set_shade(!cfg.player_shaded); +} + +void +mainwin_quit_cb(void) +{ + if (mainwin_timeout_id) + g_source_remove(mainwin_timeout_id); + + aud_quit(); +} + +gboolean +mainwin_vis_cb(GtkWidget *widget, GdkEventButton *event) +{ + if (event->button == 1) { + cfg.vis_type++; + + if (cfg.vis_type > VIS_OFF) + cfg.vis_type = VIS_ANALYZER; + + mainwin_vis_set_type(cfg.vis_type); + } else if (event->button == 3) { + ui_manager_popup_menu_show(GTK_MENU(mainwin_visualization_menu), + event->x_root, event->y_root, 3, + event->time); + } + return TRUE; +} + +static void +mainwin_destroy(GtkWidget * widget, gpointer data) +{ + mainwin_quit_cb(); +} + +static gchar *mainwin_tb_old_text = NULL; + +void +mainwin_lock_info_text(const gchar * text) +{ + if (mainwin_info_text_locked != TRUE) + mainwin_tb_old_text = g_strdup(aud_active_skin->properties.mainwin_othertext_is_status ? + UI_SKINNED_TEXTBOX(mainwin_othertext)->text : UI_SKINNED_TEXTBOX(mainwin_info)->text); + + mainwin_info_text_locked = TRUE; + if (aud_active_skin->properties.mainwin_othertext_is_status) + ui_skinned_textbox_set_text(mainwin_othertext, text); + else + ui_skinned_textbox_set_text(mainwin_info, text); +} + +void +mainwin_release_info_text(void) +{ + mainwin_info_text_locked = FALSE; + + if (mainwin_tb_old_text != NULL) + { + if (aud_active_skin->properties.mainwin_othertext_is_status) + ui_skinned_textbox_set_text(mainwin_othertext, mainwin_tb_old_text); + else + ui_skinned_textbox_set_text(mainwin_info, mainwin_tb_old_text); + g_free(mainwin_tb_old_text); + mainwin_tb_old_text = NULL; + } +} + + +static gchar * +make_mainwin_title(const gchar * title) +{ + if (title) + return g_strdup_printf(_("%s - Audacious"), title); + else + return g_strdup(_("Audacious")); +} + +void +mainwin_set_song_title(const gchar * title) +{ + gchar *mainwin_title_text = make_mainwin_title(title); + gtk_window_set_title(GTK_WINDOW(mainwin), mainwin_title_text); + g_free(mainwin_title_text); +} + +static void +mainwin_refresh_visible(void) +{ + if (!aud_active_skin || !cfg.player_visible) + return; + + gtk_widget_show_all(mainwin); + + if (!aud_active_skin->properties.mainwin_text_visible) + gtk_widget_hide(mainwin_info); + + if (!aud_active_skin->properties.mainwin_vis_visible) + gtk_widget_hide(mainwin_vis); + + if (!aud_active_skin->properties.mainwin_menurow_visible) + gtk_widget_hide(mainwin_menurow); + + if (aud_active_skin->properties.mainwin_othertext) { + gtk_widget_hide(mainwin_rate_text); + gtk_widget_hide(mainwin_freq_text); + gtk_widget_hide(mainwin_monostereo); + + if (!aud_active_skin->properties.mainwin_othertext_visible) + gtk_widget_hide(mainwin_othertext); + } else { + gtk_widget_hide(mainwin_othertext); + } + + if (!aud_active_skin->properties.mainwin_vis_visible) + gtk_widget_hide(mainwin_vis); + + if (!playback_get_playing()) { + gtk_widget_hide(mainwin_minus_num); + gtk_widget_hide(mainwin_10min_num); + gtk_widget_hide(mainwin_min_num); + gtk_widget_hide(mainwin_10sec_num); + gtk_widget_hide(mainwin_sec_num); + + gtk_widget_hide(mainwin_stime_min); + gtk_widget_hide(mainwin_stime_sec); + + gtk_widget_hide(mainwin_position); + gtk_widget_hide(mainwin_sposition); + } + + if (cfg.player_shaded) { + ui_svis_clear_data(mainwin_svis); + if (cfg.vis_type != VIS_OFF) + ui_svis_set_visible(mainwin_svis, TRUE); + else + ui_svis_set_visible(mainwin_svis, FALSE); + + ui_skinned_textbox_set_scroll(mainwin_info, FALSE); + if (!playback_get_playing()) { + gtk_widget_hide(mainwin_sposition); + gtk_widget_hide(mainwin_stime_min); + gtk_widget_hide(mainwin_stime_sec); + } + } else { + gtk_widget_hide(mainwin_srew); + gtk_widget_hide(mainwin_splay); + gtk_widget_hide(mainwin_spause); + gtk_widget_hide(mainwin_sstop); + gtk_widget_hide(mainwin_sfwd); + gtk_widget_hide(mainwin_seject); + gtk_widget_hide(mainwin_stime_min); + gtk_widget_hide(mainwin_stime_sec); + gtk_widget_hide(mainwin_svis); + gtk_widget_hide(mainwin_sposition); + ui_vis_clear_data(mainwin_vis); + if (cfg.vis_type != VIS_OFF) + ui_vis_set_visible(mainwin_vis, TRUE); + else + ui_vis_set_visible(mainwin_vis, FALSE); + + ui_skinned_textbox_set_scroll(mainwin_info, cfg.autoscroll); + } +} + +void +mainwin_refresh_hints(void) +{ + /* positioning and size attributes */ + if (aud_active_skin->properties.mainwin_vis_x && aud_active_skin->properties.mainwin_vis_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_vis), aud_active_skin->properties.mainwin_vis_x, + aud_active_skin->properties.mainwin_vis_y); + + if (aud_active_skin->properties.mainwin_vis_width) + gtk_widget_set_size_request(mainwin_vis, aud_active_skin->properties.mainwin_vis_width * MAINWIN_SCALE_FACTOR, + UI_VIS(mainwin_vis)->height* MAINWIN_SCALE_FACTOR); + + if (aud_active_skin->properties.mainwin_text_x && aud_active_skin->properties.mainwin_text_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_info), aud_active_skin->properties.mainwin_text_x, + aud_active_skin->properties.mainwin_text_y); + + if (aud_active_skin->properties.mainwin_text_width) { + UI_SKINNED_TEXTBOX(mainwin_info)->width = aud_active_skin->properties.mainwin_text_width; + gtk_widget_set_size_request(mainwin_info, aud_active_skin->properties.mainwin_text_width * MAINWIN_SCALE_FACTOR, + UI_SKINNED_TEXTBOX(mainwin_info)->height * MAINWIN_SCALE_FACTOR ); + } + + if (aud_active_skin->properties.mainwin_infobar_x && aud_active_skin->properties.mainwin_infobar_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_othertext), aud_active_skin->properties.mainwin_infobar_x, + aud_active_skin->properties.mainwin_infobar_y); + + if (aud_active_skin->properties.mainwin_number_0_x && aud_active_skin->properties.mainwin_number_0_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_minus_num), aud_active_skin->properties.mainwin_number_0_x, + aud_active_skin->properties.mainwin_number_0_y); + + if (aud_active_skin->properties.mainwin_number_1_x && aud_active_skin->properties.mainwin_number_1_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_10min_num), aud_active_skin->properties.mainwin_number_1_x, + aud_active_skin->properties.mainwin_number_1_y); + + if (aud_active_skin->properties.mainwin_number_2_x && aud_active_skin->properties.mainwin_number_2_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_min_num), aud_active_skin->properties.mainwin_number_2_x, + aud_active_skin->properties.mainwin_number_2_y); + + if (aud_active_skin->properties.mainwin_number_3_x && aud_active_skin->properties.mainwin_number_3_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_10sec_num), aud_active_skin->properties.mainwin_number_3_x, + aud_active_skin->properties.mainwin_number_3_y); + + if (aud_active_skin->properties.mainwin_number_4_x && aud_active_skin->properties.mainwin_number_4_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_sec_num), aud_active_skin->properties.mainwin_number_4_x, + aud_active_skin->properties.mainwin_number_4_y); + + if (aud_active_skin->properties.mainwin_playstatus_x && aud_active_skin->properties.mainwin_playstatus_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), mainwin_playstatus, aud_active_skin->properties.mainwin_playstatus_x, + aud_active_skin->properties.mainwin_playstatus_y); + + if (aud_active_skin->properties.mainwin_volume_x && aud_active_skin->properties.mainwin_volume_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_volume), aud_active_skin->properties.mainwin_volume_x, + aud_active_skin->properties.mainwin_volume_y); + + if (aud_active_skin->properties.mainwin_balance_x && aud_active_skin->properties.mainwin_balance_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_balance), aud_active_skin->properties.mainwin_balance_x, + aud_active_skin->properties.mainwin_balance_y); + + if (aud_active_skin->properties.mainwin_position_x && aud_active_skin->properties.mainwin_position_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_position), aud_active_skin->properties.mainwin_position_x, + aud_active_skin->properties.mainwin_position_y); + + if (aud_active_skin->properties.mainwin_previous_x && aud_active_skin->properties.mainwin_previous_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), mainwin_rew, aud_active_skin->properties.mainwin_previous_x, + aud_active_skin->properties.mainwin_previous_y); + + if (aud_active_skin->properties.mainwin_play_x && aud_active_skin->properties.mainwin_play_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_play), aud_active_skin->properties.mainwin_play_x, + aud_active_skin->properties.mainwin_play_y); + + if (aud_active_skin->properties.mainwin_pause_x && aud_active_skin->properties.mainwin_pause_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_pause), aud_active_skin->properties.mainwin_pause_x, + aud_active_skin->properties.mainwin_pause_y); + + if (aud_active_skin->properties.mainwin_stop_x && aud_active_skin->properties.mainwin_stop_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_stop), aud_active_skin->properties.mainwin_stop_x, + aud_active_skin->properties.mainwin_stop_y); + + if (aud_active_skin->properties.mainwin_next_x && aud_active_skin->properties.mainwin_next_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_fwd), aud_active_skin->properties.mainwin_next_x, + aud_active_skin->properties.mainwin_next_y); + + if (aud_active_skin->properties.mainwin_eject_x && aud_active_skin->properties.mainwin_eject_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_eject), aud_active_skin->properties.mainwin_eject_x, + aud_active_skin->properties.mainwin_eject_y); + + if (aud_active_skin->properties.mainwin_eqbutton_x && aud_active_skin->properties.mainwin_eqbutton_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_eq), aud_active_skin->properties.mainwin_eqbutton_x, + aud_active_skin->properties.mainwin_eqbutton_y); + + if (aud_active_skin->properties.mainwin_plbutton_x && aud_active_skin->properties.mainwin_plbutton_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_pl), aud_active_skin->properties.mainwin_plbutton_x, + aud_active_skin->properties.mainwin_plbutton_y); + + if (aud_active_skin->properties.mainwin_shuffle_x && aud_active_skin->properties.mainwin_shuffle_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_shuffle), aud_active_skin->properties.mainwin_shuffle_x, + aud_active_skin->properties.mainwin_shuffle_y); + + if (aud_active_skin->properties.mainwin_repeat_x && aud_active_skin->properties.mainwin_repeat_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_repeat), aud_active_skin->properties.mainwin_repeat_x, + aud_active_skin->properties.mainwin_repeat_y); + + if (aud_active_skin->properties.mainwin_about_x && aud_active_skin->properties.mainwin_about_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_about), aud_active_skin->properties.mainwin_about_x, + aud_active_skin->properties.mainwin_about_y); + + if (aud_active_skin->properties.mainwin_minimize_x && aud_active_skin->properties.mainwin_minimize_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_minimize), cfg.player_shaded ? 244 : aud_active_skin->properties.mainwin_minimize_x, + cfg.player_shaded ? 3 : aud_active_skin->properties.mainwin_minimize_y); + + if (aud_active_skin->properties.mainwin_shade_x && aud_active_skin->properties.mainwin_shade_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_shade), cfg.player_shaded ? 254 : aud_active_skin->properties.mainwin_shade_x, + cfg.player_shaded ? 3 : aud_active_skin->properties.mainwin_shade_y); + + if (aud_active_skin->properties.mainwin_close_x && aud_active_skin->properties.mainwin_close_y) + gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_close), cfg.player_shaded ? 264 : aud_active_skin->properties.mainwin_close_x, + cfg.player_shaded ? 3 : aud_active_skin->properties.mainwin_close_y); + + mainwin_refresh_visible(); + + /* window size, mainwinWidth && mainwinHeight properties */ + if (aud_active_skin->properties.mainwin_height && aud_active_skin->properties.mainwin_width) + { + dock_window_resize(GTK_WINDOW(mainwin), cfg.player_shaded ? MAINWIN_SHADED_WIDTH * MAINWIN_SCALE_FACTOR : aud_active_skin->properties.mainwin_width * MAINWIN_SCALE_FACTOR, + cfg.player_shaded ? MAINWIN_SHADED_HEIGHT * MAINWIN_SCALE_FACTOR : aud_active_skin->properties.mainwin_height * MAINWIN_SCALE_FACTOR, + aud_active_skin->properties.mainwin_width * MAINWIN_SCALE_FACTOR, + aud_active_skin->properties.mainwin_height * MAINWIN_SCALE_FACTOR); + + gdk_flush(); + } +} + +void +mainwin_set_song_info(gint bitrate, + gint frequency, + gint n_channels) +{ + gchar *text; + gchar *title; + Playlist *playlist = playlist_get_active(); + + GDK_THREADS_ENTER(); + if (bitrate != -1) { + bitrate /= 1000; + + if (bitrate < 1000) { + /* Show bitrate in 1000s */ + text = g_strdup_printf("%3d", bitrate); + } + else { + /* Show bitrate in 100,000s */ + text = g_strdup_printf("%2dH", bitrate / 100); + } + ui_skinned_textbox_set_text(mainwin_rate_text, text); + g_free(text); + } + else + ui_skinned_textbox_set_text(mainwin_rate_text, _("VBR")); + + /* Show sampling frequency in kHz */ + text = g_strdup_printf("%2d", frequency / 1000); + ui_skinned_textbox_set_text(mainwin_freq_text, text); + g_free(text); + + ui_skinned_monostereo_set_num_channels(mainwin_monostereo, n_channels); + + if (!playback_get_paused() && mainwin_playstatus != NULL) + ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PLAY); + + if (aud_active_skin && aud_active_skin->properties.mainwin_othertext) + { + if (bitrate != -1) + text = g_strdup_printf("%d kbps, %0.1f kHz, %s", + bitrate, + (gfloat) frequency / 1000, + (n_channels > 1) ? _("stereo") : _("mono")); + else + text = g_strdup_printf("VBR, %0.1f kHz, %s", + (gfloat) frequency / 1000, + (n_channels > 1) ? _("stereo") : _("mono")); + + ui_skinned_textbox_set_text(mainwin_othertext, text); + g_free(text); + } + + title = playlist_get_info_text(playlist); + mainwin_set_song_title(title); + g_free(title); + GDK_THREADS_LEAVE(); +} + +void +mainwin_clear_song_info(void) +{ + if (!mainwin) + return; + + /* clear title */ + mainwin_set_song_title(NULL); + + /* clear sampling parameters */ + playback_set_sample_params(0, 0, 0); + + UI_SKINNED_HORIZONTAL_SLIDER(mainwin_position)->pressed = FALSE; + UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->pressed = FALSE; + + /* clear sampling parameter displays */ + ui_skinned_textbox_set_text(mainwin_rate_text, " "); + ui_skinned_textbox_set_text(mainwin_freq_text, " "); + ui_skinned_monostereo_set_num_channels(mainwin_monostereo, 0); + + if (mainwin_playstatus != NULL) + ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_STOP); + + mainwin_refresh_visible(); + + playlistwin_hide_timer(); + ui_vis_clear_data(mainwin_vis); + ui_svis_clear_data(mainwin_svis); +} + +void +mainwin_disable_seekbar(void) +{ + if (!mainwin) + return; + + gtk_widget_hide(mainwin_position); + gtk_widget_hide(mainwin_sposition); +} + +static gboolean +mainwin_mouse_button_release(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + if (dock_is_moving(GTK_WINDOW(mainwin))) { + dock_move_release(GTK_WINDOW(mainwin)); + } + + return FALSE; +} + +void +mainwin_scrolled(GtkWidget *widget, GdkEventScroll *event, + gpointer callback_data) +{ + Playlist *playlist = playlist_get_active(); + + switch (event->direction) { + case GDK_SCROLL_UP: + mainwin_set_volume_diff(cfg.mouse_change); + break; + case GDK_SCROLL_DOWN: + mainwin_set_volume_diff(-cfg.mouse_change); + break; + case GDK_SCROLL_LEFT: + if (playlist_get_current_length(playlist) != -1) + playback_seek(CLAMP(playback_get_time() - 1000, + 0, playlist_get_current_length(playlist)) / 1000); + break; + case GDK_SCROLL_RIGHT: + if (playlist_get_current_length(playlist) != -1) + playback_seek(CLAMP(playback_get_time() + 1000, + 0, playlist_get_current_length(playlist)) / 1000); + break; + } +} + +static gboolean +mainwin_widget_contained(GdkEventButton *event, int x, int y, int w, int h) +{ + if ((event->x > x && event->y > y) && + (event->x < x+w && event->y < y+h)) + return TRUE; + + return FALSE; +} + +static gboolean +mainwin_mouse_button_press(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + if (cfg.scaled) { + /* + * A hack to make scaling transparent to callbacks. + * We should make a copy of this data instead of + * tampering with the data we get from gtk+ + */ + event->x /= cfg.scale_factor; + event->y /= cfg.scale_factor; + } + + if (event->button == 1 && event->type == GDK_2BUTTON_PRESS && event->y < 14) { + mainwin_set_shade(!cfg.player_shaded); + if (dock_is_moving(GTK_WINDOW(mainwin))) + dock_move_release(GTK_WINDOW(mainwin)); + return TRUE; + } + + if (event->button == 3) { + /* Pop up playback menu if right clicked over playback-control widgets, + * otherwise popup general menu + */ + if (mainwin_widget_contained(event, aud_active_skin->properties.mainwin_position_x, + aud_active_skin->properties.mainwin_position_y, 248, 10) || + mainwin_widget_contained(event, aud_active_skin->properties.mainwin_previous_x, + aud_active_skin->properties.mainwin_previous_y, 23, 18) || + mainwin_widget_contained(event, aud_active_skin->properties.mainwin_play_x, + aud_active_skin->properties.mainwin_play_y, 23, 18) || + mainwin_widget_contained(event, aud_active_skin->properties.mainwin_pause_x, + aud_active_skin->properties.mainwin_pause_y, 23, 18) || + mainwin_widget_contained(event, aud_active_skin->properties.mainwin_stop_x, + aud_active_skin->properties.mainwin_stop_y, 23, 18) || + mainwin_widget_contained(event, aud_active_skin->properties.mainwin_next_x, + aud_active_skin->properties.mainwin_next_y, 23, 18)) + { + + ui_manager_popup_menu_show(GTK_MENU(mainwin_playback_menu), + event->x_root, + event->y_root, 3, event->time); + } else { + /* + * Pop up the main menu a few pixels down. + * This will avoid that anything is selected + * if one right-clicks to focus the window + * without raising it. + * + ***MD I think the above is stupid, people don't expect this + * + */ + ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), + event->x_root, + event->y_root, 3, event->time); + } + return TRUE; + } + + return FALSE; +} + +static gboolean +mainwin_keypress(GtkWidget * grab_widget, + GdkEventKey * event, + gpointer data) +{ + Playlist *playlist = playlist_get_active(); + + switch (event->keyval) { + + case GDK_Up: + case GDK_KP_Up: + case GDK_KP_8: + mainwin_set_volume_diff(2); + break; + case GDK_Down: + case GDK_KP_Down: + case GDK_KP_2: + mainwin_set_volume_diff(-2); + break; + case GDK_Left: + case GDK_KP_Left: + case GDK_KP_7: + if (playlist_get_current_length(playlist) != -1) + playback_seek(CLAMP + (playback_get_time() - 5000, 0, + playlist_get_current_length(playlist)) / 1000); + break; + case GDK_Right: + case GDK_KP_Right: + case GDK_KP_9: + if (playlist_get_current_length(playlist) != -1) + playback_seek(CLAMP + (playback_get_time() + 5000, 0, + playlist_get_current_length(playlist)) / 1000); + break; + case GDK_KP_4: + playlist_prev(playlist); + break; + case GDK_KP_6: + playlist_next(playlist); + break; + case GDK_KP_Insert: + ui_jump_to_track(); + break; + case GDK_Return: + case GDK_KP_Enter: + case GDK_KP_5: + mainwin_play_pushed(); + break; + case GDK_space: + playback_pause(); + break; + case GDK_Escape: + mainwin_minimize_cb(); + break; + case GDK_Tab: + if (event->state & GDK_CONTROL_MASK) { + if (cfg.equalizer_visible) + gtk_window_present(GTK_WINDOW(equalizerwin)); + else if (cfg.playlist_visible) + gtk_window_present(GTK_WINDOW(playlistwin)); + } + break; + case GDK_c: + if (event->state & GDK_CONTROL_MASK) { + Playlist *playlist = playlist_get_active(); + gint pos = playlist_get_position(playlist); + gchar *title = playlist_get_songtitle(playlist, pos); + + if (title != NULL) { + GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_text(clip, title, -1); + gtk_clipboard_store(clip); + } + + return TRUE; + } + return FALSE; + default: + return FALSE; + } + + return TRUE; +} + +static void +mainwin_jump_to_time_cb(GtkWidget * widget, + GtkWidget * entry) +{ + guint min = 0, sec = 0, params; + gint time; + Playlist *playlist = playlist_get_active(); + + params = sscanf(gtk_entry_get_text(GTK_ENTRY(entry)), "%u:%u", + &min, &sec); + if (params == 2) + time = (min * 60) + sec; + else if (params == 1) + time = min; + else + return; + + if (playlist_get_current_length(playlist) > -1 && + time <= (playlist_get_current_length(playlist) / 1000)) + { + playback_seek(time); + gtk_widget_destroy(mainwin_jtt); + } +} + + +void +mainwin_jump_to_time(void) +{ + GtkWidget *vbox, *hbox_new, *hbox_total; + GtkWidget *time_entry, *label, *bbox, *jump, *cancel; + GtkWidget *dialog; + guint tindex; + gchar time_str[10]; + + if (!playback_get_playing()) { + dialog = + gtk_message_dialog_new (GTK_WINDOW (mainwin), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Can't jump to time when no track is being played.\n")); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + return; + } + + if (mainwin_jtt) { + gtk_window_present(GTK_WINDOW(mainwin_jtt)); + return; + } + + mainwin_jtt = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_type_hint(GTK_WINDOW(mainwin_jtt), + GDK_WINDOW_TYPE_HINT_DIALOG); + + gtk_window_set_title(GTK_WINDOW(mainwin_jtt), _("Jump to Time")); + gtk_window_set_position(GTK_WINDOW(mainwin_jtt), GTK_WIN_POS_CENTER); + gtk_window_set_transient_for(GTK_WINDOW(mainwin_jtt), + GTK_WINDOW(mainwin)); + + g_signal_connect(mainwin_jtt, "destroy", + G_CALLBACK(gtk_widget_destroyed), &mainwin_jtt); + gtk_container_border_width(GTK_CONTAINER(mainwin_jtt), 10); + + vbox = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(mainwin_jtt), vbox); + + hbox_new = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox_new, TRUE, TRUE, 5); + + time_entry = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox_new), time_entry, FALSE, FALSE, 5); + g_signal_connect(time_entry, "activate", + G_CALLBACK(mainwin_jump_to_time_cb), time_entry); + + gtk_widget_set_size_request(time_entry, 70, -1); + label = gtk_label_new(_("minutes:seconds")); + gtk_box_pack_start(GTK_BOX(hbox_new), label, FALSE, FALSE, 5); + + hbox_total = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox_total, TRUE, TRUE, 5); + gtk_widget_show(hbox_total); + + /* FIXME: Disable display of current track length. It's not + updated when track changes */ +#if 0 + label = gtk_label_new(_("Track length:")); + gtk_box_pack_start(GTK_BOX(hbox_total), label, FALSE, FALSE, 5); + + len = playlist_get_current_length() / 1000; + g_snprintf(time_str, sizeof(time_str), "%u:%2.2u", len / 60, len % 60); + label = gtk_label_new(time_str); + + gtk_box_pack_start(GTK_BOX(hbox_total), label, FALSE, FALSE, 10); +#endif + + bbox = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(vbox), bbox, TRUE, TRUE, 0); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + + cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + gtk_container_add(GTK_CONTAINER(bbox), cancel); + g_signal_connect_swapped(cancel, "clicked", + G_CALLBACK(gtk_widget_destroy), mainwin_jtt); + + jump = gtk_button_new_from_stock(GTK_STOCK_JUMP_TO); + GTK_WIDGET_SET_FLAGS(jump, GTK_CAN_DEFAULT); + gtk_container_add(GTK_CONTAINER(bbox), jump); + g_signal_connect(jump, "clicked", + G_CALLBACK(mainwin_jump_to_time_cb), time_entry); + + tindex = playback_get_time() / 1000; + g_snprintf(time_str, sizeof(time_str), "%u:%2.2u", tindex / 60, + tindex % 60); + gtk_entry_set_text(GTK_ENTRY(time_entry), time_str); + + gtk_entry_select_region(GTK_ENTRY(time_entry), 0, strlen(time_str)); + + gtk_widget_show_all(mainwin_jtt); + + gtk_widget_grab_focus(time_entry); + gtk_widget_grab_default(jump); +} + +/* + * Rewritten 09/13/06: + * + * Remove all of this flaky iter/sourcelist/strsplit stuff. + * All we care about is the filepath. + * + * We can figure this out and easily pass it to g_filename_from_uri(). + * - nenolod + */ +void +mainwin_drag_data_received(GtkWidget * widget, + GdkDragContext * context, + gint x, + gint y, + GtkSelectionData * selection_data, + guint info, + guint time, + gpointer user_data) +{ + Playlist *playlist = playlist_get_active(); + + g_return_if_fail(selection_data != NULL); + g_return_if_fail(selection_data->data != NULL); + + if (str_has_prefix_nocase((gchar *) selection_data->data, "fonts:///")) + { + gchar *path = (gchar *) selection_data->data; + gchar *decoded = g_filename_from_uri(path, NULL, NULL); + + if (decoded == NULL) + return; + + cfg.playlist_font = g_strconcat(decoded, strrchr(cfg.playlist_font, ' '), NULL); + ui_skinned_playlist_set_font(cfg.playlist_font); + playlistwin_update_list(playlist); + + g_free(decoded); + + return; + } + + /* perhaps make suffix check case-insensitive -- desowin */ + if (str_has_prefix_nocase((char*)selection_data->data, "file:///")) { + if (str_has_suffix_nocase((char*)selection_data->data, ".wsz\r\n") || + str_has_suffix_nocase((char*)selection_data->data, ".zip\r\n")) { + on_skin_view_drag_data_received(GTK_WIDGET(user_data), context, x, y, selection_data, info, time, NULL); + return; + } + } + + playlist_clear(playlist); + playlist_add_url(playlist, (gchar *) selection_data->data); + playback_initiate(); +} + +static void +on_add_url_add_clicked(GtkWidget * widget, + GtkWidget * entry) +{ + const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry)); + if (text && *text) + playlist_add_url(playlist_get_active(), text); +} + +static void +on_add_url_ok_clicked(GtkWidget * widget, + GtkWidget * entry) +{ + Playlist *playlist = playlist_get_active(); + + const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry)); + if (text && *text) + { + playlist_clear(playlist); + playlist_add_url(playlist, text); + playback_initiate(); + } +} + +static void +on_visibility_warning_toggle(GtkToggleButton *tbt, gpointer unused) +{ + cfg.warn_about_win_visibility = !gtk_toggle_button_get_active(tbt); +} + +static void +on_visibility_warning_response(GtkDialog *dlg, gint r_id, gpointer unused) +{ + switch (r_id) + { + case GTK_RESPONSE_OK: + mainwin_show(TRUE); + break; + case GTK_RESPONSE_CANCEL: + default: + break; + } + gtk_widget_destroy(GTK_WIDGET(dlg)); +} + +void +mainwin_show_visibility_warning(void) +{ + if (cfg.warn_about_win_visibility) + { + GtkWidget *label, *checkbt, *vbox; + GtkWidget *warning_dlg = + gtk_dialog_new_with_buttons( _("Audacious - visibility warning") , + GTK_WINDOW(mainwin) , + GTK_DIALOG_DESTROY_WITH_PARENT , + _("Show main player window") , + GTK_RESPONSE_OK , _("Ignore") , + GTK_RESPONSE_CANCEL , NULL ); + + vbox = gtk_vbox_new( FALSE , 4 ); + gtk_container_set_border_width( GTK_CONTAINER(vbox) , 4 ); + gtk_box_pack_start( GTK_BOX(GTK_DIALOG(warning_dlg)->vbox) , vbox , TRUE , TRUE , 0 ); + label = gtk_label_new( _("Audacious has been started with all of its windows hidden.\n" + "You may want to show the player window again to control Audacious; " + "otherwise, you'll have to control it remotely via audtool or " + "enabled plugins (such as the statusicon plugin).") ); + gtk_label_set_line_wrap( GTK_LABEL(label) , TRUE ); + gtk_misc_set_alignment( GTK_MISC(label) , 0.0 , 0.0 ); + checkbt = gtk_check_button_new_with_label( _("Always ignore, show/hide is controlled remotely") ); + gtk_box_pack_start( GTK_BOX(vbox) , label , TRUE , TRUE , 0 ); + gtk_box_pack_start( GTK_BOX(vbox) , checkbt , TRUE , TRUE , 0 ); + g_signal_connect( G_OBJECT(checkbt) , "toggled" , + G_CALLBACK(on_visibility_warning_toggle) , NULL ); + g_signal_connect( G_OBJECT(warning_dlg) , "response" , + G_CALLBACK(on_visibility_warning_response) , NULL ); + gtk_widget_show_all(warning_dlg); + } +} + +static void +on_broken_gtk_engine_warning_toggle(GtkToggleButton *tbt, gpointer unused) +{ + cfg.warn_about_broken_gtk_engines = !gtk_toggle_button_get_active(tbt); +} + +void +ui_main_check_theme_engine(void) +{ + GtkSettings *settings; + GtkWidget *widget; + gchar *theme = NULL; + + widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_ensure_style(widget); + + settings = gtk_settings_get_default(); + g_object_get(G_OBJECT(settings), "gtk-theme-name", &theme, NULL); + gtk_widget_destroy(widget); + + if (theme == NULL) + return; + + if (g_ascii_strcasecmp(theme, "Qt")) + { + g_free(theme); + return; + } + + if (cfg.warn_about_broken_gtk_engines) + { + gchar *msg; + GtkWidget *label, *checkbt, *vbox; + GtkWidget *warning_dlg = + gtk_dialog_new_with_buttons( _("Audacious - broken GTK engine usage warning") , + GTK_WINDOW(mainwin) , GTK_DIALOG_DESTROY_WITH_PARENT , + GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL ); + vbox = gtk_vbox_new( FALSE , 4 ); + gtk_container_set_border_width( GTK_CONTAINER(vbox) , 4 ); + gtk_box_pack_start( GTK_BOX(GTK_DIALOG(warning_dlg)->vbox) , vbox , + TRUE , TRUE , 0 ); + + msg = g_strdup_printf(_("Broken GTK engine in use\n\n" + "Audacious has detected that you are using a broken GTK engine.\n\n" + "The theme engine you are using, %s, is incompatible with some of the features " + "used by modern skins. The incompatible features have been disabled for this session.\n\n" + "To use these features, please consider using a different GTK theme engine."), theme); + label = gtk_label_new(msg); + gtk_label_set_use_markup(GTK_LABEL(label), TRUE); + g_free(msg); + + gtk_label_set_line_wrap( GTK_LABEL(label) , TRUE ); + gtk_misc_set_alignment( GTK_MISC(label) , 0.0 , 0.0 ); + checkbt = gtk_check_button_new_with_label( _("Do not display this warning again") ); + gtk_box_pack_start( GTK_BOX(vbox) , label , TRUE , TRUE , 0 ); + gtk_box_pack_start( GTK_BOX(vbox) , checkbt , TRUE , TRUE , 0 ); + g_signal_connect( G_OBJECT(checkbt) , "toggled" , + G_CALLBACK(on_broken_gtk_engine_warning_toggle) , NULL ); + g_signal_connect( G_OBJECT(warning_dlg) , "response" , + G_CALLBACK(gtk_widget_destroy) , NULL ); + gtk_widget_show_all(warning_dlg); + gtk_window_stick(GTK_WINDOW(warning_dlg)); + } + + cfg.disable_inline_gtk = TRUE; + + g_free(theme); +} + +void +mainwin_show_add_url_window(void) +{ + static GtkWidget *url_window = NULL; + + if (!url_window) { + url_window = + util_add_url_dialog_new(_("Enter location to play:"), + G_CALLBACK(on_add_url_ok_clicked), + G_CALLBACK(on_add_url_add_clicked)); + gtk_window_set_transient_for(GTK_WINDOW(url_window), + GTK_WINDOW(mainwin)); + g_signal_connect(url_window, "destroy", + G_CALLBACK(gtk_widget_destroyed), + &url_window); + } + + gtk_window_present(GTK_WINDOW(url_window)); +} + +static void +check_set( GtkActionGroup * action_group , + const gchar * action_name , + gboolean is_on ) +{ + /* check_set noew uses gtkaction */ + GtkAction *action = gtk_action_group_get_action( action_group , action_name ); + if ( action != NULL ) + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , is_on ); + return; +} + +void +mainwin_eject_pushed(void) +{ + run_filebrowser(TRUE); +} + +void +mainwin_rev_pushed(void) +{ + g_get_current_time(&cb_time); + + seek_initial_pos = ui_skinned_horizontal_slider_get_position(mainwin_position); + seek_state = MAINWIN_SEEK_REV; + mainwin_timeout_id = g_timeout_add(MAINWIN_UPDATE_INTERVAL, + (GSourceFunc) mainwin_idle_func, NULL); +} + +void +mainwin_rev_release(void) +{ + GTimeVal now_time; + GTimeVal delta_time; + gulong now_dur; + + g_get_current_time(&now_time); + + delta_time.tv_usec = now_time.tv_usec - cb_time.tv_usec; + delta_time.tv_sec = now_time.tv_sec - cb_time.tv_sec; + + now_dur = labs((delta_time.tv_sec * 1000) + (glong) (delta_time.tv_usec / 1000)); + + if ( now_dur <= TRISTATE_THRESHOLD ) + { + /* interpret as 'skip to previous song' */ + playlist_prev(playlist_get_active()); + } + else + { + /* interpret as 'seek' */ + mainwin_position_release_cb( mainwin_position, ui_skinned_horizontal_slider_get_position(mainwin_position) ); + } + + seek_state = MAINWIN_SEEK_NIL; + + g_source_remove(mainwin_timeout_id); + mainwin_timeout_id = 0; +} + +void +mainwin_fwd_pushed(void) +{ + g_get_current_time(&cb_time); + + seek_initial_pos = ui_skinned_horizontal_slider_get_position(mainwin_position); + seek_state = MAINWIN_SEEK_FWD; + mainwin_timeout_id = g_timeout_add(MAINWIN_UPDATE_INTERVAL, + (GSourceFunc) mainwin_idle_func, NULL); +} + +void +mainwin_fwd_release(void) +{ + GTimeVal now_time; + GTimeVal delta_time; + gulong now_dur; + + g_get_current_time(&now_time); + + delta_time.tv_usec = now_time.tv_usec - cb_time.tv_usec; + delta_time.tv_sec = now_time.tv_sec - cb_time.tv_sec; + + now_dur = labs((delta_time.tv_sec * 1000) + (glong) (delta_time.tv_usec / 1000)); + + if ( now_dur <= TRISTATE_THRESHOLD ) + { + /* interpret as 'skip to next song' */ + playlist_next(playlist_get_active()); + } + else + { + /* interpret as 'seek' */ + mainwin_position_release_cb( mainwin_position, ui_skinned_horizontal_slider_get_position(mainwin_position) ); + } + + seek_state = MAINWIN_SEEK_NIL; + + g_source_remove(mainwin_timeout_id); + mainwin_timeout_id = 0; +} + +void +mainwin_play_pushed(void) +{ + if (ab_position_a != -1) + playback_seek(ab_position_a / 1000); + if (playback_get_paused()) { + playback_pause(); + return; + } + + if (playlist_get_length(playlist_get_active())) + playback_initiate(); + else + mainwin_eject_pushed(); +} + +void +mainwin_stop_pushed(void) +{ + ip_data.stop = TRUE; + playback_stop(); + mainwin_clear_song_info(); + ab_position_a = ab_position_b = -1; + ip_data.stop = FALSE; +} + +void +mainwin_shuffle_pushed(gboolean toggled) +{ + check_set( toggleaction_group_others , "playback shuffle" , toggled ); +} + +void mainwin_shuffle_pushed_cb(void) { + mainwin_shuffle_pushed(UI_SKINNED_BUTTON(mainwin_shuffle)->inside); +} + +void +mainwin_repeat_pushed(gboolean toggled) +{ + check_set( toggleaction_group_others , "playback repeat" , toggled ); +} + +void mainwin_repeat_pushed_cb(void) { + mainwin_repeat_pushed(UI_SKINNED_BUTTON(mainwin_repeat)->inside); +} + +void mainwin_equalizer_pushed_cb(void) { + mainwin_eq_pushed(UI_SKINNED_BUTTON(mainwin_eq)->inside); +} + +void mainwin_playlist_pushed_cb(void) { + mainwin_pl_pushed(UI_SKINNED_BUTTON(mainwin_pl)->inside); +} + +void +mainwin_eq_pushed(gboolean toggled) +{ + equalizerwin_show(toggled); +} + +void +mainwin_pl_pushed(gboolean toggled) +{ + if (toggled) + playlistwin_show(); + else + playlistwin_hide(); +} + +gint +mainwin_spos_frame_cb(gint pos) +{ + if (mainwin_sposition) { + gint x = 0; + if (pos < 6) + x = 17; + else if (pos < 9) + x = 20; + else + x = 23; + + UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->knob_nx = x; + UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->knob_px = x; + } + return 1; +} + +void +mainwin_spos_motion_cb(GtkWidget *widget, gint pos) +{ + gint time; + gchar *time_msg; + Playlist *playlist = playlist_get_active(); + + pos--; + + time = ((playlist_get_current_length(playlist) / 1000) * pos) / 12; + + if (cfg.timer_mode == TIMER_REMAINING) { + time = (playlist_get_current_length(playlist) / 1000) - time; + time_msg = g_strdup_printf("-%2.2d", time / 60); + ui_skinned_textbox_set_text(mainwin_stime_min, time_msg); + g_free(time_msg); + } + else { + time_msg = g_strdup_printf(" %2.2d", time / 60); + ui_skinned_textbox_set_text(mainwin_stime_min, time_msg); + g_free(time_msg); + } + + time_msg = g_strdup_printf("%2.2d", time % 60); + ui_skinned_textbox_set_text(mainwin_stime_sec, time_msg); + g_free(time_msg); +} + +void +mainwin_spos_release_cb(GtkWidget *widget, gint pos) +{ + playback_seek(((playlist_get_current_length(playlist_get_active()) / 1000) * + (pos - 1)) / 12); +} + +void +mainwin_position_motion_cb(GtkWidget *widget, gint pos) +{ + gint length, time; + gchar *seek_msg; + + length = playlist_get_current_length(playlist_get_active()) / 1000; + time = (length * pos) / 219; + seek_msg = g_strdup_printf(_("Seek to: %d:%-2.2d/%d:%-2.2d (%d%%)"), + time / 60, time % 60, + length / 60, length % 60, + (length != 0) ? (time * 100) / length : 0); + mainwin_lock_info_text(seek_msg); + g_free(seek_msg); +} + +void +mainwin_position_release_cb(GtkWidget *widget, gint pos) +{ + gint length, time; + + length = playlist_get_current_length(playlist_get_active()) / 1000; + time = (length * pos) / 219; + playback_seek(time); + mainwin_release_info_text(); +} + +gint +mainwin_volume_frame_cb(gint pos) +{ + return (gint) rint((pos / 52.0) * 28); +} + +void +mainwin_adjust_volume_motion(gint v) +{ + gchar *volume_msg; + + volume_msg = g_strdup_printf(_("Volume: %d%%"), v); + mainwin_lock_info_text(volume_msg); + g_free(volume_msg); + + if (balance < 0) + input_set_volume(v, (v * (100 - abs(balance))) / 100); + else if (balance > 0) + input_set_volume((v * (100 - abs(balance))) / 100, v); + else + input_set_volume(v, v); +} + +void +mainwin_adjust_volume_release(void) +{ + mainwin_release_info_text(); +} + +void +mainwin_adjust_balance_motion(gint b) +{ + gchar *balance_msg; + gint v, pvl, pvr; + + balance = b; + input_get_volume(&pvl, &pvr); + v = MAX(pvl, pvr); + if (b < 0) { + balance_msg = g_strdup_printf(_("Balance: %d%% left"), -b); + input_set_volume(v, (gint) rint(((100 + b) / 100.0) * v)); + } + else if (b == 0) { + balance_msg = g_strdup_printf(_("Balance: center")); + input_set_volume(v, v); + } + else { /* b > 0 */ + balance_msg = g_strdup_printf(_("Balance: %d%% right"), b); + input_set_volume((gint) rint(((100 - b) / 100.0) * v), v); + } + mainwin_lock_info_text(balance_msg); + g_free(balance_msg); +} + +void +mainwin_adjust_balance_release(void) +{ + mainwin_release_info_text(); +} + +void +mainwin_set_volume_slider(gint percent) +{ + ui_skinned_horizontal_slider_set_position(mainwin_volume, (gint) rint((percent * 51) / 100.0)); +} + +void +mainwin_set_balance_slider(gint percent) +{ + ui_skinned_horizontal_slider_set_position(mainwin_balance, (gint) rint(((percent * 12) / 100.0) + 12)); +} + +void +mainwin_volume_motion_cb(GtkWidget *widget, gint pos) +{ + gint vol = (pos * 100) / 51; + mainwin_adjust_volume_motion(vol); + equalizerwin_set_volume_slider(vol); +} + +gboolean +mainwin_volume_release_cb(GtkWidget *widget, gint pos) +{ + mainwin_adjust_volume_release(); + return FALSE; +} + +gint +mainwin_balance_frame_cb(gint pos) +{ + return ((abs(pos - 12) * 28) / 13); +} + +void +mainwin_balance_motion_cb(GtkWidget *widget, gint pos) +{ + gint bal = ((pos - 12) * 100) / 12; + mainwin_adjust_balance_motion(bal); + equalizerwin_set_balance_slider(bal); +} + +void +mainwin_balance_release_cb(GtkWidget *widget, gint pos) +{ + mainwin_adjust_volume_release(); +} + +void +mainwin_set_volume_diff(gint diff) +{ + gint vl, vr, vol; + + input_get_volume(&vl, &vr); + vol = MAX(vl, vr); + vol = CLAMP(vol + diff, 0, 100); + + mainwin_adjust_volume_motion(vol); + mainwin_set_volume_slider(vol); + equalizerwin_set_volume_slider(vol); + + if (mainwin_volume_release_timeout) + g_source_remove(mainwin_volume_release_timeout); + mainwin_volume_release_timeout = + g_timeout_add(700, (GSourceFunc)(mainwin_volume_release_cb), NULL); +} + +void +mainwin_set_balance_diff(gint diff) +{ + gint b; + b = CLAMP(balance + diff, -100, 100); + mainwin_adjust_balance_motion(b); + mainwin_set_balance_slider(b); + equalizerwin_set_balance_slider(b); +} + +void +mainwin_show(gboolean show) +{ + if (show) + mainwin_real_show(); + else + mainwin_real_hide(); +} + +void +mainwin_real_show(void) +{ + cfg.player_visible = TRUE; + + check_set( toggleaction_group_others , "show player" , TRUE ); + + if (cfg.player_shaded) + ui_vis_clear_data(mainwin_vis); + + if (cfg.show_wm_decorations) { + if (cfg.player_x != -1 && cfg.save_window_position) + gtk_window_move(GTK_WINDOW(mainwin), cfg.player_x, cfg.player_y); + + gtk_widget_show(mainwin); + return; + } + + if (cfg.player_x != -1 && cfg.save_window_position) + gtk_window_move(GTK_WINDOW(mainwin), cfg.player_x, cfg.player_y); + + mainwin_refresh_hints(); + gtk_window_present(GTK_WINDOW(mainwin)); +} + +void +mainwin_real_hide(void) +{ + check_set( toggleaction_group_others , "show player", FALSE); + + if (cfg.player_shaded) + ui_svis_clear_data(mainwin_svis); + + gtk_widget_hide(mainwin); + + cfg.player_visible = FALSE; +} + + +void +mainwin_set_stopaftersong(gboolean stop) +{ + cfg.stopaftersong = stop; + check_set(toggleaction_group_others, "stop after current song", cfg.stopaftersong); +} + +void +mainwin_set_noplaylistadvance(gboolean no_advance) +{ + cfg.no_playlist_advance = no_advance; + check_set(toggleaction_group_others, "playback no playlist advance", cfg.no_playlist_advance); +} + +static void +mainwin_set_scaled(gboolean scaled) +{ + gint height; + + if (cfg.player_shaded) + height = MAINWIN_SHADED_HEIGHT; + else + height = aud_active_skin->properties.mainwin_height; + + dock_window_resize(GTK_WINDOW(mainwin), cfg.player_shaded ? MAINWIN_SHADED_WIDTH : aud_active_skin->properties.mainwin_width, + cfg.player_shaded ? MAINWIN_SHADED_HEIGHT : aud_active_skin->properties.mainwin_height, + aud_active_skin->properties.mainwin_width * cfg.scale_factor , aud_active_skin->properties.mainwin_height * cfg.scale_factor); + + GList *iter; + for (iter = GTK_FIXED (SKINNED_WINDOW(mainwin)->fixed)->children; iter; iter = g_list_next (iter)) { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + GtkWidget *child = child_data->widget; + g_signal_emit_by_name(child, "toggle-scaled"); + } + + mainwin_refresh_hints(); + gtk_widget_shape_combine_mask(mainwin, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + cfg.player_shaded), 0, 0); +} + +void +set_scaled(gboolean scaled) +{ + cfg.scaled = scaled; + + mainwin_set_scaled(scaled); + + if (cfg.eq_scaled_linked) + equalizerwin_set_scaled(scaled); +} + + + +void +mainwin_general_menu_callback(gpointer data, + guint action, + GtkWidget * item) +{ + Playlist *playlist = playlist_get_active(); + + switch (action) { + case MAINWIN_GENERAL_PREFS: + show_prefs_window(); + break; + case MAINWIN_GENERAL_ABOUT: + show_about_window(); + break; + case MAINWIN_GENERAL_PLAYFILE: + run_filebrowser(FALSE); + break; + case MAINWIN_GENERAL_PLAYLOCATION: + mainwin_show_add_url_window(); + break; + case MAINWIN_GENERAL_FILEINFO: + ui_fileinfo_show_current(playlist); + break; + case MAINWIN_GENERAL_FOCUSPLWIN: + gtk_window_present(GTK_WINDOW(playlistwin)); + break; + case MAINWIN_GENERAL_SHOWMWIN: + mainwin_show(GTK_CHECK_MENU_ITEM(item)->active); + break; + case MAINWIN_GENERAL_SHOWPLWIN: + if (GTK_CHECK_MENU_ITEM(item)->active) + playlistwin_show(); + else + playlistwin_hide(); + break; + case MAINWIN_GENERAL_SHOWEQWIN: + if (GTK_CHECK_MENU_ITEM(item)->active) + equalizerwin_real_show(); + else + equalizerwin_real_hide(); + break; + case MAINWIN_GENERAL_PREV: + playlist_prev(playlist); + break; + case MAINWIN_GENERAL_PLAY: + mainwin_play_pushed(); + break; + case MAINWIN_GENERAL_PAUSE: + playback_pause(); + break; + case MAINWIN_GENERAL_STOP: + mainwin_stop_pushed(); + break; + case MAINWIN_GENERAL_NEXT: + playlist_next(playlist); + break; + case MAINWIN_GENERAL_BACK5SEC: + if (playback_get_playing() + && playlist_get_current_length(playlist) != -1) + playback_seek_relative(-5); + break; + case MAINWIN_GENERAL_FWD5SEC: + if (playback_get_playing() + && playlist_get_current_length(playlist) != -1) + playback_seek_relative(5); + break; + case MAINWIN_GENERAL_START: + playlist_set_position(playlist, 0); + break; + case MAINWIN_GENERAL_JTT: + mainwin_jump_to_time(); + break; + case MAINWIN_GENERAL_JTF: + ui_jump_to_track(); + break; + case MAINWIN_GENERAL_EXIT: + mainwin_quit_cb(); + break; + case MAINWIN_GENERAL_SETAB: + if (playlist_get_current_length(playlist) != -1) { + if (ab_position_a == -1) { + ab_position_a = playback_get_time(); + ab_position_b = -1; + mainwin_lock_info_text("'Loop-Point A Position' set."); + } else if (ab_position_b == -1) { + int time = playback_get_time(); + if (time > ab_position_a) + ab_position_b = time; + mainwin_release_info_text(); + } else { + ab_position_a = playback_get_time(); + ab_position_b = -1; + mainwin_lock_info_text("'Loop-Point A Position' reset."); + } + } + break; + case MAINWIN_GENERAL_CLEARAB: + if (playlist_get_current_length(playlist) != -1) { + ab_position_a = ab_position_b = -1; + mainwin_release_info_text(); + } + break; + case MAINWIN_GENERAL_NEW_PL: + { + Playlist *new_pl = playlist_new(); + playlist_add_playlist(new_pl); + playlist_select_playlist(new_pl); + } + break; + case MAINWIN_GENERAL_PREV_PL: + playlist_select_prev(); + break; + case MAINWIN_GENERAL_NEXT_PL: + playlist_select_next(); + break; + } +} + +static void +mainwin_mr_change(GtkWidget *widget, MenuRowItem i) +{ + switch (i) { + case MENUROW_OPTIONS: + mainwin_lock_info_text(_("Options Menu")); + break; + case MENUROW_ALWAYS: + if (UI_SKINNED_MENUROW(mainwin_menurow)->always_selected) + mainwin_lock_info_text(_("Disable 'Always On Top'")); + else + mainwin_lock_info_text(_("Enable 'Always On Top'")); + break; + case MENUROW_FILEINFOBOX: + mainwin_lock_info_text(_("File Info Box")); + break; + case MENUROW_SCALE: + if (UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected) + mainwin_lock_info_text(_("Disable 'GUI Scaling'")); + else + mainwin_lock_info_text(_("Enable 'GUI Scaling'")); + break; + case MENUROW_VISUALIZATION: + mainwin_lock_info_text(_("Visualization Menu")); + break; + case MENUROW_NONE: + break; + } +} + +static void +mainwin_mr_release(GtkWidget *widget, MenuRowItem i, GdkEventButton *event) +{ + switch (i) { + case MENUROW_OPTIONS: + ui_manager_popup_menu_show(GTK_MENU(mainwin_view_menu), + event->x_root, event->y_root, 1, + event->time); + break; + case MENUROW_ALWAYS: + gtk_toggle_action_set_active( + GTK_TOGGLE_ACTION(gtk_action_group_get_action( + toggleaction_group_others , "view always on top" )) , + UI_SKINNED_MENUROW(mainwin_menurow)->always_selected ); + break; + case MENUROW_FILEINFOBOX: + ui_fileinfo_show_current(playlist_get_active()); + break; + case MENUROW_SCALE: + gtk_toggle_action_set_active( + GTK_TOGGLE_ACTION(gtk_action_group_get_action( + toggleaction_group_others , "view scaled" )) , + UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected ); + break; + case MENUROW_VISUALIZATION: + ui_manager_popup_menu_show(GTK_MENU(mainwin_visualization_menu), + event->x_root, event->y_root, 1, + event->time); + break; + case MENUROW_NONE: + break; + } + mainwin_release_info_text(); +} + +void +run_no_output_device_dialog(gpointer hook_data, gpointer user_data) +{ + const gchar *markup = + N_("Couldn't open audio.\n\n" + "Please check that:\n" + "1. You have the correct output plugin selected.\n" + "2. No other programs is blocking the soundcard.\n" + "3. Your soundcard is configured properly.\n"); + + GDK_THREADS_ENTER(); + GtkWidget *dialog = + gtk_message_dialog_new_with_markup(GTK_WINDOW(mainwin), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _(markup)); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + GDK_THREADS_LEAVE(); +} + +static void +set_timer_mode(TimerMode mode) +{ + if (mode == TIMER_ELAPSED) + check_set(radioaction_group_viewtime, "view time elapsed", TRUE); + else + check_set(radioaction_group_viewtime, "view time remaining", TRUE); +} + +static void +set_timer_mode_menu_cb(TimerMode mode) +{ + cfg.timer_mode = mode; +} + +gboolean +change_timer_mode_cb(GtkWidget *widget, GdkEventButton *event) +{ + if (event->button == 1) { + change_timer_mode(); + } else if (event->button == 3) + return FALSE; + + return TRUE; +} + +static void change_timer_mode(void) { + if (cfg.timer_mode == TIMER_ELAPSED) + set_timer_mode(TIMER_REMAINING); + else + set_timer_mode(TIMER_ELAPSED); + if (playback_get_playing()) + mainwin_update_song_info(); +} + +static void +mainwin_playlist_prev(void) +{ + playlist_prev(playlist_get_active()); +} + +static void +mainwin_playlist_next(void) +{ + playlist_next(playlist_get_active()); +} + +void +mainwin_setup_menus(void) +{ + set_timer_mode(cfg.timer_mode); + + /* View menu */ + + check_set(toggleaction_group_others, "view always on top", cfg.always_on_top); + check_set(toggleaction_group_others, "view put on all workspaces", cfg.sticky); + check_set(toggleaction_group_others, "roll up player", cfg.player_shaded); + check_set(toggleaction_group_others, "roll up playlist editor", cfg.playlist_shaded); + check_set(toggleaction_group_others, "roll up equalizer", cfg.equalizer_shaded); + check_set(toggleaction_group_others, "view easy move", cfg.easy_move); + check_set(toggleaction_group_others, "view scaled", cfg.scaled); + + /* Songname menu */ + + check_set(toggleaction_group_others, "autoscroll songname", cfg.autoscroll); + check_set(toggleaction_group_others, "stop after current song", cfg.stopaftersong); + + /* Playback menu */ + + check_set(toggleaction_group_others, "playback repeat", cfg.repeat); + check_set(toggleaction_group_others, "playback shuffle", cfg.shuffle); + check_set(toggleaction_group_others, "playback no playlist advance", cfg.no_playlist_advance); + + /* Visualization menu */ + + switch ( cfg.vis_type ) + { + case VIS_ANALYZER: + check_set(radioaction_group_vismode, "vismode analyzer", TRUE); + break; + case VIS_SCOPE: + check_set(radioaction_group_vismode, "vismode scope", TRUE); + break; + case VIS_VOICEPRINT: + check_set(radioaction_group_vismode, "vismode voiceprint", TRUE); + break; + case VIS_OFF: + default: + check_set(radioaction_group_vismode, "vismode off", TRUE); + break; + } + + switch ( cfg.analyzer_mode ) + { + case ANALYZER_FIRE: + check_set(radioaction_group_anamode, "anamode fire", TRUE); + break; + case ANALYZER_VLINES: + check_set(radioaction_group_anamode, "anamode vertical lines", TRUE); + break; + case ANALYZER_NORMAL: + default: + check_set(radioaction_group_anamode, "anamode normal", TRUE); + break; + } + + switch ( cfg.analyzer_type ) + { + case ANALYZER_BARS: + check_set(radioaction_group_anatype, "anatype bars", TRUE); + break; + case ANALYZER_LINES: + default: + check_set(radioaction_group_anatype, "anatype lines", TRUE); + break; + } + + check_set(toggleaction_group_others, "anamode peaks", cfg.analyzer_peaks ); + + switch ( cfg.scope_mode ) + { + case SCOPE_LINE: + check_set(radioaction_group_scomode, "scomode line", TRUE); + break; + case SCOPE_SOLID: + check_set(radioaction_group_scomode, "scomode solid", TRUE); + break; + case SCOPE_DOT: + default: + check_set(radioaction_group_scomode, "scomode dot", TRUE); + break; + } + + switch ( cfg.voiceprint_mode ) + { + case VOICEPRINT_FIRE: + check_set(radioaction_group_vprmode, "vprmode fire", TRUE); + break; + case VOICEPRINT_ICE: + check_set(radioaction_group_vprmode, "vprmode ice", TRUE); + break; + case VOICEPRINT_NORMAL: + default: + check_set(radioaction_group_vprmode, "vprmode normal", TRUE); + break; + } + + switch ( cfg.vu_mode ) + { + case VU_SMOOTH: + check_set(radioaction_group_wshmode, "wshmode smooth", TRUE); + break; + case VU_NORMAL: + default: + check_set(radioaction_group_wshmode, "wshmode normal", TRUE); + break; + } + + switch ( cfg.vis_refresh ) + { + case REFRESH_HALF: + check_set(radioaction_group_refrate, "refrate half", TRUE); + break; + case REFRESH_QUARTER: + check_set(radioaction_group_refrate, "refrate quarter", TRUE); + break; + case REFRESH_EIGTH: + check_set(radioaction_group_refrate, "refrate eighth", TRUE); + break; + case REFRESH_FULL: + default: + check_set(radioaction_group_refrate, "refrate full", TRUE); + break; + } + + switch ( cfg.analyzer_falloff ) + { + case FALLOFF_SLOW: + check_set(radioaction_group_anafoff, "anafoff slow", TRUE); + break; + case FALLOFF_MEDIUM: + check_set(radioaction_group_anafoff, "anafoff medium", TRUE); + break; + case FALLOFF_FAST: + check_set(radioaction_group_anafoff, "anafoff fast", TRUE); + break; + case FALLOFF_FASTEST: + check_set(radioaction_group_anafoff, "anafoff fastest", TRUE); + break; + case FALLOFF_SLOWEST: + default: + check_set(radioaction_group_anafoff, "anafoff slowest", TRUE); + break; + } + + switch ( cfg.peaks_falloff ) + { + case FALLOFF_SLOW: + check_set(radioaction_group_peafoff, "peafoff slow", TRUE); + break; + case FALLOFF_MEDIUM: + check_set(radioaction_group_peafoff, "peafoff medium", TRUE); + break; + case FALLOFF_FAST: + check_set(radioaction_group_peafoff, "peafoff fast", TRUE); + break; + case FALLOFF_FASTEST: + check_set(radioaction_group_peafoff, "peafoff fastest", TRUE); + break; + case FALLOFF_SLOWEST: + default: + check_set(radioaction_group_peafoff, "peafoff slowest", TRUE); + break; + } + +} + +static void mainwin_info_double_clicked_cb(void) { + ui_fileinfo_show_current(playlist_get_active()); +} + +static void +mainwin_info_right_clicked_cb(GtkWidget *widget, GdkEventButton *event) +{ + ui_manager_popup_menu_show(GTK_MENU(mainwin_songname_menu), + event->x_root, event->y_root, 3, event->time); +} + +static void +mainwin_create_widgets(void) +{ + mainwin_menubtn = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_menubtn, SKINNED_WINDOW(mainwin)->fixed, + 6, 3, 9, 9, 0, 0, 0, 9, SKIN_TITLEBAR); + g_signal_connect(mainwin_menubtn, "clicked", mainwin_menubtn_cb, NULL ); + + mainwin_minimize = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_minimize, SKINNED_WINDOW(mainwin)->fixed, + 244, 3, 9, 9, 9, 0, 9, 9, SKIN_TITLEBAR); + g_signal_connect(mainwin_minimize, "clicked", mainwin_minimize_cb, NULL ); + + mainwin_shade = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_shade, SKINNED_WINDOW(mainwin)->fixed, + 254, 3, 9, 9, 0, + cfg.player_shaded ? 27 : 18, 9, cfg.player_shaded ? 27 : 18, SKIN_TITLEBAR); + g_signal_connect(mainwin_shade, "clicked", mainwin_shade_toggle, NULL ); + + mainwin_close = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_close, SKINNED_WINDOW(mainwin)->fixed, + 264, 3, 9, 9, 18, 0, 18, 9, SKIN_TITLEBAR); + g_signal_connect(mainwin_close, "clicked", mainwin_quit_cb, NULL ); + + mainwin_rew = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_rew, SKINNED_WINDOW(mainwin)->fixed, + 16, 88, 23, 18, 0, 0, 0, 18, SKIN_CBUTTONS); + g_signal_connect(mainwin_rew, "pressed", mainwin_rev_pushed, NULL); + g_signal_connect(mainwin_rew, "released", mainwin_rev_release, NULL); + + mainwin_fwd = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_fwd, SKINNED_WINDOW(mainwin)->fixed, + 108, 88, 22, 18, 92, 0, 92, 18, SKIN_CBUTTONS); + g_signal_connect(mainwin_fwd, "pressed", mainwin_fwd_pushed, NULL); + g_signal_connect(mainwin_fwd, "released", mainwin_fwd_release, NULL); + + mainwin_play = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_play, SKINNED_WINDOW(mainwin)->fixed, + 39, 88, 23, 18, 23, 0, 23, 18, SKIN_CBUTTONS); + g_signal_connect(mainwin_play, "clicked", mainwin_play_pushed, NULL ); + + mainwin_pause = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_pause, SKINNED_WINDOW(mainwin)->fixed, + 62, 88, 23, 18, 46, 0, 46, 18, SKIN_CBUTTONS); + g_signal_connect(mainwin_pause, "clicked", playback_pause, NULL ); + + mainwin_stop = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_stop, SKINNED_WINDOW(mainwin)->fixed, + 85, 88, 23, 18, 69, 0, 69, 18, SKIN_CBUTTONS); + g_signal_connect(mainwin_stop, "clicked", mainwin_stop_pushed, NULL ); + + mainwin_eject = ui_skinned_button_new(); + ui_skinned_push_button_setup(mainwin_eject, SKINNED_WINDOW(mainwin)->fixed, + 136, 89, 22, 16, 114, 0, 114, 16, SKIN_CBUTTONS); + g_signal_connect(mainwin_eject, "clicked", mainwin_eject_pushed, NULL); + + mainwin_srew = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_srew, SKINNED_WINDOW(mainwin)->fixed, 169, 4, 8, 7); + g_signal_connect(mainwin_srew, "clicked", mainwin_playlist_prev, NULL); + + mainwin_splay = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_splay, SKINNED_WINDOW(mainwin)->fixed, 177, 4, 10, 7); + g_signal_connect(mainwin_splay, "clicked", mainwin_play_pushed, NULL); + + mainwin_spause = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_spause, SKINNED_WINDOW(mainwin)->fixed, 187, 4, 10, 7); + g_signal_connect(mainwin_spause, "clicked", playback_pause, NULL); + + mainwin_sstop = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_sstop, SKINNED_WINDOW(mainwin)->fixed, 197, 4, 9, 7); + g_signal_connect(mainwin_sstop, "clicked", mainwin_stop_pushed, NULL); + + mainwin_sfwd = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_sfwd, SKINNED_WINDOW(mainwin)->fixed, 206, 4, 8, 7); + g_signal_connect(mainwin_sfwd, "clicked", mainwin_playlist_next, NULL); + + mainwin_seject = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_seject, SKINNED_WINDOW(mainwin)->fixed, 216, 4, 9, 7); + g_signal_connect(mainwin_seject, "clicked", mainwin_eject_pushed, NULL); + + mainwin_shuffle = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(mainwin_shuffle, SKINNED_WINDOW(mainwin)->fixed, + 164, 89, 46, 15, 28, 0, 28, 15, 28, 30, 28, 45, SKIN_SHUFREP); + g_signal_connect(mainwin_shuffle, "clicked", mainwin_shuffle_pushed_cb, NULL); + + mainwin_repeat = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(mainwin_repeat, SKINNED_WINDOW(mainwin)->fixed, + 210, 89, 28, 15, 0, 0, 0, 15, 0, 30, 0, 45, SKIN_SHUFREP); + g_signal_connect(mainwin_repeat, "clicked", mainwin_repeat_pushed_cb, NULL); + + mainwin_eq = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(mainwin_eq, SKINNED_WINDOW(mainwin)->fixed, + 219, 58, 23, 12, 0, 61, 46, 61, 0, 73, 46, 73, SKIN_SHUFREP); + g_signal_connect(mainwin_eq, "clicked", mainwin_equalizer_pushed_cb, NULL); + UI_SKINNED_BUTTON(mainwin_eq)->inside = cfg.equalizer_visible; + + mainwin_pl = ui_skinned_button_new(); + ui_skinned_toggle_button_setup(mainwin_pl, SKINNED_WINDOW(mainwin)->fixed, + 242, 58, 23, 12, 23, 61, 69, 61, 23, 73, 69, 73, SKIN_SHUFREP); + g_signal_connect(mainwin_pl, "clicked", mainwin_playlist_pushed_cb, NULL); + UI_SKINNED_BUTTON(mainwin_pl)->inside = cfg.playlist_visible; + + mainwin_info = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 112, 27, 153, 1, SKIN_TEXT); + ui_skinned_textbox_set_scroll(mainwin_info, cfg.autoscroll); + ui_skinned_textbox_set_xfont(mainwin_info, !cfg.mainwin_use_bitmapfont, cfg.mainwin_font); + g_signal_connect(mainwin_info, "double-clicked", mainwin_info_double_clicked_cb, NULL); + g_signal_connect(mainwin_info, "right-clicked", G_CALLBACK(mainwin_info_right_clicked_cb), NULL); + + mainwin_othertext = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 112, 43, 153, 1, SKIN_TEXT); + + mainwin_rate_text = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 111, 43, 15, 0, SKIN_TEXT); + + mainwin_freq_text = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 156, 43, 10, 0, SKIN_TEXT); + + mainwin_menurow = ui_skinned_menurow_new(SKINNED_WINDOW(mainwin)->fixed, 10, 22, 304, 0, 304, 44, SKIN_TITLEBAR); + g_signal_connect(mainwin_menurow, "change", G_CALLBACK(mainwin_mr_change), NULL); + g_signal_connect(mainwin_menurow, "release", G_CALLBACK(mainwin_mr_release), NULL); + + mainwin_volume = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 107, 57, 68, + 13, 15, 422, 0, 422, 14, 11, 15, 0, 0, 51, + mainwin_volume_frame_cb, SKIN_VOLUME); + g_signal_connect(mainwin_volume, "motion", G_CALLBACK(mainwin_volume_motion_cb), NULL); + g_signal_connect(mainwin_volume, "release", G_CALLBACK(mainwin_volume_release_cb), NULL); + + mainwin_balance = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 177, 57, 38, + 13, 15, 422, 0, 422, 14, 11, 15, 9, 0, 24, + mainwin_balance_frame_cb, SKIN_BALANCE); + g_signal_connect(mainwin_balance, "motion", G_CALLBACK(mainwin_balance_motion_cb), NULL); + g_signal_connect(mainwin_balance, "release", G_CALLBACK(mainwin_balance_release_cb), NULL); + + mainwin_monostereo = ui_skinned_monostereo_new(SKINNED_WINDOW(mainwin)->fixed, 212, 41, SKIN_MONOSTEREO); + + mainwin_playstatus = ui_skinned_playstatus_new(SKINNED_WINDOW(mainwin)->fixed, 24, 28); + + mainwin_minus_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 36, 26, SKIN_NUMBERS); + g_signal_connect(mainwin_minus_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_10min_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 48, 26, SKIN_NUMBERS); + g_signal_connect(mainwin_10min_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_min_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 60, 26, SKIN_NUMBERS); + g_signal_connect(mainwin_min_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_10sec_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 78, 26, SKIN_NUMBERS); + g_signal_connect(mainwin_10sec_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_sec_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 90, 26, SKIN_NUMBERS); + g_signal_connect(mainwin_sec_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_about = ui_skinned_button_new(); + ui_skinned_small_button_setup(mainwin_about, SKINNED_WINDOW(mainwin)->fixed, 247, 83, 20, 25); + g_signal_connect(mainwin_about, "clicked", show_about_window, NULL); + + mainwin_vis = ui_vis_new(SKINNED_WINDOW(mainwin)->fixed, 24, 43, 76); + g_signal_connect(mainwin_vis, "button-press-event", G_CALLBACK(mainwin_vis_cb), NULL); + mainwin_svis = ui_svis_new(SKINNED_WINDOW(mainwin)->fixed, 79, 5); + g_signal_connect(mainwin_svis, "button-press-event", G_CALLBACK(mainwin_vis_cb), NULL); + + mainwin_position = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 16, 72, 248, + 10, 248, 0, 278, 0, 29, 10, 10, 0, 0, 219, + NULL, SKIN_POSBAR); + g_signal_connect(mainwin_position, "motion", G_CALLBACK(mainwin_position_motion_cb), NULL); + g_signal_connect(mainwin_position, "release", G_CALLBACK(mainwin_position_release_cb), NULL); + + mainwin_sposition = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 226, 4, 17, + 7, 17, 36, 17, 36, 3, 7, 36, 0, 1, 13, + mainwin_spos_frame_cb, SKIN_TITLEBAR); + g_signal_connect(mainwin_sposition, "motion", G_CALLBACK(mainwin_spos_motion_cb), NULL); + g_signal_connect(mainwin_sposition, "release", G_CALLBACK(mainwin_spos_release_cb), NULL); + + mainwin_stime_min = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 130, 4, 15, FALSE, SKIN_TEXT); + g_signal_connect(mainwin_stime_min, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + mainwin_stime_sec = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 147, 4, 10, FALSE, SKIN_TEXT); + g_signal_connect(mainwin_stime_sec, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + + hook_associate("playback audio error", (void *) mainwin_stop_pushed, NULL); + hook_associate("playback audio error", (void *) run_no_output_device_dialog, NULL); + + hook_associate("playback seek", (HookFunction) mainwin_update_song_info, NULL); +} + +static void +mainwin_create_window(void) +{ + gint width, height; + + mainwin = ui_skinned_window_new("player"); + gtk_window_set_title(GTK_WINDOW(mainwin), _("Audacious")); + gtk_window_set_role(GTK_WINDOW(mainwin), "player"); + gtk_window_set_resizable(GTK_WINDOW(mainwin), FALSE); + + width = cfg.player_shaded ? MAINWIN_SHADED_WIDTH : aud_active_skin->properties.mainwin_width; + height = cfg.player_shaded ? MAINWIN_SHADED_HEIGHT : aud_active_skin->properties.mainwin_height; + + if (cfg.scaled) { + width *= cfg.scale_factor; + height *= cfg.scale_factor; + } + + gtk_widget_set_size_request(mainwin, width, height); + + if (cfg.player_x != -1 && cfg.save_window_position) + gtk_window_move(GTK_WINDOW(mainwin), cfg.player_x, cfg.player_y); + + g_signal_connect(mainwin, "destroy", G_CALLBACK(mainwin_destroy), NULL); + g_signal_connect(mainwin, "button_press_event", + G_CALLBACK(mainwin_mouse_button_press), NULL); + g_signal_connect(mainwin, "scroll_event", + G_CALLBACK(mainwin_scrolled), NULL); + g_signal_connect(mainwin, "button_release_event", + G_CALLBACK(mainwin_mouse_button_release), NULL); + + aud_drag_dest_set(mainwin); + + g_signal_connect(mainwin, "key_press_event", + G_CALLBACK(mainwin_keypress), NULL); + + ui_main_evlistener_init(); +} + +void +mainwin_create(void) +{ + mainwin_create_window(); + + gtk_window_add_accel_group( GTK_WINDOW(mainwin) , ui_manager_get_accel_group() ); + + mainwin_create_widgets(); +} + +gboolean +mainwin_update_song_info(void) +{ + if (!playback_get_playing()) + return FALSE; + + gint time = playback_get_time(); + gint length = playback_get_length(); + gint t; + gchar stime_prefix; + + if (ab_position_a != -1 && ab_position_b != -1 && time > ab_position_b) + playback_seek(ab_position_a/1000); + + if (length == -1 && cfg.timer_mode == TIMER_REMAINING) + cfg.timer_mode = TIMER_ELAPSED; + + playlistwin_set_time(time, length, cfg.timer_mode); + + if (cfg.timer_mode == TIMER_REMAINING) { + if (length != -1) { + ui_skinned_number_set_number(mainwin_minus_num, 11); + t = length - time; + stime_prefix = '-'; + } + else { + ui_skinned_number_set_number(mainwin_minus_num, 10); + t = time; + stime_prefix = ' '; + } + } + else { + ui_skinned_number_set_number(mainwin_minus_num, 10); + t = time; + stime_prefix = ' '; + } + t /= 1000; + + /* Show the time in the format HH:MM when we have more than 100 + * minutes. */ + if (t >= 100 * 60) + t /= 60; + ui_skinned_number_set_number(mainwin_10min_num, t / 600); + ui_skinned_number_set_number(mainwin_min_num, (t / 60) % 10); + ui_skinned_number_set_number(mainwin_10sec_num, (t / 10) % 6); + ui_skinned_number_set_number(mainwin_sec_num, t % 10); + + if (!UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->pressed) { + gchar *time_str; + + time_str = g_strdup_printf("%c%2.2d", stime_prefix, t / 60); + ui_skinned_textbox_set_text(mainwin_stime_min, time_str); + g_free(time_str); + + time_str = g_strdup_printf("%2.2d", t % 60); + ui_skinned_textbox_set_text(mainwin_stime_sec, time_str); + g_free(time_str); + } + + time /= 1000; + length /= 1000; + if (length > 0) { + if (time > length) { + ui_skinned_horizontal_slider_set_position(mainwin_position, 219); + ui_skinned_horizontal_slider_set_position(mainwin_sposition, 13); + } + /* update the slider position ONLY if there is not a seek in progress */ + else if (seek_state == MAINWIN_SEEK_NIL) { + ui_skinned_horizontal_slider_set_position(mainwin_position, (time * 219) / length); + ui_skinned_horizontal_slider_set_position(mainwin_sposition, + ((time * 12) / length) + 1); + } + } + else { + ui_skinned_horizontal_slider_set_position(mainwin_position, 0); + ui_skinned_horizontal_slider_set_position(mainwin_sposition, 1); + } + + return TRUE; +} + +static gboolean +mainwin_idle_func(gpointer data) +{ + GDK_THREADS_ENTER(); + + /* tristate buttons seek */ + if ( seek_state != MAINWIN_SEEK_NIL ) + { + GTimeVal now_time; + GTimeVal delta_time; + gulong now_dur; + g_get_current_time(&now_time); + + delta_time.tv_usec = now_time.tv_usec - cb_time.tv_usec; + delta_time.tv_sec = now_time.tv_sec - cb_time.tv_sec; + + now_dur = labs((delta_time.tv_sec * 1000) + (glong) (delta_time.tv_usec / 1000)); + + if ( now_dur > TRISTATE_THRESHOLD ) + { + gint np; + if (seek_state == MAINWIN_SEEK_REV) + np = seek_initial_pos - labs((gulong)(now_dur/100)); /* seek back */ + else + np = seek_initial_pos + labs((gulong)(now_dur/100)); /* seek forward */ + + /* boundaries check */ + if (np < 0 ) + np = 0; + else if ( np > 219 ) + np = 219; + + ui_skinned_horizontal_slider_set_position( mainwin_position , np ); + mainwin_position_motion_cb( mainwin_position, np ); + } + } + + GDK_THREADS_LEAVE(); + return TRUE; +} + + +/* toggleactionentries actions */ + +void +action_anamode_peaks( GtkToggleAction * action ) +{ + cfg.analyzer_peaks = gtk_toggle_action_get_active( action ); +} + +void +action_autoscroll_songname( GtkToggleAction * action ) +{ + mainwin_set_title_scroll(gtk_toggle_action_get_active(action)); + playlistwin_set_sinfo_scroll(cfg.autoscroll); /* propagate scroll setting to playlistwin_sinfo */ +} + +void +action_playback_noplaylistadvance( GtkToggleAction * action ) +{ + cfg.no_playlist_advance = gtk_toggle_action_get_active( action ); +} + +void +action_playback_repeat( GtkToggleAction * action ) +{ + cfg.repeat = gtk_toggle_action_get_active( action ); + UI_SKINNED_BUTTON(mainwin_repeat)->inside = cfg.repeat; + gtk_widget_queue_draw(mainwin_repeat); +} + +void +action_playback_shuffle( GtkToggleAction * action ) +{ + cfg.shuffle = gtk_toggle_action_get_active( action ); + playlist_set_shuffle(cfg.shuffle); + UI_SKINNED_BUTTON(mainwin_shuffle)->inside = cfg.shuffle; + gtk_widget_queue_draw(mainwin_shuffle); +} + +void +action_stop_after_current_song( GtkToggleAction * action ) +{ + cfg.stopaftersong = gtk_toggle_action_get_active( action ); +} + +void +action_view_always_on_top( GtkToggleAction * action ) +{ + UI_SKINNED_MENUROW(mainwin_menurow)->always_selected = gtk_toggle_action_get_active( action ); + cfg.always_on_top = UI_SKINNED_MENUROW(mainwin_menurow)->always_selected; + gtk_widget_queue_draw(mainwin_menurow); + hint_set_always(cfg.always_on_top); +} + +void +action_view_scaled( GtkToggleAction * action ) +{ + UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected = gtk_toggle_action_get_active( action ); + gtk_widget_queue_draw(mainwin_menurow); + set_scaled(UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected); + gdk_flush(); +} + +void +action_view_easymove( GtkToggleAction * action ) +{ + cfg.easy_move = gtk_toggle_action_get_active( action ); +} + +void +action_view_on_all_workspaces( GtkToggleAction * action ) +{ + cfg.sticky = gtk_toggle_action_get_active( action ); + hint_set_sticky(cfg.sticky); +} + +void +action_roll_up_equalizer( GtkToggleAction * action ) +{ + equalizerwin_set_shade_menu_cb(gtk_toggle_action_get_active(action)); +} + +void +action_roll_up_player( GtkToggleAction * action ) +{ + mainwin_set_shade_menu_cb(gtk_toggle_action_get_active(action)); +} + +void +action_roll_up_playlist_editor( GtkToggleAction * action ) +{ + playlistwin_set_shade(gtk_toggle_action_get_active(action)); +} + +void +action_show_equalizer( GtkToggleAction * action ) +{ + if (gtk_toggle_action_get_active(action)) + equalizerwin_real_show(); + else + equalizerwin_real_hide(); +} + +void +action_show_playlist_editor( GtkToggleAction * action ) +{ + if (gtk_toggle_action_get_active(action)) + playlistwin_show(); + else + playlistwin_hide(); +} + +void +action_show_player( GtkToggleAction * action ) +{ + mainwin_show(gtk_toggle_action_get_active(action)); +} + + +/* radioactionentries actions (one callback for each radio group) */ + +void +action_anafoff( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_afalloff(gtk_radio_action_get_current_value(current)); +} + +void +action_anamode( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_analyzer_mode(gtk_radio_action_get_current_value(current)); +} + +void +action_anatype( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_analyzer_type(gtk_radio_action_get_current_value(current)); +} + +void +action_peafoff( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_pfalloff(gtk_radio_action_get_current_value(current)); +} + +void +action_refrate( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_refresh(gtk_radio_action_get_current_value(current)); +} + +void +action_scomode( GtkAction *action, GtkRadioAction *current ) +{ + cfg.scope_mode = gtk_radio_action_get_current_value(current); +} + +void +action_vismode( GtkAction *action, GtkRadioAction *current ) +{ + mainwin_vis_set_type_menu_cb(gtk_radio_action_get_current_value(current)); +} + +void +action_vprmode( GtkAction *action, GtkRadioAction *current ) +{ + cfg.voiceprint_mode = gtk_radio_action_get_current_value(current); +} + +void +action_wshmode( GtkAction *action, GtkRadioAction *current ) +{ + cfg.vu_mode = gtk_radio_action_get_current_value(current); +} + +void +action_viewtime( GtkAction *action, GtkRadioAction *current ) +{ + set_timer_mode_menu_cb(gtk_radio_action_get_current_value(current)); +} + + +/* actionentries actions */ + +void +action_about_audacious( void ) +{ + show_about_window(); +} + +void +action_play_file( void ) +{ + run_filebrowser(TRUE); +} + +void +action_play_location( void ) +{ + mainwin_show_add_url_window(); +} + +void +action_ab_set( void ) +{ + Playlist *playlist = playlist_get_active(); + if (playlist_get_current_length(playlist) != -1) + { + if (ab_position_a == -1) + { + ab_position_a = playback_get_time(); + ab_position_b = -1; + mainwin_lock_info_text("LOOP-POINT A POSITION SET."); + } + else if (ab_position_b == -1) + { + int time = playback_get_time(); + if (time > ab_position_a) + ab_position_b = time; + mainwin_release_info_text(); + } + else + { + ab_position_a = playback_get_time(); + ab_position_b = -1; + mainwin_lock_info_text("LOOP-POINT A POSITION RESET."); + } + } +} + +void +action_ab_clear( void ) +{ + Playlist *playlist = playlist_get_active(); + if (playlist_get_current_length(playlist) != -1) + { + ab_position_a = ab_position_b = -1; + mainwin_release_info_text(); + } +} + +void +action_current_track_info( void ) +{ + ui_fileinfo_show_current(playlist_get_active()); +} + +void +action_jump_to_file( void ) +{ + ui_jump_to_track(); +} + +void +action_jump_to_playlist_start( void ) +{ + Playlist *playlist = playlist_get_active(); + playlist_set_position(playlist, 0); +} + +void +action_jump_to_time( void ) +{ + mainwin_jump_to_time(); +} + +void +action_playback_next( void ) +{ + Playlist *playlist = playlist_get_active(); + playlist_next(playlist); +} + +void +action_playback_previous( void ) +{ + Playlist *playlist = playlist_get_active(); + playlist_prev(playlist); +} + +void +action_playback_play( void ) +{ + mainwin_play_pushed(); +} + +void +action_playback_pause( void ) +{ + playback_pause(); +} + +void +action_playback_stop( void ) +{ + mainwin_stop_pushed(); +} + +void +action_preferences( void ) +{ + show_prefs_window(); +} + +void +action_quit( void ) +{ + mainwin_quit_cb(); +} + +void +util_menu_main_show( gint x , gint y , guint button , guint time ) +{ + /* convenience function that shows the main popup menu wherever requested */ + ui_manager_popup_menu_show( GTK_MENU(mainwin_general_menu), + x , y , button , time ); + return; +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_main.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_main.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,193 @@ +/* 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. + */ + +#ifndef AUDACIOUS_UI_MAIN_H +#define AUDACIOUS_UI_MAIN_H + +#include + +#include "ui_vis.h" +#include "ui_svis.h" + +/* yes, main window size is fixed */ +#define MAINWIN_WIDTH (gint)275 +#define MAINWIN_HEIGHT (gint)116 +#define MAINWIN_TITLEBAR_HEIGHT (gint)14 +#define MAINWIN_SHADED_WIDTH MAINWIN_WIDTH +#define MAINWIN_SHADED_HEIGHT MAINWIN_TITLEBAR_HEIGHT +#define MAINWIN_SCALE_FACTOR (cfg.scaled ? cfg.scale_factor : 1) + +#define MAINWIN_UPDATE_INTERVAL 100 + +#define MAINWIN_DEFAULT_POS_X 20 +#define MAINWIN_DEFAULT_POS_Y 20 + +#define MAINWIN_DEFAULT_FONT "Sans Bold 9" + + +typedef enum { + TIMER_ELAPSED, + TIMER_REMAINING +} TimerMode; + +enum { + MAINWIN_GENERAL_ABOUT, + + MAINWIN_GENERAL_PLAYFILE, + MAINWIN_GENERAL_PLAYLOCATION, + + MAINWIN_GENERAL_FILEINFO, + MAINWIN_GENERAL_PREFS, + + MAINWIN_GENERAL_SHOWMWIN, + MAINWIN_GENERAL_SHOWPLWIN, + + MAINWIN_GENERAL_FOCUSMWIN, + MAINWIN_GENERAL_FOCUSPLWIN, + + MAINWIN_GENERAL_SHOWEQWIN, + MAINWIN_GENERAL_EXIT, + + MAINWIN_GENERAL_PREV, + MAINWIN_GENERAL_PLAY, + MAINWIN_GENERAL_PAUSE, + MAINWIN_GENERAL_STOP, + MAINWIN_GENERAL_NEXT, + MAINWIN_GENERAL_STOPFADE, + MAINWIN_GENERAL_BACK5SEC, + MAINWIN_GENERAL_FWD5SEC, + MAINWIN_GENERAL_START, + MAINWIN_GENERAL_BACK10, + MAINWIN_GENERAL_FWD10, + MAINWIN_GENERAL_JTT, + MAINWIN_GENERAL_JTF, + MAINWIN_GENERAL_QUEUE, + MAINWIN_GENERAL_CQUEUE, + MAINWIN_GENERAL_VOLUP, + MAINWIN_GENERAL_VOLDOWN, + MAINWIN_GENERAL_SETAB, + MAINWIN_GENERAL_CLEARAB, + + MAINWIN_GENERAL_NEXT_PL, + MAINWIN_GENERAL_PREV_PL, + MAINWIN_GENERAL_NEW_PL +}; + +extern GtkWidget *mainwin; +extern GtkWidget *err; + +extern gboolean mainwin_moving; +extern gboolean mainwin_focus; + +extern GtkWidget *mainwin_jtf; +extern GtkWidget *mainwin_eq, *mainwin_pl; +extern GtkWidget *mainwin_info; + +extern GtkWidget *mainwin_stime_min, *mainwin_stime_sec; + +extern GtkWidget *mainwin_vis; +extern GtkWidget *mainwin_svis; + +extern GtkWidget *mainwin_playstatus; + +extern GtkWidget *mainwin_minus_num, *mainwin_10min_num, *mainwin_min_num; +extern GtkWidget *mainwin_10sec_num, *mainwin_sec_num; + +extern GtkWidget *mainwin_position, *mainwin_sposition; + +void mainwin_create(void); + +void mainwin_lock_info_text(const gchar * text); +void mainwin_release_info_text(void); +void mainwin_play_pushed(void); +void mainwin_stop_pushed(void); +void mainwin_eject_pushed(void); + +void mainwin_rev_pushed(void); +void mainwin_rev_release(void); +void mainwin_fwd_pushed(void); +void mainwin_fwd_release(void); + +void mainwin_adjust_volume_motion(gint v); +void mainwin_adjust_volume_release(void); +void mainwin_adjust_balance_motion(gint b); +void mainwin_adjust_balance_release(void); +void mainwin_set_volume_slider(gint percent); +void mainwin_set_balance_slider(gint percent); + +void mainwin_vis_set_type(VisType mode); + +void mainwin_refresh_hints(void); +void mainwin_set_info_text(void); +void mainwin_set_song_info(gint rate, gint freq, gint nch); +void mainwin_clear_song_info(void); +void mainwin_set_stopaftersong(gboolean stop); +void mainwin_set_noplaylistadvance(gboolean no_advance); + +void mainwin_set_always_on_top(gboolean always); +void mainwin_set_volume_diff(gint diff); +void mainwin_set_balance_diff(gint diff); + +void mainwin_show(gboolean); +void mainwin_real_show(void); +void mainwin_real_hide(void); +void mainwin_move(gint x, gint y); +void mainwin_shuffle_pushed(gboolean toggled); +void mainwin_repeat_pushed(gboolean toggled); +void mainwin_disable_seekbar(void); +void mainwin_set_title(const gchar * text); +void mainwin_show_add_url_window(void); +void mainwin_minimize_cb(void); +void mainwin_general_menu_callback(gpointer cb_data, + guint action, + GtkWidget * widget); + +gboolean mainwin_update_song_info(void); +void mainwin_drag_data_received(GtkWidget * widget, + GdkDragContext * context, + gint x, + gint y, + GtkSelectionData * selection_data, + guint info, + guint time, + gpointer user_data); + +void mainwin_setup_menus(void); +gboolean change_timer_mode_cb(GtkWidget *widget, GdkEventButton *event); + +void mainwin_jump_to_file(void); +void mainwin_jump_to_time(void); + +void mainwin_ewmh_activate(void); + +void mainwin_show_visibility_warning(void); + +/* FIXME: placed here for now */ +void playback_get_sample_params(gint * bitrate, + gint * frequency, + gint * numchannels); + +void ui_main_check_theme_engine(void); + +void util_menu_main_show( gint x , gint y , guint button , guint time ); + +#endif /* AUDACIOUS_UI_MAIN_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_main_evlisteners.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_main_evlisteners.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,474 @@ +/* + * Audacious + * Copyright (c) 2006-2007 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 "ui_playlist_evlisteners.h" + +#include +#include + +#include "hook.h" +#include "playback.h" +#include "playlist.h" +#include "playlist_evmessages.h" +#include "visualization.h" + +#include "ui_credits.h" +#include "ui_equalizer.h" +#include "ui_fileopener.h" +#include "ui_jumptotrack.h" +#include "ui_main.h" +#include "ui_playlist.h" +#include "ui_preferences.h" +#include "ui_skinned_playstatus.h" +#include "ui_skinned_textbox.h" +#include "ui_skinned_window.h" + +static gint song_info_timeout_source = 0; +static gint update_vis_timeout_source = 0; + +/* XXX: there has to be a better way than polling here! */ +/* also: where should this function go? should it stay here? --mf0102 */ +static gboolean +update_vis_func(gpointer unused) +{ + if (!playback_get_playing()) + return FALSE; + + input_update_vis(playback_get_time()); + + return TRUE; +} + +static void +ui_main_evlistener_title_change(gpointer hook_data, gpointer user_data) +{ + gchar *text = (gchar *) hook_data; + + ui_skinned_textbox_set_text(mainwin_info, text); + playlistwin_update_list(playlist_get_active()); +} + +static void +ui_main_evlistener_hide_seekbar(gpointer hook_data, gpointer user_data) +{ + mainwin_disable_seekbar(); +} + +static void +ui_main_evlistener_volume_change(gpointer hook_data, gpointer user_data) +{ + gint *h_vol = (gint *) hook_data; + gint vl, vr, b, v; + + vl = CLAMP(h_vol[0], 0, 100); + vr = CLAMP(h_vol[1], 0, 100); + v = MAX(vl, vr); + if (vl > vr) + b = (gint) rint(((gdouble) vr / vl) * 100) - 100; + else if (vl < vr) + b = 100 - (gint) rint(((gdouble) vl / vr) * 100); + else + b = 0; + + mainwin_set_volume_slider(v); + equalizerwin_set_volume_slider(v); + mainwin_set_balance_slider(b); + equalizerwin_set_balance_slider(b); +} + +static void +ui_main_evlistener_playback_initiate(gpointer hook_data, gpointer user_data) +{ + playback_initiate(); +} + +static void +ui_main_evlistener_playback_begin(gpointer hook_data, gpointer user_data) +{ + PlaylistEntry *entry = (PlaylistEntry*)hook_data; + g_return_if_fail(entry != NULL); + + equalizerwin_load_auto_preset(entry->filename); + hook_call("equalizer changed", NULL); + + ui_vis_clear_data(mainwin_vis); + ui_svis_clear_data(mainwin_svis); + mainwin_disable_seekbar(); + mainwin_update_song_info(); + + if (cfg.player_shaded) { + gtk_widget_show(mainwin_stime_min); + gtk_widget_show(mainwin_stime_sec); + gtk_widget_show(mainwin_sposition); + } else { + gtk_widget_show(mainwin_minus_num); + gtk_widget_show(mainwin_10min_num); + gtk_widget_show(mainwin_min_num); + gtk_widget_show(mainwin_10sec_num); + gtk_widget_show(mainwin_sec_num); + gtk_widget_show(mainwin_position); + } + + song_info_timeout_source = + g_timeout_add_seconds(1, (GSourceFunc) mainwin_update_song_info, NULL); + + update_vis_timeout_source = + g_timeout_add(10, (GSourceFunc) update_vis_func, NULL); + + vis_playback_start(); + + ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PLAY); +} + +static void +ui_main_evlistener_playback_stop(gpointer hook_data, gpointer user_data) +{ + if (song_info_timeout_source) + g_source_remove(song_info_timeout_source); + + vis_playback_stop(); + free_vis_data(); + + ui_skinned_playstatus_set_buffering(mainwin_playstatus, FALSE); +} + +static void +ui_main_evlistener_playback_pause(gpointer hook_data, gpointer user_data) +{ + ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PAUSE); +} + +static void +ui_main_evlistener_playback_unpause(gpointer hook_data, gpointer user_data) +{ + ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PLAY); +} + +static void +ui_main_evlistener_playback_seek(gpointer hook_data, gpointer user_data) +{ + free_vis_data(); +} + +static void +ui_main_evlistener_playback_play_file(gpointer hook_data, gpointer user_data) +{ + if (cfg.random_skin_on_play) + skin_set_random_skin(); +} + +static void +ui_main_evlistener_playlist_end_reached(gpointer hook_data, gpointer user_data) +{ + mainwin_clear_song_info(); + + if (cfg.stopaftersong) + mainwin_set_stopaftersong(FALSE); +} + +static void +ui_main_evlistener_playlist_info_change(gpointer hook_data, gpointer user_data) +{ + PlaylistEventInfoChange *msg = (PlaylistEventInfoChange *) hook_data; + + mainwin_set_song_info(msg->bitrate, msg->samplerate, msg->channels); +} + +static void +ui_main_evlistener_mainwin_set_always_on_top(gpointer hook_data, gpointer user_data) +{ + gboolean *ontop = (gboolean*)hook_data; + mainwin_set_always_on_top(*ontop); +} + +static void +ui_main_evlistener_mainwin_show(gpointer hook_data, gpointer user_data) +{ + gboolean *show = (gboolean*)hook_data; + mainwin_show(*show); +} + +static void +ui_main_evlistener_equalizerwin_show(gpointer hook_data, gpointer user_data) +{ + gboolean *show = (gboolean*)hook_data; + equalizerwin_show(*show); +} + +static void +ui_main_evlistener_prefswin_show(gpointer hook_data, gpointer user_data) +{ + gboolean *show = (gboolean*)hook_data; + if (*show == TRUE) + show_prefs_window(); + else + hide_prefs_window(); +} + +static void +ui_main_evlistener_aboutwin_show(gpointer hook_data, gpointer user_data) +{ + gboolean *show = (gboolean*)hook_data; + if (*show == TRUE) + show_about_window(); + else + hide_about_window(); +} + + +static void +ui_main_evlistener_ui_jump_to_track_show(gpointer hook_data, gpointer user_data) +{ + gboolean *show = (gboolean*)hook_data; + if (*show == TRUE) + ui_jump_to_track(); + else + ui_jump_to_track_hide(); +} + +static void +ui_main_evlistener_filebrowser_show(gpointer hook_data, gpointer user_data) +{ + gboolean *play_button = (gboolean*)hook_data; + run_filebrowser(*play_button); +} + +static void +ui_main_evlistener_filebrowser_hide(gpointer hook_data, gpointer user_data) +{ + hide_filebrowser(); +} + +static void +ui_main_evlistener_visualization_timeout(gpointer hook_data, gpointer user_data) +{ + if (hook_data == NULL) { + if (cfg.player_shaded && cfg.player_visible) + ui_svis_timeout_func(mainwin_svis, NULL); + else + ui_vis_timeout_func(mainwin_vis, NULL); + return; + } + + VisNode *vis = (VisNode*) hook_data; + + guint8 intern_vis_data[512]; + gint16 mono_freq[2][256]; + gboolean mono_freq_calced = FALSE; + gint16 mono_pcm[2][512], stereo_pcm[2][512]; + gboolean mono_pcm_calced = FALSE, stereo_pcm_calced = FALSE; + gint i; + + if (cfg.vis_type == VIS_OFF) + return; + + if (cfg.vis_type == VIS_ANALYZER) { + /* Spectrum analyzer */ + /* 76 values */ + const gint long_xscale[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, + 52, 53, 54, 55, 56, 57, 58, 61, 66, 71, 76, 81, 87, 93, + 100, 107, + 114, 122, 131, 140, 150, 161, 172, 184, 255 + }; + /* 20 values */ + const int short_xscale[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 15, 20, 27, + 36, 47, 62, 82, 107, 141, 184, 255 + }; + const double y_scale = 3.60673760222; /* 20.0 / log(256) */ + const int *xscale; + gint j, y, max; + + if (!mono_freq_calced) + calc_mono_freq(mono_freq, vis->data, vis->nch); + + memset(intern_vis_data, 0, 75); + + if (cfg.analyzer_type == ANALYZER_BARS) { + if (cfg.player_shaded) { + max = 13; + } + else { + max = 19; + } + xscale = short_xscale; + } + else { + if (cfg.player_shaded) { + max = 37; + } + else { + max = 75; + } + xscale = long_xscale; + } + + for (i = 0; i < max; i++) { + for (j = xscale[i], y = 0; j < xscale[i + 1]; j++) { + if (mono_freq[0][j] > y) + y = mono_freq[0][j]; + } + y >>= 7; + if (y != 0) { + intern_vis_data[i] = log(y) * y_scale; + if (intern_vis_data[i] > 15) + intern_vis_data[i] = 15; + } + else + intern_vis_data[i] = 0; + } + + } + else if(cfg.vis_type == VIS_VOICEPRINT){ + if (cfg.player_shaded && cfg.player_visible) { + /* VU */ + gint vu, val; + + if (!stereo_pcm_calced) + calc_stereo_pcm(stereo_pcm, vis->data, vis->nch); + vu = 0; + for (i = 0; i < 512; i++) { + val = abs(stereo_pcm[0][i]); + if (val > vu) + vu = val; + } + intern_vis_data[0] = (vu * 37) >> 15; + if (intern_vis_data[0] > 37) + intern_vis_data[0] = 37; + if (vis->nch == 2) { + vu = 0; + for (i = 0; i < 512; i++) { + val = abs(stereo_pcm[1][i]); + if (val > vu) + vu = val; + } + intern_vis_data[1] = (vu * 37) >> 15; + if (intern_vis_data[1] > 37) + intern_vis_data[1] = 37; + } + else + intern_vis_data[1] = intern_vis_data[0]; + } + else { /*Voiceprint*/ + if (!mono_freq_calced) + calc_mono_freq(mono_freq, vis->data, vis->nch); + memset(intern_vis_data, 0, 256); + + /* For the values [0-16] we use the frequency that's 3/2 as much. + If we assume the 512 values calculated by calc_mono_freq to + cover 0-22kHz linearly we get a range of + [0-16] * 3/2 * 22000/512 = [0-1,031] Hz. + Most stuff above that is harmonics and we want to utilize the + 16 samples we have to the max[tm] + */ + for (i = 0; i < 50 ; i+=3){ + intern_vis_data[i/3] += (mono_freq[0][i/2] >> 5); + + /*Boost frequencies above 257Hz a little*/ + //if(i > 4 * 3) + // intern_vis_data[i/3] += 8; + } + } + } + else { /* (cfg.vis_type == VIS_SCOPE) */ + + /* Oscilloscope */ + gint pos, step; + + if (!mono_pcm_calced) + calc_mono_pcm(mono_pcm, vis->data, vis->nch); + + step = (vis->length << 8) / 74; + for (i = 0, pos = 0; i < 75; i++, pos += step) { + intern_vis_data[i] = ((mono_pcm[0][pos >> 8]) >> 12) + 7; + if (intern_vis_data[i] == 255) + intern_vis_data[i] = 0; + else if (intern_vis_data[i] > 12) + intern_vis_data[i] = 12; + /* Do not see the point of that? (comparison always false) -larne. + if (intern_vis_data[i] < 0) + intern_vis_data[i] = 0; */ + } + } + + if (cfg.player_shaded && cfg.player_visible) + ui_svis_timeout_func(mainwin_svis, intern_vis_data); + else + ui_vis_timeout_func(mainwin_vis, intern_vis_data); +} + +static void +ui_main_evlistener_config_save(gpointer hook_data, gpointer user_data) +{ + ConfigDb *db = (ConfigDb *) hook_data; + + if (SKINNED_WINDOW(mainwin)->x != -1 && + SKINNED_WINDOW(mainwin)->y != -1 ) + { + cfg_db_set_int(db, NULL, "player_x", SKINNED_WINDOW(mainwin)->x); + cfg_db_set_int(db, NULL, "player_y", SKINNED_WINDOW(mainwin)->y); + } + + cfg_db_set_bool(db, NULL, "mainwin_use_bitmapfont", + cfg.mainwin_use_bitmapfont); +} + +static void +ui_main_evlistener_equalizer_changed(gpointer hook_data, gpointer user_data) +{ + output_set_eq(cfg.equalizer_active, cfg.equalizer_preamp, + cfg.equalizer_bands); +} + +void +ui_main_evlistener_init(void) +{ + hook_associate("title change", ui_main_evlistener_title_change, NULL); + hook_associate("hide seekbar", ui_main_evlistener_hide_seekbar, NULL); + hook_associate("volume set", ui_main_evlistener_volume_change, NULL); + hook_associate("playback initiate", ui_main_evlistener_playback_initiate, NULL); + hook_associate("playback begin", ui_main_evlistener_playback_begin, NULL); + hook_associate("playback stop", ui_main_evlistener_playback_stop, NULL); + hook_associate("playback pause", ui_main_evlistener_playback_pause, NULL); + hook_associate("playback unpause", ui_main_evlistener_playback_unpause, NULL); + hook_associate("playback seek", ui_main_evlistener_playback_seek, NULL); + hook_associate("playback play file", ui_main_evlistener_playback_play_file, NULL); + hook_associate("playlist end reached", ui_main_evlistener_playlist_end_reached, NULL); + hook_associate("playlist info change", ui_main_evlistener_playlist_info_change, NULL); + hook_associate("mainwin set always on top", ui_main_evlistener_mainwin_set_always_on_top, NULL); + hook_associate("mainwin show", ui_main_evlistener_mainwin_show, NULL); + hook_associate("equalizerwin show", ui_main_evlistener_equalizerwin_show, NULL); + hook_associate("prefswin show", ui_main_evlistener_prefswin_show, NULL); + hook_associate("aboutwin show", ui_main_evlistener_aboutwin_show, NULL); + hook_associate("ui jump to track show", ui_main_evlistener_ui_jump_to_track_show, NULL); + hook_associate("filebrowser show", ui_main_evlistener_filebrowser_show, NULL); + hook_associate("filebrowser hide", ui_main_evlistener_filebrowser_hide, NULL); + hook_associate("visualization timeout", ui_main_evlistener_visualization_timeout, NULL); + hook_associate("config save", ui_main_evlistener_config_save, NULL); + + hook_associate("equalizer changed", ui_main_evlistener_equalizer_changed, NULL); +} + diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_main_evlisteners.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_main_evlisteners.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,28 @@ +/* + * Audacious + * Copyright (c) 2006-2007 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 + +#ifndef AUDACIOUS_UI_MAIN_EVLISTENERS_H +#define AUDACIOUS_UI_MAIN_EVLISTENERS_H + +void ui_main_evlistener_init(void); + +#endif /* AUDACIOUS_UI_MAIN_EVLISTENERS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_manager.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_manager.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,872 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui_manager.h" +#include "actions-mainwin.h" +#include "actions-playlist.h" +#include "actions-equalizer.h" + +/* this header contains prototypes for plugin-available menu functions */ +#include "ui_plugin_menu.h" + +/* TODO ui_main.h is only included because ui_manager.c needs the values of + TimerMode enum; move that enum elsewhere so we can get rid of this include */ +#include "ui_main.h" + +#include "icons-stock.h" + +#include "sync-menu.h" + +static GtkUIManager *ui_manager = NULL; +static gboolean menu_created = FALSE; + + +/* toggle action entries */ + +static GtkToggleActionEntry toggleaction_entries_others[] = { + + { "autoscroll songname", NULL , N_("Autoscroll Songname"), NULL, + N_("Autoscroll Songname"), G_CALLBACK(action_autoscroll_songname) , FALSE }, + + { "stop after current song", NULL , N_("Stop after Current Song"), "M", + N_("Stop after Current Song"), G_CALLBACK(action_stop_after_current_song) , FALSE }, + + { "anamode peaks", NULL , N_("Peaks"), NULL, + N_("Peaks"), G_CALLBACK(action_anamode_peaks) , FALSE }, + + { "playback repeat", NULL , N_("Repeat"), "R", + N_("Repeat"), G_CALLBACK(action_playback_repeat) , FALSE }, + + { "playback shuffle", NULL , N_("Shuffle"), "S", + N_("Shuffle"), G_CALLBACK(action_playback_shuffle) , FALSE }, + + { "playback no playlist advance", NULL , N_("No Playlist Advance"), "N", + N_("No Playlist Advance"), G_CALLBACK(action_playback_noplaylistadvance) , FALSE }, + + { "show player", NULL , N_("Show Player"), "M", + N_("Show Player"), G_CALLBACK(action_show_player) , FALSE }, + + { "show playlist editor", NULL , N_("Show Playlist Editor"), "E", + N_("Show Playlist Editor"), G_CALLBACK(action_show_playlist_editor) , FALSE }, + + { "show equalizer", NULL , N_("Show Equalizer"), "G", + N_("Show Equalizer"), G_CALLBACK(action_show_equalizer) , FALSE }, + + { "view always on top", NULL , N_("Always on Top"), "O", + N_("Always on Top"), G_CALLBACK(action_view_always_on_top) , FALSE }, + + { "view put on all workspaces", NULL , N_("Put on All Workspaces"), "S", + N_("Put on All Workspaces"), G_CALLBACK(action_view_on_all_workspaces) , FALSE }, + + { "roll up player", NULL , N_("Roll up Player"), "W", + N_("Roll up Player"), G_CALLBACK(action_roll_up_player) , FALSE }, + + { "roll up playlist editor", NULL , N_("Roll up Playlist Editor"), "W", + N_("Roll up Playlist Editor"), G_CALLBACK(action_roll_up_playlist_editor) , FALSE }, + + { "roll up equalizer", NULL , N_("Roll up Equalizer"), "W", + N_("Roll up Equalizer"), G_CALLBACK(action_roll_up_equalizer) , FALSE }, + + { "view scaled", NULL , N_("Scale"), "D", + N_("DoubleSize"), G_CALLBACK(action_view_scaled) , FALSE }, + + { "view easy move", NULL , N_("Easy Move"), "E", + N_("Easy Move"), G_CALLBACK(action_view_easymove) , FALSE } +}; + + + +/* radio action entries */ + +static GtkRadioActionEntry radioaction_entries_vismode[] = { + { "vismode analyzer", NULL , N_("Analyzer"), NULL, N_("Analyzer"), VIS_ANALYZER }, + { "vismode scope", NULL , N_("Scope"), NULL, N_("Scope"), VIS_SCOPE }, + { "vismode voiceprint", NULL , N_("Voiceprint"), NULL, N_("Voiceprint"), VIS_VOICEPRINT }, + { "vismode off", NULL , N_("Off"), NULL, N_("Off"), VIS_OFF } +}; + +static GtkRadioActionEntry radioaction_entries_anamode[] = { + { "anamode normal", NULL , N_("Normal"), NULL, N_("Normal"), ANALYZER_NORMAL }, + { "anamode fire", NULL , N_("Fire"), NULL, N_("Fire"), ANALYZER_FIRE }, + { "anamode vertical lines", NULL , N_("Vertical Lines"), NULL, N_("Vertical Lines"), ANALYZER_VLINES } +}; + +static GtkRadioActionEntry radioaction_entries_anatype[] = { + { "anatype lines", NULL , N_("Lines"), NULL, N_("Lines"), ANALYZER_LINES }, + { "anatype bars", NULL , N_("Bars"), NULL, N_("Bars"), ANALYZER_BARS } +}; + +static GtkRadioActionEntry radioaction_entries_scomode[] = { + { "scomode dot", NULL , N_("Dot Scope"), NULL, N_("Dot Scope"), SCOPE_DOT }, + { "scomode line", NULL , N_("Line Scope"), NULL, N_("Line Scope"), SCOPE_LINE }, + { "scomode solid", NULL , N_("Solid Scope"), NULL, N_("Solid Scope"), SCOPE_SOLID } +}; + +static GtkRadioActionEntry radioaction_entries_vprmode[] = { + { "vprmode normal", NULL , N_("Normal"), NULL, N_("Normal"), VOICEPRINT_NORMAL }, + { "vprmode fire", NULL , N_("Fire"), NULL, N_("Fire"), VOICEPRINT_FIRE }, + { "vprmode ice", NULL , N_("Ice"), NULL, N_("Ice"), VOICEPRINT_ICE } +}; + +static GtkRadioActionEntry radioaction_entries_wshmode[] = { + { "wshmode normal", NULL , N_("Normal"), NULL, N_("Normal"), VU_NORMAL }, + { "wshmode smooth", NULL , N_("Smooth"), NULL, N_("Smooth"), VU_SMOOTH } +}; + +static GtkRadioActionEntry radioaction_entries_refrate[] = { + { "refrate full", NULL , N_("Full (~50 fps)"), NULL, N_("Full (~50 fps)"), REFRESH_FULL }, + { "refrate half", NULL , N_("Half (~25 fps)"), NULL, N_("Half (~25 fps)"), REFRESH_HALF }, + { "refrate quarter", NULL , N_("Quarter (~13 fps)"), NULL, N_("Quarter (~13 fps)"), REFRESH_QUARTER }, + { "refrate eighth", NULL , N_("Eighth (~6 fps)"), NULL, N_("Eighth (~6 fps)"), REFRESH_EIGTH } +}; + +static GtkRadioActionEntry radioaction_entries_anafoff[] = { + { "anafoff slowest", NULL , N_("Slowest"), NULL, N_("Slowest"), FALLOFF_SLOWEST }, + { "anafoff slow", NULL , N_("Slow"), NULL, N_("Slow"), FALLOFF_SLOW }, + { "anafoff medium", NULL , N_("Medium"), NULL, N_("Medium"), FALLOFF_MEDIUM }, + { "anafoff fast", NULL , N_("Fast"), NULL, N_("Fast"), FALLOFF_FAST }, + { "anafoff fastest", NULL , N_("Fastest"), NULL, N_("Fastest"), FALLOFF_FASTEST } +}; + +static GtkRadioActionEntry radioaction_entries_peafoff[] = { + { "peafoff slowest", NULL , N_("Slowest"), NULL, N_("Slowest"), FALLOFF_SLOWEST }, + { "peafoff slow", NULL , N_("Slow"), NULL, N_("Slow"), FALLOFF_SLOW }, + { "peafoff medium", NULL , N_("Medium"), NULL, N_("Medium"), FALLOFF_MEDIUM }, + { "peafoff fast", NULL , N_("Fast"), NULL, N_("Fast"), FALLOFF_FAST }, + { "peafoff fastest", NULL , N_("Fastest"), NULL, N_("Fastest"), FALLOFF_FASTEST } +}; + +static GtkRadioActionEntry radioaction_entries_viewtime[] = { + { "view time elapsed", NULL , N_("Time Elapsed"), "E", N_("Time Elapsed"), TIMER_ELAPSED }, + { "view time remaining", NULL , N_("Time Remaining"), "R", N_("Time Remaining"), TIMER_REMAINING } +}; + + + +/* normal actions */ + +static GtkActionEntry action_entries_playback[] = { + + { "playback", NULL, N_("Playback") }, + + { "playback play", GTK_STOCK_MEDIA_PLAY , N_("Play"), "X", + N_("Play"), G_CALLBACK(action_playback_play) }, + + { "playback pause", GTK_STOCK_MEDIA_PAUSE , N_("Pause"), "C", + N_("Pause"), G_CALLBACK(action_playback_pause) }, + + { "playback stop", GTK_STOCK_MEDIA_STOP , N_("Stop"), "V", + N_("Stop"), G_CALLBACK(action_playback_stop) }, + + { "playback previous", GTK_STOCK_MEDIA_PREVIOUS , N_("Previous"), "Z", + N_("Previous"), G_CALLBACK(action_playback_previous) }, + + { "playback next", GTK_STOCK_MEDIA_NEXT , N_("Next"), "B", + N_("Next"), G_CALLBACK(action_playback_next) } +}; + + +static GtkActionEntry action_entries_visualization[] = { + { "visualization", NULL, N_("Visualization") }, + { "vismode", NULL, N_("Visualization Mode") }, + { "anamode", NULL, N_("Analyzer Mode") }, + { "scomode", NULL, N_("Scope Mode") }, + { "vprmode", NULL, N_("Voiceprint Mode") }, + { "wshmode", NULL, N_("WindowShade VU Mode") }, + { "refrate", NULL, N_("Refresh Rate") }, + { "anafoff", NULL, N_("Analyzer Falloff") }, + { "peafoff", NULL, N_("Peaks Falloff") } +}; + +static GtkActionEntry action_entries_playlist[] = { + + { "playlist", NULL, N_("Playlist") }, + + { "playlist new", GTK_STOCK_NEW , N_("New Playlist"), "N", + N_("New Playlist"), G_CALLBACK(action_playlist_new) }, + + { "playlist select next", GTK_STOCK_MEDIA_NEXT, N_("Select Next Playlist"), "P", + N_("Select Next Playlist"), G_CALLBACK(action_playlist_next) }, + + { "playlist select previous", GTK_STOCK_MEDIA_PREVIOUS, N_("Select Previous Playlist"), "P", + N_("Select Previous Playlist"), G_CALLBACK(action_playlist_prev) }, + + { "playlist delete", GTK_STOCK_DELETE , N_("Delete Playlist"), "D", + N_("Delete Playlist"), G_CALLBACK(action_playlist_delete) }, + + { "playlist load", GTK_STOCK_OPEN, N_("Load List"), "O", + N_("Loads a playlist file into the selected playlist."), G_CALLBACK(action_playlist_load_list) }, + + { "playlist save", GTK_STOCK_SAVE, N_("Save List"), "S", + N_("Saves the selected playlist."), G_CALLBACK(action_playlist_save_list) }, + + { "playlist save default", GTK_STOCK_SAVE, N_("Save Default List"), "S", + N_("Saves the selected playlist to the default location."), + G_CALLBACK(action_playlist_save_default_list) }, + + { "playlist refresh", GTK_STOCK_REFRESH, N_("Refresh List"), "F5", + N_("Refreshes metadata associated with a playlist entry."), + G_CALLBACK(action_playlist_refresh_list) }, + + { "playlist manager", AUD_STOCK_PLAYLIST , N_("List Manager"), "P", + N_("Opens the playlist manager."), + G_CALLBACK(action_open_list_manager) } +}; + +static GtkActionEntry action_entries_view[] = { + + { "view", NULL, N_("View") } +}; + +static GtkActionEntry action_entries_playlist_add[] = { + { "playlist add url", GTK_STOCK_NETWORK, N_("Add Internet Address..."), "H", + N_("Adds a remote track to the playlist."), + G_CALLBACK(action_playlist_add_url) }, + + { "playlist add files", GTK_STOCK_ADD, N_("Add Files..."), "F", + N_("Adds files to the playlist."), + G_CALLBACK(action_playlist_add_files) }, +}; + +static GtkActionEntry action_entries_playlist_select[] = { + { "playlist search and select", GTK_STOCK_FIND, N_("Search and Select"), "F", + N_("Searches the playlist and selects playlist entries based on specific criteria."), + G_CALLBACK(action_playlist_search_and_select) }, + + { "playlist invert selection", NULL , N_("Invert Selection"), NULL, + N_("Inverts the selected and unselected entries."), + G_CALLBACK(action_playlist_invert_selection) }, + + { "playlist select all", NULL , N_("Select All"), "A", + N_("Selects all of the playlist entries."), + G_CALLBACK(action_playlist_select_all) }, + + { "playlist select none", NULL , N_("Select None"), "A", + N_("Deselects all of the playlist entries."), + G_CALLBACK(action_playlist_select_none) }, +}; + +static GtkActionEntry action_entries_playlist_delete[] = { + { "playlist remove all", GTK_STOCK_CLEAR, N_("Remove All"), NULL, + N_("Removes all entries from the playlist."), + G_CALLBACK(action_playlist_remove_all) }, + + { "playlist clear queue", GTK_STOCK_CLEAR, N_("Clear Queue"), "Q", + N_("Clears the queue associated with this playlist."), + G_CALLBACK(action_playlist_clear_queue) }, + + { "playlist remove unavailable", GTK_STOCK_DIALOG_ERROR , N_("Remove Unavailable Files"), NULL, + N_("Removes unavailable files from the playlist."), + G_CALLBACK(action_playlist_remove_unavailable) }, + + { "playlist remove dups menu", NULL , N_("Remove Duplicates") }, + + { "playlist remove dups by title", NULL , N_("By Title"), NULL, + N_("Removes duplicate entries from the playlist by title."), + G_CALLBACK(action_playlist_remove_dupes_by_title) }, + + { "playlist remove dups by filename", NULL , N_("By Filename"), NULL, + N_("Removes duplicate entries from the playlist by filename."), + G_CALLBACK(action_playlist_remove_dupes_by_filename) }, + + { "playlist remove dups by full path", NULL , N_("By Path + Filename"), NULL, + N_("Removes duplicate entries from the playlist by their full path."), + G_CALLBACK(action_playlist_remove_dupes_by_full_path) }, + + { "playlist remove unselected", GTK_STOCK_REMOVE, N_("Remove Unselected"), NULL, + N_("Remove unselected entries from the playlist."), + G_CALLBACK(action_playlist_remove_unselected) }, + + { "playlist remove selected", GTK_STOCK_REMOVE, N_("Remove Selected"), "Delete", + N_("Remove selected entries from the playlist."), + G_CALLBACK(action_playlist_remove_selected) }, +}; + +static GtkActionEntry action_entries_playlist_sort[] = { + { "playlist randomize list", AUD_STOCK_RANDOMIZEPL , N_("Randomize List"), "R", + N_("Randomizes the playlist."), + G_CALLBACK(action_playlist_randomize_list) }, + + { "playlist reverse list", GTK_STOCK_GO_UP , N_("Reverse List"), NULL, + N_("Reverses the playlist."), + G_CALLBACK(action_playlist_reverse_list) }, + + { "playlist sort menu", GTK_STOCK_GO_DOWN , N_("Sort List") }, + + { "playlist sort by title", NULL , N_("By Title"), NULL, + N_("Sorts the list by title."), + G_CALLBACK(action_playlist_sort_by_title) }, + + { "playlist sort by artist", NULL , N_("By Artist"), NULL, + N_("Sorts the list by artist."), + G_CALLBACK(action_playlist_sort_by_artist) }, + + { "playlist sort by filename", NULL , N_("By Filename"), NULL, + N_("Sorts the list by filename."), + G_CALLBACK(action_playlist_sort_by_filename) }, + + { "playlist sort by full path", NULL , N_("By Path + Filename"), NULL, + N_("Sorts the list by full pathname."), + G_CALLBACK(action_playlist_sort_by_full_path) }, + + { "playlist sort by date", NULL , N_("By Date"), NULL, + N_("Sorts the list by modification time."), + G_CALLBACK(action_playlist_sort_by_date) }, + + { "playlist sort by track number", NULL , N_("By Track Number"), NULL, + N_("Sorts the list by track number."), + G_CALLBACK(action_playlist_sort_by_track_number) }, + + { "playlist sort by playlist entry", NULL , N_("By Playlist Entry"), NULL, + N_("Sorts the list by playlist entry."), + G_CALLBACK(action_playlist_sort_by_playlist_entry) }, + + { "playlist sort selected menu", GTK_STOCK_GO_DOWN , N_("Sort Selected") }, + + { "playlist sort selected by title", NULL , N_("By Title"), NULL, + N_("Sorts the list by title."), + G_CALLBACK(action_playlist_sort_selected_by_title) }, + + { "playlist sort selected by artist", NULL, N_("By Artist"), NULL, + N_("Sorts the list by artist."), + G_CALLBACK(action_playlist_sort_selected_by_artist) }, + + { "playlist sort selected by filename", NULL , N_("By Filename"), NULL, + N_("Sorts the list by filename."), + G_CALLBACK(action_playlist_sort_selected_by_filename) }, + + { "playlist sort selected by full path", NULL , N_("By Path + Filename"), NULL, + N_("Sorts the list by full pathname."), + G_CALLBACK(action_playlist_sort_selected_by_full_path) }, + + { "playlist sort selected by date", NULL , N_("By Date"), NULL, + N_("Sorts the list by modification time."), + G_CALLBACK(action_playlist_sort_selected_by_date) }, + + { "playlist sort selected by track number", NULL , N_("By Track Number"), NULL, + N_("Sorts the list by track number."), + G_CALLBACK(action_playlist_sort_selected_by_track_number) }, + + { "playlist sort selected by playlist entry", NULL, N_("By Playlist Entry"), NULL, + N_("Sorts the list by playlist entry."), + G_CALLBACK(action_playlist_sort_selected_by_playlist_entry) }, +}; + +static GtkActionEntry action_entries_others[] = { + + { "dummy", NULL, "dummy" }, + + /* XXX Carbon support */ + { "file", NULL, N_("File") }, + { "help", NULL, N_("Help") }, + + { "plugins-menu", AUD_STOCK_PLUGIN, N_("Plugin Services") }, + + { "current track info", GTK_STOCK_INFO , N_("View Track Details"), "I", + N_("View track details"), G_CALLBACK(action_current_track_info) }, + + { "playlist track info", GTK_STOCK_INFO , N_("View Track Details"), "I", + N_("View track details"), G_CALLBACK(action_playlist_track_info) }, + + { "about audacious", GTK_STOCK_DIALOG_INFO , N_("About Audacious"), NULL, + N_("About Audacious"), G_CALLBACK(action_about_audacious) }, + + { "play file", GTK_STOCK_OPEN , N_("Play File"), "L", + N_("Load and play a file"), G_CALLBACK(action_play_file) }, + + { "play location", GTK_STOCK_NETWORK , N_("Play Location"), "L", + N_("Play media from the selected location"), G_CALLBACK(action_play_location) }, + + { "plugins", NULL , N_("Plugin services") }, + + { "preferences", GTK_STOCK_PREFERENCES , N_("Preferences"), "P", + N_("Open preferences window"), G_CALLBACK(action_preferences) }, + + { "quit", GTK_STOCK_QUIT , N_("_Quit"), NULL, + N_("Quit Audacious"), G_CALLBACK(action_quit) }, + + { "ab set", NULL , N_("Set A-B"), "A", + N_("Set A-B"), G_CALLBACK(action_ab_set) }, + + { "ab clear", NULL , N_("Clear A-B"), "A", + N_("Clear A-B"), G_CALLBACK(action_ab_clear) }, + + { "jump to playlist start", GTK_STOCK_GOTO_TOP , N_("Jump to Playlist Start"), "Z", + N_("Jump to Playlist Start"), G_CALLBACK(action_jump_to_playlist_start) }, + + { "jump to file", GTK_STOCK_JUMP_TO , N_("Jump to File"), "J", + N_("Jump to File"), G_CALLBACK(action_jump_to_file) }, + + { "jump to time", GTK_STOCK_JUMP_TO , N_("Jump to Time"), "J", + N_("Jump to Time"), G_CALLBACK(action_jump_to_time) }, + + { "queue toggle", AUD_STOCK_QUEUETOGGLE , N_("Queue Toggle"), "Q", + N_("Enables/disables the entry in the playlist's queue."), + G_CALLBACK(action_queue_toggle) }, +}; + + +static GtkActionEntry action_entries_equalizer[] = { + + { "equ preset load menu", NULL, N_("Load") }, + { "equ preset import menu", NULL, N_("Import") }, + { "equ preset save menu", NULL, N_("Save") }, + { "equ preset delete menu", NULL, N_("Delete") }, + + { "equ load preset", NULL, N_("Preset"), NULL, + N_("Load preset"), G_CALLBACK(action_equ_load_preset) }, + + { "equ load auto preset", NULL, N_("Auto-load preset"), NULL, + N_("Load auto-load preset"), G_CALLBACK(action_equ_load_auto_preset) }, + + { "equ load default preset", NULL, N_("Default"), NULL, + N_("Load default preset into equalizer"), G_CALLBACK(action_equ_load_default_preset) }, + + { "equ zero preset", NULL, N_("Zero"), NULL, + N_("Set equalizer preset levels to zero"), G_CALLBACK(action_equ_zero_preset) }, + + { "equ load preset file", NULL, N_("From file"), NULL, + N_("Load preset from file"), G_CALLBACK(action_equ_load_preset_file) }, + + { "equ load preset eqf", NULL, N_("From WinAMP EQF file"), NULL, + N_("Load preset from WinAMP EQF file"), G_CALLBACK(action_equ_load_preset_eqf) }, + + { "equ import winamp presets", NULL, N_("WinAMP Presets"), NULL, + N_("Import WinAMP presets"), G_CALLBACK(action_equ_import_winamp_presets) }, + + { "equ save preset", NULL, N_("Preset"), NULL, + N_("Save preset"), G_CALLBACK(action_equ_save_preset) }, + + { "equ save auto preset", NULL, N_("Auto-load preset"), NULL, + N_("Save auto-load preset"), G_CALLBACK(action_equ_save_auto_preset) }, + + { "equ save default preset", NULL, N_("Default"), NULL, + N_("Save default preset"), G_CALLBACK(action_equ_save_default_preset) }, + + { "equ save preset file", NULL, N_("To file"), NULL, + N_("Save preset to file"), G_CALLBACK(action_equ_save_preset_file) }, + + { "equ save preset eqf", NULL, N_("To WinAMP EQF file"), NULL, + N_("Save preset to WinAMP EQF file"), G_CALLBACK(action_equ_save_preset_eqf) }, + + { "equ delete preset", NULL, N_("Preset"), NULL, + N_("Delete preset"), G_CALLBACK(action_equ_delete_preset) }, + + { "equ delete auto preset", NULL, N_("Auto-load preset"), NULL, + N_("Delete auto-load preset"), G_CALLBACK(action_equ_delete_auto_preset) } +}; + + + +/* ***************************** */ + + +static GtkActionGroup * +ui_manager_new_action_group( const gchar * group_name ) +{ + GtkActionGroup *group = gtk_action_group_new( group_name ); + gtk_action_group_set_translation_domain( group , PACKAGE_NAME ); + return group; +} + +void +ui_manager_init ( void ) +{ + /* toggle actions */ + toggleaction_group_others = ui_manager_new_action_group("toggleaction_others"); + gtk_action_group_add_toggle_actions( + toggleaction_group_others , toggleaction_entries_others , + G_N_ELEMENTS(toggleaction_entries_others) , NULL ); + + /* radio actions */ + radioaction_group_anamode = ui_manager_new_action_group("radioaction_anamode"); + gtk_action_group_add_radio_actions( + radioaction_group_anamode , radioaction_entries_anamode , + G_N_ELEMENTS(radioaction_entries_anamode) , 0 , G_CALLBACK(action_anamode) , NULL ); + + radioaction_group_anatype = ui_manager_new_action_group("radioaction_anatype"); + gtk_action_group_add_radio_actions( + radioaction_group_anatype , radioaction_entries_anatype , + G_N_ELEMENTS(radioaction_entries_anatype) , 0 , G_CALLBACK(action_anatype) , NULL ); + + radioaction_group_scomode = ui_manager_new_action_group("radioaction_scomode"); + gtk_action_group_add_radio_actions( + radioaction_group_scomode , radioaction_entries_scomode , + G_N_ELEMENTS(radioaction_entries_scomode) , 0 , G_CALLBACK(action_scomode) , NULL ); + + radioaction_group_vprmode = ui_manager_new_action_group("radioaction_vprmode"); + gtk_action_group_add_radio_actions( + radioaction_group_vprmode , radioaction_entries_vprmode , + G_N_ELEMENTS(radioaction_entries_vprmode) , 0 , G_CALLBACK(action_vprmode) , NULL ); + + radioaction_group_wshmode = ui_manager_new_action_group("radioaction_wshmode"); + gtk_action_group_add_radio_actions( + radioaction_group_wshmode , radioaction_entries_wshmode , + G_N_ELEMENTS(radioaction_entries_wshmode) , 0 , G_CALLBACK(action_wshmode) , NULL ); + + radioaction_group_refrate = ui_manager_new_action_group("radioaction_refrate"); + gtk_action_group_add_radio_actions( + radioaction_group_refrate , radioaction_entries_refrate , + G_N_ELEMENTS(radioaction_entries_refrate) , 0 , G_CALLBACK(action_refrate) , NULL ); + + radioaction_group_anafoff = ui_manager_new_action_group("radioaction_anafoff"); + gtk_action_group_add_radio_actions( + radioaction_group_anafoff , radioaction_entries_anafoff , + G_N_ELEMENTS(radioaction_entries_anafoff) , 0 , G_CALLBACK(action_anafoff) , NULL ); + + radioaction_group_peafoff = ui_manager_new_action_group("radioaction_peafoff"); + gtk_action_group_add_radio_actions( + radioaction_group_peafoff , radioaction_entries_peafoff , + G_N_ELEMENTS(radioaction_entries_peafoff) , 0 , G_CALLBACK(action_peafoff) , NULL ); + + radioaction_group_vismode = ui_manager_new_action_group("radioaction_vismode"); + gtk_action_group_add_radio_actions( + radioaction_group_vismode , radioaction_entries_vismode , + G_N_ELEMENTS(radioaction_entries_vismode) , 0 , G_CALLBACK(action_vismode) , NULL ); + + radioaction_group_viewtime = ui_manager_new_action_group("radioaction_viewtime"); + gtk_action_group_add_radio_actions( + radioaction_group_viewtime , radioaction_entries_viewtime , + G_N_ELEMENTS(radioaction_entries_viewtime) , 0 , G_CALLBACK(action_viewtime) , NULL ); + + /* normal actions */ + action_group_playback = ui_manager_new_action_group("action_playback"); + gtk_action_group_add_actions( + action_group_playback , action_entries_playback , + G_N_ELEMENTS(action_entries_playback) , NULL ); + + action_group_playlist = ui_manager_new_action_group("action_playlist"); + gtk_action_group_add_actions( + action_group_playlist , action_entries_playlist , + G_N_ELEMENTS(action_entries_playlist) , NULL ); + + action_group_visualization = ui_manager_new_action_group("action_visualization"); + gtk_action_group_add_actions( + action_group_visualization , action_entries_visualization , + G_N_ELEMENTS(action_entries_visualization) , NULL ); + + action_group_view = ui_manager_new_action_group("action_view"); + gtk_action_group_add_actions( + action_group_view , action_entries_view , + G_N_ELEMENTS(action_entries_view) , NULL ); + + action_group_others = ui_manager_new_action_group("action_others"); + gtk_action_group_add_actions( + action_group_others , action_entries_others , + G_N_ELEMENTS(action_entries_others) , NULL ); + + action_group_playlist_add = ui_manager_new_action_group("action_playlist_add"); + gtk_action_group_add_actions( + action_group_playlist_add, action_entries_playlist_add, + G_N_ELEMENTS(action_entries_playlist_add), NULL ); + + action_group_playlist_select = ui_manager_new_action_group("action_playlist_select"); + gtk_action_group_add_actions( + action_group_playlist_select, action_entries_playlist_select, + G_N_ELEMENTS(action_entries_playlist_select), NULL ); + + action_group_playlist_delete = ui_manager_new_action_group("action_playlist_delete"); + gtk_action_group_add_actions( + action_group_playlist_delete, action_entries_playlist_delete, + G_N_ELEMENTS(action_entries_playlist_delete), NULL ); + + action_group_playlist_sort = ui_manager_new_action_group("action_playlist_sort"); + gtk_action_group_add_actions( + action_group_playlist_sort, action_entries_playlist_sort, + G_N_ELEMENTS(action_entries_playlist_sort), NULL ); + + action_group_equalizer = ui_manager_new_action_group("action_equalizer"); + gtk_action_group_add_actions( + action_group_equalizer, action_entries_equalizer, + G_N_ELEMENTS(action_entries_equalizer), NULL); + + /* ui */ + ui_manager = gtk_ui_manager_new(); + gtk_ui_manager_insert_action_group( ui_manager , toggleaction_group_others , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_anamode , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_anatype , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_scomode , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_vprmode , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_wshmode , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_refrate , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_anafoff , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_peafoff , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_vismode , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_viewtime , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playback , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_visualization , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_view , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_others , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_add , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_select , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_delete , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_sort , 0 ); + gtk_ui_manager_insert_action_group( ui_manager , action_group_equalizer , 0 ); + + return; +} + +#ifdef GDK_WINDOWING_QUARTZ +static GtkWidget *carbon_menubar; +#endif + +static void +ui_manager_create_menus_init_pmenu( gchar * path ) +{ + GtkWidget *plugins_menu_item = gtk_ui_manager_get_widget( ui_manager , path ); + if ( plugins_menu_item ) + { + /* initially set count of items under plugins_menu_item to 0 */ + g_object_set_data( G_OBJECT(plugins_menu_item) , "ic" , GINT_TO_POINTER(0) ); + /* and since it's 0, hide the plugins_menu_item */ + gtk_widget_hide( plugins_menu_item ); + } + return; +} + + +void +ui_manager_create_menus ( void ) +{ + GError *gerr = NULL; + + /* attach xml menu definitions */ + gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/mainwin.ui" , &gerr ); + + if ( gerr != NULL ) + { + g_critical( "Error creating UI: %s" , gerr->message ); + g_error_free( gerr ); + return; + } + + /* create GtkMenu widgets using path from xml definitions */ + mainwin_songname_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/songname-menu" ); + mainwin_visualization_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/visualization" ); + mainwin_playback_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/playback" ); + mainwin_playlist_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/playlist" ); + mainwin_view_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/view" ); + mainwin_general_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu" ); + + /* initialize plugins-menu for mainwin-menus */ + ui_manager_create_menus_init_pmenu( "/mainwin-menus/main-menu/plugins-menu" ); + +#ifdef GDK_WINDOWING_QUARTZ + gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/carbon-menubar.ui" , &gerr ); + + if ( gerr != NULL ) + { + g_critical( "Error creating UI: %s" , gerr->message ); + g_error_free( gerr ); + return; + } + + carbon_menubar = ui_manager_get_popup_menu( ui_manager , "/carbon-menubar/main-menu" ); + sync_menu_takeover_menu(GTK_MENU_SHELL(carbon_menubar)); +#endif + + gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/playlist.ui" , &gerr ); + + if ( gerr != NULL ) + { + g_critical( "Error creating UI: %s" , gerr->message ); + g_error_free( gerr ); + return; + } + + playlistwin_popup_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/playlist-rightclick-menu"); + + playlistwin_pladd_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/add-menu"); + playlistwin_pldel_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/del-menu"); + playlistwin_plsel_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/select-menu"); + playlistwin_plsort_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/misc-menu"); + playlistwin_pllist_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/playlist-menu"); + + /* initialize plugins-menu for playlist-menus */ + ui_manager_create_menus_init_pmenu( "/playlist-menus/playlist-menu/plugins-menu" ); + ui_manager_create_menus_init_pmenu( "/playlist-menus/add-menu/plugins-menu" ); + ui_manager_create_menus_init_pmenu( "/playlist-menus/del-menu/plugins-menu" ); + ui_manager_create_menus_init_pmenu( "/playlist-menus/select-menu/plugins-menu" ); + ui_manager_create_menus_init_pmenu( "/playlist-menus/misc-menu/plugins-menu" ); + ui_manager_create_menus_init_pmenu( "/playlist-menus/playlist-rightclick-menu/plugins-menu" ); + + gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/equalizer.ui" , &gerr ); + + if ( gerr != NULL ) + { + g_critical( "Error creating UI: %s" , gerr->message ); + g_error_free( gerr ); + return; + } + + equalizerwin_presets_menu = ui_manager_get_popup_menu(ui_manager, "/equalizer-menus/preset-menu"); + + menu_created = TRUE; + + return; +} + + +GtkAccelGroup * +ui_manager_get_accel_group ( void ) +{ + return gtk_ui_manager_get_accel_group( ui_manager ); +} + + +GtkWidget * +ui_manager_get_popup_menu ( GtkUIManager * self , const gchar * path ) +{ + GtkWidget *menu_item = gtk_ui_manager_get_widget( self , path ); + + if (GTK_IS_MENU_ITEM(menu_item)) + return gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)); + else + return NULL; +} + + +static void +menu_popup_pos_func (GtkMenu * menu , gint * x , gint * y , gboolean * push_in , gint * point ) +{ + GtkRequisition requisition; + gint screen_width; + gint screen_height; + + gtk_widget_size_request(GTK_WIDGET(menu), &requisition); + + screen_width = gdk_screen_width(); + screen_height = gdk_screen_height(); + + *x = CLAMP(point[0] - 2, 0, MAX(0, screen_width - requisition.width)); + *y = CLAMP(point[1] - 2, 0, MAX(0, screen_height - requisition.height)); + + *push_in = FALSE; +} + + +void +ui_manager_popup_menu_show ( GtkMenu * menu , gint x , gint y , guint button , guint time ) +{ + gint pos[2]; + pos[0] = x; + pos[1] = y; + + gtk_menu_popup( menu , NULL , NULL , + (GtkMenuPositionFunc) menu_popup_pos_func , pos , button , time ); +} + + + +/******************************/ +/* plugin-available functions */ + +#define _MP_GWID(y) gtk_ui_manager_get_widget( ui_manager , y ) + +static GtkWidget* +audacious_menu_plugin_menuwid( menu_id ) +{ + switch (menu_id) + { + case AUDACIOUS_MENU_MAIN: + return _MP_GWID("/mainwin-menus/main-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST: + return _MP_GWID("/playlist-menus/playlist-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST_RCLICK: + return _MP_GWID("/playlist-menus/playlist-rightclick-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST_ADD: + return _MP_GWID("/playlist-menus/add-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST_REMOVE: + return _MP_GWID("/playlist-menus/del-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST_SELECT: + return _MP_GWID("/playlist-menus/select-menu/plugins-menu"); + case AUDACIOUS_MENU_PLAYLIST_MISC: + return _MP_GWID("/playlist-menus/misc-menu/plugins-menu"); + default: + return NULL; + } +} + + +gint +menu_plugin_item_add( gint menu_id , GtkWidget * item ) +{ + if ( menu_created ) + { + GtkWidget *plugins_menu = NULL; + GtkWidget *plugins_menu_item = audacious_menu_plugin_menuwid( menu_id ); + if ( plugins_menu_item ) + { + gint ic = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(plugins_menu_item),"ic")); + if ( ic == 0 ) /* no items under plugins_menu_item, create the submenu */ + { + plugins_menu = gtk_menu_new(); + gtk_menu_item_set_submenu( GTK_MENU_ITEM(plugins_menu_item), plugins_menu ); + } + else /* items available under plugins_menu_item, pick the existing submenu */ + { + plugins_menu = gtk_menu_item_get_submenu( GTK_MENU_ITEM(plugins_menu_item) ); + if ( !plugins_menu ) return -1; + } + gtk_menu_shell_append( GTK_MENU_SHELL(plugins_menu) , item ); + gtk_widget_show( plugins_menu_item ); + g_object_set_data( G_OBJECT(plugins_menu_item) , "ic" , GINT_TO_POINTER(++ic) ); + return 0; /* success */ + } + } + return -1; /* failure */ +} + + +gint +menu_plugin_item_remove( gint menu_id , GtkWidget * item ) +{ + if ( menu_created ) + { + GtkWidget *plugins_menu = NULL; + GtkWidget *plugins_menu_item = audacious_menu_plugin_menuwid( menu_id ); + if ( plugins_menu_item ) + { + gint ic = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(plugins_menu_item),"ic")); + if ( ic > 0 ) + { + plugins_menu = gtk_menu_item_get_submenu( GTK_MENU_ITEM(plugins_menu_item) ); + if ( plugins_menu ) + { + /* remove the plugin-added entry */ + gtk_container_remove( GTK_CONTAINER(plugins_menu) , item ); + g_object_set_data( G_OBJECT(plugins_menu_item) , "ic" , GINT_TO_POINTER(--ic) ); + if ( ic == 0 ) /* if the menu is empty now, destroy it */ + { + gtk_menu_item_remove_submenu( GTK_MENU_ITEM(plugins_menu_item) ); + gtk_widget_destroy( plugins_menu ); + gtk_widget_hide( plugins_menu_item ); + } + return 0; /* success */ + } + } + } + } + return -1; /* failure */ +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_manager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_manager.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,77 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 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_MANAGER_H +#define AUDACIOUS_UI_MANAGER_H + +#include +#include +#include + +G_BEGIN_DECLS + +GtkWidget *mainwin_songname_menu; +GtkWidget *mainwin_general_menu; +GtkWidget *mainwin_visualization_menu; +GtkWidget *mainwin_playback_menu; +GtkWidget *mainwin_playlist_menu; +GtkWidget *mainwin_view_menu; + +GtkWidget *playlistwin_pladd_menu; +GtkWidget *playlistwin_pldel_menu; +GtkWidget *playlistwin_plsel_menu; +GtkWidget *playlistwin_plsort_menu; +GtkWidget *playlistwin_pllist_menu; +GtkWidget *playlistwin_popup_menu; + +GtkWidget *equalizerwin_presets_menu; + +GtkActionGroup *toggleaction_group_others; +GtkActionGroup *radioaction_group_anamode; /* Analyzer mode */ +GtkActionGroup *radioaction_group_anatype; /* Analyzer type */ +GtkActionGroup *radioaction_group_scomode; /* Scope mode */ +GtkActionGroup *radioaction_group_vprmode; /* Voiceprint mode */ +GtkActionGroup *radioaction_group_wshmode; /* WindowShade VU mode */ +GtkActionGroup *radioaction_group_refrate; /* Refresh rate */ +GtkActionGroup *radioaction_group_anafoff; /* Analyzer Falloff */ +GtkActionGroup *radioaction_group_peafoff; /* Peak Falloff */ +GtkActionGroup *radioaction_group_vismode; /* Visualization mode */ +GtkActionGroup *radioaction_group_viewtime; /* View time (remaining/elapsed) */ +GtkActionGroup *action_group_playback; +GtkActionGroup *action_group_visualization; +GtkActionGroup *action_group_view; +GtkActionGroup *action_group_others; +GtkActionGroup *action_group_playlist; +GtkActionGroup *action_group_playlist_add; +GtkActionGroup *action_group_playlist_select; +GtkActionGroup *action_group_playlist_delete; +GtkActionGroup *action_group_playlist_sort; +GtkActionGroup *action_group_equalizer; + + +void ui_manager_init ( void ); +void ui_manager_create_menus ( void ); +GtkAccelGroup * ui_manager_get_accel_group ( void ); +GtkWidget * ui_manager_get_popup_menu ( GtkUIManager * , const gchar * ); +void ui_manager_popup_menu_show( GtkMenu * , gint , gint , guint , guint ); +#define popup_menu_show(x1,x2,x3,x4,x5) ui_manager_popup_menu_show(x1,x2,x3,x4,x5) + +G_END_DECLS + +#endif /* AUDACIOUS_UI_MANAGER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_playlist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_playlist.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,1923 @@ +/* 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. + */ + +/* #define AUD_DEBUG 1 */ + +#include "ui_playlist.h" + +#include +#include +#include +#include +#include +#include + +#include "platform/smartinclude.h" + +#include +#include + +#include "actions-playlist.h" +#include "dnd.h" +#include "input.h" +#include "main.h" +#include "playback.h" +#include "playlist.h" +#include "playlist_container.h" +#include "strings.h" +#include "ui_dock.h" +#include "ui_equalizer.h" +#include "ui_fileinfo.h" +#include "ui_fileopener.h" +#include "ui_main.h" +#include "ui_manager.h" +#include "ui_playlist_evlisteners.h" +#include "ui_playlist_manager.h" +#include "util.h" +#include "config.h" + +#include "ui_skinned_window.h" +#include "ui_skinned_button.h" +#include "ui_skinned_textbox.h" +#include "ui_skinned_playlist_slider.h" +#include "ui_skinned_playlist.h" + +#include "icons-stock.h" +#include "images/audacious_playlist.xpm" + +GtkWidget *playlistwin; + +static GMutex *resize_mutex = NULL; + +static GtkWidget *playlistwin_list = NULL; +static GtkWidget *playlistwin_shade, *playlistwin_close; + +static gboolean playlistwin_hint_flag = FALSE; + +static GtkWidget *playlistwin_slider; +static GtkWidget *playlistwin_time_min, *playlistwin_time_sec; +static GtkWidget *playlistwin_info, *playlistwin_sinfo; +static GtkWidget *playlistwin_srew, *playlistwin_splay; +static GtkWidget *playlistwin_spause, *playlistwin_sstop; +static GtkWidget *playlistwin_sfwd, *playlistwin_seject; +static GtkWidget *playlistwin_sscroll_up, *playlistwin_sscroll_down; + +static void playlistwin_select_search_cbt_cb(GtkWidget *called_cbt, + gpointer other_cbt); +static gboolean playlistwin_select_search_kp_cb(GtkWidget *entry, + GdkEventKey *event, + gpointer searchdlg_win); + +static gboolean playlistwin_resizing = FALSE; +static gint playlistwin_resize_x, playlistwin_resize_y; + +gboolean +playlistwin_is_shaded(void) +{ + return cfg.playlist_shaded; +} + +gint +playlistwin_get_width(void) +{ + cfg.playlist_width /= PLAYLISTWIN_WIDTH_SNAP; + cfg.playlist_width *= PLAYLISTWIN_WIDTH_SNAP; + return cfg.playlist_width; +} + +gint +playlistwin_get_height_unshaded(void) +{ + cfg.playlist_height /= PLAYLISTWIN_HEIGHT_SNAP; + cfg.playlist_height *= PLAYLISTWIN_HEIGHT_SNAP; + return cfg.playlist_height; +} + +gint +playlistwin_get_height_shaded(void) +{ + return PLAYLISTWIN_SHADED_HEIGHT; +} + +gint +playlistwin_get_height(void) +{ + if (playlistwin_is_shaded()) + return playlistwin_get_height_shaded(); + else + return playlistwin_get_height_unshaded(); +} + +static void +playlistwin_update_info(Playlist *playlist) +{ + gchar *text, *sel_text, *tot_text; + gulong selection, total; + gboolean selection_more, total_more; + + playlist_get_total_time(playlist, &total, &selection, &total_more, &selection_more); + + if (selection > 0 || (selection == 0 && !selection_more)) { + if (selection > 3600) + sel_text = + g_strdup_printf("%lu:%-2.2lu:%-2.2lu%s", selection / 3600, + (selection / 60) % 60, selection % 60, + (selection_more ? "+" : "")); + else + sel_text = + g_strdup_printf("%lu:%-2.2lu%s", selection / 60, + selection % 60, (selection_more ? "+" : "")); + } + else + sel_text = g_strdup("?"); + if (total > 0 || (total == 0 && !total_more)) { + if (total > 3600) + tot_text = + g_strdup_printf("%lu:%-2.2lu:%-2.2lu%s", total / 3600, + (total / 60) % 60, total % 60, + total_more ? "+" : ""); + else + tot_text = + g_strdup_printf("%lu:%-2.2lu%s", total / 60, total % 60, + total_more ? "+" : ""); + } + else + tot_text = g_strdup("?"); + text = g_strconcat(sel_text, "/", tot_text, NULL); + ui_skinned_textbox_set_text(playlistwin_info, text ? text : ""); + g_free(text); + g_free(tot_text); + g_free(sel_text); +} + +static void +playlistwin_update_sinfo(Playlist *playlist) +{ + gchar *posstr, *timestr, *title, *info; + gint pos, time; + + pos = playlist_get_position(playlist); + title = playlist_get_songtitle(playlist, pos); + + if (!title) { + ui_skinned_textbox_set_text(playlistwin_sinfo, ""); + return; + } + + convert_title_text(title); + + time = playlist_get_songtime(playlist, pos); + + if (cfg.show_numbers_in_pl) + posstr = g_strdup_printf("%d. ", pos + 1); + else + posstr = g_strdup(""); + + if (time != -1) { + timestr = g_strdup_printf(" (%d:%-2.2d)", time / 60000, + (time / 1000) % 60); + } + else + timestr = g_strdup(""); + + info = g_strdup_printf("%s%s%s", posstr, title, timestr); + + g_free(posstr); + g_free(title); + g_free(timestr); + + ui_skinned_textbox_set_text(playlistwin_sinfo, info ? info : ""); + g_free(info); +} + +gboolean +playlistwin_item_visible(gint index) +{ + g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), FALSE); + + if (index >= UI_SKINNED_PLAYLIST(playlistwin_list)->first && + index < (UI_SKINNED_PLAYLIST(playlistwin_list)->first + UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible) ) { + return TRUE; + } + return FALSE; +} + +gint +playlistwin_list_get_visible_count(void) +{ + g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), -1); + + return UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible; +} + +gint +playlistwin_list_get_first(void) +{ + g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), -1); + + return UI_SKINNED_PLAYLIST(playlistwin_list)->first; +} + +gint +playlistwin_get_toprow(void) +{ + g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), -1); + + return (UI_SKINNED_PLAYLIST(playlistwin_list)->first); +} + +void +playlistwin_set_toprow(gint toprow) +{ + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) + UI_SKINNED_PLAYLIST(playlistwin_list)->first = toprow; + g_cond_signal(cond_scan); + playlistwin_update_list(playlist_get_active()); +} + +void +playlistwin_update_list(Playlist *playlist) +{ + /* this can happen early on. just bail gracefully. */ + g_return_if_fail(playlistwin_list); + + playlistwin_update_info(playlist); + playlistwin_update_sinfo(playlist); + gtk_widget_queue_draw(playlistwin_list); + gtk_widget_queue_draw(playlistwin_slider); +} + +static void +playlistwin_set_geometry_hints(gboolean shaded) +{ + GdkGeometry geometry; + GdkWindowHints mask; + + geometry.min_width = PLAYLISTWIN_MIN_WIDTH; + geometry.max_width = G_MAXUINT16; + + geometry.width_inc = PLAYLISTWIN_WIDTH_SNAP; + geometry.height_inc = PLAYLISTWIN_HEIGHT_SNAP; + + if (shaded) { + geometry.min_height = PLAYLISTWIN_SHADED_HEIGHT; + geometry.max_height = PLAYLISTWIN_SHADED_HEIGHT; + geometry.base_height = PLAYLISTWIN_SHADED_HEIGHT; + } + else { + geometry.min_height = PLAYLISTWIN_MIN_HEIGHT; + geometry.max_height = G_MAXUINT16; + } + + mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE | GDK_HINT_RESIZE_INC; + + gtk_window_set_geometry_hints(GTK_WINDOW(playlistwin), + playlistwin, &geometry, mask); +} + +void +playlistwin_set_sinfo_font(gchar *font) +{ + gchar *tmp = NULL, *tmp2 = NULL; + + g_return_if_fail(font); + AUDDBG("Attempt to set font \"%s\"\n", font); + + tmp = g_strdup(font); + g_return_if_fail(tmp); + + *strrchr(tmp, ' ') = '\0'; + tmp2 = g_strdup_printf("%s 8", tmp); + g_return_if_fail(tmp2); + + ui_skinned_textbox_set_xfont(playlistwin_sinfo, !cfg.mainwin_use_bitmapfont, tmp2); + + g_free(tmp); + g_free(tmp2); +} + +void +playlistwin_set_sinfo_scroll(gboolean scroll) +{ + if(playlistwin_is_shaded()) + ui_skinned_textbox_set_scroll(playlistwin_sinfo, cfg.autoscroll); + else + ui_skinned_textbox_set_scroll(playlistwin_sinfo, FALSE); +} + +void +playlistwin_set_shade(gboolean shaded) +{ + cfg.playlist_shaded = shaded; + + if (shaded) { + playlistwin_set_sinfo_font(cfg.playlist_font); + playlistwin_set_sinfo_scroll(cfg.autoscroll); + gtk_widget_show(playlistwin_sinfo); + ui_skinned_set_push_button_data(playlistwin_shade, 128, 45, 150, 42); + ui_skinned_set_push_button_data(playlistwin_close, 138, 45, -1, -1); + } + else { + gtk_widget_hide(playlistwin_sinfo); + playlistwin_set_sinfo_scroll(FALSE); + ui_skinned_set_push_button_data(playlistwin_shade, 157, 3, 62, 42); + ui_skinned_set_push_button_data(playlistwin_close, 167, 3, -1, -1); + } + + dock_shade(get_dock_window_list(), GTK_WINDOW(playlistwin), + playlistwin_get_height()); + + playlistwin_set_geometry_hints(cfg.playlist_shaded); + + gtk_window_resize(GTK_WINDOW(playlistwin), + playlistwin_get_width(), + playlistwin_get_height()); +} + +static void +playlistwin_set_shade_menu(gboolean shaded) +{ + GtkAction *action = gtk_action_group_get_action( + toggleaction_group_others , "roll up playlist editor" ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , shaded ); + + playlistwin_set_shade(shaded); + playlistwin_update_list(playlist_get_active()); +} + +void +playlistwin_shade_toggle(void) +{ + playlistwin_set_shade_menu(!cfg.playlist_shaded); +} + +static gboolean +playlistwin_release(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + playlistwin_resizing = FALSE; + return FALSE; +} + +void +playlistwin_scroll(gint num) +{ + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) + UI_SKINNED_PLAYLIST(playlistwin_list)->first += num; + playlistwin_update_list(playlist_get_active()); +} + +void +playlistwin_scroll_up_pushed(void) +{ + playlistwin_scroll(-3); +} + +void +playlistwin_scroll_down_pushed(void) +{ + playlistwin_scroll(3); +} + +static void +playlistwin_select_all(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_select_all(playlist, TRUE); + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected = 0; + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_min = 0; + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_max = playlist_get_length(playlist) - 1; + } + playlistwin_update_list(playlist); +} + +static void +playlistwin_select_none(void) +{ + playlist_select_all(playlist_get_active(), FALSE); + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected = -1; + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_min = -1; + } + playlistwin_update_list(playlist_get_active()); +} + +static void +playlistwin_select_search(void) +{ + Playlist *playlist = playlist_get_active(); + GtkWidget *searchdlg_win, *searchdlg_table; + GtkWidget *searchdlg_hbox, *searchdlg_logo, *searchdlg_helptext; + GtkWidget *searchdlg_entry_title, *searchdlg_label_title; + GtkWidget *searchdlg_entry_album, *searchdlg_label_album; + GtkWidget *searchdlg_entry_file_name, *searchdlg_label_file_name; + GtkWidget *searchdlg_entry_performer, *searchdlg_label_performer; + GtkWidget *searchdlg_checkbt_clearprevsel; + GtkWidget *searchdlg_checkbt_newplaylist; + GtkWidget *searchdlg_checkbt_autoenqueue; + gint result; + + /* create dialog */ + searchdlg_win = gtk_dialog_new_with_buttons( + _("Search entries in active playlist") , GTK_WINDOW(mainwin) , + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT , + GTK_STOCK_CANCEL , GTK_RESPONSE_REJECT , GTK_STOCK_OK , GTK_RESPONSE_ACCEPT , NULL ); + gtk_window_set_position(GTK_WINDOW(searchdlg_win), GTK_WIN_POS_CENTER); + + /* help text and logo */ + searchdlg_hbox = gtk_hbox_new( FALSE , 4 ); + searchdlg_logo = gtk_image_new_from_stock( GTK_STOCK_FIND , GTK_ICON_SIZE_DIALOG ); + searchdlg_helptext = gtk_label_new( _("Select entries in playlist by filling one or more " + "fields. Fields use regular expressions syntax, case-insensitive. If you don't know how " + "regular expressions work, simply insert a literal portion of what you're searching for.") ); + gtk_label_set_line_wrap( GTK_LABEL(searchdlg_helptext) , TRUE ); + gtk_box_pack_start( GTK_BOX(searchdlg_hbox) , searchdlg_logo , FALSE , FALSE , 0 ); + gtk_box_pack_start( GTK_BOX(searchdlg_hbox) , searchdlg_helptext , FALSE , FALSE , 0 ); + + /* title */ + searchdlg_label_title = gtk_label_new( _("Title: ") ); + searchdlg_entry_title = gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_title) , 0 , 0.5 ); + g_signal_connect( G_OBJECT(searchdlg_entry_title) , "key-press-event" , + G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); + + /* album */ + searchdlg_label_album= gtk_label_new( _("Album: ") ); + searchdlg_entry_album= gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_album) , 0 , 0.5 ); + g_signal_connect( G_OBJECT(searchdlg_entry_album) , "key-press-event" , + G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); + + /* artist */ + searchdlg_label_performer = gtk_label_new( _("Artist: ") ); + searchdlg_entry_performer = gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_performer) , 0 , 0.5 ); + g_signal_connect( G_OBJECT(searchdlg_entry_performer) , "key-press-event" , + G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); + + /* file name */ + searchdlg_label_file_name = gtk_label_new( _("Filename: ") ); + searchdlg_entry_file_name = gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_file_name) , 0 , 0.5 ); + g_signal_connect( G_OBJECT(searchdlg_entry_file_name) , "key-press-event" , + G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); + + /* some options that control behaviour */ + searchdlg_checkbt_clearprevsel = gtk_check_button_new_with_label( + _("Clear previous selection before searching") ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_clearprevsel) , TRUE ); + searchdlg_checkbt_autoenqueue = gtk_check_button_new_with_label( + _("Automatically toggle queue for matching entries") ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_autoenqueue) , FALSE ); + searchdlg_checkbt_newplaylist = gtk_check_button_new_with_label( + _("Create a new playlist with matching entries") ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_newplaylist) , FALSE ); + g_signal_connect( G_OBJECT(searchdlg_checkbt_autoenqueue) , "clicked" , + G_CALLBACK(playlistwin_select_search_cbt_cb) , searchdlg_checkbt_newplaylist ); + g_signal_connect( G_OBJECT(searchdlg_checkbt_newplaylist) , "clicked" , + G_CALLBACK(playlistwin_select_search_cbt_cb) , searchdlg_checkbt_autoenqueue ); + + /* place fields in searchdlg_table */ + searchdlg_table = gtk_table_new( 8 , 2 , FALSE ); + gtk_table_set_row_spacing( GTK_TABLE(searchdlg_table) , 0 , 8 ); + gtk_table_set_row_spacing( GTK_TABLE(searchdlg_table) , 4 , 8 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_hbox , + 0 , 2 , 0 , 1 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_title , + 0 , 1 , 1 , 2 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_title , + 1 , 2 , 1 , 2 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_album, + 0 , 1 , 2 , 3 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_album, + 1 , 2 , 2 , 3 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_performer , + 0 , 1 , 3 , 4 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_performer , + 1 , 2 , 3 , 4 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_file_name , + 0 , 1 , 4 , 5 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_file_name , + 1 , 2 , 4 , 5 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_clearprevsel , + 0 , 2 , 5 , 6 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_autoenqueue , + 0 , 2 , 6 , 7 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_newplaylist , + 0 , 2 , 7 , 8 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 ); + + gtk_container_set_border_width( GTK_CONTAINER(searchdlg_table) , 5 ); + gtk_container_add( GTK_CONTAINER(GTK_DIALOG(searchdlg_win)->vbox) , searchdlg_table ); + gtk_widget_show_all( searchdlg_win ); + result = gtk_dialog_run( GTK_DIALOG(searchdlg_win) ); + switch(result) + { + case GTK_RESPONSE_ACCEPT: + { + gint matched_entries_num = 0; + /* create a TitleInput tuple with user search data */ + Tuple *tuple = tuple_new(); + gchar *searchdata = NULL; + + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_title) ); + AUDDBG("title=\"%s\"\n", searchdata); + tuple_associate_string(tuple, FIELD_TITLE, NULL, searchdata); + + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_album) ); + AUDDBG("album=\"%s\"\n", searchdata); + tuple_associate_string(tuple, FIELD_ALBUM, NULL, searchdata); + + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_performer) ); + AUDDBG("performer=\"%s\"\n", searchdata); + tuple_associate_string(tuple, FIELD_ARTIST, NULL, searchdata); + + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_file_name) ); + AUDDBG("filename=\"%s\"\n", searchdata); + tuple_associate_string(tuple, FIELD_FILE_NAME, NULL, searchdata); + + /* check if previous selection should be cleared before searching */ + if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_clearprevsel)) == TRUE ) + playlistwin_select_none(); + /* now send this tuple to the real search function */ + matched_entries_num = playlist_select_search( playlist , tuple , 0 ); + /* we do not need the tuple and its data anymore */ + mowgli_object_unref(tuple); + playlistwin_update_list(playlist_get_active()); + /* check if a new playlist should be created after searching */ + if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_newplaylist)) == TRUE ) + playlist_new_from_selected(); + /* check if matched entries should be queued */ + else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_autoenqueue)) == TRUE ) + playlist_queue(playlist_get_active()); + break; + } + default: + break; + } + /* done here :) */ + gtk_widget_destroy( searchdlg_win ); +} + +static void +playlistwin_inverse_selection(void) +{ + playlist_select_invert_all(playlist_get_active()); + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected = -1; + UI_SKINNED_PLAYLIST(playlistwin_list)->prev_min = -1; + } + playlistwin_update_list(playlist_get_active()); +} + +static void +playlistwin_resize(gint width, gint height) +{ + gint tx, ty; + gint dx, dy; + + g_return_if_fail(width > 0 && height > 0); + + tx = (width - PLAYLISTWIN_MIN_WIDTH) / PLAYLISTWIN_WIDTH_SNAP; + tx = (tx * PLAYLISTWIN_WIDTH_SNAP) + PLAYLISTWIN_MIN_WIDTH; + if (tx < PLAYLISTWIN_MIN_WIDTH) + tx = PLAYLISTWIN_MIN_WIDTH; + + if (!cfg.playlist_shaded) + { + ty = (height - PLAYLISTWIN_MIN_HEIGHT) / PLAYLISTWIN_HEIGHT_SNAP; + ty = (ty * PLAYLISTWIN_HEIGHT_SNAP) + PLAYLISTWIN_MIN_HEIGHT; + if (ty < PLAYLISTWIN_MIN_HEIGHT) + ty = PLAYLISTWIN_MIN_HEIGHT; + } + else + ty = cfg.playlist_height; + + if (tx == cfg.playlist_width && ty == cfg.playlist_height) + return; + + /* difference between previous size and new size */ + dx = tx - cfg.playlist_width; + dy = ty - cfg.playlist_height; + + cfg.playlist_width = width = tx; + cfg.playlist_height = height = ty; + + g_mutex_lock(resize_mutex); + ui_skinned_playlist_resize_relative(playlistwin_list, dx, dy); + + ui_skinned_playlist_slider_move_relative(playlistwin_slider, dx); + ui_skinned_playlist_slider_resize_relative(playlistwin_slider, dy); + + playlistwin_update_sinfo(playlist_get_active()); + + ui_skinned_button_move_relative(playlistwin_shade, dx, 0); + ui_skinned_button_move_relative(playlistwin_close, dx, 0); + ui_skinned_textbox_move_relative(playlistwin_time_min, dx, dy); + ui_skinned_textbox_move_relative(playlistwin_time_sec, dx, dy); + ui_skinned_textbox_move_relative(playlistwin_info, dx, dy); + ui_skinned_button_move_relative(playlistwin_srew, dx, dy); + ui_skinned_button_move_relative(playlistwin_splay, dx, dy); + ui_skinned_button_move_relative(playlistwin_spause, dx, dy); + ui_skinned_button_move_relative(playlistwin_sstop, dx, dy); + ui_skinned_button_move_relative(playlistwin_sfwd, dx, dy); + ui_skinned_button_move_relative(playlistwin_seject, dx, dy); + ui_skinned_button_move_relative(playlistwin_sscroll_up, dx, dy); + ui_skinned_button_move_relative(playlistwin_sscroll_down, dx, dy); + + gtk_widget_set_size_request(playlistwin_sinfo, playlistwin_get_width() - 35, + aud_active_skin->properties.textbox_bitmap_font_height); + GList *iter; + for (iter = GTK_FIXED (SKINNED_WINDOW(playlistwin)->fixed)->children; iter; iter = g_list_next (iter)) { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + GtkWidget *child = child_data->widget; + g_signal_emit_by_name(child, "redraw"); + } + g_mutex_unlock(resize_mutex); +} + +static void +playlistwin_motion(GtkWidget * widget, + GdkEventMotion * event, + gpointer callback_data) +{ + /* + * GDK2's resize is broken and doesn't really play nice, so we have + * to do all of this stuff by hand. + */ + if (playlistwin_resizing == TRUE) + { + if (event->x + playlistwin_resize_x != playlistwin_get_width() || + event->y + playlistwin_resize_y != playlistwin_get_height()) + { + playlistwin_resize(event->x + playlistwin_resize_x, + event->y + playlistwin_resize_y); + gdk_window_resize(playlistwin->window, + cfg.playlist_width, playlistwin_get_height()); + gdk_flush(); + } + } + else if (dock_is_moving(GTK_WINDOW(playlistwin))) + dock_move_motion(GTK_WINDOW(playlistwin), event); +} + +static void +playlistwin_show_filebrowser(void) +{ + run_filebrowser(FALSE); +} + +static void +playlistwin_fileinfo(void) +{ + Playlist *playlist = playlist_get_active(); + + /* Show the first selected file, or the current file if nothing is + * selected */ + GList *list = playlist_get_selected(playlist); + if (list) { + ui_fileinfo_show(playlist, GPOINTER_TO_INT(list->data)); + g_list_free(list); + } + else + ui_fileinfo_show_current(playlist); +} + +static void +show_playlist_save_error(GtkWindow *parent, + const gchar *filename) +{ + GtkWidget *dialog; + + g_return_if_fail(GTK_IS_WINDOW(parent)); + g_return_if_fail(filename); + + dialog = gtk_message_dialog_new(GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Error writing playlist \"%s\": %s"), + filename, strerror(errno)); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +static gboolean +show_playlist_overwrite_prompt(GtkWindow * parent, + const gchar * filename) +{ + GtkWidget *dialog; + gint result; + + g_return_val_if_fail(GTK_IS_WINDOW(parent), FALSE); + g_return_val_if_fail(filename != NULL, FALSE); + + dialog = gtk_message_dialog_new(GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + _("%s already exist. Continue?"), + filename); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ + result = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + return (result == GTK_RESPONSE_YES); +} + +static void +show_playlist_save_format_error(GtkWindow * parent, + const gchar * filename) +{ + const gchar *markup = + N_("Unable to save playlist.\n\n" + "Unknown file type for '%s'.\n"); + + GtkWidget *dialog; + + g_return_if_fail(GTK_IS_WINDOW(parent)); + g_return_if_fail(filename != NULL); + + dialog = + gtk_message_dialog_new_with_markup(GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _(markup), + filename); + + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +static void +playlistwin_save_playlist(const gchar * filename) +{ + PlaylistContainer *plc; + gchar *ext = strrchr(filename, '.') + 1; + + plc = playlist_container_find(ext); + if (plc == NULL) { + show_playlist_save_format_error(GTK_WINDOW(playlistwin), filename); + return; + } + + str_replace_in(&cfg.playlist_path, g_path_get_dirname(filename)); + + if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) + if (!show_playlist_overwrite_prompt(GTK_WINDOW(playlistwin), filename)) + return; + + if (!playlist_save(playlist_get_active(), filename)) + show_playlist_save_error(GTK_WINDOW(playlistwin), filename); +} + +static void +playlistwin_load_playlist(const gchar * filename) +{ + const gchar *title; + Playlist *playlist = playlist_get_active(); + + g_return_if_fail(filename != NULL); + + str_replace_in(&cfg.playlist_path, g_path_get_dirname(filename)); + + playlist_clear(playlist); + mainwin_clear_song_info(); + + playlist_load(playlist, filename); + title = playlist_get_current_name(playlist); + if(!title || !title[0]) + playlist_set_current_name(playlist, filename); +} + +static gchar * +playlist_file_selection_load(const gchar * title, + const gchar * default_filename) +{ + GtkWidget *dialog; + gchar *filename; + + g_return_val_if_fail(title != NULL, NULL); + + dialog = make_filebrowser(title, FALSE); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), cfg.playlist_path); + if (default_filename) + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), default_filename); + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + else + filename = NULL; + + gtk_widget_destroy(dialog); + return filename; +} + +static void +on_static_toggle(GtkToggleButton *button, gpointer data) +{ + Playlist *playlist = playlist_get_active(); + + playlist->attribute = + gtk_toggle_button_get_active(button) ? + playlist->attribute | PLAYLIST_STATIC : + playlist->attribute & ~PLAYLIST_STATIC; +} + +static void +on_relative_toggle(GtkToggleButton *button, gpointer data) +{ + Playlist *playlist = playlist_get_active(); + + playlist->attribute = + gtk_toggle_button_get_active(button) ? + playlist->attribute | PLAYLIST_USE_RELATIVE : + playlist->attribute & ~PLAYLIST_USE_RELATIVE; +} + +static gchar * +playlist_file_selection_save(const gchar * title, + const gchar * default_filename) +{ + GtkWidget *dialog; + gchar *filename; + GtkWidget *hbox; + GtkWidget *toggle, *toggle2; + + g_return_val_if_fail(title != NULL, NULL); + + dialog = make_filebrowser(title, TRUE); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), cfg.playlist_path); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), default_filename); + + hbox = gtk_hbox_new(FALSE, 5); + + /* static playlist */ + toggle = gtk_check_button_new_with_label(_("Save as Static Playlist")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), + (playlist_get_active()->attribute & PLAYLIST_STATIC) ? TRUE : FALSE); + g_signal_connect(G_OBJECT(toggle), "toggled", G_CALLBACK(on_static_toggle), dialog); + gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, FALSE, 0); + + /* use relative path */ + toggle2 = gtk_check_button_new_with_label(_("Use Relative Path")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle2), + (playlist_get_active()->attribute & PLAYLIST_USE_RELATIVE) ? TRUE : FALSE); + g_signal_connect(G_OBJECT(toggle2), "toggled", G_CALLBACK(on_relative_toggle), dialog); + gtk_box_pack_start(GTK_BOX(hbox), toggle2, FALSE, FALSE, 0); + + gtk_widget_show_all(hbox); + gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), hbox); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + else + filename = NULL; + + gtk_widget_destroy(dialog); + return filename; +} + +void +playlistwin_select_playlist_to_load(const gchar * default_filename) +{ + gchar *filename = + playlist_file_selection_load(_("Load Playlist"), default_filename); + + if (filename) { + playlistwin_load_playlist(filename); + g_free(filename); + } +} + +static void +playlistwin_select_playlist_to_save(const gchar * default_filename) +{ + gchar *dot = NULL, *basename = NULL; + gchar *filename = + playlist_file_selection_save(_("Save Playlist"), default_filename); + + if (filename) { + /* Default extension */ + basename = g_path_get_basename(filename); + dot = strrchr(basename, '.'); + if( dot == NULL || dot == basename) { + gchar *oldname = filename; +#ifdef HAVE_XSPF_PLAYLIST + filename = g_strconcat(oldname, ".xspf", NULL); +#else + filename = g_strconcat(oldname, ".m3u", NULL); +#endif + g_free(oldname); + } + g_free(basename); + + playlistwin_save_playlist(filename); + g_free(filename); + } +} + +#define REGION_L(x1,x2,y1,y2) \ + (event->x >= (x1) && event->x < (x2) && \ + event->y >= cfg.playlist_height - (y1) && \ + event->y < cfg.playlist_height - (y2)) + +#define REGION_R(x1,x2,y1,y2) \ + (event->x >= playlistwin_get_width() - (x1) && \ + event->x < playlistwin_get_width() - (x2) && \ + event->y >= cfg.playlist_height - (y1) && \ + event->y < cfg.playlist_height - (y2)) + +static void +playlistwin_scrolled(GtkWidget * widget, + GdkEventScroll * event, + gpointer callback_data) +{ + if (event->direction == GDK_SCROLL_DOWN) + playlistwin_scroll(cfg.scroll_pl_by); + + if (event->direction == GDK_SCROLL_UP) + playlistwin_scroll(-cfg.scroll_pl_by); + + g_cond_signal(cond_scan); +} + +static gboolean +playlistwin_press(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + gint xpos, ypos; + GtkRequisition req; + + gtk_window_get_position(GTK_WINDOW(playlistwin), &xpos, &ypos); + + if (event->button == 1 && !cfg.show_wm_decorations && + ((!cfg.playlist_shaded && + event->x > playlistwin_get_width() - 20 && + event->y > cfg.playlist_height - 20) || + (cfg.playlist_shaded && + event->x >= playlistwin_get_width() - 31 && + event->x < playlistwin_get_width() - 22))) { + + if (event->type != GDK_2BUTTON_PRESS && + event->type != GDK_3BUTTON_PRESS) { + playlistwin_resizing = TRUE; + playlistwin_resize_x = cfg.playlist_width - event->x; + playlistwin_resize_y = cfg.playlist_height - event->y; + } + } + else if (event->button == 1 && REGION_L(12, 37, 29, 11)) { + /* ADD button menu */ + gtk_widget_size_request(playlistwin_pladd_menu, &req); + ui_manager_popup_menu_show(GTK_MENU(playlistwin_pladd_menu), + xpos + 12, + (ypos + playlistwin_get_height()) - 8 - req.height, + event->button, + event->time); + } + else if (event->button == 1 && REGION_L(41, 66, 29, 11)) { + /* SUB button menu */ + gtk_widget_size_request(playlistwin_pldel_menu, &req); + ui_manager_popup_menu_show(GTK_MENU(playlistwin_pldel_menu), + xpos + 40, + (ypos + playlistwin_get_height()) - 8 - req.height, + event->button, + event->time); + } + else if (event->button == 1 && REGION_L(70, 95, 29, 11)) { + /* SEL button menu */ + gtk_widget_size_request(playlistwin_plsel_menu, &req); + ui_manager_popup_menu_show(GTK_MENU(playlistwin_plsel_menu), + xpos + 68, + (ypos + playlistwin_get_height()) - 8 - req.height, + event->button, + event->time); + } + else if (event->button == 1 && REGION_L(99, 124, 29, 11)) { + /* MISC button menu */ + gtk_widget_size_request(playlistwin_plsort_menu, &req); + ui_manager_popup_menu_show(GTK_MENU(playlistwin_plsort_menu), + xpos + 100, + (ypos + playlistwin_get_height()) - 8 - req.height, + event->button, + event->time); + } + else if (event->button == 1 && REGION_R(46, 23, 29, 11)) { + /* LIST button menu */ + gtk_widget_size_request(playlistwin_pllist_menu, &req); + ui_manager_popup_menu_show(GTK_MENU(playlistwin_pllist_menu), + xpos + playlistwin_get_width() - req.width - 12, + (ypos + playlistwin_get_height()) - 8 - req.height, + event->button, + event->time); + } + else if (event->button == 1 && event->type == GDK_BUTTON_PRESS && + (cfg.easy_move || event->y < 14)) + { + return FALSE; + } + else if (event->button == 1 && event->type == GDK_2BUTTON_PRESS + && event->y < 14) { + /* double click on title bar */ + playlistwin_shade_toggle(); + if (dock_is_moving(GTK_WINDOW(playlistwin))) + dock_move_release(GTK_WINDOW(playlistwin)); + return TRUE; + } + else if (event->button == 3) { + /* + * Pop up the main menu a few pixels down to avoid + * anything to be selected initially. + */ + ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), event->x_root, + event->y_root + 2, 3, event->time); + } + + return TRUE; +} + +static gboolean +playlistwin_delete(GtkWidget * w, gpointer data) +{ + playlistwin_hide(); + return TRUE; +} + +static gboolean +playlistwin_keypress_up_down_handler(UiSkinnedPlaylist * pl, + gboolean up, guint state) +{ + Playlist *playlist = playlist_get_active(); + if ((!(pl->prev_selected || pl->first) && up) || + ((pl->prev_selected >= playlist_get_length(playlist) - 1) && !up)) + return FALSE; + + if ((state & GDK_MOD1_MASK) && (state & GDK_SHIFT_MASK)) + return FALSE; + if (!(state & GDK_MOD1_MASK)) + playlist_select_all(playlist, FALSE); + + if (pl->prev_selected == -1 || + (!playlistwin_item_visible(pl->prev_selected) && + !(state & GDK_SHIFT_MASK && pl->prev_min != -1))) { + pl->prev_selected = pl->first; + } + else if (state & GDK_SHIFT_MASK) { + if (pl->prev_min == -1) { + pl->prev_max = pl->prev_selected; + pl->prev_min = pl->prev_selected; + } + pl->prev_max += (up ? -1 : 1); + pl->prev_max = + CLAMP(pl->prev_max, 0, playlist_get_length(playlist) - 1); + + pl->first = MIN(pl->first, pl->prev_max); + pl->first = MAX(pl->first, pl->prev_max - + pl->num_visible + 1); + playlist_select_range(playlist, pl->prev_min, pl->prev_max, TRUE); + return TRUE; + } + else if (state & GDK_MOD1_MASK) { + if (up) + ui_skinned_playlist_move_up(pl); + else + ui_skinned_playlist_move_down(pl); + if (pl->prev_min < pl->first) + pl->first = pl->prev_min; + else if (pl->prev_max >= (pl->first + pl->num_visible)) + pl->first = pl->prev_max - pl->num_visible + 1; + return TRUE; + } + else if (up) + pl->prev_selected--; + else + pl->prev_selected++; + + pl->prev_selected = + CLAMP(pl->prev_selected, 0, playlist_get_length(playlist) - 1); + + if (pl->prev_selected < pl->first) + pl->first--; + else if (pl->prev_selected >= (pl->first + pl->num_visible)) + pl->first++; + + playlist_select_range(playlist, pl->prev_selected, pl->prev_selected, TRUE); + pl->prev_min = -1; + + return TRUE; +} + +/* FIXME: Handle the keys through menu */ + +static gboolean +playlistwin_keypress(GtkWidget * w, GdkEventKey * event, gpointer data) +{ + g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), FALSE); + Playlist *playlist = playlist_get_active(); + + guint keyval; + gboolean refresh = FALSE; + guint cur_pos; + + if (cfg.playlist_shaded) + return FALSE; + + switch (keyval = event->keyval) { + case GDK_KP_Up: + case GDK_KP_Down: + case GDK_Up: + case GDK_Down: + refresh = playlistwin_keypress_up_down_handler(UI_SKINNED_PLAYLIST(playlistwin_list), + keyval == GDK_Up + || keyval == GDK_KP_Up, + event->state); + break; + case GDK_Page_Up: + playlistwin_scroll(-UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible); + refresh = TRUE; + break; + case GDK_Page_Down: + playlistwin_scroll(UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible); + refresh = TRUE; + break; + case GDK_Home: + UI_SKINNED_PLAYLIST(playlistwin_list)->first = 0; + refresh = TRUE; + break; + case GDK_End: + UI_SKINNED_PLAYLIST(playlistwin_list)->first = + playlist_get_length(playlist) - UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible; + refresh = TRUE; + break; + case GDK_Return: + if (UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected > -1 + && playlistwin_item_visible(UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected)) { + playlist_set_position(playlist, UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected); + if (!playback_get_playing()) + playback_initiate(); + } + refresh = TRUE; + break; + case GDK_3: + if (event->state & GDK_CONTROL_MASK) + playlistwin_fileinfo(); + break; + case GDK_Delete: + if (event->state & GDK_CONTROL_MASK) + playlist_delete(playlist, TRUE); + else + playlist_delete(playlist, FALSE); + break; + case GDK_Insert: + if (event->state & GDK_MOD1_MASK) + mainwin_show_add_url_window(); + else + playlistwin_show_filebrowser(); + break; + case GDK_Left: + case GDK_KP_Left: + case GDK_KP_7: + if (playlist_get_current_length(playlist) != -1) + playback_seek(CLAMP + (playback_get_time() - 5000, 0, + playlist_get_current_length(playlist)) / 1000); + break; + case GDK_Right: + case GDK_KP_Right: + case GDK_KP_9: + if (playlist_get_current_length(playlist) != -1) + playback_seek(CLAMP + (playback_get_time() + 5000, 0, + playlist_get_current_length(playlist)) / 1000); + break; + case GDK_KP_4: + playlist_prev(playlist); + break; + case GDK_KP_6: + playlist_next(playlist); + break; + + case GDK_Escape: + mainwin_minimize_cb(); + break; + case GDK_Tab: + if (event->state & GDK_CONTROL_MASK) { + if (cfg.player_visible) + gtk_window_present(GTK_WINDOW(mainwin)); + else if (cfg.equalizer_visible) + gtk_window_present(GTK_WINDOW(equalizerwin)); + } + break; + case GDK_space: + cur_pos=playlist_get_position(playlist); + UI_SKINNED_PLAYLIST(playlistwin_list)->first = + cur_pos - (UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible >> 1); + refresh = TRUE; + break; + default: + return FALSE; + } + + if (refresh) { + g_cond_signal(cond_scan); + playlistwin_update_list(playlist_get_active()); + } + + return TRUE; +} + +void +playlistwin_hide_timer(void) +{ + ui_skinned_textbox_set_text(playlistwin_time_min, " "); + ui_skinned_textbox_set_text(playlistwin_time_sec, " "); +} + +void +playlistwin_set_time(gint time, gint length, TimerMode mode) +{ + gchar *text, sign; + + if (mode == TIMER_REMAINING && length != -1) { + time = length - time; + sign = '-'; + } + else + sign = ' '; + + time /= 1000; + + if (time < 0) + time = 0; + if (time > 99 * 60) + time /= 60; + + text = g_strdup_printf("%c%-2.2d", sign, time / 60); + ui_skinned_textbox_set_text(playlistwin_time_min, text); + g_free(text); + + text = g_strdup_printf("%-2.2d", time % 60); + ui_skinned_textbox_set_text(playlistwin_time_sec, text); + g_free(text); +} + +static void +playlistwin_drag_motion(GtkWidget * widget, + GdkDragContext * context, + gint x, gint y, + GtkSelectionData * selection_data, + guint info, guint time, gpointer user_data) +{ + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { + UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion = TRUE; + UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion_x = x; + UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion_y = y; + } + playlistwin_update_list(playlist_get_active()); + playlistwin_hint_flag = TRUE; +} + +static void +playlistwin_drag_end(GtkWidget * widget, + GdkDragContext * context, gpointer user_data) +{ + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) + UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion = FALSE; + playlistwin_hint_flag = FALSE; + playlistwin_update_list(playlist_get_active()); +} + +static void +playlistwin_drag_data_received(GtkWidget * widget, + GdkDragContext * context, + gint x, gint y, + GtkSelectionData * + selection_data, guint info, + guint time, gpointer user_data) +{ + gint pos; + Playlist *playlist = playlist_get_active(); + + g_return_if_fail(selection_data); + + if (!selection_data->data) { + g_message("Received no DND data!"); + return; + } + if (UI_SKINNED_IS_PLAYLIST(playlistwin_list) && + (x < playlistwin_get_width() - 20 || y < cfg.playlist_height - 38)) { + pos = y / UI_SKINNED_PLAYLIST(playlistwin_list)->fheight + UI_SKINNED_PLAYLIST(playlistwin_list)->first; + + pos = MIN(pos, playlist_get_length(playlist)); + playlist_ins_url(playlist, (gchar *) selection_data->data, pos); + } + else + playlist_add_url(playlist, (gchar *) selection_data->data); +} + +static void +local_playlist_prev(void) +{ + playlist_prev(playlist_get_active()); +} + +static void +local_playlist_next(void) +{ + playlist_next(playlist_get_active()); +} + +static void +playlistwin_create_widgets(void) +{ + /* This function creates the custom widgets used by the playlist editor */ + + /* text box for displaying song title in shaded mode */ + playlistwin_sinfo = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, + 4, 4, playlistwin_get_width() - 35, TRUE, SKIN_TEXT); + + playlistwin_set_sinfo_font(cfg.playlist_font); + + playlistwin_shade = ui_skinned_button_new(); + /* shade/unshade window push button */ + if (cfg.playlist_shaded) + ui_skinned_push_button_setup(playlistwin_shade, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 21, 3, + 9, 9, 128, 45, 150, 42, SKIN_PLEDIT); + else + ui_skinned_push_button_setup(playlistwin_shade, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 21, 3, + 9, 9, 157, 3, 62, 42, SKIN_PLEDIT); + + g_signal_connect(playlistwin_shade, "clicked", playlistwin_shade_toggle, NULL ); + + /* close window push button */ + playlistwin_close = ui_skinned_button_new(); + ui_skinned_push_button_setup(playlistwin_close, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 11, 3, 9, 9, + cfg.playlist_shaded ? 138 : 167, + cfg.playlist_shaded ? 45 : 3, 52, 42, SKIN_PLEDIT); + + g_signal_connect(playlistwin_close, "clicked", playlistwin_hide, NULL ); + + /* playlist list box */ + playlistwin_list = ui_skinned_playlist_new(SKINNED_WINDOW(playlistwin)->fixed, 12, 20, + playlistwin_get_width() - 31, + cfg.playlist_height - 58); + ui_skinned_playlist_set_font(cfg.playlist_font); + + /* playlist list box slider */ + playlistwin_slider = ui_skinned_playlist_slider_new(SKINNED_WINDOW(playlistwin)->fixed, playlistwin_get_width() - 15, + 20, cfg.playlist_height - 58); + + /* track time (minute) */ + playlistwin_time_min = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 82, + cfg.playlist_height - 15, 15, FALSE, SKIN_TEXT); + g_signal_connect(playlistwin_time_min, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + /* track time (second) */ + playlistwin_time_sec = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 64, + cfg.playlist_height - 15, 10, FALSE, SKIN_TEXT); + g_signal_connect(playlistwin_time_sec, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); + + /* playlist information (current track length / total track length) */ + playlistwin_info = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 143, + cfg.playlist_height - 28, 90, FALSE, SKIN_TEXT); + + /* mini play control buttons at right bottom corner */ + + /* rewind button */ + playlistwin_srew = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_srew, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 144, + cfg.playlist_height - 16, 8, 7); + g_signal_connect(playlistwin_srew, "clicked", local_playlist_prev, NULL); + + /* play button */ + playlistwin_splay = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_splay, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 138, + cfg.playlist_height - 16, 10, 7); + g_signal_connect(playlistwin_splay, "clicked", mainwin_play_pushed, NULL); + + /* pause button */ + playlistwin_spause = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_spause, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 128, + cfg.playlist_height - 16, 10, 7); + g_signal_connect(playlistwin_spause, "clicked", playback_pause, NULL); + + /* stop button */ + playlistwin_sstop = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_sstop, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 118, + cfg.playlist_height - 16, 9, 7); + g_signal_connect(playlistwin_sstop, "clicked", mainwin_stop_pushed, NULL); + + /* forward button */ + playlistwin_sfwd = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_sfwd, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 109, + cfg.playlist_height - 16, 8, 7); + g_signal_connect(playlistwin_sfwd, "clicked", local_playlist_next, NULL); + + /* eject button */ + playlistwin_seject = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_seject, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 100, + cfg.playlist_height - 16, 9, 7); + g_signal_connect(playlistwin_seject, "clicked", mainwin_eject_pushed, NULL); + + playlistwin_sscroll_up = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_sscroll_up, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 14, + cfg.playlist_height - 35, 8, 5); + g_signal_connect(playlistwin_sscroll_up, "clicked", playlistwin_scroll_up_pushed, NULL); + + playlistwin_sscroll_down = ui_skinned_button_new(); + ui_skinned_small_button_setup(playlistwin_sscroll_down, SKINNED_WINDOW(playlistwin)->fixed, + playlistwin_get_width() - 14, + cfg.playlist_height - 30, 8, 5); + g_signal_connect(playlistwin_sscroll_down, "clicked", playlistwin_scroll_down_pushed, NULL); + + ui_playlist_evlistener_init(); +} + +static void +selection_received(GtkWidget * widget, + GtkSelectionData * selection_data, gpointer data) +{ + if (selection_data->type == GDK_SELECTION_TYPE_STRING && + selection_data->length > 0) + playlist_add_url(playlist_get_active(), (gchar *) selection_data->data); +} + +static void +playlistwin_create_window(void) +{ + GdkPixbuf *icon; + + playlistwin = ui_skinned_window_new("playlist"); + gtk_window_set_title(GTK_WINDOW(playlistwin), _("Audacious Playlist Editor")); + gtk_window_set_role(GTK_WINDOW(playlistwin), "playlist"); + gtk_window_set_default_size(GTK_WINDOW(playlistwin), + playlistwin_get_width(), + playlistwin_get_height()); + gtk_window_set_resizable(GTK_WINDOW(playlistwin), TRUE); + playlistwin_set_geometry_hints(cfg.playlist_shaded); + + gtk_window_set_transient_for(GTK_WINDOW(playlistwin), + GTK_WINDOW(mainwin)); + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(playlistwin), TRUE); + + icon = gdk_pixbuf_new_from_xpm_data((const gchar **) audacious_playlist_icon); + gtk_window_set_icon(GTK_WINDOW(playlistwin), icon); + g_object_unref(icon); + + if (cfg.playlist_x != -1 && cfg.save_window_position) + gtk_window_move(GTK_WINDOW(playlistwin), + cfg.playlist_x, cfg.playlist_y); + + gtk_widget_add_events(playlistwin, GDK_POINTER_MOTION_MASK | + GDK_FOCUS_CHANGE_MASK | GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_SCROLL_MASK | GDK_VISIBILITY_NOTIFY_MASK); + gtk_widget_realize(playlistwin); + + g_signal_connect(playlistwin, "delete_event", + G_CALLBACK(playlistwin_delete), NULL); + g_signal_connect(playlistwin, "button_press_event", + G_CALLBACK(playlistwin_press), NULL); + g_signal_connect(playlistwin, "button_release_event", + G_CALLBACK(playlistwin_release), NULL); + g_signal_connect(playlistwin, "scroll_event", + G_CALLBACK(playlistwin_scrolled), NULL); + g_signal_connect(playlistwin, "motion_notify_event", + G_CALLBACK(playlistwin_motion), NULL); + + aud_drag_dest_set(playlistwin); + + /* DnD stuff */ + g_signal_connect(playlistwin, "drag-leave", + G_CALLBACK(playlistwin_drag_end), NULL); + g_signal_connect(playlistwin, "drag-data-delete", + G_CALLBACK(playlistwin_drag_end), NULL); + g_signal_connect(playlistwin, "drag-end", + G_CALLBACK(playlistwin_drag_end), NULL); + g_signal_connect(playlistwin, "drag-drop", + G_CALLBACK(playlistwin_drag_end), NULL); + g_signal_connect(playlistwin, "drag-data-received", + G_CALLBACK(playlistwin_drag_data_received), NULL); + g_signal_connect(playlistwin, "drag-motion", + G_CALLBACK(playlistwin_drag_motion), NULL); + + g_signal_connect(playlistwin, "key_press_event", + G_CALLBACK(playlistwin_keypress), NULL); + g_signal_connect(playlistwin, "selection_received", + G_CALLBACK(selection_received), NULL); +} + +void +playlistwin_create(void) +{ + resize_mutex = g_mutex_new(); + playlistwin_create_window(); + + playlistwin_create_widgets(); + playlistwin_update_info(playlist_get_active()); + + gtk_window_add_accel_group(GTK_WINDOW(playlistwin), ui_manager_get_accel_group()); +} + + +void +playlistwin_show(void) +{ + gtk_window_move(GTK_WINDOW(playlistwin), cfg.playlist_x, cfg.playlist_y); + GtkAction *action = gtk_action_group_get_action( + toggleaction_group_others , "show playlist editor" ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , TRUE ); + + cfg.playlist_visible = TRUE; + UI_SKINNED_BUTTON(mainwin_pl)->inside = TRUE; + gtk_widget_queue_draw(mainwin_pl); + + playlistwin_set_toprow(0); + playlist_check_pos_current(playlist_get_active()); + + gtk_widget_show_all(playlistwin); + if (!cfg.playlist_shaded) + gtk_widget_hide(playlistwin_sinfo); + gtk_window_present(GTK_WINDOW(playlistwin)); +} + +void +playlistwin_hide(void) +{ + GtkAction *action = gtk_action_group_get_action( + toggleaction_group_others , "show playlist editor" ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , FALSE ); + + gtk_widget_hide(playlistwin); + cfg.playlist_visible = FALSE; + UI_SKINNED_BUTTON(mainwin_pl)->inside = FALSE; + gtk_widget_queue_draw(mainwin_pl); + + if ( cfg.player_visible ) + { + gtk_window_present(GTK_WINDOW(mainwin)); + gtk_widget_grab_focus(mainwin); + } +} + +void action_playlist_track_info(void) +{ + playlistwin_fileinfo(); +} + +void action_queue_toggle(void) +{ + playlist_queue(playlist_get_active()); +} + +void action_playlist_sort_by_playlist_entry(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort(playlist, PLAYLIST_SORT_PLAYLIST); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_track_number(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort(playlist, PLAYLIST_SORT_TRACK); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_title(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort(playlist, PLAYLIST_SORT_TITLE); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_artist(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort(playlist, PLAYLIST_SORT_ARTIST); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_full_path(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort(playlist, PLAYLIST_SORT_PATH); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_date(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort(playlist, PLAYLIST_SORT_DATE); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_by_filename(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort(playlist, PLAYLIST_SORT_FILENAME); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_playlist_entry(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort_selected(playlist, PLAYLIST_SORT_PLAYLIST); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_track_number(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort_selected(playlist, PLAYLIST_SORT_TRACK); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_title(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort_selected(playlist, PLAYLIST_SORT_TITLE); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_artist(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort_selected(playlist, PLAYLIST_SORT_ARTIST); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_full_path(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort_selected(playlist, PLAYLIST_SORT_PATH); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_date(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort_selected(playlist, PLAYLIST_SORT_DATE); + playlistwin_update_list(playlist); +} + +void action_playlist_sort_selected_by_filename(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_sort_selected(playlist, PLAYLIST_SORT_FILENAME); + playlistwin_update_list(playlist); +} + +void action_playlist_randomize_list(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_random(playlist); + playlistwin_update_list(playlist); +} + +void action_playlist_reverse_list(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_reverse(playlist); + playlistwin_update_list(playlist); +} + +void +action_playlist_clear_queue(void) +{ + playlist_clear_queue(playlist_get_active()); +} + +void +action_playlist_remove_unavailable(void) +{ + playlist_remove_dead_files(playlist_get_active()); +} + +void +action_playlist_remove_dupes_by_title(void) +{ + playlist_remove_duplicates(playlist_get_active(), PLAYLIST_DUPS_TITLE); +} + +void +action_playlist_remove_dupes_by_filename(void) +{ + playlist_remove_duplicates(playlist_get_active(), PLAYLIST_DUPS_FILENAME); +} + +void +action_playlist_remove_dupes_by_full_path(void) +{ + playlist_remove_duplicates(playlist_get_active(), PLAYLIST_DUPS_PATH); +} + +void +action_playlist_remove_all(void) +{ + playlist_clear(playlist_get_active()); + + /* XXX -- should this really be coupled here? -nenolod */ + mainwin_clear_song_info(); +} + +void +action_playlist_remove_selected(void) +{ + playlist_delete(playlist_get_active(), FALSE); +} + +void +action_playlist_remove_unselected(void) +{ + playlist_delete(playlist_get_active(), TRUE); +} + +void +action_playlist_add_files(void) +{ + run_filebrowser(FALSE); +} + +void +action_playlist_add_url(void) +{ + mainwin_show_add_url_window(); +} + +void +action_playlist_new( void ) +{ + Playlist *new_pl = playlist_new(); + playlist_add_playlist(new_pl); + playlist_select_playlist(new_pl); +} + +void +action_playlist_prev( void ) +{ + playlist_select_prev(); +} + +void +action_playlist_next( void ) +{ + playlist_select_next(); +} + +void +action_playlist_delete( void ) +{ + playlist_remove_playlist( playlist_get_active() ); +} + +void +action_playlist_save_list(void) +{ + Playlist *playlist = playlist_get_active(); + + playlistwin_select_playlist_to_save(playlist_get_current_name(playlist)); +} + +void +action_playlist_save_default_list(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_save(playlist, aud_paths[BMP_PATH_PLAYLIST_FILE]); +} + +void +action_playlist_load_list(void) +{ + Playlist *playlist = playlist_get_active(); + + playlistwin_select_playlist_to_load(playlist_get_current_name(playlist)); +} + +void +action_playlist_refresh_list(void) +{ + Playlist *playlist = playlist_get_active(); + + playlist_read_info_selection(playlist); + playlistwin_update_list(playlist); +} + +void +action_open_list_manager(void) +{ + playlist_manager_ui_show(); +} + +void +action_playlist_search_and_select(void) +{ + playlistwin_select_search(); +} + +void +action_playlist_invert_selection(void) +{ + playlistwin_inverse_selection(); +} + +void +action_playlist_select_none(void) +{ + playlistwin_select_none(); +} + +void +action_playlist_select_all(void) +{ + playlistwin_select_all(); +} + + +static void +playlistwin_select_search_cbt_cb(GtkWidget *called_cbt, gpointer other_cbt) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(called_cbt)) == TRUE) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(other_cbt), FALSE); + return; +} + +static gboolean +playlistwin_select_search_kp_cb(GtkWidget *entry, GdkEventKey *event, + gpointer searchdlg_win) +{ + switch (event->keyval) + { + case GDK_Return: + if (gtk_im_context_filter_keypress (GTK_ENTRY (entry)->im_context, event)) { + GTK_ENTRY (entry)->need_im_reset = TRUE; + return TRUE; + } else { + gtk_dialog_response(GTK_DIALOG(searchdlg_win), GTK_RESPONSE_ACCEPT); + return TRUE; + } + default: + return FALSE; + } +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_playlist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_playlist.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,80 @@ +/* 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. + */ + +#ifndef AUDACIOUS_UI_PLAYLIST_H +#define AUDACIOUS_UI_PLAYLIST_H + +#include + +#include "ui_main.h" +#include "playlist.h" + +#define PLAYLISTWIN_FRAME_TOP_HEIGHT 20 +#define PLAYLISTWIN_FRAME_BOTTOM_HEIGHT 38 +#define PLAYLISTWIN_FRAME_LEFT_WIDTH 12 +#define PLAYLISTWIN_FRAME_RIGHT_WIDTH 19 + +#define PLAYLISTWIN_MIN_WIDTH MAINWIN_WIDTH +#define PLAYLISTWIN_MIN_HEIGHT MAINWIN_HEIGHT +#define PLAYLISTWIN_WIDTH_SNAP 25 +#define PLAYLISTWIN_HEIGHT_SNAP 29 +#define PLAYLISTWIN_SHADED_HEIGHT MAINWIN_SHADED_HEIGHT +#define PLAYLISTWIN_WIDTH cfg.playlist_width +#define PLAYLISTWIN_HEIGHT \ + (cfg.playlist_shaded ? PLAYLISTWIN_SHADED_HEIGHT : cfg.playlist_height) + +#define PLAYLISTWIN_DEFAULT_WIDTH 275 +#define PLAYLISTWIN_DEFAULT_HEIGHT 232 +#define PLAYLISTWIN_DEFAULT_POS_X 295 +#define PLAYLISTWIN_DEFAULT_POS_Y 20 + +#define PLAYLISTWIN_DEFAULT_FONT "Sans Bold 8" + +gboolean playlistwin_is_shaded(void); +gint playlistwin_get_width(void); +gint playlistwin_get_height(void); +void playlistwin_update_list(Playlist *playlist); +gboolean playlistwin_item_visible(gint index); +gint playlistwin_get_toprow(void); +void playlistwin_set_toprow(gint top); +void playlistwin_set_shade_menu_cb(gboolean shaded); +void playlistwin_set_shade(gboolean shaded); +void playlistwin_shade_toggle(void); +void playlistwin_create(void); +void playlistwin_hide_timer(void); +void playlistwin_set_time(gint time, gint length, TimerMode mode); +void playlistwin_show(void); +void playlistwin_hide(void); +void playlistwin_scroll(gint num); +void playlistwin_scroll_up_pushed(void); +void playlistwin_scroll_down_pushed(void); +void playlistwin_select_playlist_to_load(const gchar * default_filename); +void playlistwin_set_sinfo_font(gchar *font); +void playlistwin_set_sinfo_scroll(gboolean scroll); +gint playlistwin_list_get_visible_count(void); +gint playlistwin_list_get_first(void); + +extern GtkWidget *playlistwin; + +extern gboolean playlistwin_focus; + +#endif /* AUDACIOUS_UI_PLAYLIST_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_playlist_evlisteners.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_playlist_evlisteners.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,54 @@ +/* + * Audacious + * Copyright (c) 2006-2007 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 "ui_playlist_evlisteners.h" + +#include + +#include "hook.h" +#include "playlist.h" +#include "ui_playlist.h" +#include "ui_playlist_manager.h" + +static void +ui_playlist_evlistener_playlist_update(gpointer hook_data, gpointer user_data) +{ + Playlist *playlist = (Playlist *) hook_data; + if (playlist != NULL) + playlistwin_update_list(playlist); + + playlist_manager_update(); +} + +static void +ui_playlist_evlistener_playlistwin_show(gpointer hook_data, gpointer user_data) +{ + gboolean *show = (gboolean*)hook_data; + if (*show == TRUE) + playlistwin_show(); + else + playlistwin_hide(); +} + +void ui_playlist_evlistener_init(void) +{ + hook_associate("playlist update", ui_playlist_evlistener_playlist_update, NULL); + hook_associate("playlistwin show", ui_playlist_evlistener_playlistwin_show, NULL); +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_playlist_evlisteners.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_playlist_evlisteners.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,26 @@ +/* + * Audacious + * Copyright (c) 2006-2007 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_PLAYLIST_EVLISTENERS_H +#define AUDACIOUS_UI_PLAYLIST_EVLISTENERS_H + +void ui_playlist_evlistener_init(void); + +#endif /* AUDACIOUS_UI_PLAYLIST_EVLISTENERS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_playlist_manager.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_playlist_manager.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,498 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 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 "ui_playlist_manager.h" +#include "ui_playlist.h" +#include "playlist.h" +#include "ui_main.h" + +#include +#include +#include +#include + + +#define DISABLE_MANAGER_UPDATE() g_object_set_data(G_OBJECT(listview),"opt1",GINT_TO_POINTER(1)) +#define ENABLE_MANAGER_UPDATE() g_object_set_data(G_OBJECT(listview),"opt1",GINT_TO_POINTER(0)) + + +static GtkWidget *playman_win = NULL; + + +/* in this enum, place the columns according to visualization order + (information not displayed in columns should be placed right before PLLIST_NUMCOLS) */ +enum +{ + PLLIST_COL_NAME = 0, + PLLIST_COL_ENTRIESNUM, + PLLIST_PLPOINTER, + PLLIST_TEXT_WEIGHT, + PLLIST_NUMCOLS +}; + + +static GtkTreeIter +playlist_manager_populate ( GtkListStore * store ) +{ + GList *playlists = NULL; + Playlist *active, *iter_playlist, *next_playlist; + GtkTreeIter iter, insert, next, active_iter; + gboolean valid, have_active_iter; + + active = playlist_get_active(); + playlists = playlist_get_playlists(); + valid = gtk_tree_model_get_iter_first( GTK_TREE_MODEL(store) , &iter ); + have_active_iter = FALSE; + while ( playlists != NULL ) + { + GList *entries = NULL; + gint entriesnum = 0; + gchar *pl_name = NULL; + Playlist *playlist = (Playlist*)playlists->data; + + if(playlist != active) //XXX the active playlist has been locked in playlist_new_from_selected() + PLAYLIST_LOCK(playlist); + + /* for each playlist, pick name and number of entries */ + pl_name = (gchar*)playlist_get_current_name( playlist ); + for (entries = playlist->entries; entries; entries = g_list_next(entries)) + entriesnum++; + + if(playlist != active) + PLAYLIST_UNLOCK(playlist); + + /* update the tree model conservatively */ + + if ( !valid ) + { + /* append */ + gtk_list_store_append( store , &insert ); + goto store_set; + } + + gtk_tree_model_get( GTK_TREE_MODEL(store) , &iter , + PLLIST_PLPOINTER , &iter_playlist , -1 ); + + if ( playlist == iter_playlist ) + { + /* already have - just update */ + insert = iter; + valid = gtk_tree_model_iter_next( GTK_TREE_MODEL(store) , &iter ); + goto store_set; + } + + /* handle movement/deletion/insertion of single elements */ + if ( gtk_tree_model_iter_next( GTK_TREE_MODEL(store) , &next ) ) + { + gtk_tree_model_get( GTK_TREE_MODEL(store) , &next , + PLLIST_PLPOINTER , &next_playlist , -1 ); + if ( playlist == next_playlist ) + { + /* remove */ + gtk_list_store_remove( store , &iter ); + iter = next; + valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter); + goto next_playlist; + } + } + + /* insert */ + gtk_list_store_insert_before( store , &insert , &iter ); + +store_set: + gtk_list_store_set( store, &insert, + PLLIST_COL_NAME , pl_name , + PLLIST_COL_ENTRIESNUM , entriesnum , + PLLIST_PLPOINTER , playlist , + PLLIST_TEXT_WEIGHT , playlist == active ? + PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL , + -1 ); + if ( !have_active_iter && playlist == active ) + { + active_iter = insert; + have_active_iter = TRUE; + } + +next_playlist: + playlists = g_list_next(playlists); + } + + while (valid) + { + /* remove any other elements */ + next = iter; + valid = gtk_tree_model_iter_next( GTK_TREE_MODEL(store) , &next ); + gtk_list_store_remove( store , &iter ); + iter = next; + } + + if ( !have_active_iter ) + gtk_tree_model_get_iter_first( GTK_TREE_MODEL(store) , &active_iter ); + + return active_iter; +} + + +static void +playlist_manager_cb_new ( gpointer listview ) +{ + GList *playlists = NULL; + Playlist *newpl = NULL; + GtkTreeIter iter; + GtkListStore *store; + gchar *pl_name = NULL; + + /* this ensures that playlist_manager_update() will + not perform update, since we're already doing it here */ + DISABLE_MANAGER_UPDATE(); + + newpl = playlist_new(); + pl_name = (gchar*)playlist_get_current_name( newpl ); + playlists = playlist_get_playlists(); + playlist_add_playlist( newpl ); + + store = (GtkListStore*)gtk_tree_view_get_model( GTK_TREE_VIEW(listview) ); + gtk_list_store_append( store , &iter ); + gtk_list_store_set( store, &iter, + PLLIST_COL_NAME , pl_name , + PLLIST_COL_ENTRIESNUM , 0 , + PLLIST_PLPOINTER , newpl , + PLLIST_TEXT_WEIGHT , PANGO_WEIGHT_NORMAL , + -1 ); + + ENABLE_MANAGER_UPDATE(); + + return; +} + + +static void +playlist_manager_cb_del ( gpointer listview ) +{ + GtkTreeSelection *listsel = gtk_tree_view_get_selection( GTK_TREE_VIEW(listview) ); + GtkTreeModel *store; + GtkTreeIter iter; + Playlist *active; + gboolean was_active; + + if ( gtk_tree_selection_get_selected( listsel , &store , &iter ) == TRUE ) + { + Playlist *playlist = NULL; + gtk_tree_model_get( store, &iter, PLLIST_PLPOINTER , &playlist , -1 ); + + active = playlist_get_active(); + was_active = ( playlist == active ); + + if ( gtk_tree_model_iter_n_children( store , NULL ) < 2 ) + { + /* let playlist_manager_update() handle the deletion of the last playlist */ + playlist_remove_playlist( playlist ); + } + else + { + gtk_list_store_remove( (GtkListStore*)store , &iter ); + /* this ensures that playlist_manager_update() will + not perform update, since we're already doing it here */ + DISABLE_MANAGER_UPDATE(); + playlist_remove_playlist( playlist ); + ENABLE_MANAGER_UPDATE(); + } + + if ( was_active && gtk_tree_model_get_iter_first( store , &iter ) ) + { + /* update bolded playlist */ + active = playlist_get_active(); + do { + gtk_tree_model_get( store , &iter , + PLLIST_PLPOINTER , &playlist , -1 ); + gtk_list_store_set( GTK_LIST_STORE(store) , &iter , + PLLIST_TEXT_WEIGHT , playlist == active ? + PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL , + -1 ); + } while ( gtk_tree_model_iter_next( store , &iter ) ); + } + } + + return; +} + + +static void +playlist_manager_cb_lv_dclick ( GtkTreeView * listview , GtkTreePath * path , + GtkTreeViewColumn * col , gpointer userdata ) +{ + GtkTreeModel *store; + GtkTreeIter iter; + Playlist *playlist = NULL, *active; + + store = gtk_tree_view_get_model( GTK_TREE_VIEW(listview) ); + if ( gtk_tree_model_get_iter( store , &iter , path ) == TRUE ) + { + gtk_tree_model_get( store , &iter , PLLIST_PLPOINTER , &playlist , -1 ); + DISABLE_MANAGER_UPDATE(); + playlist_select_playlist( playlist ); + ENABLE_MANAGER_UPDATE(); + } + + if ( gtk_tree_model_get_iter_first( store , &iter ) ) + { + /* update bolded playlist */ + active = playlist_get_active(); + do { + gtk_tree_model_get( store , &iter , + PLLIST_PLPOINTER , &playlist , -1 ); + gtk_list_store_set( GTK_LIST_STORE(store) , &iter , + PLLIST_TEXT_WEIGHT , playlist == active ? + PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL , + -1 ); + } while ( gtk_tree_model_iter_next( store , &iter ) ); + } + + return; +} + + +static void +playlist_manager_cb_lv_pmenu_rename ( GtkMenuItem *menuitem , gpointer lv ) +{ + GtkTreeSelection *listsel = gtk_tree_view_get_selection( GTK_TREE_VIEW(lv) ); + GtkTreeModel *store; + GtkTreeIter iter; + + if ( gtk_tree_selection_get_selected( listsel , &store , &iter ) == TRUE ) + { + GtkTreePath *path = gtk_tree_model_get_path( GTK_TREE_MODEL(store) , &iter ); + GtkCellRenderer *rndrname = g_object_get_data( G_OBJECT(lv) , "rn" ); + /* set the name renderer to editable and start editing */ + g_object_set( G_OBJECT(rndrname) , "editable" , TRUE , NULL ); + gtk_tree_view_set_cursor_on_cell( GTK_TREE_VIEW(lv) , path , + gtk_tree_view_get_column( GTK_TREE_VIEW(lv) , PLLIST_COL_NAME ) , rndrname , TRUE ); + gtk_tree_path_free( path ); + } +} + +static void +playlist_manager_cb_lv_name_edited ( GtkCellRendererText *cell , gchar *path_string , + gchar *new_text , gpointer listview ) +{ + /* this is currently used to change playlist names */ + GtkTreeModel *store = gtk_tree_view_get_model( GTK_TREE_VIEW(listview) ); + GtkTreeIter iter; + + if ( gtk_tree_model_get_iter_from_string( store , &iter , path_string ) == TRUE ) + { + Playlist *playlist = NULL; + gtk_tree_model_get( GTK_TREE_MODEL(store), &iter, PLLIST_PLPOINTER , &playlist , -1 ); + DISABLE_MANAGER_UPDATE(); + playlist_set_current_name( playlist , new_text ); + ENABLE_MANAGER_UPDATE(); + gtk_list_store_set( GTK_LIST_STORE(store), &iter, PLLIST_COL_NAME , new_text , -1 ); + } + /* set the renderer uneditable again */ + g_object_set( G_OBJECT(cell) , "editable" , FALSE , NULL ); +} + + +static gboolean +playlist_manager_cb_lv_btpress ( GtkWidget *lv , GdkEventButton *event ) +{ + if (( event->type == GDK_BUTTON_PRESS ) && ( event->button == 3 )) + { + GtkWidget *pmenu = (GtkWidget*)g_object_get_data( G_OBJECT(lv) , "menu" ); + gtk_menu_popup( GTK_MENU(pmenu) , NULL , NULL , NULL , NULL , + (event != NULL) ? event->button : 0, + event->time); + return TRUE; + } + + return FALSE; +} + + +static gboolean +playlist_manager_cb_keypress ( GtkWidget *win , GdkEventKey *event ) +{ + switch (event->keyval) + { + case GDK_Escape: + gtk_widget_destroy( playman_win ); + return TRUE; + default: + return FALSE; + } +} + + +void +playlist_manager_ui_show ( void ) +{ + GtkWidget *playman_vbox; + GtkWidget *playman_pl_lv, *playman_pl_lv_frame, *playman_pl_lv_sw; + GtkCellRenderer *playman_pl_lv_textrndr_name, *playman_pl_lv_textrndr_entriesnum; + GtkTreeViewColumn *playman_pl_lv_col_name, *playman_pl_lv_col_entriesnum; + GtkListStore *pl_store; + GtkWidget *playman_pl_lv_pmenu, *playman_pl_lv_pmenu_rename; + GtkWidget *playman_bbar_hbbox; + GtkWidget *playman_bbar_bt_new, *playman_bbar_bt_del, *playman_bbar_bt_close; + GdkGeometry playman_win_hints; + GtkTreeIter active_iter; + GtkTreePath *active_path; + + if ( playman_win != NULL ) + { + gtk_window_present( GTK_WINDOW(playman_win) ); + return; + } + + playman_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_type_hint( GTK_WINDOW(playman_win), GDK_WINDOW_TYPE_HINT_DIALOG ); + gtk_window_set_transient_for( GTK_WINDOW(playman_win) , GTK_WINDOW(mainwin) ); + gtk_window_set_position( GTK_WINDOW(playman_win), GTK_WIN_POS_CENTER ); + gtk_window_set_title( GTK_WINDOW(playman_win), _("Playlist Manager") ); + gtk_container_set_border_width( GTK_CONTAINER(playman_win), 10 ); + g_signal_connect( G_OBJECT(playman_win) , "destroy" , + G_CALLBACK(gtk_widget_destroyed) , &playman_win ); + g_signal_connect( G_OBJECT(playman_win) , "key-press-event" , + G_CALLBACK(playlist_manager_cb_keypress) , NULL ); + playman_win_hints.min_width = 400; + playman_win_hints.min_height = 250; + gtk_window_set_geometry_hints( GTK_WINDOW(playman_win) , GTK_WIDGET(playman_win) , + &playman_win_hints , GDK_HINT_MIN_SIZE ); + + playman_vbox = gtk_vbox_new( FALSE , 10 ); + gtk_container_add( GTK_CONTAINER(playman_win) , playman_vbox ); + + /* current liststore model + ---------------------------------------------- + G_TYPE_STRING -> playlist name + G_TYPE_UINT -> number of entries in playlist + G_TYPE_POINTER -> playlist pointer (Playlist*) + PANGO_TYPE_WEIGHT -> font weight + ---------------------------------------------- + */ + pl_store = gtk_list_store_new( PLLIST_NUMCOLS , + G_TYPE_STRING , G_TYPE_UINT , G_TYPE_POINTER , PANGO_TYPE_WEIGHT ); + active_iter = playlist_manager_populate( pl_store ); + + playman_pl_lv_frame = gtk_frame_new( NULL ); + playman_pl_lv = gtk_tree_view_new_with_model( GTK_TREE_MODEL(pl_store) ); + + g_object_set_data( G_OBJECT(playman_win) , "lv" , playman_pl_lv ); + g_object_set_data( G_OBJECT(playman_pl_lv) , "opt1" , GINT_TO_POINTER(0) ); + playman_pl_lv_textrndr_entriesnum = gtk_cell_renderer_text_new(); /* uneditable */ + playman_pl_lv_textrndr_name = gtk_cell_renderer_text_new(); /* can become editable */ + g_object_set( G_OBJECT(playman_pl_lv_textrndr_entriesnum) , "weight-set" , TRUE , NULL ); + g_object_set( G_OBJECT(playman_pl_lv_textrndr_name) , "weight-set" , TRUE , NULL ); + g_signal_connect( G_OBJECT(playman_pl_lv_textrndr_name) , "edited" , + G_CALLBACK(playlist_manager_cb_lv_name_edited) , playman_pl_lv ); + g_object_set_data( G_OBJECT(playman_pl_lv) , "rn" , playman_pl_lv_textrndr_name ); + playman_pl_lv_col_name = gtk_tree_view_column_new_with_attributes( + _("Playlist") , playman_pl_lv_textrndr_name , + "text" , PLLIST_COL_NAME , + "weight", PLLIST_TEXT_WEIGHT , + NULL ); + gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(playman_pl_lv_col_name) , TRUE ); + gtk_tree_view_append_column( GTK_TREE_VIEW(playman_pl_lv), playman_pl_lv_col_name ); + playman_pl_lv_col_entriesnum = gtk_tree_view_column_new_with_attributes( + _("Entries") , playman_pl_lv_textrndr_entriesnum , + "text" , PLLIST_COL_ENTRIESNUM , + "weight", PLLIST_TEXT_WEIGHT , + NULL ); + gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(playman_pl_lv_col_entriesnum) , FALSE ); + gtk_tree_view_append_column( GTK_TREE_VIEW(playman_pl_lv), playman_pl_lv_col_entriesnum ); + playman_pl_lv_sw = gtk_scrolled_window_new( NULL , NULL ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(playman_pl_lv_sw) , + GTK_POLICY_NEVER , GTK_POLICY_ALWAYS ); + gtk_container_add( GTK_CONTAINER(playman_pl_lv_sw) , playman_pl_lv ); + gtk_container_add( GTK_CONTAINER(playman_pl_lv_frame) , playman_pl_lv_sw ); + gtk_box_pack_start( GTK_BOX(playman_vbox) , playman_pl_lv_frame , TRUE , TRUE , 0 ); + + /* listview popup menu */ + playman_pl_lv_pmenu = gtk_menu_new(); + playman_pl_lv_pmenu_rename = gtk_menu_item_new_with_mnemonic( _( "_Rename" ) ); + g_signal_connect( G_OBJECT(playman_pl_lv_pmenu_rename) , "activate" , + G_CALLBACK(playlist_manager_cb_lv_pmenu_rename) , playman_pl_lv ); + gtk_menu_shell_append( GTK_MENU_SHELL(playman_pl_lv_pmenu) , playman_pl_lv_pmenu_rename ); + gtk_widget_show_all( playman_pl_lv_pmenu ); + g_object_set_data( G_OBJECT(playman_pl_lv) , "menu" , playman_pl_lv_pmenu ); + g_signal_connect_swapped( G_OBJECT(playman_win) , "destroy" , + G_CALLBACK(gtk_widget_destroy) , playman_pl_lv_pmenu ); + + /* button bar */ + playman_bbar_hbbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(playman_bbar_hbbox) , GTK_BUTTONBOX_END ); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(playman_bbar_hbbox), 5); + playman_bbar_bt_close = gtk_button_new_from_stock( GTK_STOCK_CLOSE ); + playman_bbar_bt_del = gtk_button_new_from_stock( GTK_STOCK_DELETE ); + playman_bbar_bt_new = gtk_button_new_from_stock( GTK_STOCK_NEW ); + gtk_container_add( GTK_CONTAINER(playman_bbar_hbbox) , playman_bbar_bt_close ); + gtk_container_add( GTK_CONTAINER(playman_bbar_hbbox) , playman_bbar_bt_del ); + gtk_container_add( GTK_CONTAINER(playman_bbar_hbbox) , playman_bbar_bt_new ); + gtk_button_box_set_child_secondary( GTK_BUTTON_BOX(playman_bbar_hbbox) , + playman_bbar_bt_close , TRUE ); + gtk_box_pack_start( GTK_BOX(playman_vbox) , playman_bbar_hbbox , FALSE , FALSE , 0 ); + + g_signal_connect( G_OBJECT(playman_pl_lv) , "button-press-event" , + G_CALLBACK(playlist_manager_cb_lv_btpress) , NULL ); + g_signal_connect( G_OBJECT(playman_pl_lv) , "row-activated" , + G_CALLBACK(playlist_manager_cb_lv_dclick) , NULL ); + g_signal_connect_swapped( G_OBJECT(playman_bbar_bt_new) , "clicked" , + G_CALLBACK(playlist_manager_cb_new) , playman_pl_lv ); + g_signal_connect_swapped( G_OBJECT(playman_bbar_bt_del) , "clicked" , + G_CALLBACK(playlist_manager_cb_del) , playman_pl_lv ); + g_signal_connect_swapped( G_OBJECT(playman_bbar_bt_close) , "clicked" , + G_CALLBACK(gtk_widget_destroy) , playman_win ); + + /* have active playlist selected and scrolled to */ + active_path = gtk_tree_model_get_path( GTK_TREE_MODEL(pl_store) , + &active_iter ); + gtk_tree_view_set_cursor( GTK_TREE_VIEW(playman_pl_lv) , + active_path , NULL , FALSE ); + gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW(playman_pl_lv) , + active_path , NULL , TRUE , 0.5 , 0.0 ); + gtk_tree_path_free( active_path ); + + g_object_unref( pl_store ); + + gtk_widget_show_all( playman_win ); +} + + +void +playlist_manager_update ( void ) +{ + /* this function is called whenever there is a change in playlist, such as + playlist created/deleted or entry added/deleted in a playlist; if the playlist + manager is active, it should be updated to keep consistency of information */ + + /* CAREFUL! this currently locks/unlocks all the playlists */ + + if ( playman_win != NULL ) + { + GtkWidget *lv = (GtkWidget*)g_object_get_data( G_OBJECT(playman_win) , "lv" ); + if ( GPOINTER_TO_INT(g_object_get_data(G_OBJECT(lv),"opt1")) == 0 ) + { + GtkListStore *store = (GtkListStore*)gtk_tree_view_get_model( GTK_TREE_VIEW(lv) ); + playlist_manager_populate( store ); + } + return; + } + else + return; /* if the playlist manager is not active, simply return */ +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_playlist_manager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_playlist_manager.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,26 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2007 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_PLAYLIST_MANAGER_H +#define AUDACIOUS_UI_PLAYLIST_MANAGER_H + +void playlist_manager_update ( void ); +void playlist_manager_ui_show ( void ); + +#endif /* AUDACIOUS_UI_PLAYLIST_MANAGER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skin.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skin.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,2048 @@ +/* Audacious + * Copyright (C) 2005-2007 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. + */ + +/*#define AUD_DEBUG*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* TODO: enforce default sizes! */ + +#include +#include +#include +#include +#include + +#include "ui_skin.h" +#include "ui_equalizer.h" +#include "main.h" +#include "ui_playlist.h" +#include "ui_skinselector.h" +#include "util.h" + +#include "debug.h" + +#include "platform/smartinclude.h" +#include "vfs.h" + +#include "ui_skinned_window.h" +#include "ui_skinned_button.h" +#include "ui_skinned_number.h" +#include "ui_skinned_horizontal_slider.h" +#include "ui_skinned_playstatus.h" + +#define EXTENSION_TARGETS 7 + +static gchar *ext_targets[EXTENSION_TARGETS] = +{ "bmp", "xpm", "png", "svg", "gif", "jpg", "jpeg" }; + +struct _SkinPixmapIdMapping { + SkinPixmapId id; + const gchar *name; + const gchar *alt_name; + gint width, height; +}; + +struct _SkinMaskInfo { + gint width, height; + gchar *inistr; +}; + +typedef struct _SkinPixmapIdMapping SkinPixmapIdMapping; +typedef struct _SkinMaskInfo SkinMaskInfo; + + +Skin *aud_active_skin = NULL; + +static gint skin_current_num; + +static SkinMaskInfo skin_mask_info[] = { + {275, 116, "Normal"}, + {275, 16, "WindowShade"}, + {275, 116, "Equalizer"}, + {275, 16, "EqualizerWS"} +}; + +static SkinPixmapIdMapping skin_pixmap_id_map[] = { + {SKIN_MAIN, "main", NULL, 0, 0}, + {SKIN_CBUTTONS, "cbuttons", NULL, 0, 0}, + {SKIN_SHUFREP, "shufrep", NULL, 0, 0}, + {SKIN_TEXT, "text", NULL, 0, 0}, + {SKIN_TITLEBAR, "titlebar", NULL, 0, 0}, + {SKIN_VOLUME, "volume", NULL, 0, 0}, + {SKIN_BALANCE, "balance", "volume", 0, 0}, + {SKIN_MONOSTEREO, "monoster", NULL, 0, 0}, + {SKIN_PLAYPAUSE, "playpaus", NULL, 0, 0}, + {SKIN_NUMBERS, "nums_ex", "numbers", 0, 0}, + {SKIN_POSBAR, "posbar", NULL, 0, 0}, + {SKIN_EQMAIN, "eqmain", NULL, 0, 0}, + {SKIN_PLEDIT, "pledit", NULL, 0, 0}, + {SKIN_EQ_EX, "eq_ex", NULL, 0, 0} +}; + +static guint skin_pixmap_id_map_size = G_N_ELEMENTS(skin_pixmap_id_map); + +static const guchar skin_default_viscolor[24][3] = { + {9, 34, 53}, + {10, 18, 26}, + {0, 54, 108}, + {0, 58, 116}, + {0, 62, 124}, + {0, 66, 132}, + {0, 70, 140}, + {0, 74, 148}, + {0, 78, 156}, + {0, 82, 164}, + {0, 86, 172}, + {0, 92, 184}, + {0, 98, 196}, + {0, 104, 208}, + {0, 110, 220}, + {0, 116, 232}, + {0, 122, 244}, + {0, 128, 255}, + {0, 128, 255}, + {0, 104, 208}, + {0, 80, 160}, + {0, 56, 112}, + {0, 32, 64}, + {200, 200, 200} +}; + +static gchar *original_gtk_theme = NULL; + +static GdkBitmap *skin_create_transparent_mask(const gchar *, + const gchar *, + const gchar *, + GdkWindow *, + gint, gint, gboolean); + +static void skin_set_default_vis_color(Skin * skin); + +void +skin_lock(Skin * skin) +{ + g_mutex_lock(skin->lock); +} + +void +skin_unlock(Skin * skin) +{ + g_mutex_unlock(skin->lock); +} + +gboolean +aud_active_skin_reload(void) +{ + AUDDBG("\n"); + return aud_active_skin_load(aud_active_skin->path); +} + +gboolean +aud_active_skin_load(const gchar * path) +{ + AUDDBG("%s\n", path); + g_return_val_if_fail(aud_active_skin != NULL, FALSE); + + if (!skin_load(aud_active_skin, path)) { + AUDDBG("loading failed\n"); + return FALSE; + } + + ui_skinned_window_draw_all(mainwin); + ui_skinned_window_draw_all(equalizerwin); + ui_skinned_window_draw_all(playlistwin); + + playlistwin_update_list(playlist_get_active()); + + SkinPixmap *pixmap; + pixmap = &aud_active_skin->pixmaps[SKIN_POSBAR]; + /* last 59 pixels of SKIN_POSBAR are knobs (normal and selected) */ + gtk_widget_set_size_request(mainwin_position, pixmap->width - 59, pixmap->height); + + return TRUE; +} + +void +skin_pixmap_free(SkinPixmap * p) +{ + g_return_if_fail(p != NULL); + g_return_if_fail(p->pixbuf != NULL); + + g_object_unref(p->pixbuf); + p->pixbuf = NULL; +} + +Skin * +skin_new(void) +{ + Skin *skin; + skin = g_new0(Skin, 1); + skin->lock = g_mutex_new(); + return skin; +} + +/** + * Frees the data associated for skin. + * + * Does not free skin itself or lock variable so that the skin can immediately + * populated with new skin data if needed. + */ +void +skin_free(Skin * skin) +{ + gint i; + + g_return_if_fail(skin != NULL); + + for (i = 0; i < SKIN_PIXMAP_COUNT; i++) + skin_pixmap_free(&skin->pixmaps[i]); + + for (i = 0; i < SKIN_MASK_COUNT; i++) { + if (skin->masks[i]) + g_object_unref(skin->masks[i]); + if (skin->scaled_masks[i]) + g_object_unref(skin->scaled_masks[i]); + + skin->masks[i] = NULL; + skin->scaled_masks[i] = NULL; + } + + for (i = 0; i < SKIN_COLOR_COUNT; i++) { + if (skin->colors[i]) + g_free(skin->colors[i]); + + skin->colors[i] = NULL; + } + + g_free(skin->path); + skin->path = NULL; + + skin_set_default_vis_color(skin); +} + +void +skin_destroy(Skin * skin) +{ + g_return_if_fail(skin != NULL); + skin_free(skin); + g_mutex_free(skin->lock); + g_free(skin); +} + +const SkinPixmapIdMapping * +skin_pixmap_id_lookup(guint id) +{ + guint i; + + for (i = 0; i < skin_pixmap_id_map_size; i++) { + if (id == skin_pixmap_id_map[i].id) { + return &skin_pixmap_id_map[i]; + } + } + + return NULL; +} + +const gchar * +skin_pixmap_id_to_name(SkinPixmapId id) +{ + guint i; + + for (i = 0; i < skin_pixmap_id_map_size; i++) { + if (id == skin_pixmap_id_map[i].id) + return skin_pixmap_id_map[i].name; + } + return NULL; +} + +static void +skin_set_default_vis_color(Skin * skin) +{ + memcpy(skin->vis_color, skin_default_viscolor, + sizeof(skin_default_viscolor)); +} + +/* + * I have rewritten this to take an array of possible targets, + * once we find a matching target we now return, instead of loop + * recursively. This allows for us to support many possible format + * targets for our skinning engine than just the original winamp + * formats. + * + * -- nenolod, 16 January 2006 + */ +gchar * +skin_pixmap_locate(const gchar * dirname, gchar ** basenames) +{ + gchar *filename; + gint i; + + for (i = 0; basenames[i]; i++) + if (!(filename = find_path_recursively(dirname, basenames[i]))) + g_free(filename); + else + return filename; + + /* can't find any targets -- sorry */ + return NULL; +} + +/** + * Creates possible file names for a pixmap. + * + * Basically this makes list of all possible file names that pixmap data + * can be found from by using the static ext_targets variable to get all + * possible extensions that pixmap file might have. + */ +static gchar ** +skin_pixmap_create_basenames(const SkinPixmapIdMapping * pixmap_id_mapping) +{ + gchar **basenames = g_malloc0(sizeof(gchar*) * (EXTENSION_TARGETS * 2 + 1)); + gint i, y; + + // Create list of all possible image formats that can be loaded + for (i = 0, y = 0; i < EXTENSION_TARGETS; i++, y++) + { + basenames[y] = + g_strdup_printf("%s.%s", pixmap_id_mapping->name, ext_targets[i]); + + if (pixmap_id_mapping->alt_name) + basenames[++y] = + g_strdup_printf("%s.%s", pixmap_id_mapping->alt_name, + ext_targets[i]); + } + + return basenames; +} + +/** + * Frees the data allocated by skin_pixmap_create_basenames + */ +static void +skin_pixmap_free_basenames(gchar ** basenames) +{ + int i; + for (i = 0; basenames[i] != NULL; i++) + { + g_free(basenames[i]); + basenames[i] = NULL; + } + g_free(basenames); +} + +/** + * Locates a pixmap file for skin. + */ +static gchar * +skin_pixmap_locate_basenames(const Skin * skin, + const SkinPixmapIdMapping * pixmap_id_mapping, + const gchar * path_p) +{ + gchar *filename = NULL; + const gchar *path = path_p ? path_p : skin->path; + gchar **basenames = skin_pixmap_create_basenames(pixmap_id_mapping); + + filename = skin_pixmap_locate(path, basenames); + + skin_pixmap_free_basenames(basenames); + + return filename; +} + + +static gboolean +skin_load_pixmap_id(Skin * skin, SkinPixmapId id, const gchar * path_p) +{ + const SkinPixmapIdMapping *pixmap_id_mapping; + gchar *filename; + SkinPixmap *pm = NULL; + + g_return_val_if_fail(skin != NULL, FALSE); + g_return_val_if_fail(id < SKIN_PIXMAP_COUNT, FALSE); + + pixmap_id_mapping = skin_pixmap_id_lookup(id); + g_return_val_if_fail(pixmap_id_mapping != NULL, FALSE); + + filename = skin_pixmap_locate_basenames(skin, pixmap_id_mapping, path_p); + + if (filename == NULL) + return FALSE; + + AUDDBG("loaded %s\n", filename); + + pm = &skin->pixmaps[id]; + GdkPixbuf *pix = gdk_pixbuf_new_from_file(filename, NULL); + pm->pixbuf = audacious_create_colorized_pixbuf(pix, cfg.colorize_r, cfg.colorize_g, cfg.colorize_b); + g_object_unref(pix); + pm->width = gdk_pixbuf_get_width(pm->pixbuf); + pm->height = gdk_pixbuf_get_height(pm->pixbuf); + pm->current_width = pm->width; + pm->current_height = pm->height; + + g_free(filename); + + return TRUE; +} + +void +skin_mask_create(Skin * skin, + const gchar * path, + gint id, + GdkWindow * window) +{ + skin->masks[id] = + skin_create_transparent_mask(path, "region.txt", + skin_mask_info[id].inistr, window, + skin_mask_info[id].width, + skin_mask_info[id].height, FALSE); + + skin->scaled_masks[id] = + skin_create_transparent_mask(path, "region.txt", + skin_mask_info[id].inistr, window, + skin_mask_info[id].width * 2, + skin_mask_info[id].height * 2, TRUE); +} + +static GdkBitmap * +create_default_mask(GdkWindow * parent, gint w, gint h) +{ + GdkBitmap *ret; + GdkGC *gc; + GdkColor pattern; + + ret = gdk_pixmap_new(parent, w, h, 1); + gc = gdk_gc_new(ret); + pattern.pixel = 1; + gdk_gc_set_foreground(gc, &pattern); + gdk_draw_rectangle(ret, gc, TRUE, 0, 0, w, h); + g_object_unref(gc); + + return ret; +} + +static void +skin_query_color(GdkColormap * cm, GdkColor * c) +{ +#ifdef GDK_WINDOWING_X11 + XColor xc = { 0,0,0,0,0,0 }; + + xc.pixel = c->pixel; + XQueryColor(GDK_COLORMAP_XDISPLAY(cm), GDK_COLORMAP_XCOLORMAP(cm), &xc); + c->red = xc.red; + c->green = xc.green; + c->blue = xc.blue; +#else + /* do nothing. see what breaks? */ +#endif +} + +static glong +skin_calc_luminance(GdkColor * c) +{ + return (0.212671 * c->red + 0.715160 * c->green + 0.072169 * c->blue); +} + +static void +skin_get_textcolors(GdkPixbuf * pix, GdkColor * bgc, GdkColor * fgc) +{ + /* + * Try to extract reasonable background and foreground colors + * from the font pixmap + */ + + GdkImage *gi; + GdkColormap *cm; + gint i; + + g_return_if_fail(pix != NULL); + + GdkPixmap *text = gdk_pixmap_new(NULL, gdk_pixbuf_get_width(pix), gdk_pixbuf_get_height(pix), gdk_rgb_get_visual()->depth); + gdk_draw_pixbuf(text, NULL, pix, 0, 0, 0, 0, gdk_pixbuf_get_width(pix), gdk_pixbuf_get_height(pix), + GDK_RGB_DITHER_NONE, 0, 0); + /* Get the first line of text */ + gi = gdk_drawable_get_image(text, 0, 0, 152, 6); + cm = gdk_colormap_get_system(); + + for (i = 0; i < 6; i++) { + GdkColor c; + gint x; + glong d, max_d; + + /* Get a pixel from the middle of the space character */ + bgc[i].pixel = gdk_image_get_pixel(gi, 151, i); + skin_query_color(cm, &bgc[i]); + + max_d = 0; + for (x = 1; x < 150; x++) { + c.pixel = gdk_image_get_pixel(gi, x, i); + skin_query_color(cm, &c); + + d = labs(skin_calc_luminance(&c) - skin_calc_luminance(&bgc[i])); + if (d > max_d) { + memcpy(&fgc[i], &c, sizeof(GdkColor)); + max_d = d; + } + } + } + g_object_unref(gi); + g_object_unref(text); +} + +gboolean +init_skins(const gchar * path) +{ + aud_active_skin = skin_new(); + + skin_parse_hints(aud_active_skin, NULL); + + /* create the windows if they haven't been created yet, needed for bootstrapping */ + if (mainwin == NULL) + { + mainwin_create(); + equalizerwin_create(); + playlistwin_create(); + } + + if (!aud_active_skin_load(path)) { + if (path != NULL) + AUDDBG("Unable to load skin (%s), trying default...\n", path); + else + AUDDBG("Skin not defined: trying default...\n"); + + /* can't load configured skin, retry with default */ + if (!aud_active_skin_load(BMP_DEFAULT_SKIN_PATH)) { + AUDDBG("Unable to load default skin (%s)! Giving up.\n", + BMP_DEFAULT_SKIN_PATH); + return FALSE; + } + } + + if (cfg.random_skin_on_play) + skinlist_update(); + + return TRUE; +} + +void cleanup_skins() +{ + skin_destroy(aud_active_skin); + aud_active_skin = NULL; +} + + +/* + * Opens and parses a skin's hints file. + * Hints files are somewhat like "scripts" in Winamp3/5. + * We'll probably add scripts to it next. + */ +void +skin_parse_hints(Skin * skin, gchar *path_p) +{ + gchar *filename, *tmp; + INIFile *inifile; + + path_p = path_p ? path_p : skin->path; + + skin->properties.mainwin_othertext = FALSE; + skin->properties.mainwin_vis_x = 24; + skin->properties.mainwin_vis_y = 43; + skin->properties.mainwin_vis_width = 76; + skin->properties.mainwin_text_x = 112; + skin->properties.mainwin_text_y = 27; + skin->properties.mainwin_text_width = 153; + skin->properties.mainwin_infobar_x = 112; + skin->properties.mainwin_infobar_y = 43; + skin->properties.mainwin_number_0_x = 36; + skin->properties.mainwin_number_0_y = 26; + skin->properties.mainwin_number_1_x = 48; + skin->properties.mainwin_number_1_y = 26; + skin->properties.mainwin_number_2_x = 60; + skin->properties.mainwin_number_2_y = 26; + skin->properties.mainwin_number_3_x = 78; + skin->properties.mainwin_number_3_y = 26; + skin->properties.mainwin_number_4_x = 90; + skin->properties.mainwin_number_4_y = 26; + skin->properties.mainwin_playstatus_x = 24; + skin->properties.mainwin_playstatus_y = 28; + skin->properties.mainwin_menurow_visible = TRUE; + skin->properties.mainwin_volume_x = 107; + skin->properties.mainwin_volume_y = 57; + skin->properties.mainwin_balance_x = 177; + skin->properties.mainwin_balance_y = 57; + skin->properties.mainwin_position_x = 16; + skin->properties.mainwin_position_y = 72; + skin->properties.mainwin_othertext_is_status = FALSE; + skin->properties.mainwin_othertext_visible = skin->properties.mainwin_othertext; + skin->properties.mainwin_text_visible = TRUE; + skin->properties.mainwin_vis_visible = TRUE; + skin->properties.mainwin_previous_x = 16; + skin->properties.mainwin_previous_y = 88; + skin->properties.mainwin_play_x = 39; + skin->properties.mainwin_play_y = 88; + skin->properties.mainwin_pause_x = 62; + skin->properties.mainwin_pause_y = 88; + skin->properties.mainwin_stop_x = 85; + skin->properties.mainwin_stop_y = 88; + skin->properties.mainwin_next_x = 108; + skin->properties.mainwin_next_y = 88; + skin->properties.mainwin_eject_x = 136; + skin->properties.mainwin_eject_y = 89; + skin->properties.mainwin_width = 275; + skin_mask_info[0].width = skin->properties.mainwin_width; + skin->properties.mainwin_height = 116; + skin_mask_info[0].height = skin->properties.mainwin_height; + skin->properties.mainwin_about_x = 247; + skin->properties.mainwin_about_y = 83; + skin->properties.mainwin_shuffle_x = 164; + skin->properties.mainwin_shuffle_y = 89; + skin->properties.mainwin_repeat_x = 210; + skin->properties.mainwin_repeat_y = 89; + skin->properties.mainwin_eqbutton_x = 219; + skin->properties.mainwin_eqbutton_y = 58; + skin->properties.mainwin_plbutton_x = 242; + skin->properties.mainwin_plbutton_y = 58; + skin->properties.textbox_bitmap_font_width = 5; + skin->properties.textbox_bitmap_font_height = 6; + skin->properties.mainwin_minimize_x = 244; + skin->properties.mainwin_minimize_y = 3; + skin->properties.mainwin_shade_x = 254; + skin->properties.mainwin_shade_y = 3; + skin->properties.mainwin_close_x = 264; + skin->properties.mainwin_close_y = 3; + + if (path_p == NULL) + return; + + filename = find_file_recursively(path_p, "skin.hints"); + + if (filename == NULL) + return; + + inifile = open_ini_file(filename); + if (!inifile) + return; + + tmp = read_ini_string(inifile, "skin", "mainwinOthertext"); + + if (tmp != NULL) + { + skin->properties.mainwin_othertext = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinVisX"); + + if (tmp != NULL) + { + skin->properties.mainwin_vis_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinVisY"); + + if (tmp != NULL) + { + skin->properties.mainwin_vis_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinVisWidth"); + + if (tmp != NULL) + { + skin->properties.mainwin_vis_width = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinTextX"); + + if (tmp != NULL) + { + skin->properties.mainwin_text_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinTextY"); + + if (tmp != NULL) + { + skin->properties.mainwin_text_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinTextWidth"); + + if (tmp != NULL) + { + skin->properties.mainwin_text_width = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinInfoBarX"); + + if (tmp != NULL) + { + skin->properties.mainwin_infobar_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinInfoBarY"); + + if (tmp != NULL) + { + skin->properties.mainwin_infobar_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNumber0X"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_0_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNumber0Y"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_0_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNumber1X"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_1_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNumber1Y"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_1_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNumber2X"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_2_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNumber2Y"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_2_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNumber3X"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_3_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNumber3Y"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_3_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNumber4X"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_4_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNumber4Y"); + + if (tmp != NULL) + { + skin->properties.mainwin_number_4_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPlayStatusX"); + + if (tmp != NULL) + { + skin->properties.mainwin_playstatus_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPlayStatusY"); + + if (tmp != NULL) + { + skin->properties.mainwin_playstatus_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinMenurowVisible"); + + if (tmp != NULL) + { + skin->properties.mainwin_menurow_visible = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinVolumeX"); + + if (tmp != NULL) + { + skin->properties.mainwin_volume_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinVolumeY"); + + if (tmp != NULL) + { + skin->properties.mainwin_volume_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinBalanceX"); + + if (tmp != NULL) + { + skin->properties.mainwin_balance_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinBalanceY"); + + if (tmp != NULL) + { + skin->properties.mainwin_balance_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPositionX"); + + if (tmp != NULL) + { + skin->properties.mainwin_position_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPositionY"); + + if (tmp != NULL) + { + skin->properties.mainwin_position_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinOthertextIsStatus"); + + if (tmp != NULL) + { + skin->properties.mainwin_othertext_is_status = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinOthertextVisible"); + + if (tmp != NULL) + { + skin->properties.mainwin_othertext_visible = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinTextVisible"); + + if (tmp != NULL) + { + skin->properties.mainwin_text_visible = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinVisVisible"); + + if (tmp != NULL) + { + skin->properties.mainwin_vis_visible = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPreviousX"); + + if (tmp != NULL) + { + skin->properties.mainwin_previous_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPreviousY"); + + if (tmp != NULL) + { + skin->properties.mainwin_previous_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPlayX"); + + if (tmp != NULL) + { + skin->properties.mainwin_play_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPlayY"); + + if (tmp != NULL) + { + skin->properties.mainwin_play_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPauseX"); + + if (tmp != NULL) + { + skin->properties.mainwin_pause_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPauseY"); + + if (tmp != NULL) + { + skin->properties.mainwin_pause_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinStopX"); + + if (tmp != NULL) + { + skin->properties.mainwin_stop_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinStopY"); + + if (tmp != NULL) + { + skin->properties.mainwin_stop_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNextX"); + + if (tmp != NULL) + { + skin->properties.mainwin_next_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinNextY"); + + if (tmp != NULL) + { + skin->properties.mainwin_next_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinEjectX"); + + if (tmp != NULL) + { + skin->properties.mainwin_eject_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinEjectY"); + + if (tmp != NULL) + { + skin->properties.mainwin_eject_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinWidth"); + + if (tmp != NULL) + { + skin->properties.mainwin_width = atoi(tmp); + g_free(tmp); + } + + skin_mask_info[0].width = skin->properties.mainwin_width; + + tmp = read_ini_string(inifile, "skin", "mainwinHeight"); + + if (tmp != NULL) + { + skin->properties.mainwin_height = atoi(tmp); + g_free(tmp); + } + + skin_mask_info[0].height = skin->properties.mainwin_height; + + tmp = read_ini_string(inifile, "skin", "mainwinAboutX"); + + if (tmp != NULL) + { + skin->properties.mainwin_about_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinAboutY"); + + if (tmp != NULL) + { + skin->properties.mainwin_about_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinShuffleX"); + + if (tmp != NULL) + { + skin->properties.mainwin_shuffle_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinShuffleY"); + + if (tmp != NULL) + { + skin->properties.mainwin_shuffle_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinRepeatX"); + + if (tmp != NULL) + { + skin->properties.mainwin_repeat_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinRepeatY"); + + if (tmp != NULL) + { + skin->properties.mainwin_repeat_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinEQButtonX"); + + if (tmp != NULL) + { + skin->properties.mainwin_eqbutton_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinEQButtonY"); + + if (tmp != NULL) + { + skin->properties.mainwin_eqbutton_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPLButtonX"); + + if (tmp != NULL) + { + skin->properties.mainwin_plbutton_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinPLButtonY"); + + if (tmp != NULL) + { + skin->properties.mainwin_plbutton_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "textboxBitmapFontWidth"); + + if (tmp != NULL) + { + skin->properties.textbox_bitmap_font_width = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "textboxBitmapFontHeight"); + + if (tmp != NULL) + { + skin->properties.textbox_bitmap_font_height = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinMinimizeX"); + + if (tmp != NULL) + { + skin->properties.mainwin_minimize_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinMinimizeY"); + + if (tmp != NULL) + { + skin->properties.mainwin_minimize_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinShadeX"); + + if (tmp != NULL) + { + skin->properties.mainwin_shade_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinShadeY"); + + if (tmp != NULL) + { + skin->properties.mainwin_shade_y = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinCloseX"); + + if (tmp != NULL) + { + skin->properties.mainwin_close_x = atoi(tmp); + g_free(tmp); + } + + tmp = read_ini_string(inifile, "skin", "mainwinCloseY"); + + if (tmp != NULL) + { + skin->properties.mainwin_close_y = atoi(tmp); + g_free(tmp); + } + + if (filename != NULL) + g_free(filename); + + close_ini_file(inifile); +} + +static guint +hex_chars_to_int(gchar hi, gchar lo) +{ + /* + * Converts a value in the range 0x00-0xFF + * to a integer in the range 0-65535 + */ + gchar str[3]; + + str[0] = hi; + str[1] = lo; + str[2] = 0; + + return (CLAMP(strtol(str, NULL, 16), 0, 0xFF) << 8); +} + +static GdkColor * +skin_load_color(INIFile *inifile, + const gchar * section, const gchar * key, + gchar * default_hex) +{ + gchar *value; + GdkColor *color = NULL; + + if (inifile || default_hex) { + if (inifile) { + value = read_ini_string(inifile, section, key); + if (value == NULL) { + value = g_strdup(default_hex); + } + } else { + value = g_strdup(default_hex); + } + if (value) { + gchar *ptr = value; + gint len; + + color = g_new0(GdkColor, 1); + g_strstrip(value); + + if (value[0] == '#') + ptr++; + len = strlen(ptr); + /* + * The handling of incomplete values is done this way + * to maximize winamp compatibility + */ + if (len >= 6) { + color->red = hex_chars_to_int(*ptr, *(ptr + 1)); + ptr += 2; + } + if (len >= 4) { + color->green = hex_chars_to_int(*ptr, *(ptr + 1)); + ptr += 2; + } + if (len >= 2) + color->blue = hex_chars_to_int(*ptr, *(ptr + 1)); + + g_free(value); + } + } + return color; +} + + + +GdkBitmap * +skin_create_transparent_mask(const gchar * path, + const gchar * file, + const gchar * section, + GdkWindow * window, + gint width, + gint height, gboolean scale) +{ + GdkBitmap *mask = NULL; + GdkGC *gc = NULL; + GdkColor pattern; + GdkPoint *gpoints; + + gchar *filename = NULL; + INIFile *inifile = NULL; + gboolean created_mask = FALSE; + GArray *num, *point; + guint i, j; + gint k; + + if (path) + filename = find_file_recursively(path, file); + + /* filename will be null if path wasn't set */ + if (!filename) + return create_default_mask(window, width, height); + + inifile = open_ini_file(filename); + + if ((num = read_ini_array(inifile, section, "NumPoints")) == NULL) { + g_free(filename); + close_ini_file(inifile); + return NULL; + } + + if ((point = read_ini_array(inifile, section, "PointList")) == NULL) { + g_array_free(num, TRUE); + g_free(filename); + close_ini_file(inifile); + return NULL; + } + + close_ini_file(inifile); + + mask = gdk_pixmap_new(window, width, height, 1); + gc = gdk_gc_new(mask); + + pattern.pixel = 0; + gdk_gc_set_foreground(gc, &pattern); + gdk_draw_rectangle(mask, gc, TRUE, 0, 0, width, height); + pattern.pixel = 1; + gdk_gc_set_foreground(gc, &pattern); + + j = 0; + for (i = 0; i < num->len; i++) { + if ((int)(point->len - j) >= (g_array_index(num, gint, i) * 2)) { + created_mask = TRUE; + gpoints = g_new(GdkPoint, g_array_index(num, gint, i)); + for (k = 0; k < g_array_index(num, gint, i); k++) { + gpoints[k].x = + g_array_index(point, gint, j + k * 2) * (scale ? cfg.scale_factor : 1 ); + gpoints[k].y = + g_array_index(point, gint, + j + k * 2 + 1) * (scale ? cfg.scale_factor : 1); + } + j += k * 2; + gdk_draw_polygon(mask, gc, TRUE, gpoints, + g_array_index(num, gint, i)); + g_free(gpoints); + } + } + g_array_free(num, TRUE); + g_array_free(point, TRUE); + g_free(filename); + + if (!created_mask) + gdk_draw_rectangle(mask, gc, TRUE, 0, 0, width, height); + + g_object_unref(gc); + + return mask; +} + +void +skin_load_viscolor(Skin * skin, const gchar * path, const gchar * basename) +{ + VFSFile *file; + gint i, c; + gchar line[256], *filename; + GArray *a; + + g_return_if_fail(skin != NULL); + g_return_if_fail(path != NULL); + g_return_if_fail(basename != NULL); + + skin_set_default_vis_color(skin); + + filename = find_file_recursively(path, basename); + if (!filename) + return; + + if (!(file = vfs_fopen(filename, "r"))) { + g_free(filename); + return; + } + + g_free(filename); + + for (i = 0; i < 24; i++) { + if (vfs_fgets(line, 255, file)) { + a = string_to_garray(line); + if (a->len > 2) { + for (c = 0; c < 3; c++) + skin->vis_color[i][c] = g_array_index(a, gint, c); + } + g_array_free(a, TRUE); + } + else + break; + } + + vfs_fclose(file); +} + +static void +skin_numbers_generate_dash(Skin * skin) +{ + GdkPixbuf *pixbuf; + SkinPixmap *numbers; + + g_return_if_fail(skin != NULL); + + numbers = &skin->pixmaps[SKIN_NUMBERS]; + if (!numbers->pixbuf || numbers->current_width < 99) + return; + + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, + 108, numbers->current_height); + + skin_draw_pixbuf(NULL, skin, pixbuf, SKIN_NUMBERS, 0, 0, 0, 0, 99, numbers->current_height); + skin_draw_pixbuf(NULL, skin, pixbuf, SKIN_NUMBERS, 90, 0, 99, 0, 9, numbers->current_height); + skin_draw_pixbuf(NULL, skin, pixbuf, SKIN_NUMBERS, 20, 6, 101, 6, 5, 1); + + g_object_unref(numbers->pixbuf); + + numbers->pixbuf = pixbuf; + numbers->current_width = 108; + numbers->width = 108; +} + +static gboolean +skin_load_pixmaps(Skin * skin, const gchar * path) +{ + GdkPixbuf *text_pb; + guint i; + gchar *filename; + INIFile *inifile; + + if(!skin) return FALSE; + if(!path) return FALSE; + + AUDDBG("Loading pixmaps in %s\n", path); + + for (i = 0; i < SKIN_PIXMAP_COUNT; i++) + if (!skin_load_pixmap_id(skin, i, path) && !cfg.allow_broken_skins) + return FALSE; + + text_pb = skin->pixmaps[SKIN_TEXT].pixbuf; + + if (text_pb) + skin_get_textcolors(text_pb, skin->textbg, skin->textfg); + + if (skin->pixmaps[SKIN_NUMBERS].pixbuf && + skin->pixmaps[SKIN_NUMBERS].width < 108 ) + skin_numbers_generate_dash(skin); + + filename = find_file_recursively(path, "pledit.txt"); + inifile = open_ini_file(filename); + + skin->colors[SKIN_PLEDIT_NORMAL] = + skin_load_color(inifile, "Text", "Normal", "#2499ff"); + skin->colors[SKIN_PLEDIT_CURRENT] = + skin_load_color(inifile, "Text", "Current", "#ffeeff"); + skin->colors[SKIN_PLEDIT_NORMALBG] = + skin_load_color(inifile, "Text", "NormalBG", "#0a120a"); + skin->colors[SKIN_PLEDIT_SELECTEDBG] = + skin_load_color(inifile, "Text", "SelectedBG", "#0a124a"); + + if (inifile) + close_ini_file(inifile); + + if (filename) + g_free(filename); + + skin_mask_create(skin, path, SKIN_MASK_MAIN, mainwin->window); + skin_mask_create(skin, path, SKIN_MASK_MAIN_SHADE, mainwin->window); + + skin_mask_create(skin, path, SKIN_MASK_EQ, equalizerwin->window); + skin_mask_create(skin, path, SKIN_MASK_EQ_SHADE, equalizerwin->window); + + skin_load_viscolor(skin, path, "viscolor.txt"); + + return TRUE; +} + +static void +skin_set_gtk_theme(GtkSettings * settings, Skin * skin) +{ + if (original_gtk_theme == NULL) + g_object_get(settings, "gtk-theme-name", &original_gtk_theme, NULL); + + /* the way GTK does things can be very broken. --nenolod */ + + gchar *tmp = g_strdup_printf("%s/.themes/aud-%s", g_get_home_dir(), + basename(skin->path)); + + gchar *troot = g_strdup_printf("%s/.themes", g_get_home_dir()); + g_mkdir_with_parents(troot, 0755); + g_free(troot); + + symlink(skin->path, tmp); + gtk_settings_set_string_property(settings, "gtk-theme-name", + basename(tmp), "audacious"); + g_free(tmp); +} + +/** + * Checks if all pixmap files exist that skin needs. + */ +static gboolean +skin_check_pixmaps(const Skin * skin, const gchar * skin_path) +{ + guint i; + for (i = 0; i < SKIN_PIXMAP_COUNT; i++) + { + gchar *filename = skin_pixmap_locate_basenames(skin, + skin_pixmap_id_lookup(i), + skin_path); + if (!filename) + return FALSE; + g_free(filename); + } + return TRUE; +} + +static gboolean +skin_load_nolock(Skin * skin, const gchar * path, gboolean force) +{ + GtkSettings *settings; + gchar *gtkrcpath; + gchar *newpath, *skin_path; + int archive = 0; + + AUDDBG("Attempt to load skin \"%s\"\n", path); + + g_return_val_if_fail(skin != NULL, FALSE); + g_return_val_if_fail(path != NULL, FALSE); + REQUIRE_LOCK(skin->lock); + + if (!g_file_test(path, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_DIR)) + return FALSE; + + if(force) AUDDBG("reloading forced!\n"); + if (!force && skin->path && !strcmp(skin->path, path)) { + AUDDBG("skin %s already loaded\n", path); + return FALSE; + } + + if (file_is_archive(path)) { + AUDDBG("Attempt to load archive\n"); + if (!(skin_path = archive_decompress(path))) { + AUDDBG("Unable to extract skin archive (%s)\n", path); + return FALSE; + } + archive = 1; + } else { + skin_path = g_strdup(path); + } + + // Check if skin path has all necessary files. + if (!cfg.allow_broken_skins && !skin_check_pixmaps(skin, skin_path)) { + if(archive) del_directory(skin_path); + g_free(skin_path); + AUDDBG("Skin path (%s) doesn't have all wanted pixmaps\n", skin_path); + return FALSE; + } + + // skin_free() frees skin->path and variable path can actually be skin->path + // and we want to get the path before possibly freeing it. + newpath = g_strdup(path); + skin_free(skin); + skin->path = newpath; + + memset(&(skin->properties), 0, sizeof(SkinProperties)); /* do it only if all tests above passed! --asphyx */ + + skin_current_num++; + + /* Parse the hints for this skin. */ + skin_parse_hints(skin, skin_path); + + if (!skin_load_pixmaps(skin, skin_path)) { + if(archive) del_directory(skin_path); + g_free(skin_path); + AUDDBG("Skin loading failed\n"); + return FALSE; + } + + /* restore gtk theme if changed by previous skin */ + settings = gtk_settings_get_default(); + + if (original_gtk_theme != NULL) { + gtk_settings_set_string_property(settings, "gtk-theme-name", + original_gtk_theme, "audacious"); + g_free(original_gtk_theme); + original_gtk_theme = NULL; + } + +#ifndef _WIN32 + if (!cfg.disable_inline_gtk && !archive) { + gtkrcpath = find_path_recursively(skin->path, "gtkrc"); + if (gtkrcpath != NULL) + skin_set_gtk_theme(settings, skin); + g_free(gtkrcpath); + } +#endif + + if(archive) del_directory(skin_path); + g_free(skin_path); + + gtk_widget_shape_combine_mask(mainwin, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + cfg.player_shaded), 0, 0); + gtk_widget_shape_combine_mask(equalizerwin, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + cfg.equalizer_shaded), 0, 0); + + return TRUE; +} + +void +skin_install_skin(const gchar * path) +{ + gchar *command; + + g_return_if_fail(path != NULL); + + command = g_strdup_printf("cp %s %s", + path, aud_paths[BMP_PATH_USER_SKIN_DIR]); + if (system(command)) { + AUDDBG("Unable to install skin (%s) into user directory (%s)\n", + path, aud_paths[BMP_PATH_USER_SKIN_DIR]); + } + g_free(command); +} + +static SkinPixmap * +skin_get_pixmap(Skin * skin, SkinPixmapId map_id) +{ + g_return_val_if_fail(skin != NULL, NULL); + g_return_val_if_fail(map_id < SKIN_PIXMAP_COUNT, NULL); + + return &skin->pixmaps[map_id]; +} + +gboolean +skin_load(Skin * skin, const gchar * path) +{ + gboolean ret; + + g_return_val_if_fail(skin != NULL, FALSE); + + if (!path) + return FALSE; + + skin_lock(skin); + ret = skin_load_nolock(skin, path, FALSE); + skin_unlock(skin); + + if(!ret) { + AUDDBG("loading failed\n"); + return FALSE; /* don't try to update anything if loading failed --asphyx */ + } + + SkinPixmap *pixmap = NULL; + pixmap = skin_get_pixmap(skin, SKIN_NUMBERS); + if (pixmap) { + ui_skinned_number_set_size(mainwin_minus_num, 9, pixmap->height); + ui_skinned_number_set_size(mainwin_10min_num, 9, pixmap->height); + ui_skinned_number_set_size(mainwin_min_num, 9, pixmap->height); + ui_skinned_number_set_size(mainwin_10sec_num, 9, pixmap->height); + ui_skinned_number_set_size(mainwin_sec_num, 9, pixmap->height); + } + + pixmap = skin_get_pixmap(skin, SKIN_MAIN); + if (pixmap && skin->properties.mainwin_height > pixmap->height) + skin->properties.mainwin_height = pixmap->height; + + pixmap = skin_get_pixmap(skin, SKIN_PLAYPAUSE); + if (pixmap) + ui_skinned_playstatus_set_size(mainwin_playstatus, 11, pixmap->height); + + pixmap = skin_get_pixmap(skin, SKIN_EQMAIN); + if (pixmap->height >= 313) + gtk_widget_show(equalizerwin_graph); + + return TRUE; +} + +gboolean +skin_reload_forced(void) +{ + gboolean error; + AUDDBG("\n"); + + skin_lock(aud_active_skin); + error = skin_load_nolock(aud_active_skin, aud_active_skin->path, TRUE); + skin_unlock(aud_active_skin); + + return error; +} + +void +skin_reload(Skin * skin) +{ + AUDDBG("\n"); + g_return_if_fail(skin != NULL); + skin_load_nolock(skin, skin->path, TRUE); +} + +GdkBitmap * +skin_get_mask(Skin * skin, SkinMaskId mi) +{ + GdkBitmap **masks; + + g_return_val_if_fail(skin != NULL, NULL); + g_return_val_if_fail(mi < SKIN_PIXMAP_COUNT, NULL); + + masks = cfg.scaled ? skin->scaled_masks : skin->masks; + return masks[mi]; +} + +GdkColor * +skin_get_color(Skin * skin, SkinColorId color_id) +{ + GdkColor *ret = NULL; + + g_return_val_if_fail(skin != NULL, NULL); + + switch (color_id) { + case SKIN_TEXTBG: + if (skin->pixmaps[SKIN_TEXT].pixbuf) + ret = skin->textbg; + else + ret = skin->def_textbg; + break; + case SKIN_TEXTFG: + if (skin->pixmaps[SKIN_TEXT].pixbuf) + ret = skin->textfg; + else + ret = skin->def_textfg; + break; + default: + if (color_id < SKIN_COLOR_COUNT) + ret = skin->colors[color_id]; + break; + } + return ret; +} + +void +skin_get_viscolor(Skin * skin, guchar vis_color[24][3]) +{ + gint i; + + g_return_if_fail(skin != NULL); + + for (i = 0; i < 24; i++) { + vis_color[i][0] = skin->vis_color[i][0]; + vis_color[i][1] = skin->vis_color[i][1]; + vis_color[i][2] = skin->vis_color[i][2]; + } +} + +gint +skin_get_id(void) +{ + return skin_current_num; +} + +void +skin_draw_pixbuf(GtkWidget *widget, Skin * skin, GdkPixbuf * pix, + SkinPixmapId pixmap_id, + gint xsrc, gint ysrc, gint xdest, gint ydest, + gint width, gint height) +{ + SkinPixmap *pixmap; + + g_return_if_fail(skin != NULL); + + pixmap = skin_get_pixmap(skin, pixmap_id); + g_return_if_fail(pixmap != NULL); + g_return_if_fail(pixmap->pixbuf != NULL); + + /* perhaps we should use transparency or resize widget? */ + if (xsrc+width > pixmap->width || ysrc+height > pixmap->height) { + if (widget) { + /* it's better to hide widget using SKIN_PLAYPAUSE/SKIN_POSBAR than display mess */ + if ((pixmap_id == SKIN_PLAYPAUSE && pixmap->width != 42) || pixmap_id == SKIN_POSBAR) { + gtk_widget_hide(widget); + return; + } + gint x, y; + x = -1; + y = -1; + + if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(mainwin)->fixed) { + GList *iter; + for (iter = GTK_FIXED (SKINNED_WINDOW(mainwin)->fixed)->children; iter; iter = g_list_next (iter)) { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + if (child_data->widget == widget) { + x = child_data->x; + y = child_data->y; + break; + } + } + + if (x != -1 && y != -1) { + /* Some skins include SKIN_VOLUME and/or SKIN_BALANCE + without knobs */ + if (pixmap_id == SKIN_VOLUME || pixmap_id == SKIN_BALANCE) { + if (ysrc+height > 421 && xsrc+width <= pixmap->width) + return; + } + /* let's copy what's under widget */ + gdk_pixbuf_copy_area(skin_get_pixmap(aud_active_skin, SKIN_MAIN)->pixbuf, + x, y, width, height, pix, xdest, ydest); + + /* XMMS skins seems to have SKIN_MONOSTEREO with size 58x20 instead of 58x24 */ + if (pixmap_id == SKIN_MONOSTEREO) + height = pixmap->height/2; + } + } else if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(equalizerwin)->fixed) { + if (!(pixmap_id == SKIN_EQMAIN && ysrc == 314)) /* equalizer preamp on equalizer graph */ + gtk_widget_hide(widget); + } else if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(playlistwin)->fixed) { + /* I haven't seen any skin with substandard playlist */ + gtk_widget_hide(widget); + } + } else + return; + } + + width = MIN(width, pixmap->width - xsrc); + height = MIN(height, pixmap->height - ysrc); + gdk_pixbuf_copy_area(pixmap->pixbuf, xsrc, ysrc, width, height, + pix, xdest, ydest); +} + +void +skin_get_eq_spline_colors(Skin * skin, guint32 colors[19]) +{ + gint i; + GdkPixbuf *pixbuf; + SkinPixmap *eqmainpm; + guchar* pixels,*p; + guint rowstride, n_channels; + g_return_if_fail(skin != NULL); + + eqmainpm = &skin->pixmaps[SKIN_EQMAIN]; + if (eqmainpm->pixbuf && + eqmainpm->current_width >= 116 && eqmainpm->current_height >= 313) + pixbuf = eqmainpm->pixbuf; + else + return; + + if (!GDK_IS_PIXBUF(pixbuf)) + return; + + pixels = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + for (i = 0; i < 19; i++) + { + p = pixels + rowstride * (i + 294) + 115 * n_channels; + colors[i] = (p[0] << 16) | (p[1] << 8) | p[2]; + /* should we really treat the Alpha channel? */ + /*if (n_channels == 4) + colors[i] = (colors[i] << 8) | p[3];*/ + } +} + + +static void +skin_draw_playlistwin_frame_top(Skin * skin, GdkPixbuf * pix, + gint width, gint height, gboolean focus) +{ + /* The title bar skin consists of 2 sets of 4 images, 1 set + * for focused state and the other for unfocused. The 4 images + * are: + * + * a. right corner (25,20) + * b. left corner (25,20) + * c. tiler (25,20) + * d. title (100,20) + * + * min allowed width = 100+25+25 = 150 + */ + + gint i, y, c; + + /* get y offset of the pixmap set to use */ + if (focus) + y = 0; + else + y = 21; + + /* left corner */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 0, y, 0, 0, 25, 20); + + /* titlebar title */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 26, y, + (width - 100) / 2, 0, 100, 20); + + /* titlebar right corner */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 153, y, + width - 25, 0, 25, 20); + + /* tile draw the remaining frame */ + + /* compute tile count */ + c = (width - (100 + 25 + 25)) / 25; + + for (i = 0; i < c / 2; i++) { + /* left of title */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, + 25 + i * 25, 0, 25, 20); + + /* right of title */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, + (width + 100) / 2 + i * 25, 0, 25, 20); + } + + if (c & 1) { + /* Odd tile count, so one remaining to draw. Here we split + * it into two and draw half on either side of the title */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, + ((c / 2) * 25) + 25, 0, 12, 20); + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, + (width / 2) + ((c / 2) * 25) + 50, 0, 13, 20); + } +} + +static void +skin_draw_playlistwin_frame_bottom(Skin * skin, GdkPixbuf * pix, + gint width, gint height, gboolean focus) +{ + /* The bottom frame skin consists of 1 set of 4 images. The 4 + * images are: + * + * a. left corner with menu buttons (125,38) + * b. visualization window (75,38) + * c. right corner with play buttons (150,38) + * d. frame tile (25,38) + * + * (min allowed width = 125+150+25=300 + */ + + gint i, c; + + /* bottom left corner (menu buttons) */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 0, 72, + 0, height - 38, 125, 38); + + c = (width - 275) / 25; + + /* draw visualization window, if width allows */ + if (c >= 3) { + c -= 3; + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 205, 0, + width - (150 + 75), height - 38, 75, 38); + } + + /* Bottom right corner (playbuttons etc) */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, + 126, 72, width - 150, height - 38, 150, 38); + + /* Tile draw the remaining undrawn portions */ + for (i = 0; i < c; i++) + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 179, 0, + 125 + i * 25, height - 38, 25, 38); +} + +static void +skin_draw_playlistwin_frame_sides(Skin * skin, GdkPixbuf * pix, + gint width, gint height, gboolean focus) +{ + /* The side frames consist of 2 tile images. 1 for the left, 1 for + * the right. + * a. left (12,29) + * b. right (19,29) + */ + + gint i; + + /* frame sides */ + for (i = 0; i < (height - (20 + 38)) / 29; i++) { + /* left */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 0, 42, + 0, 20 + i * 29, 12, 29); + + /* right */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 32, 42, + width - 19, 20 + i * 29, 19, 29); + } +} + + +void +skin_draw_playlistwin_frame(Skin * skin, GdkPixbuf * pix, + gint width, gint height, gboolean focus) +{ + skin_draw_playlistwin_frame_top(skin, pix, width, height, focus); + skin_draw_playlistwin_frame_bottom(skin, pix, width, height, focus); + skin_draw_playlistwin_frame_sides(skin, pix, width, height, focus); +} + + +void +skin_draw_playlistwin_shaded(Skin * skin, GdkPixbuf * pix, + gint width, gboolean focus) +{ + /* The shade mode titlebar skin consists of 4 images: + * a) left corner offset (72,42) size (25,14) + * b) right corner, focused offset (99,57) size (50,14) + * c) right corner, unfocused offset (99,42) size (50,14) + * d) bar tile offset (72,57) size (25,14) + */ + + gint i; + + /* left corner */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 72, 42, 0, 0, 25, 14); + + /* bar tile */ + for (i = 0; i < (width - 75) / 25; i++) + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 72, 57, + (i * 25) + 25, 0, 25, 14); + + /* right corner */ + skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 99, focus ? 42 : 57, + width - 50, 0, 50, 14); +} + + +void +skin_draw_mainwin_titlebar(Skin * skin, GdkPixbuf * pix, + gboolean shaded, gboolean focus) +{ + /* The titlebar skin consists of 2 sets of 2 images, one for for + * shaded and the other for unshaded mode, giving a total of 4. + * The images are exactly 275x14 pixels, aligned and arranged + * vertically on each other in the pixmap in the following order: + * + * a) unshaded, focused offset (27, 0) + * b) unshaded, unfocused offset (27, 15) + * c) shaded, focused offset (27, 29) + * d) shaded, unfocused offset (27, 42) + */ + + gint y_offset; + + if (shaded) { + if (focus) + y_offset = 29; + else + y_offset = 42; + } + else { + if (focus) + y_offset = 0; + else + y_offset = 15; + } + + skin_draw_pixbuf(NULL, skin, pix, SKIN_TITLEBAR, 27, y_offset, + 0, 0, aud_active_skin->properties.mainwin_width, MAINWIN_TITLEBAR_HEIGHT); +} + + +void +skin_set_random_skin(void) +{ + SkinNode *node; + guint32 randval; + + /* Get a random value to select the skin to use */ + randval = g_random_int_range(0, g_list_length(skinlist)); + node = g_list_nth(skinlist, randval)->data; + aud_active_skin_load(node->path); +} + + +void ui_skinned_widget_draw(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gboolean scale) { + g_return_if_fail(widget != NULL); + g_return_if_fail(obj != NULL); + + if (scale) { + gint s_width = width * cfg.scale_factor, + s_height = height * cfg.scale_factor; + GdkPixbuf *image = gdk_pixbuf_scale_simple(obj, s_width, s_height, GDK_INTERP_NEAREST); + gdk_draw_pixbuf(widget->window, NULL, image, 0, 0, 0, 0, s_width, s_height, GDK_RGB_DITHER_NONE, 0, 0); + g_object_unref(image); + } else { + gdk_draw_pixbuf(widget->window, NULL, obj, 0, 0, 0, 0, width, height, GDK_RGB_DITHER_NONE, 0, 0); + } +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skin.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,247 @@ +/* Audacious + * Copyright (C) 2005-2007 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. + */ + +#ifndef AUDACIOUS_UI_SKIN_H +#define AUDACIOUS_UI_SKIN_H + +#include +#include +#include + +#include "audconfig.h" + +#define BMP_DEFAULT_SKIN_PATH \ + DATA_DIR G_DIR_SEPARATOR_S "Skins" G_DIR_SEPARATOR_S "Default" + + +typedef enum { + SKIN_MAIN = 0, + SKIN_CBUTTONS, + SKIN_TITLEBAR, + SKIN_SHUFREP, + SKIN_TEXT, + SKIN_VOLUME, + SKIN_BALANCE, + SKIN_MONOSTEREO, + SKIN_PLAYPAUSE, + SKIN_NUMBERS, + SKIN_POSBAR, + SKIN_PLEDIT, + SKIN_EQMAIN, + SKIN_EQ_EX, + SKIN_PIXMAP_COUNT +} SkinPixmapId; + +typedef enum { + SKIN_MASK_MAIN = 0, + SKIN_MASK_MAIN_SHADE, + SKIN_MASK_EQ, + SKIN_MASK_EQ_SHADE, + SKIN_MASK_COUNT +} SkinMaskId; + +typedef enum { + SKIN_PLEDIT_NORMAL = 0, + SKIN_PLEDIT_CURRENT, + SKIN_PLEDIT_NORMALBG, + SKIN_PLEDIT_SELECTEDBG, + SKIN_TEXTBG, + SKIN_TEXTFG, + SKIN_COLOR_COUNT +} SkinColorId; + +typedef struct _SkinProperties { + /* this enables the othertext engine, not it's visibility -nenolod */ + gboolean mainwin_othertext; + + /* Vis properties */ + gint mainwin_vis_x; + gint mainwin_vis_y; + gint mainwin_vis_width; + gboolean mainwin_vis_visible; + + /* Text properties */ + gint mainwin_text_x; + gint mainwin_text_y; + gint mainwin_text_width; + gboolean mainwin_text_visible; + + /* Infobar properties */ + gint mainwin_infobar_x; + gint mainwin_infobar_y; + gboolean mainwin_othertext_visible; + + gint mainwin_number_0_x; + gint mainwin_number_0_y; + + gint mainwin_number_1_x; + gint mainwin_number_1_y; + + gint mainwin_number_2_x; + gint mainwin_number_2_y; + + gint mainwin_number_3_x; + gint mainwin_number_3_y; + + gint mainwin_number_4_x; + gint mainwin_number_4_y; + + gint mainwin_playstatus_x; + gint mainwin_playstatus_y; + + gint mainwin_volume_x; + gint mainwin_volume_y; + + gint mainwin_balance_x; + gint mainwin_balance_y; + + gint mainwin_position_x; + gint mainwin_position_y; + + gint mainwin_previous_x; + gint mainwin_previous_y; + + gint mainwin_play_x; + gint mainwin_play_y; + + gint mainwin_pause_x; + gint mainwin_pause_y; + + gint mainwin_stop_x; + gint mainwin_stop_y; + + gint mainwin_next_x; + gint mainwin_next_y; + + gint mainwin_eject_x; + gint mainwin_eject_y; + + gint mainwin_eqbutton_x; + gint mainwin_eqbutton_y; + + gint mainwin_plbutton_x; + gint mainwin_plbutton_y; + + gint mainwin_shuffle_x; + gint mainwin_shuffle_y; + + gint mainwin_repeat_x; + gint mainwin_repeat_y; + + gint mainwin_about_x; + gint mainwin_about_y; + + gint mainwin_minimize_x; + gint mainwin_minimize_y; + + gint mainwin_shade_x; + gint mainwin_shade_y; + + gint mainwin_close_x; + gint mainwin_close_y; + + gint mainwin_width; + gint mainwin_height; + + gboolean mainwin_menurow_visible; + gboolean mainwin_othertext_is_status; + + gint textbox_bitmap_font_width; + gint textbox_bitmap_font_height; +} SkinProperties; + +#define SKIN_PIXMAP(x) ((SkinPixmap *)(x)) +typedef struct _SkinPixmap { + GdkPixbuf *pixbuf; + + /* The real size of the pixmap */ + gint width, height; + + /* The size of the pixmap from the current skin, + which might be smaller */ + gint current_width, current_height; +} SkinPixmap; + + +#define SKIN(x) ((Skin *)(x)) +typedef struct _Skin { + GMutex *lock; + gchar *path; + gchar *def_path; + SkinPixmap pixmaps[SKIN_PIXMAP_COUNT]; + GdkColor textbg[6], def_textbg[6]; + GdkColor textfg[6], def_textfg[6]; + GdkColor *colors[SKIN_COLOR_COUNT]; + guchar vis_color[24][3]; + GdkBitmap *masks[SKIN_MASK_COUNT]; + GdkBitmap *scaled_masks[SKIN_MASK_COUNT]; + SkinProperties properties; +} Skin; + +extern Skin *aud_active_skin; + +gboolean init_skins(const gchar * path); +void cleanup_skins(void); + +gboolean aud_active_skin_load(const gchar * path); +gboolean aud_active_skin_reload(void); + +Skin *skin_new(void); +gboolean skin_load(Skin * skin, const gchar * path); +gboolean skin_reload_forced(void); +void skin_reload(Skin * skin); +void skin_free(Skin * skin); + +GdkBitmap *skin_get_mask(Skin * skin, SkinMaskId mi); +GdkColor *skin_get_color(Skin * skin, SkinColorId color_id); + +void skin_get_viscolor(Skin * skin, guchar vis_color[24][3]); +gint skin_get_id(void); +void skin_draw_pixbuf(GtkWidget *widget, Skin * skin, GdkPixbuf * pix, + SkinPixmapId pixmap_id, + gint xsrc, gint ysrc, gint xdest, gint ydest, + gint width, gint height); + +void skin_get_eq_spline_colors(Skin * skin, guint32 colors[19]); +void skin_install_skin(const gchar * path); + +void skin_draw_playlistwin_shaded(Skin * skin, GdkPixbuf * pix, + gint width, gboolean focus); +void skin_draw_playlistwin_frame(Skin * skin, GdkPixbuf * pix, + gint width, gint height, gboolean focus); + +void skin_draw_mainwin_titlebar(Skin * skin, GdkPixbuf * pix, + gboolean shaded, gboolean focus); + + +void skin_parse_hints(Skin * skin, gchar *path_p); + + +void skin_set_random_skin(void); + + +void ui_skinned_widget_draw(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gboolean scale); + +#endif /* AUDACIOUS_UI_SKIN_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_button.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_button.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,535 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * 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 "ui_skinned_button.h" +#include + +#define UI_SKINNED_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_button_get_type(), UiSkinnedButtonPrivate)) +typedef struct _UiSkinnedButtonPrivate UiSkinnedButtonPrivate; + +enum { + PRESSED, + RELEASED, + CLICKED, + DOUBLED, + REDRAW, + LAST_SIGNAL +}; + +struct _UiSkinnedButtonPrivate { + //Skinned part + GdkGC *gc; + gint w; + gint h; + SkinPixmapId skin_index1; + SkinPixmapId skin_index2; + gboolean scaled; + gint move_x, move_y; + + gint nx, ny, px, py; + //Toogle button needs also those + gint pnx, pny, ppx, ppy; +}; + + +static GtkWidgetClass *parent_class = NULL; +static void ui_skinned_button_class_init(UiSkinnedButtonClass *klass); +static void ui_skinned_button_init(UiSkinnedButton *button); +static void ui_skinned_button_destroy(GtkObject *object); +static void ui_skinned_button_realize(GtkWidget *widget); +static void ui_skinned_button_unrealize(GtkWidget *widget); +static void ui_skinned_button_map(GtkWidget *widget); +static void ui_skinned_button_unmap(GtkWidget *widget); +static void ui_skinned_button_size_request(GtkWidget *widget, GtkRequisition *requisition); +static gint ui_skinned_button_expose(GtkWidget *widget,GdkEventExpose *event); + +static void ui_skinned_button_size_allocate(GtkWidget *widget, GtkAllocation *allocation); +static void ui_skinned_button_update_state(UiSkinnedButton *button); + +static guint button_signals[LAST_SIGNAL] = { 0 }; +static gint ui_skinned_button_button_press(GtkWidget *widget, GdkEventButton *event); +static gint ui_skinned_button_button_release(GtkWidget *widget, GdkEventButton *event); +static void button_pressed(UiSkinnedButton *button); +static void button_released(UiSkinnedButton *button); +static void ui_skinned_button_pressed(UiSkinnedButton *button); +static void ui_skinned_button_released(UiSkinnedButton *button); +static void ui_skinned_button_clicked(UiSkinnedButton *button); +static void ui_skinned_button_set_pressed (UiSkinnedButton *button, gboolean pressed); + +static void ui_skinned_button_toggle_scaled(UiSkinnedButton *button); + +static gint ui_skinned_button_enter_notify(GtkWidget *widget, GdkEventCrossing *event); +static gint ui_skinned_button_leave_notify(GtkWidget *widget, GdkEventCrossing *event); +static void ui_skinned_button_redraw(UiSkinnedButton *button); + +GType ui_skinned_button_get_type() { + static GType button_type = 0; + if (!button_type) { + static const GTypeInfo button_info = { + sizeof (UiSkinnedButtonClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_button_class_init, + NULL, + NULL, + sizeof (UiSkinnedButton), + 0, + (GInstanceInitFunc) ui_skinned_button_init, + }; + button_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedButton_", &button_info, 0); + } + + return button_type; +} + +static void ui_skinned_button_class_init (UiSkinnedButtonClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_button_destroy; + + widget_class->realize = ui_skinned_button_realize; + widget_class->unrealize = ui_skinned_button_unrealize; + widget_class->map = ui_skinned_button_map; + widget_class->unmap = ui_skinned_button_unmap; + widget_class->expose_event = ui_skinned_button_expose; + widget_class->size_request = ui_skinned_button_size_request; + widget_class->size_allocate = ui_skinned_button_size_allocate; + widget_class->button_press_event = ui_skinned_button_button_press; + widget_class->button_release_event = ui_skinned_button_button_release; + widget_class->enter_notify_event = ui_skinned_button_enter_notify; + widget_class->leave_notify_event = ui_skinned_button_leave_notify; + + klass->pressed = button_pressed; + klass->released = button_released; + klass->clicked = NULL; + klass->scaled = ui_skinned_button_toggle_scaled; + klass->redraw = ui_skinned_button_redraw; + + button_signals[PRESSED] = + g_signal_new ("pressed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (UiSkinnedButtonClass, pressed), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + button_signals[RELEASED] = + g_signal_new ("released", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (UiSkinnedButtonClass, released), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + button_signals[CLICKED] = + g_signal_new ("clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedButtonClass, clicked), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + button_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedButtonClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + button_signals[REDRAW] = + g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedButtonClass, redraw), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedButtonPrivate)); +} + +static void ui_skinned_button_init (UiSkinnedButton *button) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + button->inside = FALSE; + button->type = TYPE_NOT_SET; + priv->move_x = 0; + priv->move_y = 0; + button->event_window = NULL; +} + +static void ui_skinned_button_destroy (GtkObject *object) { + UiSkinnedButton *button; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_BUTTON (object)); + + button = UI_SKINNED_BUTTON(object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_button_realize (GtkWidget *widget) { + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_BUTTON(widget)); + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + GdkWindowAttr attributes; + gint attributes_mask; + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; + + if (button->type == TYPE_SMALL || button->type == TYPE_NOT_SET) { + widget->window = gtk_widget_get_parent_window (widget); + g_object_ref (widget->window); + attributes.wclass = GDK_INPUT_ONLY; + attributes_mask = GDK_WA_X | GDK_WA_Y; + button->event_window = gdk_window_new (widget->window, &attributes, attributes_mask); + GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW); + gdk_window_set_user_data(button->event_window, widget); + } else { + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.event_mask |= GDK_EXPOSURE_MASK; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_NO_WINDOW); + gdk_window_set_user_data(widget->window, widget); + } + + widget->style = gtk_style_attach(widget->style, widget->window); +} + +static void ui_skinned_button_unrealize (GtkWidget *widget) { + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + + if ( button->event_window != NULL ) + { + gdk_window_set_user_data( button->event_window , NULL ); + gdk_window_destroy( button->event_window ); + button->event_window = NULL; + } + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static void ui_skinned_button_map (GtkWidget *widget) +{ + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + + if (button->event_window != NULL) + gdk_window_show (button->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->map) + (* GTK_WIDGET_CLASS (parent_class)->map) (widget); +} + +static void ui_skinned_button_unmap (GtkWidget *widget) +{ + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + + if (button->event_window != NULL) + gdk_window_hide (button->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->unmap) + (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget); +} + +static void ui_skinned_button_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(widget); + requisition->width = priv->w*(priv->scaled ? cfg.scale_factor : 1); + requisition->height = priv->h*(priv->scaled ? cfg.scale_factor : 1); +} + +static void ui_skinned_button_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + widget->allocation = *allocation; + widget->allocation.x = ceil(widget->allocation.x*(priv->scaled ? cfg.scale_factor : 1)); + widget->allocation.y = ceil(widget->allocation.y*(priv->scaled ? cfg.scale_factor : 1)); + + if (GTK_WIDGET_REALIZED (widget)) + { + if ( button->event_window != NULL ) + gdk_window_move_resize(button->event_window, ceil(allocation->x*(priv->scaled ? cfg.scale_factor : 1)), ceil(allocation->y*(priv->scaled ? cfg.scale_factor : 1)), allocation->width, allocation->height); + else + gdk_window_move_resize(widget->window, ceil(allocation->x*(priv->scaled ? cfg.scale_factor : 1)), ceil(allocation->y*(priv->scaled ? cfg.scale_factor : 1)), allocation->width, allocation->height); + } + + if (button->x + priv->move_x == ceil(widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1))) + priv->move_x = 0; + if (button->y + priv->move_y == ceil(widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1))) + priv->move_y = 0; + + button->x = ceil(widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1)); + button->y = ceil(widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1)); +} + +static gboolean ui_skinned_button_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + g_return_val_if_fail (priv->w > 0 && priv->h > 0, FALSE); + + //TYPE_SMALL doesn't have its own face + if (button->type == TYPE_SMALL || button->type == TYPE_NOT_SET) + return FALSE; + + /* paranoia */ + if (button->event_window != NULL) + return FALSE; + + GdkPixbuf *obj; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->w, priv->h); + + switch (button->type) { + case TYPE_PUSH: + skin_draw_pixbuf(widget, aud_active_skin, obj, + button->pressed ? priv->skin_index2 : priv->skin_index1, + button->pressed ? priv->px : priv->nx, + button->pressed ? priv->py : priv->ny, + 0, 0, priv->w, priv->h); + break; + case TYPE_TOGGLE: + if (button->inside) + skin_draw_pixbuf(widget, aud_active_skin, obj, + button->pressed ? priv->skin_index2 : priv->skin_index1, + button->pressed ? priv->ppx : priv->pnx, + button->pressed ? priv->ppy : priv->pny, + 0, 0, priv->w, priv->h); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, + button->pressed ? priv->skin_index2 : priv->skin_index1, + button->pressed ? priv->px : priv->nx, + button->pressed ? priv->py : priv->ny, + 0, 0, priv->w, priv->h); + break; + default: + break; + } + + ui_skinned_widget_draw(widget, obj, priv->w, priv->h, priv->scaled); + g_object_unref(obj); + + return FALSE; +} + +GtkWidget* ui_skinned_button_new () { + UiSkinnedButton *button = g_object_new (ui_skinned_button_get_type (), NULL); + + return GTK_WIDGET(button); +} + +void ui_skinned_push_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, SkinPixmapId si) { + + UiSkinnedButton *sbutton = UI_SKINNED_BUTTON(button); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(sbutton); + priv->w = w; + priv->h = h; + sbutton->x = x; + sbutton->y = y; + priv->nx = nx; + priv->ny = ny; + priv->px = px; + priv->py = py; + sbutton->type = TYPE_PUSH; + priv->skin_index1 = si; + priv->skin_index2 = si; + priv->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(button), sbutton->x, sbutton->y); +} + +void ui_skinned_toggle_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, gint pnx, gint pny, gint ppx, gint ppy, SkinPixmapId si) { + + UiSkinnedButton *sbutton = UI_SKINNED_BUTTON(button); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(sbutton); + priv->w = w; + priv->h = h; + sbutton->x = x; + sbutton->y = y; + priv->nx = nx; + priv->ny = ny; + priv->px = px; + priv->py = py; + priv->pnx = pnx; + priv->pny = pny; + priv->ppx = ppx; + priv->ppy = ppy; + sbutton->type = TYPE_TOGGLE; + priv->skin_index1 = si; + priv->skin_index2 = si; + priv->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(button), sbutton->x, sbutton->y); +} + +void ui_skinned_small_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h) { + + UiSkinnedButton *sbutton = UI_SKINNED_BUTTON(button); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(sbutton); + priv->w = w; + priv->h = h; + sbutton->x = x; + sbutton->y = y; + sbutton->type = TYPE_SMALL; + priv->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(button), sbutton->x, sbutton->y); +} + +static void button_pressed(UiSkinnedButton *button) { + button->button_down = TRUE; + ui_skinned_button_update_state(button); +} + +static void button_released(UiSkinnedButton *button) { + button->button_down = FALSE; + if(button->hover) ui_skinned_button_clicked(button); + ui_skinned_button_update_state(button); +} + +static void ui_skinned_button_update_state(UiSkinnedButton *button) { + ui_skinned_button_set_pressed(button, button->button_down); +} + +static void ui_skinned_button_set_pressed (UiSkinnedButton *button, gboolean pressed) { + if (pressed != button->pressed) { + button->pressed = pressed; + gtk_widget_queue_draw(GTK_WIDGET(button)); + } +} + +static gboolean ui_skinned_button_button_press(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedButton *button; + + if (event->type == GDK_BUTTON_PRESS) { + button = UI_SKINNED_BUTTON(widget); + + if (event->button == 1) + ui_skinned_button_pressed (button); + else if (event->button == 3) { + event->x = event->x + button->x; + event->y = event->y + button->y; + return FALSE; + } + } + + return TRUE; +} + +static gboolean ui_skinned_button_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedButton *button; + if (event->button == 1) { + button = UI_SKINNED_BUTTON(widget); + ui_skinned_button_released(button); + } + return TRUE; +} + +static void ui_skinned_button_pressed(UiSkinnedButton *button) { + g_return_if_fail(UI_SKINNED_IS_BUTTON(button)); + g_signal_emit(button, button_signals[PRESSED], 0); +} + +static void ui_skinned_button_released(UiSkinnedButton *button) { + g_return_if_fail(UI_SKINNED_IS_BUTTON(button)); + g_signal_emit(button, button_signals[RELEASED], 0); +} + +static void ui_skinned_button_clicked(UiSkinnedButton *button) { + g_return_if_fail(UI_SKINNED_IS_BUTTON(button)); + button->inside = !button->inside; + g_signal_emit(button, button_signals[CLICKED], 0); +} + +static gboolean ui_skinned_button_enter_notify(GtkWidget *widget, GdkEventCrossing *event) { + UiSkinnedButton *button; + + button = UI_SKINNED_BUTTON(widget); + button->hover = TRUE; + if(button->button_down) ui_skinned_button_set_pressed(button, TRUE); + + return FALSE; +} + +static gboolean ui_skinned_button_leave_notify(GtkWidget *widget, GdkEventCrossing *event) { + UiSkinnedButton *button; + + button = UI_SKINNED_BUTTON (widget); + button->hover = FALSE; + if(button->button_down) ui_skinned_button_set_pressed(button, FALSE); + + return FALSE; +} + +static void ui_skinned_button_toggle_scaled(UiSkinnedButton *button) { + GtkWidget *widget = GTK_WIDGET (button); + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + priv->scaled = !priv->scaled; + + gtk_widget_set_size_request(widget, priv->w*(priv->scaled ? cfg.scale_factor : 1), priv->h*(priv->scaled ? cfg.scale_factor : 1)); + + gtk_widget_queue_draw(widget); +} + +static void ui_skinned_button_redraw(UiSkinnedButton *button) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + if (priv->move_x || priv->move_y) + gtk_fixed_move(GTK_FIXED(gtk_widget_get_parent(GTK_WIDGET(button))), GTK_WIDGET(button), + button->x+priv->move_x, button->y+priv->move_y); + + gtk_widget_queue_draw(GTK_WIDGET(button)); +} + + +void ui_skinned_set_push_button_data(GtkWidget *button, gint nx, gint ny, gint px, gint py) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(button); + if (nx > -1) priv->nx = nx; + if (ny > -1) priv->ny = ny; + if (px > -1) priv->px = px; + if (py > -1) priv->py = py; + gtk_widget_queue_draw(button); +} + +void ui_skinned_button_set_skin_index(GtkWidget *button, SkinPixmapId si) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + priv->skin_index1 = priv->skin_index2 = si; +} + +void ui_skinned_button_set_skin_index1(GtkWidget *button, SkinPixmapId si) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + priv->skin_index1 = si; +} + +void ui_skinned_button_set_skin_index2(GtkWidget *button, SkinPixmapId si) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + priv->skin_index2 = si; +} + +void ui_skinned_button_move_relative(GtkWidget *button, gint x, gint y) { + UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); + priv->move_x += x; + priv->move_y += y; +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_button.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_button.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,74 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * 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_SKINNED_BUTTON_H +#define AUDACIOUS_UI_SKINNED_BUTTON_H + +#include +#include "ui_skin.h" + +#define UI_SKINNED_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ui_skinned_button_get_type(), UiSkinnedButton)) +#define UI_SKINNED_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ui_skinned_button_get_type(), UiSkinnedButtonClass)) +#define UI_SKINNED_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ui_skinned_button_get_type())) + +typedef struct _UiSkinnedButton UiSkinnedButton; +typedef struct _UiSkinnedButtonClass UiSkinnedButtonClass; + +enum { + TYPE_NOT_SET, + TYPE_PUSH, + TYPE_TOGGLE, + TYPE_SMALL +}; + +struct _UiSkinnedButton { + GtkWidget widget; + + GdkWindow *event_window; + gboolean button_down; + gboolean pressed; + gboolean hover; + gboolean inside; + gint type; + gint x, y; +}; + +struct _UiSkinnedButtonClass { + GtkWidgetClass parent_class; + void (* pressed) (UiSkinnedButton *button); + void (* released) (UiSkinnedButton *button); + void (* clicked) (UiSkinnedButton *button); + void (* right_clicked) (UiSkinnedButton *button); + void (* scaled) (UiSkinnedButton *button); + void (* redraw) (UiSkinnedButton *button); +}; + +GType ui_skinned_button_get_type(void) G_GNUC_CONST; +GtkWidget* ui_skinned_button_new(); +void ui_skinned_push_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, SkinPixmapId si); +void ui_skinned_set_push_button_data(GtkWidget *button, gint nx, gint ny, gint px, gint py); +void ui_skinned_toggle_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, gint pnx, gint pny, gint ppx, gint ppy, SkinPixmapId si); +void ui_skinned_small_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h); +void ui_skinned_button_set_skin_index(GtkWidget *button, SkinPixmapId si); +void ui_skinned_button_set_skin_index1(GtkWidget *button, SkinPixmapId si); +void ui_skinned_button_set_skin_index2(GtkWidget *button, SkinPixmapId si); +void ui_skinned_button_move_relative(GtkWidget *button, gint x, gint y); + +#endif /* AUDACIOUS_UI_SKINNED_BUTTON_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_equalizer_graph.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_equalizer_graph.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,307 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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 . + */ + +#include "ui_skin.h" +#include "ui_skinned_equalizer_graph.h" +#include "main.h" +#include "equalizer_flow.h" + +#define UI_TYPE_SKINNED_EQUALIZER_GRAPH (ui_skinned_equalizer_graph_get_type()) + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_skinned_equalizer_graph_class_init (UiSkinnedEqualizerGraphClass *klass); +static void ui_skinned_equalizer_graph_init (UiSkinnedEqualizerGraph *equalizer_graph); +static void ui_skinned_equalizer_graph_destroy (GtkObject *object); +static void ui_skinned_equalizer_graph_realize (GtkWidget *widget); +static void ui_skinned_equalizer_graph_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_equalizer_graph_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_equalizer_graph_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_skinned_equalizer_graph_toggle_scaled (UiSkinnedEqualizerGraph *equalizer_graph); + +static GtkWidgetClass *parent_class = NULL; +static guint equalizer_graph_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_equalizer_graph_get_type() { + static GType equalizer_graph_type = 0; + if (!equalizer_graph_type) { + static const GTypeInfo equalizer_graph_info = { + sizeof (UiSkinnedEqualizerGraphClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_equalizer_graph_class_init, + NULL, + NULL, + sizeof (UiSkinnedEqualizerGraph), + 0, + (GInstanceInitFunc) ui_skinned_equalizer_graph_init, + }; + equalizer_graph_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedEqualizerGraph_", &equalizer_graph_info, 0); + } + + return equalizer_graph_type; +} + +static void ui_skinned_equalizer_graph_class_init(UiSkinnedEqualizerGraphClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_equalizer_graph_destroy; + + widget_class->realize = ui_skinned_equalizer_graph_realize; + widget_class->expose_event = ui_skinned_equalizer_graph_expose; + widget_class->size_request = ui_skinned_equalizer_graph_size_request; + widget_class->size_allocate = ui_skinned_equalizer_graph_size_allocate; + + klass->scaled = ui_skinned_equalizer_graph_toggle_scaled; + + equalizer_graph_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedEqualizerGraphClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_skinned_equalizer_graph_init(UiSkinnedEqualizerGraph *equalizer_graph) { + equalizer_graph->width = 113; + equalizer_graph->height = 19; +} + +GtkWidget* ui_skinned_equalizer_graph_new(GtkWidget *fixed, gint x, gint y) { + UiSkinnedEqualizerGraph *equalizer_graph = g_object_new (ui_skinned_equalizer_graph_get_type (), NULL); + + equalizer_graph->x = x; + equalizer_graph->y = y; + equalizer_graph->skin_index = SKIN_EQMAIN; + equalizer_graph->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(equalizer_graph), equalizer_graph->x, equalizer_graph->y); + + return GTK_WIDGET(equalizer_graph); +} + +static void ui_skinned_equalizer_graph_destroy(GtkObject *object) { + UiSkinnedEqualizerGraph *equalizer_graph; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_EQUALIZER_GRAPH (object)); + + equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_equalizer_graph_realize(GtkWidget *widget) { + UiSkinnedEqualizerGraph *equalizer_graph; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_EQUALIZER_GRAPH(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_equalizer_graph_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedEqualizerGraph *equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH(widget); + + requisition->width = equalizer_graph->width*(equalizer_graph->scaled ? cfg.scale_factor : 1); + requisition->height = equalizer_graph->height*(equalizer_graph->scaled ? cfg.scale_factor : 1); +} + +static void ui_skinned_equalizer_graph_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedEqualizerGraph *equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (equalizer_graph->scaled ? cfg.scale_factor : 1); + widget->allocation.y *= (equalizer_graph->scaled ? cfg.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + equalizer_graph->x = widget->allocation.x/(equalizer_graph->scaled ? cfg.scale_factor : 1); + equalizer_graph->y = widget->allocation.y/(equalizer_graph->scaled ? cfg.scale_factor : 1); +} + +void +init_spline(gfloat * x, gfloat * y, gint n, gfloat * y2) +{ + gint i, k; + gfloat p, qn, sig, un, *u; + + u = (gfloat *) g_malloc(n * sizeof(gfloat)); + + y2[0] = u[0] = 0.0; + + for (i = 1; i < n - 1; i++) { + sig = ((gfloat) x[i] - x[i - 1]) / ((gfloat) x[i + 1] - x[i - 1]); + p = sig * y2[i - 1] + 2.0; + y2[i] = (sig - 1.0) / p; + u[i] = + (((gfloat) y[i + 1] - y[i]) / (x[i + 1] - x[i])) - + (((gfloat) y[i] - y[i - 1]) / (x[i] - x[i - 1])); + u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; + } + qn = un = 0.0; + + y2[n - 1] = (un - qn * u[n - 2]) / (qn * y2[n - 2] + 1.0); + for (k = n - 2; k >= 0; k--) + y2[k] = y2[k] * y2[k + 1] + u[k]; + g_free(u); +} + +gfloat +eval_spline(gfloat xa[], gfloat ya[], gfloat y2a[], gint n, gfloat x) +{ + gint klo, khi, k; + gfloat h, b, a; + + klo = 0; + khi = n - 1; + while (khi - klo > 1) { + k = (khi + klo) >> 1; + if (xa[k] > x) + khi = k; + else + klo = k; + } + h = xa[khi] - xa[klo]; + a = (xa[khi] - x) / h; + b = (x - xa[klo]) / h; + return (a * ya[klo] + b * ya[khi] + + ((a * a * a - a) * y2a[klo] + + (b * b * b - b) * y2a[khi]) * (h * h) / 6.0); +} + +static gboolean ui_skinned_equalizer_graph_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_GRAPH (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedEqualizerGraph *equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH (widget); + g_return_val_if_fail (equalizer_graph->width > 0 && equalizer_graph->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, equalizer_graph->width, equalizer_graph->height); + + guint32 cols[19], rowstride; + gint i, y, ymin, ymax, py = 0; + gfloat x[] = { 0, 11, 23, 35, 47, 59, 71, 83, 97, 109 }, yf[10]; + guchar* pixels, *p; + gint n_channels; + /* + * This avoids the init_spline() function to be inlined. + * Inlining the function caused troubles when compiling with + * `-O' (at least on FreeBSD). + */ + void (*__init_spline) (gfloat *, gfloat *, gint, gfloat *) = init_spline; + + skin_draw_pixbuf(widget, aud_active_skin, obj, equalizer_graph->skin_index, 0, 294, 0, 0, + equalizer_graph->width, equalizer_graph->height); + skin_draw_pixbuf(widget, aud_active_skin, obj, equalizer_graph->skin_index, 0, 314, + 0, 9 + ((cfg.equalizer_preamp * 9) / 20), + equalizer_graph->width, 1); + + skin_get_eq_spline_colors(aud_active_skin, cols); + + __init_spline(x, cfg.equalizer_bands, AUD_EQUALIZER_NBANDS, yf); + for (i = 0; i < 109; i++) { + y = 9 - + (gint) ((eval_spline(x, cfg.equalizer_bands, yf, AUD_EQUALIZER_NBANDS, i) * + 9.0) / EQUALIZER_MAX_GAIN); + if (y < 0) + y = 0; + if (y > 18) + y = 18; + if (!i) + py = y; + if (y < py) { + ymin = y; + ymax = py; + } + else { + ymin = py; + ymax = y; + } + py = y; + + pixels = gdk_pixbuf_get_pixels(obj); + rowstride = gdk_pixbuf_get_rowstride(obj); + n_channels = gdk_pixbuf_get_n_channels(obj); + + for (y = ymin; y <= ymax; y++) + { + p = pixels + (y * rowstride) + (( i + 2) * n_channels); + p[0] = (cols[y] & 0xff0000) >> 16; + p[1] = (cols[y] & 0x00ff00) >> 8; + p[2] = (cols[y] & 0x0000ff); + /* do we really need to treat the alpha channel? */ + /*if (n_channels == 4) + p[3] = cols[y] >> 24;*/ + } + } + + ui_skinned_widget_draw(widget, obj, equalizer_graph->width, equalizer_graph->height, equalizer_graph->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static void ui_skinned_equalizer_graph_toggle_scaled(UiSkinnedEqualizerGraph *equalizer_graph) { + GtkWidget *widget = GTK_WIDGET (equalizer_graph); + + equalizer_graph->scaled = !equalizer_graph->scaled; + gtk_widget_set_size_request(widget, equalizer_graph->width*(equalizer_graph->scaled ? cfg.scale_factor : 1), + equalizer_graph->height*(equalizer_graph->scaled ? cfg.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(equalizer_graph)); +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_equalizer_graph.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_equalizer_graph.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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_SKINNED_EQUALIZER_GRAPH_H +#define AUDACIOUS_UI_SKINNED_EQUALIZER_GRAPH_H + +#include +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_EQUALIZER_GRAPH(obj) GTK_CHECK_CAST (obj, ui_skinned_equalizer_graph_get_type (), UiSkinnedEqualizerGraph) +#define UI_SKINNED_EQUALIZER_GRAPH_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_equalizer_graph_get_type (), UiSkinnedEqualizerGraphClass) +#define UI_SKINNED_IS_EQUALIZER_GRAPH(obj) GTK_CHECK_TYPE (obj, ui_skinned_equalizer_graph_get_type ()) + +typedef struct _UiSkinnedEqualizerGraph UiSkinnedEqualizerGraph; +typedef struct _UiSkinnedEqualizerGraphClass UiSkinnedEqualizerGraphClass; + +struct _UiSkinnedEqualizerGraph { + GtkWidget widget; + + gint x, y, width, height; + SkinPixmapId skin_index; + gboolean scaled; +}; + +struct _UiSkinnedEqualizerGraphClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedEqualizerGraph *eq_graph); +}; + +GtkWidget* ui_skinned_equalizer_graph_new(GtkWidget *fixed, gint x, gint y); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_EQUALIZER_GRAPH_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_equalizer_slider.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_equalizer_slider.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,392 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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 . + */ + +#include "ui_skin.h" +#include "ui_skinned_equalizer_slider.h" +#include "ui_equalizer.h" +#include "ui_main.h" +#include "equalizer_flow.h" +#include + +#define UI_TYPE_SKINNED_EQUALIZER_SLIDER (ui_skinned_equalizer_slider_get_type()) +#define UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UI_TYPE_SKINNED_EQUALIZER_SLIDER, UiSkinnedEqualizerSliderPrivate)) +typedef struct _UiSkinnedEqualizerSliderPrivate UiSkinnedEqualizerSliderPrivate; + +enum { + DOUBLED, + LAST_SIGNAL +}; + +struct _UiSkinnedEqualizerSliderPrivate { + SkinPixmapId skin_index; + gboolean scaled; + gint position; + gint width, height; + gboolean pressed; + gint drag_y; + gfloat value; /* store gain as is to prevent truncation --asphyx */ +}; + +static void ui_skinned_equalizer_slider_class_init (UiSkinnedEqualizerSliderClass *klass); +static void ui_skinned_equalizer_slider_init (UiSkinnedEqualizerSlider *equalizer_slider); +static void ui_skinned_equalizer_slider_destroy (GtkObject *object); +static void ui_skinned_equalizer_slider_realize (GtkWidget *widget); +static void ui_skinned_equalizer_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_equalizer_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_equalizer_slider_expose (GtkWidget *widget, GdkEventExpose *event); +static gboolean ui_skinned_equalizer_slider_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_equalizer_slider_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_equalizer_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static gboolean ui_skinned_equalizer_slider_scroll (GtkWidget *widget, GdkEventScroll *event); +static void ui_skinned_equalizer_slider_toggle_scaled (UiSkinnedEqualizerSlider *equalizer_slider); +void ui_skinned_equalizer_slider_set_mainwin_text (UiSkinnedEqualizerSlider * es); + +static GtkWidgetClass *parent_class = NULL; +static guint equalizer_slider_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_equalizer_slider_get_type() { + static GType equalizer_slider_type = 0; + if (!equalizer_slider_type) { + static const GTypeInfo equalizer_slider_info = { + sizeof (UiSkinnedEqualizerSliderClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_equalizer_slider_class_init, + NULL, + NULL, + sizeof (UiSkinnedEqualizerSlider), + 0, + (GInstanceInitFunc) ui_skinned_equalizer_slider_init, + }; + equalizer_slider_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedEqualizerSlider_", &equalizer_slider_info, 0); + } + + return equalizer_slider_type; +} + +static void ui_skinned_equalizer_slider_class_init(UiSkinnedEqualizerSliderClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_equalizer_slider_destroy; + + widget_class->realize = ui_skinned_equalizer_slider_realize; + widget_class->expose_event = ui_skinned_equalizer_slider_expose; + widget_class->size_request = ui_skinned_equalizer_slider_size_request; + widget_class->size_allocate = ui_skinned_equalizer_slider_size_allocate; + widget_class->button_press_event = ui_skinned_equalizer_slider_button_press; + widget_class->button_release_event = ui_skinned_equalizer_slider_button_release; + widget_class->motion_notify_event = ui_skinned_equalizer_slider_motion_notify; + widget_class->scroll_event = ui_skinned_equalizer_slider_scroll; + + klass->scaled = ui_skinned_equalizer_slider_toggle_scaled; + + equalizer_slider_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedEqualizerSliderClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedEqualizerSliderPrivate)); +} + +static void ui_skinned_equalizer_slider_init(UiSkinnedEqualizerSlider *equalizer_slider) { + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(equalizer_slider); + priv->pressed = FALSE; +} + +GtkWidget* ui_skinned_equalizer_slider_new(GtkWidget *fixed, gint x, gint y) { + UiSkinnedEqualizerSlider *es = g_object_new (ui_skinned_equalizer_slider_get_type (), NULL); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(es); + + es->x = x; + es->y = y; + priv->width = 14; + priv->height = 63; + priv->skin_index = SKIN_EQMAIN; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(es), es->x, es->y); + + return GTK_WIDGET(es); +} + +static void ui_skinned_equalizer_slider_destroy(GtkObject *object) { + UiSkinnedEqualizerSlider *equalizer_slider; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (object)); + + equalizer_slider = UI_SKINNED_EQUALIZER_SLIDER (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_equalizer_slider_realize(GtkWidget *widget) { + UiSkinnedEqualizerSlider *equalizer_slider; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + equalizer_slider = UI_SKINNED_EQUALIZER_SLIDER(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_equalizer_slider_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + + requisition->width = priv->width*(priv->scaled ? cfg.scale_factor : 1); + requisition->height = priv->height*(priv->scaled ? cfg.scale_factor : 1); +} + +static void ui_skinned_equalizer_slider_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedEqualizerSlider *equalizer_slider = UI_SKINNED_EQUALIZER_SLIDER (widget); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(equalizer_slider); + + widget->allocation = *allocation; + widget->allocation.x *= (priv->scaled ? cfg.scale_factor : 1); + widget->allocation.y *= (priv->scaled ? cfg.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + equalizer_slider->x = widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1); + equalizer_slider->y = widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1); +} + +static gboolean ui_skinned_equalizer_slider_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedEqualizerSlider *es = UI_SKINNED_EQUALIZER_SLIDER (widget); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(es); + g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->width, priv->height); + + gint frame; + frame = 27 - ((priv->position * 27) / 50); + if (frame < 14) + skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, (frame * 15) + 13, 164, 0, 0, priv->width, priv->height); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, ((frame - 14) * 15) + 13, 229, 0, 0, priv->width, priv->height); + + if (priv->pressed) + skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, 0, 176, 1, priv->position, 11, 11); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, 0, 164, 1, priv->position, 11, 11); + + ui_skinned_widget_draw(widget, obj, priv->width, priv->height, priv->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static gboolean ui_skinned_equalizer_slider_button_press(GtkWidget *widget, GdkEventButton *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedEqualizerSlider *es = UI_SKINNED_EQUALIZER_SLIDER (widget); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(es); + + gint y; + + if (event->type == GDK_BUTTON_PRESS) { + if (event->button == 1) { + priv->pressed = TRUE; + y = event->y/(priv->scaled ? cfg.scale_factor : 1); + + if (y >= priv->position && y < priv->position + 11) + priv->drag_y = y - priv->position; + else { + priv->position = y - 5; + priv->drag_y = 5; + if (priv->position < 0) + priv->position = 0; + if (priv->position > 50) + priv->position = 50; + if (priv->position >= 24 && priv->position <= 26) + priv->position = 25; + + priv->value = ((gfloat) (25 - priv->position) * EQUALIZER_MAX_GAIN / 25.0 ); + equalizerwin_eq_changed(); + } + + ui_skinned_equalizer_slider_set_mainwin_text(es); + gtk_widget_queue_draw(widget); + } + } + + return TRUE; +} + +static gboolean ui_skinned_equalizer_slider_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + + if (event->button == 1) { + priv->pressed = FALSE; + mainwin_release_info_text(); + gtk_widget_queue_draw(widget); + } + return TRUE; +} + +static gboolean ui_skinned_equalizer_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + UiSkinnedEqualizerSlider *es = UI_SKINNED_EQUALIZER_SLIDER(widget); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + + if (priv->pressed) { + gint y; + + y = event->y/(priv->scaled ? cfg.scale_factor : 1); + priv->position = y - priv->drag_y; + + if (priv->position < 0) + priv->position = 0; + if (priv->position > 50) + priv->position = 50; + if (priv->position >= 24 && priv->position <= 26) + priv->position = 25; + + priv->value = ((gfloat) (25 - priv->position) * EQUALIZER_MAX_GAIN / 25.0 ); + ui_skinned_equalizer_slider_set_mainwin_text(es); + equalizerwin_eq_changed(); + gtk_widget_queue_draw(widget); + } + + return TRUE; +} + +static gboolean ui_skinned_equalizer_slider_scroll(GtkWidget *widget, GdkEventScroll *event) { + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + + if (event->direction == GDK_SCROLL_UP) { + priv->position -= 2; + + if (priv->position < 0) + priv->position = 0; + } + else { + priv->position += 2; + + if (priv->position > 50) + priv->position = 50; + } + + priv->value = ((gfloat) (25 - priv->position) * EQUALIZER_MAX_GAIN / 25.0 ); + equalizerwin_eq_changed(); + gtk_widget_queue_draw(widget); + return TRUE; +} + +static void ui_skinned_equalizer_slider_toggle_scaled(UiSkinnedEqualizerSlider *equalizer_slider) { + GtkWidget *widget = GTK_WIDGET (equalizer_slider); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(equalizer_slider); + + priv->scaled = !priv->scaled; + + gtk_widget_set_size_request(widget, priv->width*(priv->scaled ? cfg.scale_factor : 1), + priv->height*(priv->scaled ? cfg.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(equalizer_slider)); +} + +void ui_skinned_equalizer_slider_set_position(GtkWidget *widget, gfloat pos) { + g_return_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget)); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + + if (priv->pressed) + return; + + priv->value = (pos > EQUALIZER_MAX_GAIN) ? EQUALIZER_MAX_GAIN : ((pos < -EQUALIZER_MAX_GAIN) ? -EQUALIZER_MAX_GAIN : pos); + priv->position = 25 - (gint) ((pos * 25.0) / EQUALIZER_MAX_GAIN); + + if (priv->position < 0) + priv->position = 0; + + if (priv->position > 50) + priv->position = 50; + + if (priv->position >= 24 && priv->position <= 26) + priv->position = 25; + + gtk_widget_queue_draw(widget); +} + +gfloat ui_skinned_equalizer_slider_get_position(GtkWidget *widget) { + g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), -1); + UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); + return priv->value; +} + +void ui_skinned_equalizer_slider_set_mainwin_text(UiSkinnedEqualizerSlider * es) { + gint band = 0; + const gchar *bandname[11] = { N_("PREAMP"), N_("60HZ"), N_("170HZ"), + N_("310HZ"), N_("600HZ"), N_("1KHZ"), + N_("3KHZ"), N_("6KHZ"), N_("12KHZ"), + N_("14KHZ"), N_("16KHZ") + }; + gchar *tmp; + + if (es->x > 21) + band = ((es->x - 78) / 18) + 1; + + tmp = + g_strdup_printf("EQ: %s: %+.1f DB", _(bandname[band]), + ui_skinned_equalizer_slider_get_position(GTK_WIDGET(es))); + mainwin_lock_info_text(tmp); + g_free(tmp); +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_equalizer_slider.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_equalizer_slider.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,60 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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 . + */ + +#ifndef AUDACIOUS_UI_SKINNED_EQUALIZER_SLIDER_H +#define AUDACIOUS_UI_SKINNED_EQUALIZER_SLIDER_H + +#include +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_EQUALIZER_SLIDER(obj) GTK_CHECK_CAST (obj, ui_skinned_equalizer_slider_get_type (), UiSkinnedEqualizerSlider) +#define UI_SKINNED_EQUALIZER_SLIDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_equalizer_slider_get_type (), UiSkinnedEqualizerSliderClass) +#define UI_SKINNED_IS_EQUALIZER_SLIDER(obj) GTK_CHECK_TYPE (obj, ui_skinned_equalizer_slider_get_type ()) + +typedef struct _UiSkinnedEqualizerSlider UiSkinnedEqualizerSlider; +typedef struct _UiSkinnedEqualizerSliderClass UiSkinnedEqualizerSliderClass; + +struct _UiSkinnedEqualizerSlider { + GtkWidget widget; + gint x, y; +}; + +struct _UiSkinnedEqualizerSliderClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedEqualizerSlider *equalizer_slider); +}; + +GtkWidget* ui_skinned_equalizer_slider_new(GtkWidget *fixed, gint x, gint y); +GtkType ui_skinned_equalizer_slider_get_type(void); +void ui_skinned_equalizer_slider_set_position(GtkWidget *widget, gfloat pos); +gfloat ui_skinned_equalizer_slider_get_position(GtkWidget *widget); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_EQUALIZER_SLIDER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_horizontal_slider.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_horizontal_slider.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,386 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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. + */ + +#include "ui_skinned_horizontal_slider.h" +#include "main.h" +#include + +#define UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_horizontal_slider_get_type(), UiSkinnedHorizontalSliderPrivate)) +typedef struct _UiSkinnedHorizontalSliderPrivate UiSkinnedHorizontalSliderPrivate; + +enum { + MOTION, + RELEASE, + DOUBLED, + LAST_SIGNAL +}; + +struct _UiSkinnedHorizontalSliderPrivate { + SkinPixmapId skin_index; + gboolean scaled; + gint frame, frame_offset, frame_height, min, max; + gint knob_width, knob_height; + gint position; + gint width, height; + gint (*frame_cb) (gint); +}; + +static void ui_skinned_horizontal_slider_class_init (UiSkinnedHorizontalSliderClass *klass); +static void ui_skinned_horizontal_slider_init (UiSkinnedHorizontalSlider *horizontal_slider); +static void ui_skinned_horizontal_slider_destroy (GtkObject *object); +static void ui_skinned_horizontal_slider_realize (GtkWidget *widget); +static void ui_skinned_horizontal_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_horizontal_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_horizontal_slider_expose (GtkWidget *widget, GdkEventExpose *event); +static gboolean ui_skinned_horizontal_slider_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_horizontal_slider_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_horizontal_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static void ui_skinned_horizontal_slider_toggle_scaled (UiSkinnedHorizontalSlider *horizontal_slider); + +static GtkWidgetClass *parent_class = NULL; +static guint horizontal_slider_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_horizontal_slider_get_type() { + static GType horizontal_slider_type = 0; + if (!horizontal_slider_type) { + static const GTypeInfo horizontal_slider_info = { + sizeof (UiSkinnedHorizontalSliderClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_horizontal_slider_class_init, + NULL, + NULL, + sizeof (UiSkinnedHorizontalSlider), + 0, + (GInstanceInitFunc) ui_skinned_horizontal_slider_init, + }; + horizontal_slider_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedHorizontalSlider_", &horizontal_slider_info, 0); + } + + return horizontal_slider_type; +} + +static void ui_skinned_horizontal_slider_class_init(UiSkinnedHorizontalSliderClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_horizontal_slider_destroy; + + widget_class->realize = ui_skinned_horizontal_slider_realize; + widget_class->expose_event = ui_skinned_horizontal_slider_expose; + widget_class->size_request = ui_skinned_horizontal_slider_size_request; + widget_class->size_allocate = ui_skinned_horizontal_slider_size_allocate; + widget_class->button_press_event = ui_skinned_horizontal_slider_button_press; + widget_class->button_release_event = ui_skinned_horizontal_slider_button_release; + widget_class->motion_notify_event = ui_skinned_horizontal_slider_motion_notify; + + klass->motion = NULL; + klass->release = NULL; + klass->scaled = ui_skinned_horizontal_slider_toggle_scaled; + + horizontal_slider_signals[MOTION] = + g_signal_new ("motion", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedHorizontalSliderClass, motion), NULL, NULL, + gtk_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + + horizontal_slider_signals[RELEASE] = + g_signal_new ("release", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedHorizontalSliderClass, release), NULL, NULL, + gtk_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + + horizontal_slider_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedHorizontalSliderClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedHorizontalSliderPrivate)); +} + +static void ui_skinned_horizontal_slider_init(UiSkinnedHorizontalSlider *horizontal_slider) { + horizontal_slider->pressed = FALSE; +} + +GtkWidget* ui_skinned_horizontal_slider_new(GtkWidget *fixed, gint x, gint y, gint w, gint h, gint knx, gint kny, + gint kpx, gint kpy, gint kw, gint kh, gint fh, + gint fo, gint min, gint max, gint(*fcb) (gint), SkinPixmapId si) { + + UiSkinnedHorizontalSlider *hs = g_object_new (ui_skinned_horizontal_slider_get_type (), NULL); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(hs); + + hs->x = x; + hs->y = y; + priv->width = w; + priv->height = h; + hs->knob_nx = knx; + hs->knob_ny = kny; + hs->knob_px = kpx; + hs->knob_py = kpy; + priv->knob_width = kw; + priv->knob_height = kh; + priv->frame_height = fh; + priv->frame_offset = fo; + priv->min = min; + priv->position = min; + priv->max = max; + priv->frame_cb = fcb; + if (priv->frame_cb) + priv->frame = priv->frame_cb(0); + priv->skin_index = si; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(hs), hs->x, hs->y); + + return GTK_WIDGET(hs); +} + +static void ui_skinned_horizontal_slider_destroy(GtkObject *object) { + UiSkinnedHorizontalSlider *horizontal_slider; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (object)); + + horizontal_slider = UI_SKINNED_HORIZONTAL_SLIDER (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_horizontal_slider_realize(GtkWidget *widget) { + UiSkinnedHorizontalSlider *horizontal_slider; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + horizontal_slider = UI_SKINNED_HORIZONTAL_SLIDER(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_horizontal_slider_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); + + requisition->width = priv->width*(priv->scaled ? cfg.scale_factor : 1); + requisition->height = priv->height*(priv->scaled ? cfg.scale_factor : 1); +} + +static void ui_skinned_horizontal_slider_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedHorizontalSlider *horizontal_slider = UI_SKINNED_HORIZONTAL_SLIDER (widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(horizontal_slider); + + widget->allocation = *allocation; + widget->allocation.x = ceil(widget->allocation.x*(priv->scaled ? cfg.scale_factor : 1)); + widget->allocation.y = ceil(widget->allocation.y*(priv->scaled ? cfg.scale_factor : 1)); + + if (priv->knob_height == priv->height) + priv->knob_height = ceil(allocation->height/(priv->scaled ? cfg.scale_factor : 1)); + priv->width = ceil(allocation->width/(priv->scaled ? cfg.scale_factor : 1)); + priv->height = ceil(allocation->height/(priv->scaled ? cfg.scale_factor : 1)); + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + horizontal_slider->x = ceil(widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1)); + horizontal_slider->y = ceil(widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1)); +} + +static gboolean ui_skinned_horizontal_slider_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER (widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(hs); + g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + + if (priv->position > priv->max) priv->position = priv->max; + else if (priv->position < priv->min) priv->position = priv->min; + + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->width, priv->height); + + skin_draw_pixbuf(widget, aud_active_skin, obj, + priv->skin_index, priv->frame_offset, + priv->frame * priv->frame_height, + 0, 0, priv->width, priv->height); + if (hs->pressed) + skin_draw_pixbuf(widget, aud_active_skin, obj, + priv->skin_index, hs->knob_px, + hs->knob_py, priv->position, + ((priv->height - priv->knob_height) / 2), + priv->knob_width, priv->knob_height); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, + priv->skin_index, hs->knob_nx, + hs->knob_ny, priv->position, + ((priv->height - priv->knob_height) / 2), + priv->knob_width, priv->knob_height); + + ui_skinned_widget_draw(widget, obj, priv->width, priv->height, priv->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static gboolean ui_skinned_horizontal_slider_button_press(GtkWidget *widget, GdkEventButton *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER (widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(hs); + + if (event->type == GDK_BUTTON_PRESS) { + if (event->button == 1) { + gint x; + + x = event->x - (priv->knob_width / (priv->scaled ? 1 : cfg.scale_factor)); + hs->pressed = TRUE; + + priv->position = x/(priv->scaled ? cfg.scale_factor : 1); + if (priv->position < priv->min) + priv->position = priv->min; + if (priv->position > priv->max) + priv->position = priv->max; + if (priv->frame_cb) + priv->frame = priv->frame_cb(priv->position); + + g_signal_emit_by_name(widget, "motion", priv->position); + gtk_widget_queue_draw(widget); + } else if (event->button == 3) { + if (hs->pressed) { + hs->pressed = FALSE; + g_signal_emit_by_name(widget, "release", priv->position); + gtk_widget_queue_draw(widget); + } + event->x = event->x + hs->x; + event->y = event->y + hs->y; + return FALSE; + } + } + return TRUE; +} + +static gboolean ui_skinned_horizontal_slider_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER(widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); + + if (hs->pressed) { + hs->pressed = FALSE; + g_signal_emit_by_name(widget, "release", priv->position); + gtk_widget_queue_draw(widget); + } + return TRUE; +} + +static gboolean ui_skinned_horizontal_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER(widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); + + if (hs->pressed) { + gint x; + + x = event->x - (priv->knob_width / (priv->scaled ? 1 : cfg.scale_factor)); + priv->position = x/(priv->scaled ? cfg.scale_factor : 1); + + if (priv->position < priv->min) + priv->position = priv->min; + + if (priv->position > priv->max) + priv->position = priv->max; + + if (priv->frame_cb) + priv->frame = priv->frame_cb(priv->position); + + g_signal_emit_by_name(widget, "motion", priv->position); + gtk_widget_queue_draw(widget); + } + + return TRUE; +} + +static void ui_skinned_horizontal_slider_toggle_scaled(UiSkinnedHorizontalSlider *horizontal_slider) { + GtkWidget *widget = GTK_WIDGET (horizontal_slider); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(horizontal_slider); + + priv->scaled = !priv->scaled; + + gtk_widget_set_size_request(widget, + priv->width*(priv->scaled ? cfg.scale_factor : 1), + priv->height*(priv->scaled ? cfg.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(horizontal_slider)); +} + +void ui_skinned_horizontal_slider_set_position(GtkWidget *widget, gint pos) { + g_return_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget)); + UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER(widget); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); + + if (pos == priv->position || hs->pressed) + return; + + priv->position = pos; + + if (priv->frame_cb) + priv->frame = priv->frame_cb(priv->position); + + gtk_widget_queue_draw(widget); +} + +gint ui_skinned_horizontal_slider_get_position(GtkWidget *widget) { + g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), -1); + UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); + return priv->position; +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_horizontal_slider.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_horizontal_slider.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,69 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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_SKINNED_HORIZONTAL_SLIDER_H +#define AUDACIOUS_UI_SKINNED_HORIZONTAL_SLIDER_H + +#include +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_HORIZONTAL_SLIDER(obj) GTK_CHECK_CAST (obj, ui_skinned_horizontal_slider_get_type (), UiSkinnedHorizontalSlider) +#define UI_SKINNED_HORIZONTAL_SLIDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_horizontal_slider_get_type (), UiSkinnedHorizontalSliderClass) +#define UI_SKINNED_IS_HORIZONTAL_SLIDER(obj) GTK_CHECK_TYPE (obj, ui_skinned_horizontal_slider_get_type ()) + +typedef struct _UiSkinnedHorizontalSlider UiSkinnedHorizontalSlider; +typedef struct _UiSkinnedHorizontalSliderClass UiSkinnedHorizontalSliderClass; + +struct _UiSkinnedHorizontalSlider { + GtkWidget widget; + gboolean pressed; + gint x, y; + gint knob_nx, knob_ny, knob_px, knob_py; +}; + +struct _UiSkinnedHorizontalSliderClass { + GtkWidgetClass parent_class; + void (* motion) (UiSkinnedHorizontalSlider *horizontal_slider); + void (* release) (UiSkinnedHorizontalSlider *horizontal_slider); + void (* scaled) (UiSkinnedHorizontalSlider *horizontal_slider); + void (* redraw) (UiSkinnedHorizontalSlider *horizontal_slider); +}; +GtkWidget* ui_skinned_horizontal_slider_new(GtkWidget *fixed, gint x, gint y, gint w, gint h, gint knx, gint kny, + gint kpx, gint kpy, gint kw, gint kh, gint fh, + gint fo, gint min, gint max, gint(*fcb) (gint), SkinPixmapId si); +GtkType ui_skinned_horizontal_slider_get_type(void); +void ui_skinned_horizontal_slider_set_position(GtkWidget *widget, gint pos); +gint ui_skinned_horizontal_slider_get_position(GtkWidget *widget); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_HORIZONTAL_SLIDER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_menurow.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_menurow.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,331 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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. + */ + +#include "ui_skinned_menurow.h" +#include "main.h" + +enum { + DOUBLED, + CHANGE, + RELEASE, + LAST_SIGNAL +}; + +static void ui_skinned_menurow_class_init (UiSkinnedMenurowClass *klass); +static void ui_skinned_menurow_init (UiSkinnedMenurow *menurow); +static void ui_skinned_menurow_destroy (GtkObject *object); +static void ui_skinned_menurow_realize (GtkWidget *widget); +static void ui_skinned_menurow_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_menurow_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_menurow_expose (GtkWidget *widget, GdkEventExpose *event); +static MenuRowItem menurow_find_selected (UiSkinnedMenurow * mr, gint x, gint y); +static gboolean ui_skinned_menurow_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_menurow_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_menurow_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static void ui_skinned_menurow_toggle_scaled (UiSkinnedMenurow *menurow); + +static GtkWidgetClass *parent_class = NULL; +static guint menurow_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_menurow_get_type() { + static GType menurow_type = 0; + if (!menurow_type) { + static const GTypeInfo menurow_info = { + sizeof (UiSkinnedMenurowClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_menurow_class_init, + NULL, + NULL, + sizeof (UiSkinnedMenurow), + 0, + (GInstanceInitFunc) ui_skinned_menurow_init, + }; + menurow_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedMenurow_", &menurow_info, 0); + } + + return menurow_type; +} + +static void ui_skinned_menurow_class_init(UiSkinnedMenurowClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_menurow_destroy; + + widget_class->realize = ui_skinned_menurow_realize; + widget_class->expose_event = ui_skinned_menurow_expose; + widget_class->size_request = ui_skinned_menurow_size_request; + widget_class->size_allocate = ui_skinned_menurow_size_allocate; + widget_class->button_press_event = ui_skinned_menurow_button_press; + widget_class->button_release_event = ui_skinned_menurow_button_release; + widget_class->motion_notify_event = ui_skinned_menurow_motion_notify; + + klass->scaled = ui_skinned_menurow_toggle_scaled; + klass->change = NULL; + klass->release = NULL; + + menurow_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedMenurowClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + + menurow_signals[CHANGE] = + g_signal_new ("change", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedMenurowClass, change), NULL, NULL, + gtk_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + + menurow_signals[RELEASE] = + g_signal_new ("release", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedMenurowClass, release), NULL, NULL, + g_cclosure_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER); + +} + +static void ui_skinned_menurow_init(UiSkinnedMenurow *menurow) { + menurow->scale_selected = cfg.scaled; + menurow->always_selected = cfg.always_on_top; +} + +GtkWidget* ui_skinned_menurow_new(GtkWidget *fixed, gint x, gint y, gint nx, gint ny, gint sx, gint sy, SkinPixmapId si) { + UiSkinnedMenurow *menurow = g_object_new (ui_skinned_menurow_get_type (), NULL); + + menurow->x = x; + menurow->y = y; + menurow->width = 8; + menurow->height = 43; + menurow->nx = nx; + menurow->ny = ny; + menurow->sx = sx; + menurow->sy = sy; + menurow->selected = MENUROW_NONE; + + menurow->skin_index = si; + + menurow->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(menurow), menurow->x, menurow->y); + + return GTK_WIDGET(menurow); +} + +static void ui_skinned_menurow_destroy(GtkObject *object) { + UiSkinnedMenurow *menurow; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_MENUROW (object)); + + menurow = UI_SKINNED_MENUROW (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_menurow_realize(GtkWidget *widget) { + UiSkinnedMenurow *menurow; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_MENUROW(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + menurow = UI_SKINNED_MENUROW(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_menurow_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW(widget); + + requisition->width = menurow->width*(menurow->scaled ? cfg.scale_factor : 1); + requisition->height = menurow->height*(menurow->scaled ? cfg.scale_factor : 1); +} + +static void ui_skinned_menurow_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (menurow->scaled ? cfg.scale_factor : 1); + widget->allocation.y *= (menurow->scaled ? cfg.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + menurow->x = widget->allocation.x/(menurow->scaled ? cfg.scale_factor : 1); + menurow->y = widget->allocation.y/(menurow->scaled ? cfg.scale_factor : 1); +} + +static gboolean ui_skinned_menurow_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_MENUROW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW (widget); + g_return_val_if_fail (menurow->width > 0 && menurow->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, menurow->width, menurow->height); + + if (menurow->selected == MENUROW_NONE) { + if (cfg.always_show_cb || menurow->pushed) + skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, + menurow->nx, menurow->ny, 0, 0, 8, 43); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, + menurow->nx + 8, menurow->ny, 0, 0, 8, 43); + } + else { + skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, + menurow->sx + ((menurow->selected - 1) * 8), + menurow->sy, 0, 0, 8, 43); + } + if (cfg.always_show_cb || menurow->pushed) { + if (menurow->always_selected) + skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, + menurow->sx + 8, menurow->sy + 10, 0, 10, 8, 8); + if (menurow->scale_selected) + skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, + menurow->sx + 24, menurow->sy + 26, 0, 26, 8, 8); + } + + ui_skinned_widget_draw(widget, obj, menurow->width, menurow->height, menurow->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static MenuRowItem menurow_find_selected(UiSkinnedMenurow * mr, gint x, gint y) { + MenuRowItem ret = MENUROW_NONE; + + x = x/(mr->scaled ? cfg.scale_factor : 1); + y = y/(mr->scaled ? cfg.scale_factor : 1); + if (x > 0 && x < 8) { + if (y >= 0 && y <= 10) + ret = MENUROW_OPTIONS; + if (y >= 10 && y <= 17) + ret = MENUROW_ALWAYS; + if (y >= 18 && y <= 25) + ret = MENUROW_FILEINFOBOX; + if (y >= 26 && y <= 33) + ret = MENUROW_SCALE; + if (y >= 34 && y <= 42) + ret = MENUROW_VISUALIZATION; + } + return ret; +} + +static gboolean ui_skinned_menurow_button_press(GtkWidget *widget, GdkEventButton *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_MENUROW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW (widget); + + if (event->type == GDK_BUTTON_PRESS) { + if (event->button == 1) { + + menurow->pushed = TRUE; + menurow->selected = menurow_find_selected(menurow, event->x, event->y); + + gtk_widget_queue_draw(widget); + g_signal_emit_by_name(widget, "change", menurow->selected); + } + } + + return TRUE; +} + +static gboolean ui_skinned_menurow_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW(widget); + if (menurow->pushed) { + menurow->pushed = FALSE; + + if (menurow->selected == MENUROW_ALWAYS) + menurow->always_selected = !menurow->always_selected; + + if (menurow->selected == MENUROW_SCALE) + menurow->scale_selected = !menurow->scale_selected; + + if ((int)(menurow->selected) != -1) + g_signal_emit_by_name(widget, "release", menurow->selected, event); + + menurow->selected = MENUROW_NONE; + gtk_widget_queue_draw(widget); + } + + return TRUE; +} + +static gboolean ui_skinned_menurow_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_MENUROW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW(widget); + + if (menurow->pushed) { + menurow->selected = menurow_find_selected(menurow, event->x, event->y); + + gtk_widget_queue_draw(widget); + g_signal_emit_by_name(widget, "change", menurow->selected); + } + + return TRUE; +} + +static void ui_skinned_menurow_toggle_scaled(UiSkinnedMenurow *menurow) { + GtkWidget *widget = GTK_WIDGET (menurow); + + menurow->scaled = !menurow->scaled; + gtk_widget_set_size_request(widget, menurow->width* (menurow->scaled ? cfg.scale_factor : 1), + menurow->height * (menurow->scaled ? cfg.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(menurow)); +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_menurow.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_menurow.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,77 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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_SKINNED_MENUROW_H +#define AUDACIOUS_UI_SKINNED_MENUROW_H + +#include +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_MENUROW(obj) GTK_CHECK_CAST (obj, ui_skinned_menurow_get_type (), UiSkinnedMenurow) +#define UI_SKINNED_MENUROW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_menurow_get_type (), UiSkinnedMenurowClass) +#define UI_SKINNED_IS_MENUROW(obj) GTK_CHECK_TYPE (obj, ui_skinned_menurow_get_type ()) + +typedef struct _UiSkinnedMenurow UiSkinnedMenurow; +typedef struct _UiSkinnedMenurowClass UiSkinnedMenurowClass; + +typedef enum { + MENUROW_NONE, MENUROW_OPTIONS, MENUROW_ALWAYS, MENUROW_FILEINFOBOX, + MENUROW_SCALE, MENUROW_VISUALIZATION +} MenuRowItem; + +struct _UiSkinnedMenurow { + GtkWidget widget; + + gint x, y, width, height; + gboolean scaled; + gint nx, ny; + gint sx, sy; + MenuRowItem selected; + gboolean always_selected; + gboolean scale_selected; + gboolean pushed; + SkinPixmapId skin_index; +}; + +struct _UiSkinnedMenurowClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedMenurow *menurow); + void (* change) (UiSkinnedMenurow *menurow); + void (* release) (UiSkinnedMenurow *menurow); +}; + +GtkWidget* ui_skinned_menurow_new (GtkWidget *fixed, gint x, gint y, gint nx, gint ny, gint sx, gint sy, SkinPixmapId si); +GtkType ui_skinned_menurow_get_type(void); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_MENUROW_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_monostereo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_monostereo.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,222 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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. + */ + +#include "ui_skin.h" +#include "ui_skinned_monostereo.h" +#include "main.h" + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_skinned_monostereo_class_init (UiSkinnedMonoStereoClass *klass); +static void ui_skinned_monostereo_init (UiSkinnedMonoStereo *monostereo); +static void ui_skinned_monostereo_destroy (GtkObject *object); +static void ui_skinned_monostereo_realize (GtkWidget *widget); +static void ui_skinned_monostereo_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_monostereo_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_monostereo_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_skinned_monostereo_toggle_scaled (UiSkinnedMonoStereo *monostereo); + +static GtkWidgetClass *parent_class = NULL; +static guint monostereo_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_monostereo_get_type() { + static GType monostereo_type = 0; + if (!monostereo_type) { + static const GTypeInfo monostereo_info = { + sizeof (UiSkinnedMonoStereoClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_monostereo_class_init, + NULL, + NULL, + sizeof (UiSkinnedMonoStereo), + 0, + (GInstanceInitFunc) ui_skinned_monostereo_init, + }; + monostereo_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedMonoStereo_", &monostereo_info, 0); + } + + return monostereo_type; +} + +static void ui_skinned_monostereo_class_init(UiSkinnedMonoStereoClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_monostereo_destroy; + + widget_class->realize = ui_skinned_monostereo_realize; + widget_class->expose_event = ui_skinned_monostereo_expose; + widget_class->size_request = ui_skinned_monostereo_size_request; + widget_class->size_allocate = ui_skinned_monostereo_size_allocate; + + klass->scaled = ui_skinned_monostereo_toggle_scaled; + + monostereo_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedMonoStereoClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_skinned_monostereo_init(UiSkinnedMonoStereo *monostereo) { + monostereo->width = 56; + monostereo->height = 12; +} + +GtkWidget* ui_skinned_monostereo_new(GtkWidget *fixed, gint x, gint y, SkinPixmapId si) { + UiSkinnedMonoStereo *monostereo = g_object_new (ui_skinned_monostereo_get_type (), NULL); + + monostereo->x = x; + monostereo->y = y; + monostereo->skin_index = si; + monostereo->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(monostereo), monostereo->x, monostereo->y); + + return GTK_WIDGET(monostereo); +} + +static void ui_skinned_monostereo_destroy(GtkObject *object) { + UiSkinnedMonoStereo *monostereo; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_MONOSTEREO (object)); + + monostereo = UI_SKINNED_MONOSTEREO (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_monostereo_realize(GtkWidget *widget) { + UiSkinnedMonoStereo *monostereo; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_MONOSTEREO(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + monostereo = UI_SKINNED_MONOSTEREO(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_monostereo_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO(widget); + + requisition->width = monostereo->width*(monostereo->scaled ? cfg.scale_factor : 1); + requisition->height = monostereo->height*(monostereo->scaled ? cfg.scale_factor : 1); +} + +static void ui_skinned_monostereo_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (monostereo->scaled ? cfg.scale_factor : 1); + widget->allocation.y *= (monostereo->scaled ? cfg.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + monostereo->x = widget->allocation.x/(monostereo->scaled ? cfg.scale_factor : 1); + monostereo->y = widget->allocation.y/(monostereo->scaled ? cfg.scale_factor : 1); +} + +static gboolean ui_skinned_monostereo_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_MONOSTEREO (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO (widget); + g_return_val_if_fail (monostereo->width > 0 && monostereo->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, monostereo->width, monostereo->height); + + switch (monostereo->num_channels) { + case 1: + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 29, 0, 0, 0, 27, 12); + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 0, 12, 27, 0, 29, 12); + break; + case 2: + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 29, 12, 0, 0, 27, 12); + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 0, 0, 27, 0, 29, 12); + break; + default: + case 0: + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 29, 12, 0, 0, 27, 12); + skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 0, 12, 27, 0, 29, 12); + break; + } + + ui_skinned_widget_draw(widget, obj, monostereo->width, monostereo->height, monostereo->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static void ui_skinned_monostereo_toggle_scaled(UiSkinnedMonoStereo *monostereo) { + GtkWidget *widget = GTK_WIDGET (monostereo); + + monostereo->scaled = !monostereo->scaled; + gtk_widget_set_size_request(widget, monostereo->width*(monostereo->scaled ? cfg.scale_factor : 1), monostereo->height*(monostereo->scaled ? cfg.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(monostereo)); +} + +void ui_skinned_monostereo_set_num_channels(GtkWidget *widget, gint nch) { + g_return_if_fail (UI_SKINNED_IS_MONOSTEREO (widget)); + UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO (widget); + + monostereo->num_channels = nch; + gtk_widget_queue_draw(widget); +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_monostereo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_monostereo.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,66 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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_SKINNED_MONOSTEREO_H +#define AUDACIOUS_UI_SKINNED_MONOSTEREO_H + +#include +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_MONOSTEREO(obj) GTK_CHECK_CAST (obj, ui_skinned_monostereo_get_type (), UiSkinnedMonoStereo) +#define UI_SKINNED_MONOSTEREO_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_monostereo_get_type (), UiSkinnedMonoStereoClass) +#define UI_SKINNED_IS_MONOSTEREO(obj) GTK_CHECK_TYPE (obj, ui_skinned_monostereo_get_type ()) + +typedef struct _UiSkinnedMonoStereo UiSkinnedMonoStereo; +typedef struct _UiSkinnedMonoStereoClass UiSkinnedMonoStereoClass; + +struct _UiSkinnedMonoStereo { + GtkWidget widget; + + gint x, y, width, height; + gint num_channels; + SkinPixmapId skin_index; + gboolean scaled; +}; + +struct _UiSkinnedMonoStereoClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedMonoStereo *menurow); +}; + +GtkWidget* ui_skinned_monostereo_new (GtkWidget *fixed, gint x, gint y, SkinPixmapId si); +GtkType ui_skinned_monostereo_get_type(void); +void ui_skinned_monostereo_set_num_channels(GtkWidget *widget, gint nch); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_MONOSTEREO_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_number.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_number.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,234 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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. + */ + +#include "ui_skinned_number.h" +#include "main.h" +#include "strings.h" +#include +#include +#include +#include + +#define UI_TYPE_SKINNED_NUMBER (ui_skinned_number_get_type()) + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_skinned_number_class_init (UiSkinnedNumberClass *klass); +static void ui_skinned_number_init (UiSkinnedNumber *number); +static void ui_skinned_number_destroy (GtkObject *object); +static void ui_skinned_number_realize (GtkWidget *widget); +static void ui_skinned_number_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_number_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_number_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_skinned_number_toggle_scaled (UiSkinnedNumber *number); + +static GtkWidgetClass *parent_class = NULL; +static guint number_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_number_get_type() { + static GType number_type = 0; + if (!number_type) { + static const GTypeInfo number_info = { + sizeof (UiSkinnedNumberClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_number_class_init, + NULL, + NULL, + sizeof (UiSkinnedNumber), + 0, + (GInstanceInitFunc) ui_skinned_number_init, + }; + number_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedNumber_", &number_info, 0); + } + + return number_type; +} + +static void ui_skinned_number_class_init(UiSkinnedNumberClass *klass) { + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_number_destroy; + + widget_class->realize = ui_skinned_number_realize; + widget_class->expose_event = ui_skinned_number_expose; + widget_class->size_request = ui_skinned_number_size_request; + widget_class->size_allocate = ui_skinned_number_size_allocate; + + klass->scaled = ui_skinned_number_toggle_scaled; + + number_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedNumberClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_skinned_number_init(UiSkinnedNumber *number) { + number->width = 9; + number->height = 13; +} + +GtkWidget* ui_skinned_number_new(GtkWidget *fixed, gint x, gint y, SkinPixmapId si) { + UiSkinnedNumber *number = g_object_new (ui_skinned_number_get_type (), NULL); + + number->x = x; + number->y = y; + number->num = 0; + number->skin_index = si; + + number->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(number), number->x, number->y); + + return GTK_WIDGET(number); +} + +static void ui_skinned_number_destroy(GtkObject *object) { + UiSkinnedNumber *number; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_NUMBER (object)); + + number = UI_SKINNED_NUMBER (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_number_realize(GtkWidget *widget) { + UiSkinnedNumber *number; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_NUMBER(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + number = UI_SKINNED_NUMBER(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_number_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedNumber *number = UI_SKINNED_NUMBER(widget); + + requisition->width = number->width * ( number->scaled ? cfg.scale_factor : 1 ); + requisition->height = number->height*( number->scaled ? cfg.scale_factor : 1); +} + +static void ui_skinned_number_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (number->scaled ? cfg.scale_factor: 1 ); + widget->allocation.y *= (number->scaled ? cfg.scale_factor: 1 ); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + number->x = widget->allocation.x/(number->scaled ? cfg.scale_factor : 1); + number->y = widget->allocation.y/(number->scaled ? cfg.scale_factor : 1); +} + +static gboolean ui_skinned_number_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_NUMBER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); + g_return_val_if_fail (number->width > 0 && number->height > 0, FALSE); + + GdkPixbuf *obj; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, number->width, number->height); + + if (number->num > 11 || number->num < 0) + number->num = 10; + + skin_draw_pixbuf(widget, aud_active_skin, obj, + number->skin_index, number->num * 9, 0, + 0, 0, number->width, number->height); + + ui_skinned_widget_draw(widget, obj, number->width, number->height, number->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static void ui_skinned_number_toggle_scaled(UiSkinnedNumber *number) { + GtkWidget *widget = GTK_WIDGET (number); + number->scaled = !number->scaled; + + gtk_widget_set_size_request(widget, number->width * ( number->scaled ? cfg.scale_factor : 1), + number->height * ( number->scaled ? cfg.scale_factor : 1) ); + + gtk_widget_queue_draw(GTK_WIDGET(number)); +} + +void ui_skinned_number_set_number(GtkWidget *widget, gint num) { + g_return_if_fail(UI_SKINNED_IS_NUMBER(widget)); + UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); + + if (number->num == num) + return; + + number->num = num; + gtk_widget_queue_draw(GTK_WIDGET(number)); +} + +void ui_skinned_number_set_size(GtkWidget *widget, gint width, gint height) { + g_return_if_fail(UI_SKINNED_IS_NUMBER(widget)); + UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); + + number->width = width; + number->height = height; + + gtk_widget_set_size_request(widget, width*(number->scaled ? cfg.scale_factor : 1 ), + height*(number->scaled ? cfg.scale_factor : 1 )); +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_number.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_number.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,61 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * 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_SKINNED_NUMBER_H +#define AUDACIOUS_UI_SKINNED_NUMBER_H + +#include +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_NUMBER(obj) GTK_CHECK_CAST (obj, ui_skinned_number_get_type (), UiSkinnedNumber) +#define UI_SKINNED_NUMBER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_number_get_type (), UiSkinnedNumberClass) +#define UI_SKINNED_IS_NUMBER(obj) GTK_CHECK_TYPE (obj, ui_skinned_number_get_type ()) + +typedef struct _UiSkinnedNumber UiSkinnedNumber; +typedef struct _UiSkinnedNumberClass UiSkinnedNumberClass; + +struct _UiSkinnedNumber { + GtkWidget widget; + + gint x, y, width, height; + gint num; + gboolean scaled; + SkinPixmapId skin_index; +}; + +struct _UiSkinnedNumberClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedNumber *textbox); +}; + +GtkWidget* ui_skinned_number_new (GtkWidget *fixed, gint x, gint y, SkinPixmapId si); +GtkType ui_skinned_number_get_type(void); +void ui_skinned_number_set_number(GtkWidget *widget, gint num); +void ui_skinned_number_set_size(GtkWidget *widget, gint width, gint height); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_NUMBER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_playlist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_playlist.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,1105 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * Copyright (c) 2008 William Pitcock + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * + * 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. + */ + +/* + * A note about Pango and some funky spacey fonts: Weirdly baselined + * fonts, or fonts with weird ascents or descents _will_ display a + * little bit weird in the playlist widget, but the display engine + * won't make it look too bad, just a little deranged. I honestly + * don't think it's worth fixing (around...), it doesn't have to be + * perfectly fitting, just the general look has to be ok, which it + * IMHO is. + * + * A second note: The numbers aren't perfectly aligned, but in the + * end it looks better when using a single Pango layout for each + * number. + */ + +#include "ui_skinned_playlist.h" + +#include "debug.h" +#include "input.h" +#include "main.h" +#include "playback.h" +#include "playlist.h" +#include "strings.h" +#include "ui_fileinfopopup.h" +#include "ui_manager.h" +#include "ui_playlist.h" +#include "ui_skin.h" +#include "util.h" + +static PangoFontDescription *playlist_list_font = NULL; +static gint ascent, descent, width_delta_digit_one; +static gboolean has_slant; +static guint padding; + +/* FIXME: the following globals should not be needed. */ +static gint width_approx_letters; +static gint width_colon, width_colon_third; +static gint width_approx_digits, width_approx_digits_half; + +#define UI_SKINNED_PLAYLIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_playlist_get_type(), UiSkinnedPlaylistPrivate)) +typedef struct _UiSkinnedPlaylistPrivate UiSkinnedPlaylistPrivate; + +enum { + REDRAW, + LAST_SIGNAL +}; + +struct _UiSkinnedPlaylistPrivate { + SkinPixmapId skin_index; + gint width, height; + gint resize_width, resize_height; + gint drag_pos; + gboolean dragging, auto_drag_down, auto_drag_up; + gint auto_drag_up_tag, auto_drag_down_tag; +}; + +static void ui_skinned_playlist_class_init (UiSkinnedPlaylistClass *klass); +static void ui_skinned_playlist_init (UiSkinnedPlaylist *playlist); +static void ui_skinned_playlist_destroy (GtkObject *object); +static void ui_skinned_playlist_realize (GtkWidget *widget); +static void ui_skinned_playlist_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_playlist_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_playlist_expose (GtkWidget *widget, GdkEventExpose *event); +static gboolean ui_skinned_playlist_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_playlist_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_playlist_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static gboolean ui_skinned_playlist_leave_notify (GtkWidget *widget, GdkEventCrossing *event); +static void ui_skinned_playlist_redraw (UiSkinnedPlaylist *playlist); +static gboolean ui_skinned_playlist_popup_show (gpointer data); +static void ui_skinned_playlist_popup_hide (GtkWidget *widget); +static void ui_skinned_playlist_popup_timer_start (GtkWidget *widget); +static void ui_skinned_playlist_popup_timer_stop (GtkWidget *widget); + +static GtkWidgetClass *parent_class = NULL; +static guint playlist_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_playlist_get_type() { + static GType playlist_type = 0; + if (!playlist_type) { + static const GTypeInfo playlist_info = { + sizeof (UiSkinnedPlaylistClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_playlist_class_init, + NULL, + NULL, + sizeof (UiSkinnedPlaylist), + 0, + (GInstanceInitFunc) ui_skinned_playlist_init, + }; + playlist_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedPlaylist_", &playlist_info, 0); + } + + return playlist_type; +} + +static void ui_skinned_playlist_class_init(UiSkinnedPlaylistClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_playlist_destroy; + + widget_class->realize = ui_skinned_playlist_realize; + widget_class->expose_event = ui_skinned_playlist_expose; + widget_class->size_request = ui_skinned_playlist_size_request; + widget_class->size_allocate = ui_skinned_playlist_size_allocate; + widget_class->button_press_event = ui_skinned_playlist_button_press; + widget_class->button_release_event = ui_skinned_playlist_button_release; + widget_class->motion_notify_event = ui_skinned_playlist_motion_notify; + widget_class->leave_notify_event = ui_skinned_playlist_leave_notify; + + klass->redraw = ui_skinned_playlist_redraw; + + playlist_signals[REDRAW] = + g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedPlaylistClass, redraw), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedPlaylistPrivate)); +} + +static void ui_skinned_playlist_init(UiSkinnedPlaylist *playlist) { + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(playlist); + playlist->pressed = FALSE; + priv->resize_width = 0; + priv->resize_height = 0; + playlist->prev_selected = -1; + playlist->prev_min = -1; + playlist->prev_max = -1; + + g_object_set_data(G_OBJECT(playlist), "timer_id", GINT_TO_POINTER(0)); + g_object_set_data(G_OBJECT(playlist), "timer_active", GINT_TO_POINTER(0)); + + GtkWidget *popup = fileinfopopup_create(); + g_object_set_data(G_OBJECT(playlist), "popup", popup); + g_object_set_data(G_OBJECT(playlist), "popup_active", GINT_TO_POINTER(0)); + g_object_set_data(G_OBJECT(playlist), "popup_position", GINT_TO_POINTER(-1)); +} + +GtkWidget* ui_skinned_playlist_new(GtkWidget *fixed, gint x, gint y, gint w, gint h) { + + UiSkinnedPlaylist *hs = g_object_new (ui_skinned_playlist_get_type (), NULL); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(hs); + + hs->x = x; + hs->y = y; + priv->width = w; + priv->height = h; + priv->skin_index = SKIN_PLEDIT; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(hs), hs->x, hs->y); + gtk_widget_set_double_buffered(GTK_WIDGET(hs), TRUE); + + return GTK_WIDGET(hs); +} + +static void ui_skinned_playlist_destroy(GtkObject *object) { + UiSkinnedPlaylist *playlist; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYLIST (object)); + + playlist = UI_SKINNED_PLAYLIST (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_playlist_realize(GtkWidget *widget) { + UiSkinnedPlaylist *playlist; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYLIST(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + playlist = UI_SKINNED_PLAYLIST(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_playlist_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); + + requisition->width = priv->width; + requisition->height = priv->height; +} + +static void ui_skinned_playlist_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedPlaylist *playlist = UI_SKINNED_PLAYLIST (widget); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(playlist); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + playlist->x = widget->allocation.x; + playlist->y = widget->allocation.y; + + if (priv->height != widget->allocation.height || priv->width != widget->allocation.width) { + priv->width = priv->width + priv->resize_width; + priv->height = priv->height + priv->resize_height; + priv->resize_width = 0; + priv->resize_height = 0; + gtk_widget_queue_draw(widget); + } +} + +static gboolean ui_skinned_playlist_auto_drag_down_func(gpointer data) { + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST(data); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(data); + + if (priv->auto_drag_down) { + ui_skinned_playlist_move_down(pl); + pl->first++; + playlistwin_update_list(playlist_get_active()); + return TRUE; + } + return FALSE; +} + +static gboolean ui_skinned_playlist_auto_drag_up_func(gpointer data) { + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST(data); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(data); + + if (priv->auto_drag_up) { + ui_skinned_playlist_move_up(pl); + pl->first--; + playlistwin_update_list(playlist_get_active()); + return TRUE; + + } + return FALSE; +} + +void ui_skinned_playlist_move_up(UiSkinnedPlaylist * pl) { + GList *list; + Playlist *playlist = playlist_get_active(); + + if (!playlist) + return; + + PLAYLIST_LOCK(playlist); + if ((list = playlist->entries) == NULL) { + PLAYLIST_UNLOCK(playlist); + return; + } + if (PLAYLIST_ENTRY(list->data)->selected) { + /* We are at the top */ + PLAYLIST_UNLOCK(playlist); + return; + } + while (list) { + if (PLAYLIST_ENTRY(list->data)->selected) + glist_moveup(list); + list = g_list_next(list); + } + PLAYLIST_INCR_SERIAL(playlist); + PLAYLIST_UNLOCK(playlist); + if (pl->prev_selected != -1) + pl->prev_selected--; + if (pl->prev_min != -1) + pl->prev_min--; + if (pl->prev_max != -1) + pl->prev_max--; +} + +void ui_skinned_playlist_move_down(UiSkinnedPlaylist * pl) { + GList *list; + Playlist *playlist = playlist_get_active(); + + if (!playlist) + return; + + PLAYLIST_LOCK(playlist); + + if (!(list = g_list_last(playlist->entries))) { + PLAYLIST_UNLOCK(playlist); + return; + } + + if (PLAYLIST_ENTRY(list->data)->selected) { + /* We are at the bottom */ + PLAYLIST_UNLOCK(playlist); + return; + } + + while (list) { + if (PLAYLIST_ENTRY(list->data)->selected) + glist_movedown(list); + list = g_list_previous(list); + } + + PLAYLIST_INCR_SERIAL(playlist); + PLAYLIST_UNLOCK(playlist); + + if (pl->prev_selected != -1) + pl->prev_selected++; + if (pl->prev_min != -1) + pl->prev_min++; + if (pl->prev_max != -1) + pl->prev_max++; +} + +static void +playlist_list_draw_string(cairo_t *cr, UiSkinnedPlaylist *pl, + PangoFontDescription * font, + gint line, + gint width, + const gchar * text, + guint ppos) +{ + guint plist_length_int; + Playlist *playlist = playlist_get_active(); + PangoLayout *layout; + + REQUIRE_LOCK(playlist->mutex); + + cairo_new_path(cr); + + if (cfg.show_numbers_in_pl) { + gchar *pos_string = g_strdup_printf(cfg.show_separator_in_pl == TRUE ? "%d" : "%d.", ppos); + plist_length_int = + gint_count_digits(playlist_get_length(playlist)) + !cfg.show_separator_in_pl + 1; /* cf.show_separator_in_pl will be 0 if false */ + + padding = plist_length_int; + padding = ((padding + 1) * width_approx_digits); + + layout = gtk_widget_create_pango_layout(playlistwin, pos_string); + pango_layout_set_font_description(layout, playlist_list_font); + pango_layout_set_width(layout, plist_length_int * 100); + + pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); + + cairo_move_to(cr, (width_approx_digits * + (-1 + plist_length_int - strlen(pos_string))) + + (width_approx_digits / 4), (line - 1) * pl->fheight + + ascent + abs(descent)); + pango_cairo_show_layout(cr, layout); + + g_free(pos_string); + g_object_unref(layout); + + if (!cfg.show_separator_in_pl) + padding -= (width_approx_digits * 1.5); + } else { + padding = 3; + } + + width -= padding; + + layout = gtk_widget_create_pango_layout(playlistwin, text); + + pango_layout_set_font_description(layout, playlist_list_font); + pango_layout_set_width(layout, width * PANGO_SCALE); + pango_layout_set_single_paragraph_mode(layout, TRUE); + pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); + + cairo_move_to(cr, padding + (width_approx_letters / 4), + (line - 1) * pl->fheight + + ascent + abs(descent)); + pango_cairo_show_layout(cr, layout); + + g_object_unref(layout); +} + +static gboolean ui_skinned_playlist_expose(GtkWidget *widget, GdkEventExpose *event) { + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST (widget); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(pl); + g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); + + Playlist *playlist = playlist_get_active(); + PlaylistEntry *entry; + GList *list; + PangoLayout *layout; + gchar *title; + gint width, height; + gint i, max_first; + guint padding, padding_dwidth, padding_plength; + guint max_time_len = 0; + gfloat queue_tailpadding = 0; + gint tpadding; + gsize tpadding_dwidth = 0; + gint x, y; + guint tail_width; + guint tail_len; + gboolean in_selection = FALSE; + + gchar tail[100]; + gchar queuepos[255]; + gchar length[40]; + + gchar **frags; + gchar *frag0; + + gint plw_w, plw_h; + + cairo_t *cr; + gint yc; + gint pos; + gdouble rounding_offset; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_PLAYLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + cr = gdk_cairo_create(widget->window); + + width = priv->width; + height = priv->height; + + plw_w = playlistwin_get_width(); + plw_h = playlistwin_get_height(); + + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_NORMALBG)); + + cairo_rectangle(cr, 0, 0, width, height); + cairo_paint(cr); + + if (!playlist_list_font) { + g_critical("Couldn't open playlist font"); + return FALSE; + } + + pl->fheight = (ascent + abs(descent)); + pl->num_visible = height / pl->fheight; + + rounding_offset = pl->fheight / 3; + + max_first = playlist_get_length(playlist) - pl->num_visible; + max_first = MAX(max_first, 0); + + pl->first = CLAMP(pl->first, 0, max_first); + + PLAYLIST_LOCK(playlist); + list = playlist->entries; + list = g_list_nth(list, pl->first); + + /* It sucks having to run the iteration twice but this is the only + way you can reliably get the maximum width so we can get our + playlist nice and aligned... -- plasmaroo */ + + for (i = pl->first; + list && i < pl->first + pl->num_visible; + list = g_list_next(list), i++) { + entry = list->data; + + if (entry->length != -1) + { + g_snprintf(length, sizeof(length), "%d:%-2.2d", + entry->length / 60000, (entry->length / 1000) % 60); + tpadding_dwidth = MAX(tpadding_dwidth, strlen(length)); + } + } + + /* Reset */ + list = playlist->entries; + list = g_list_nth(list, pl->first); + + for (i = pl->first; + list && i < pl->first + pl->num_visible; + list = g_list_next(list), i++) { + entry = list->data; + + if (entry->selected && !in_selection) { + yc = ((i - pl->first) * pl->fheight); + + cairo_new_path(cr); + + cairo_move_to(cr, 0, yc + (rounding_offset * 2)); + cairo_curve_to(cr, 0, yc + rounding_offset, 0, yc + 0.5, 0 + rounding_offset, yc + 0.5); + + cairo_line_to(cr, 0 + width - (rounding_offset * 2), yc + 0.5); + cairo_curve_to(cr, 0 + width - rounding_offset, yc + 0.5, + 0 + width, yc + 0.5, 0 + width, yc + rounding_offset); + + in_selection = TRUE; + } + + if ((!entry->selected || + (i == pl->first + pl->num_visible - 1) || !g_list_next(list)) + && in_selection) { + + if (!entry->selected) + yc = (((i - 1) - pl->first) * pl->fheight); + else /* last visible item */ + yc = ((i - pl->first) * pl->fheight); + + cairo_line_to(cr, 0 + width, yc + pl->fheight - (rounding_offset * 2)); + cairo_curve_to (cr, 0 + width, yc + pl->fheight - rounding_offset, + 0 + width, yc + pl->fheight - 0.5, + 0 + width-rounding_offset, yc + pl->fheight - 0.5); + + cairo_line_to (cr, 0 + (rounding_offset * 2), yc + pl->fheight - 0.5); + cairo_curve_to (cr, 0 + rounding_offset, yc + pl->fheight - 0.5, + 0, yc + pl->fheight - 0.5, + 0, yc + pl->fheight - rounding_offset); + + cairo_close_path (cr); + + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_SELECTEDBG)); + + cairo_fill(cr); + + in_selection = FALSE; + } + } + + list = playlist->entries; + list = g_list_nth(list, pl->first); + + /* now draw the text */ + for (i = pl->first; + list && i < pl->first + pl->num_visible; + list = g_list_next(list), i++) { + entry = list->data; + + /* FIXME: entry->title should NEVER be NULL, and there should + NEVER be a need to do a UTF-8 conversion. Playlist title + strings should be kept properly. */ + + if (!entry->title) { + gchar *realfn = g_filename_from_uri(entry->filename, NULL, NULL); + gchar *basename = g_path_get_basename(realfn ? realfn : entry->filename); + title = filename_to_utf8(basename); + g_free(basename); g_free(realfn); + } + else + title = str_assert_utf8(entry->title); + + title = convert_title_text(title); + + pos = playlist_get_queue_position(playlist, entry); + + tail[0] = 0; + queuepos[0] = 0; + length[0] = 0; + + if (pos != -1) + g_snprintf(queuepos, sizeof(queuepos), "%d", pos + 1); + + if (entry->length != -1) + { + g_snprintf(length, sizeof(length), "%d:%-2.2d", + entry->length / 60000, (entry->length / 1000) % 60); + } + + strncat(tail, length, sizeof(tail) - 1); + tail_len = strlen(tail); + + max_time_len = MAX(max_time_len, tail_len); + + if (pos != -1 && tpadding_dwidth <= 0) + tail_width = width - (width_approx_digits * (strlen(queuepos) + 2.25)); + else if (pos != -1) + tail_width = width - (width_approx_digits * (tpadding_dwidth + strlen(queuepos) + 4)); + else if (tpadding_dwidth > 0) + tail_width = width - (width_approx_digits * (tpadding_dwidth + 2.5)); + else + tail_width = width; + + if (i == playlist_get_position_nolock(playlist)) + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_CURRENT)); + else + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_NORMAL)); + + playlist_list_draw_string(cr, pl, playlist_list_font, + i - pl->first, tail_width, title, + i + 1); + + x = width - width_approx_digits * 2; + y = ((i - pl->first) - 1) * pl->fheight + ascent; + + frags = NULL; + frag0 = NULL; + + if ((strlen(tail) > 0) && (tail != NULL)) { + frags = g_strsplit(tail, ":", 0); + frag0 = g_strconcat(frags[0], ":", NULL); + + layout = gtk_widget_create_pango_layout(playlistwin, frags[1]); + pango_layout_set_font_description(layout, playlist_list_font); + pango_layout_set_width(layout, tail_len * 100); + pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); + + cairo_new_path(cr); + cairo_move_to(cr, x - (0.5 * width_approx_digits), y + abs(descent)); + pango_cairo_show_layout(cr, layout); + g_object_unref(layout); + + layout = gtk_widget_create_pango_layout(playlistwin, frag0); + pango_layout_set_font_description(layout, playlist_list_font); + pango_layout_set_width(layout, tail_len * 100); + pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT); + + cairo_move_to(cr, x - (0.75 * width_approx_digits), y + abs(descent)); + pango_cairo_show_layout(cr, layout); + g_object_unref(layout); + + g_free(frag0); + g_strfreev(frags); + } + + if (pos != -1) { + if (tpadding_dwidth > 0) + queue_tailpadding = tpadding_dwidth + 1; + else + queue_tailpadding = -0.75; + + cairo_rectangle(cr, + x - + (((queue_tailpadding + + strlen(queuepos)) * + width_approx_digits) + + (width_approx_digits / 4)), + y + abs(descent), + (strlen(queuepos)) * + width_approx_digits + + (width_approx_digits / 2), + pl->fheight - 2); + + layout = + gtk_widget_create_pango_layout(playlistwin, queuepos); + pango_layout_set_font_description(layout, playlist_list_font); + pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); + + cairo_move_to(cr, + x - + ((queue_tailpadding + + strlen(queuepos)) * width_approx_digits) + + (width_approx_digits / 4), + y + abs(descent)); + pango_cairo_show_layout(cr, layout); + + g_object_unref(layout); + } + + cairo_stroke(cr); + + g_free(title); + } + + + /* + * Drop target hovering over the playlist, so draw some hint where the + * drop will occur. + * + * This is (currently? unfixably?) broken when dragging files from Qt/KDE apps, + * probably due to DnD signaling problems (actually i have no clue). + * + */ + + if (pl->drag_motion) { + guint pos, plength, lpadding; + + if (cfg.show_numbers_in_pl) { + lpadding = gint_count_digits(playlist_get_length(playlist)) + 1; + lpadding = ((lpadding + 1) * width_approx_digits); + } + else { + lpadding = 3; + }; + + /* We already hold the mutex and have the playlist locked, so call + the non-locking function. */ + plength = playlist_get_length(playlist); + + x = pl->drag_motion_x; + y = pl->drag_motion_y; + + if ((x > pl->x) && !(x > priv->width)) { + + if ((y > pl->y) + && !(y > (priv->height + pl->y))) { + + pos = (y / pl->fheight) + + pl->first; + + if (pos > (plength)) { + pos = plength; + } + + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_CURRENT)); + + cairo_new_path(cr); + + cairo_move_to(cr, 0, ((pos - pl->first) * pl->fheight)); + cairo_rel_line_to(cr, priv->width - 1, 0); + + cairo_set_line_width(cr, 1); + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + cairo_stroke(cr); + } + + } + + /* When dropping on the borders of the playlist, outside the text area, + * files get appended at the end of the list. Show that too. + */ + + if ((y < pl->y) || (y > priv->height + pl->y)) { + if ((y >= 0) || (y <= (priv->height + pl->y))) { + pos = plength; + + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_CURRENT)); + + cairo_new_path(cr); + + cairo_move_to(cr, 0, ((pos - pl->first) * pl->fheight)); + cairo_rel_line_to(cr, priv->width - 1, 0); + + cairo_set_line_width(cr, 1); + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + cairo_stroke(cr); + } + } + } + + gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_NORMAL)); + cairo_set_line_width(cr, 1); + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + + if (cfg.show_numbers_in_pl) + { + padding_plength = playlist_get_length(playlist); + + if (padding_plength == 0) { + padding_dwidth = 0; + } + else { + padding_dwidth = gint_count_digits(playlist_get_length(playlist)); + } + + padding = + (padding_dwidth * + width_approx_digits) + width_approx_digits; + + + /* For italic or oblique fonts we add another half of the + * approximate width */ + if (has_slant) + padding += width_approx_digits_half; + + if (cfg.show_separator_in_pl) { + cairo_new_path(cr); + + cairo_move_to(cr, padding, 0); + cairo_rel_line_to(cr, 0, priv->height - 1); + + cairo_stroke(cr); + } + } + + if (tpadding_dwidth != 0) + { + tpadding = (tpadding_dwidth * width_approx_digits) + (width_approx_digits * 1.5); + + if (has_slant) + tpadding += width_approx_digits_half; + + if (cfg.show_separator_in_pl) { + cairo_new_path(cr); + + cairo_move_to(cr, priv->width - tpadding, 0); + cairo_rel_line_to(cr, 0, priv->height - 1); + + cairo_stroke(cr); + } + } + + PLAYLIST_UNLOCK(playlist); + + cairo_destroy(cr); + + return FALSE; +} + +gint ui_skinned_playlist_get_position(GtkWidget *widget, gint x, gint y) { + gint iy, length; + gint ret; + Playlist *playlist = playlist_get_active(); + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST (widget); + + if (!pl->fheight) + return -1; + + if ((length = playlist_get_length(playlist)) == 0) + return -1; + iy = y; + + ret = (iy / pl->fheight) + pl->first; + + if (ret > length - 1) + ret = -1; + + return ret; +} + +static gboolean ui_skinned_playlist_button_press(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST (widget); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); + + gint nr; + Playlist *playlist = playlist_get_active(); + + nr = ui_skinned_playlist_get_position(widget, event->x, event->y); + if (nr == -1) + return FALSE; + + if (event->button == 3) { + ui_manager_popup_menu_show(GTK_MENU(playlistwin_popup_menu), + event->x_root, event->y_root + 5, + event->button, event->time); + GList* selection = playlist_get_selected(playlist); + if (g_list_find(selection, GINT_TO_POINTER(nr)) == NULL) { + playlist_select_all(playlist, FALSE); + playlist_select_range(playlist, nr, nr, TRUE); + } + } else if (event->button == 1) { + if (!(event->state & GDK_CONTROL_MASK)) + playlist_select_all(playlist, FALSE); + + if ((event->state & GDK_MOD1_MASK)) + playlist_queue_position(playlist, nr); + + if (event->state & GDK_SHIFT_MASK && pl->prev_selected != -1) { + playlist_select_range(playlist, pl->prev_selected, nr, TRUE); + pl->prev_min = pl->prev_selected; + pl->prev_max = nr; + priv->drag_pos = nr - pl->first; + } + else { + if (playlist_select_invert(playlist, nr)) { + if (event->state & GDK_CONTROL_MASK) { + if (pl->prev_min == -1) { + pl->prev_min = pl->prev_selected; + pl->prev_max = pl->prev_selected; + } + if (nr < pl->prev_min) + pl->prev_min = nr; + else if (nr > pl->prev_max) + pl->prev_max = nr; + } + else + pl->prev_min = -1; + pl->prev_selected = nr; + priv->drag_pos = nr - pl->first; + } + } + if (event->type == GDK_2BUTTON_PRESS) { + /* + * Ungrab the pointer to prevent us from + * hanging on to it during the sometimes slow + * playback_initiate(). + */ + gdk_pointer_ungrab(GDK_CURRENT_TIME); + playlist_set_position(playlist, nr); + if (!playback_get_playing()) + playback_initiate(); + } + + priv->dragging = TRUE; + } + playlistwin_update_list(playlist); + ui_skinned_playlist_popup_hide(widget); + ui_skinned_playlist_popup_timer_stop(widget); + + return TRUE; +} + +static gboolean ui_skinned_playlist_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); + + priv->dragging = FALSE; + priv->auto_drag_down = FALSE; + priv->auto_drag_up = FALSE; + gtk_widget_queue_draw(widget); + + ui_skinned_playlist_popup_hide(widget); + ui_skinned_playlist_popup_timer_stop(widget); + return TRUE; +} + +static gboolean ui_skinned_playlist_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST(widget); + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); + + gint nr, y, off, i; + if (priv->dragging) { + y = event->y; + nr = (y / pl->fheight); + if (nr < 0) { + nr = 0; + if (!priv->auto_drag_up) { + priv->auto_drag_up = TRUE; + priv->auto_drag_up_tag = + g_timeout_add(100, ui_skinned_playlist_auto_drag_up_func, pl); + } + } + else if (priv->auto_drag_up) + priv->auto_drag_up = FALSE; + + if (nr >= pl->num_visible) { + nr = pl->num_visible - 1; + if (!priv->auto_drag_down) { + priv->auto_drag_down = TRUE; + priv->auto_drag_down_tag = + g_timeout_add(100, ui_skinned_playlist_auto_drag_down_func, pl); + } + } + else if (priv->auto_drag_down) + priv->auto_drag_down = FALSE; + + off = nr - priv->drag_pos; + if (off) { + for (i = 0; i < abs(off); i++) { + if (off < 0) + ui_skinned_playlist_move_up(pl); + else + ui_skinned_playlist_move_down(pl); + + } + playlistwin_update_list(playlist_get_active()); + } + priv->drag_pos = nr; + } else if (cfg.show_filepopup_for_tuple) { + gint pos = ui_skinned_playlist_get_position(widget, event->x, event->y); + gint cur_pos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "popup_position")); + if (pos != cur_pos) { + g_object_set_data(G_OBJECT(widget), "popup_position", GINT_TO_POINTER(pos)); + ui_skinned_playlist_popup_hide(widget); + ui_skinned_playlist_popup_timer_stop(widget); + if (pos != -1) + ui_skinned_playlist_popup_timer_start(widget); + } + } + + return TRUE; +} + +static gboolean ui_skinned_playlist_leave_notify(GtkWidget *widget, GdkEventCrossing *event) { + ui_skinned_playlist_popup_hide(widget); + ui_skinned_playlist_popup_timer_stop(widget); + + return FALSE; +} + +static void ui_skinned_playlist_redraw(UiSkinnedPlaylist *playlist) { + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(playlist); + + if (priv->resize_height || priv->resize_width) + gtk_widget_set_size_request(GTK_WIDGET(playlist), priv->width+priv->resize_width, priv->height+priv->resize_height); + + gtk_widget_queue_draw(GTK_WIDGET(playlist)); +} + +void ui_skinned_playlist_set_font(const gchar * font) { + /* Welcome to bad hack central 2k3 */ + gchar *font_lower; + gint width_temp; + gint width_temp_0; + + playlist_list_font = pango_font_description_from_string(font); + + text_get_extents(font, + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz ", + &width_approx_letters, NULL, &ascent, &descent); + + width_approx_letters = (width_approx_letters / 53); + + /* Experimental: We don't weigh the 1 into total because it's width is almost always + * very different from the rest + */ + text_get_extents(font, "023456789", &width_approx_digits, NULL, NULL, + NULL); + width_approx_digits = (width_approx_digits / 9); + + /* Precache some often used calculations */ + width_approx_digits_half = width_approx_digits / 2; + + /* FIXME: We assume that any other number is broader than the "1" */ + text_get_extents(font, "1", &width_temp, NULL, NULL, NULL); + text_get_extents(font, "2", &width_temp_0, NULL, NULL, NULL); + + if (abs(width_temp_0 - width_temp) < 2) { + width_delta_digit_one = 0; + } + else { + width_delta_digit_one = ((width_temp_0 - width_temp) / 2) + 2; + } + + text_get_extents(font, ":", &width_colon, NULL, NULL, NULL); + width_colon_third = width_colon / 4; + + font_lower = g_utf8_strdown(font, strlen(font)); + /* This doesn't take any i18n into account, but i think there is none with TTF fonts + * FIXME: This can probably be retrieved trough Pango too + */ + has_slant = g_strstr_len(font_lower, strlen(font_lower), "oblique") + || g_strstr_len(font_lower, strlen(font_lower), "italic"); + + g_free(font_lower); +} + +void ui_skinned_playlist_resize_relative(GtkWidget *widget, gint w, gint h) { + UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); + priv->resize_width += w; + priv->resize_height += h; +} + +static gboolean ui_skinned_playlist_popup_show(gpointer data) { + GtkWidget *widget = data; + gint pos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "popup_position")); + + if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "timer_active")) == 1 && pos != -1) { + Tuple *tuple; + Playlist *pl_active = playlist_get_active(); + GtkWidget *popup = g_object_get_data(G_OBJECT(widget), "popup"); + + tuple = playlist_get_tuple(pl_active, pos); + if ((tuple == NULL) || (tuple_get_int(tuple, FIELD_LENGTH, NULL) < 1)) { + gchar *title = playlist_get_songtitle(pl_active, pos); + fileinfopopup_show_from_title(popup, title); + g_free(title); + } else { + fileinfopopup_show_from_tuple(popup , tuple); + } + g_object_set_data(G_OBJECT(widget), "popup_active" , GINT_TO_POINTER(1)); + } + + ui_skinned_playlist_popup_timer_stop(widget); + return FALSE; +} + +static void ui_skinned_playlist_popup_hide(GtkWidget *widget) { + if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "popup_active")) == 1) { + GtkWidget *popup = g_object_get_data(G_OBJECT(widget), "popup"); + g_object_set_data(G_OBJECT(widget), "popup_active", GINT_TO_POINTER(0)); + fileinfopopup_hide(popup, NULL); + } +} + +static void ui_skinned_playlist_popup_timer_start(GtkWidget *widget) { + gint timer_id = g_timeout_add(cfg.filepopup_delay*100, ui_skinned_playlist_popup_show, widget); + g_object_set_data(G_OBJECT(widget), "timer_id", GINT_TO_POINTER(timer_id)); + g_object_set_data(G_OBJECT(widget), "timer_active", GINT_TO_POINTER(1)); +} + +static void ui_skinned_playlist_popup_timer_stop(GtkWidget *widget) { + if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "timer_active")) == 1) + g_source_remove(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "timer_id"))); + + g_object_set_data(G_OBJECT(widget), "timer_id", GINT_TO_POINTER(0)); + g_object_set_data(G_OBJECT(widget), "timer_active", GINT_TO_POINTER(0)); +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_playlist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_playlist.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,77 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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_SKINNED_PLAYLIST_H +#define AUDACIOUS_UI_SKINNED_PLAYLIST_H + +#include + +#include +#include + +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_PLAYLIST(obj) GTK_CHECK_CAST (obj, ui_skinned_playlist_get_type (), UiSkinnedPlaylist) +#define UI_SKINNED_PLAYLIST_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_playlist_get_type (), UiSkinnedPlaylistClass) +#define UI_SKINNED_IS_PLAYLIST(obj) GTK_CHECK_TYPE (obj, ui_skinned_playlist_get_type ()) + +typedef struct _UiSkinnedPlaylist UiSkinnedPlaylist; +typedef struct _UiSkinnedPlaylistClass UiSkinnedPlaylistClass; + +struct _UiSkinnedPlaylist { + GtkWidget widget; + gboolean pressed; + gint x, y; + gint first; + gint num_visible; + gint prev_selected, prev_min, prev_max; + gboolean drag_motion; + gint drag_motion_x, drag_motion_y; + gint fheight; +}; + +struct _UiSkinnedPlaylistClass { + GtkWidgetClass parent_class; + void (* redraw) (UiSkinnedPlaylist *playlist); +}; + +GtkWidget* ui_skinned_playlist_new(GtkWidget *fixed, gint x, gint y, gint w, gint h); +GtkType ui_skinned_playlist_get_type(void); +void ui_skinned_playlist_resize_relative(GtkWidget *widget, gint w, gint h); +void ui_skinned_playlist_set_font(const gchar * font); +void ui_skinned_playlist_move_up(UiSkinnedPlaylist *pl); +void ui_skinned_playlist_move_down(UiSkinnedPlaylist *pl); +gint ui_skinned_playlist_get_position(GtkWidget *widget, gint x, gint y); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_PLAYLIST_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_playlist_slider.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_playlist_slider.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,338 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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. + */ + +#include "ui_skin.h" +#include "ui_skinned_playlist_slider.h" +#include "main.h" +#include "ui_playlist.h" + +#define UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_playlist_slider_get_type(), UiSkinnedPlaylistSliderPrivate)) +typedef struct _UiSkinnedPlaylistSliderPrivate UiSkinnedPlaylistSliderPrivate; + +enum { + REDRAW, + LAST_SIGNAL +}; + +struct _UiSkinnedPlaylistSliderPrivate { + SkinPixmapId skin_index; + gint width, height; + + gint resize_height; + gint move_x; + gint prev_y; + gint drag_y; +}; + +static void ui_skinned_playlist_slider_class_init (UiSkinnedPlaylistSliderClass *klass); +static void ui_skinned_playlist_slider_init (UiSkinnedPlaylistSlider *playlist_slider); +static void ui_skinned_playlist_slider_destroy (GtkObject *object); +static void ui_skinned_playlist_slider_realize (GtkWidget *widget); +static void ui_skinned_playlist_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_playlist_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_playlist_slider_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_skinned_playlist_slider_set_position (GtkWidget *widget, gint y); +static gboolean ui_skinned_playlist_slider_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_playlist_slider_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_playlist_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static void ui_skinned_playlist_slider_redraw (UiSkinnedPlaylistSlider *playlist_slider); + +static GtkWidgetClass *parent_class = NULL; +static guint playlist_slider_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_playlist_slider_get_type() { + static GType playlist_slider_type = 0; + if (!playlist_slider_type) { + static const GTypeInfo playlist_slider_info = { + sizeof (UiSkinnedPlaylistSliderClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_playlist_slider_class_init, + NULL, + NULL, + sizeof (UiSkinnedPlaylistSlider), + 0, + (GInstanceInitFunc) ui_skinned_playlist_slider_init, + }; + playlist_slider_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedPlaylistSlider_", &playlist_slider_info, 0); + } + + return playlist_slider_type; +} + +static void ui_skinned_playlist_slider_class_init(UiSkinnedPlaylistSliderClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_playlist_slider_destroy; + + widget_class->realize = ui_skinned_playlist_slider_realize; + widget_class->expose_event = ui_skinned_playlist_slider_expose; + widget_class->size_request = ui_skinned_playlist_slider_size_request; + widget_class->size_allocate = ui_skinned_playlist_slider_size_allocate; + widget_class->button_press_event = ui_skinned_playlist_slider_button_press; + widget_class->button_release_event = ui_skinned_playlist_slider_button_release; + widget_class->motion_notify_event = ui_skinned_playlist_slider_motion_notify; + + klass->redraw = ui_skinned_playlist_slider_redraw; + + playlist_slider_signals[REDRAW] = + g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedPlaylistSliderClass, redraw), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedPlaylistSliderPrivate)); +} + +static void ui_skinned_playlist_slider_init(UiSkinnedPlaylistSlider *playlist_slider) { + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(playlist_slider); + playlist_slider->pressed = FALSE; + priv->resize_height = 0; + priv->move_x = 0; + priv->drag_y = 0; + priv->prev_y = 0; +} + +GtkWidget* ui_skinned_playlist_slider_new(GtkWidget *fixed, gint x, gint y, gint h) { + + UiSkinnedPlaylistSlider *hs = g_object_new (ui_skinned_playlist_slider_get_type (), NULL); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(hs); + + hs->x = x; + hs->y = y; + priv->width = 8; + priv->height = h; + priv->skin_index = SKIN_PLEDIT; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(hs), hs->x, hs->y); + + return GTK_WIDGET(hs); +} + +static void ui_skinned_playlist_slider_destroy(GtkObject *object) { + UiSkinnedPlaylistSlider *playlist_slider; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYLIST_SLIDER (object)); + + playlist_slider = UI_SKINNED_PLAYLIST_SLIDER (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_playlist_slider_realize(GtkWidget *widget) { + UiSkinnedPlaylistSlider *playlist_slider; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYLIST_SLIDER(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + playlist_slider = UI_SKINNED_PLAYLIST_SLIDER(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_playlist_slider_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + + requisition->width = priv->width; + requisition->height = priv->height; +} + +static void ui_skinned_playlist_slider_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedPlaylistSlider *playlist_slider = UI_SKINNED_PLAYLIST_SLIDER (widget); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(playlist_slider); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + if (playlist_slider->x + priv->move_x == widget->allocation.x) + priv->move_x = 0; + playlist_slider->x = widget->allocation.x; + playlist_slider->y = widget->allocation.y; + + if (priv->height != widget->allocation.height) { + priv->height = priv->height + priv->resize_height; + priv->resize_height = 0; + gtk_widget_queue_draw(widget); + } +} + +static gboolean ui_skinned_playlist_slider_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_PLAYLIST_SLIDER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER (widget); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(ps); + g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->width, priv->height); + + gint num_visible; + num_visible = playlistwin_list_get_visible_count(); + + + Playlist *playlist = playlist_get_active(); + + gint y; + if (playlist_get_length(playlist) > num_visible) + y = (playlistwin_list_get_first() * (priv->height - 19)) / + (playlist_get_length(playlist) - num_visible); + else + y = 0; + + if (y < 0) y=0; + if (y > priv->height - 19) y = priv->height - 19; + + priv->prev_y = y; + + /* FIXME: uses aud_active_skin->pixmaps directly and may need calibration */ + /* drawing background */ + gint c; + for (c = 0; c < priv->height / 29; c++) { + gdk_pixbuf_copy_area(aud_active_skin->pixmaps[SKIN_PLEDIT].pixbuf, + 36, 42, priv->width, 29, obj, 0, c*29); + } + + /* drawing knob */ + skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, ps->pressed ? 61 : 52, 53, 0, y, priv->width, 18); + + ui_skinned_widget_draw(widget, obj, priv->width, priv->height, FALSE); + + g_object_unref(obj); + + return FALSE; +} + +static void ui_skinned_playlist_slider_set_position(GtkWidget *widget, gint y) { + gint pos; + Playlist *playlist = playlist_get_active(); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + + y = CLAMP(y, 0, priv->height - 19); + + pos = (y * (playlist_get_length(playlist) - playlistwin_list_get_visible_count())) / (priv->height - 19); + playlistwin_set_toprow(pos); + + gtk_widget_queue_draw(widget); +} + +static gboolean ui_skinned_playlist_slider_button_press(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER (widget); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + + if (event->button != 1 && event->button != 2) + return TRUE; + + gint y = event->y; + if (event->type == GDK_BUTTON_PRESS) { + ps->pressed = TRUE; + if ((y >= priv->prev_y && y < priv->prev_y + 18)) { + priv->drag_y = y - priv->prev_y; + } else if (event->button == 2) { + ui_skinned_playlist_slider_set_position(widget, y); + priv->drag_y = 0; + } else { + gint n = playlistwin_list_get_visible_count() / 2; + if (y < priv->prev_y) + n *= -1; + playlistwin_scroll(n); + } + gtk_widget_queue_draw(widget); + } + return TRUE; +} + +static gboolean ui_skinned_playlist_slider_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER(widget); + + if (event->button == 1 || event->button == 2) { + ps->pressed = FALSE; + gtk_widget_queue_draw(widget); + } + return TRUE; +} + +static gboolean ui_skinned_playlist_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER(widget); + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + + if (ps->pressed) { + gint y = event->y - priv->drag_y; + ui_skinned_playlist_slider_set_position(widget, y); + } + return TRUE; +} + +static void ui_skinned_playlist_slider_redraw(UiSkinnedPlaylistSlider *playlist_slider) { + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(playlist_slider); + + if (priv->resize_height) + gtk_widget_set_size_request(GTK_WIDGET(playlist_slider), priv->width, priv->height+priv->resize_height); + if (priv->move_x) + gtk_fixed_move(GTK_FIXED(gtk_widget_get_parent(GTK_WIDGET(playlist_slider))), GTK_WIDGET(playlist_slider), + playlist_slider->x+priv->move_x, playlist_slider->y); + + gtk_widget_queue_draw(GTK_WIDGET(playlist_slider)); +} + +void ui_skinned_playlist_slider_move_relative(GtkWidget *widget, gint x) { + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + priv->move_x += x; +} + +void ui_skinned_playlist_slider_resize_relative(GtkWidget *widget, gint h) { + UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); + priv->resize_height += h; +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_playlist_slider.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_playlist_slider.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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_SKINNED_PLAYLIST_SLIDER_H +#define AUDACIOUS_UI_SKINNED_PLAYLIST_SLIDER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_PLAYLIST_SLIDER(obj) GTK_CHECK_CAST (obj, ui_skinned_playlist_slider_get_type (), UiSkinnedPlaylistSlider) +#define UI_SKINNED_PLAYLIST_SLIDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_playlist_slider_get_type (), UiSkinnedPlaylistSliderClass) +#define UI_SKINNED_IS_PLAYLIST_SLIDER(obj) GTK_CHECK_TYPE (obj, ui_skinned_playlist_slider_get_type ()) + +typedef struct _UiSkinnedPlaylistSlider UiSkinnedPlaylistSlider; +typedef struct _UiSkinnedPlaylistSliderClass UiSkinnedPlaylistSliderClass; + +struct _UiSkinnedPlaylistSlider { + GtkWidget widget; + gboolean pressed; + gint x, y; +}; + +struct _UiSkinnedPlaylistSliderClass { + GtkWidgetClass parent_class; + void (* redraw) (UiSkinnedPlaylistSlider *playlist_slider); +}; + +GtkWidget* ui_skinned_playlist_slider_new(GtkWidget *fixed, gint x, gint y, gint h); +GtkType ui_skinned_playlist_slider_get_type(void); +void ui_skinned_playlist_slider_move_relative(GtkWidget *widget, gint x); +void ui_skinned_playlist_slider_resize_relative(GtkWidget *widget, gint h); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_PLAYLIST_SLIDER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_playstatus.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_playstatus.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,246 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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. + */ + +#include "ui_skin.h" +#include "ui_skinned_playstatus.h" +#include "main.h" + +#define UI_TYPE_SKINNED_PLAYSTATUS (ui_skinned_playstatus_get_type()) + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_skinned_playstatus_class_init (UiSkinnedPlaystatusClass *klass); +static void ui_skinned_playstatus_init (UiSkinnedPlaystatus *playstatus); +static void ui_skinned_playstatus_destroy (GtkObject *object); +static void ui_skinned_playstatus_realize (GtkWidget *widget); +static void ui_skinned_playstatus_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_playstatus_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_playstatus_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_skinned_playstatus_toggle_scaled (UiSkinnedPlaystatus *playstatus); + +static GtkWidgetClass *parent_class = NULL; +static guint playstatus_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_playstatus_get_type() { + static GType playstatus_type = 0; + if (!playstatus_type) { + static const GTypeInfo playstatus_info = { + sizeof (UiSkinnedPlaystatusClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_playstatus_class_init, + NULL, + NULL, + sizeof (UiSkinnedPlaystatus), + 0, + (GInstanceInitFunc) ui_skinned_playstatus_init, + }; + playstatus_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedPlaystatus_", &playstatus_info, 0); + } + + return playstatus_type; +} + +static void ui_skinned_playstatus_class_init(UiSkinnedPlaystatusClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_playstatus_destroy; + + widget_class->realize = ui_skinned_playstatus_realize; + widget_class->expose_event = ui_skinned_playstatus_expose; + widget_class->size_request = ui_skinned_playstatus_size_request; + widget_class->size_allocate = ui_skinned_playstatus_size_allocate; + + klass->scaled = ui_skinned_playstatus_toggle_scaled; + + playstatus_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedPlaystatusClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_skinned_playstatus_init(UiSkinnedPlaystatus *playstatus) { + playstatus->width = 11; + playstatus->height = 9; +} + +GtkWidget* ui_skinned_playstatus_new(GtkWidget *fixed, gint x, gint y) { + UiSkinnedPlaystatus *playstatus = g_object_new (ui_skinned_playstatus_get_type (), NULL); + + playstatus->x = x; + playstatus->y = y; + + playstatus->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(playstatus), playstatus->x, playstatus->y); + + return GTK_WIDGET(playstatus); +} + +static void ui_skinned_playstatus_destroy(GtkObject *object) { + UiSkinnedPlaystatus *playstatus; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (object)); + + playstatus = UI_SKINNED_PLAYSTATUS (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_playstatus_realize(GtkWidget *widget) { + UiSkinnedPlaystatus *playstatus; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + playstatus = UI_SKINNED_PLAYSTATUS(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_playstatus_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS(widget); + + requisition->width = playstatus->width*(playstatus->scaled ? cfg.scale_factor : 1); + requisition->height = playstatus->height*(playstatus->scaled ? cfg.scale_factor : 1); +} + +static void ui_skinned_playstatus_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (playstatus->scaled ? cfg.scale_factor : 1); + widget->allocation.y *= (playstatus->scaled ? cfg.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + playstatus->x = widget->allocation.x/(playstatus->scaled ? cfg.scale_factor : 1); + playstatus->y = widget->allocation.y/(playstatus->scaled ? cfg.scale_factor : 1); +} + +static gboolean ui_skinned_playstatus_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); + g_return_val_if_fail (playstatus->width > 0 && playstatus->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, playstatus->width, playstatus->height); + + if (playstatus->status == STATUS_STOP && playstatus->buffering == TRUE) + playstatus->buffering = FALSE; + if (playstatus->status == STATUS_PLAY && playstatus->buffering == TRUE) + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 39, 0, 0, 0, 3, playstatus->height); + else if (playstatus->status == STATUS_PLAY) + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 36, 0, 0, 0, 3, playstatus->height); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 27, 0, 0, 0, 2, playstatus->height); + switch (playstatus->status) { + case STATUS_STOP: + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 18, 0, 2, 0, 9, playstatus->height); + break; + case STATUS_PAUSE: + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 9, 0, 2, 0, 9, playstatus->height); + break; + case STATUS_PLAY: + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 1, 0, 3, 0, 8, playstatus->height); + break; + } + + ui_skinned_widget_draw(widget, obj, playstatus->width, playstatus->height, playstatus->scaled); + + g_object_unref(obj); + + return FALSE; +} + +static void ui_skinned_playstatus_toggle_scaled(UiSkinnedPlaystatus *playstatus) { + GtkWidget *widget = GTK_WIDGET (playstatus); + + playstatus->scaled = !playstatus->scaled; + gtk_widget_set_size_request(widget, playstatus->width*(playstatus->scaled ? cfg.scale_factor : 1), playstatus->height*(playstatus->scaled ? cfg.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(playstatus)); +} + +void ui_skinned_playstatus_set_status(GtkWidget *widget, PStatus status) { + g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget)); + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); + + playstatus->status = status; + gtk_widget_queue_draw(widget); +} + +void ui_skinned_playstatus_set_buffering(GtkWidget *widget, gboolean status) { + g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget)); + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); + + playstatus->buffering = status; + gtk_widget_queue_draw(widget); +} + +void ui_skinned_playstatus_set_size(GtkWidget *widget, gint width, gint height) { + g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget)); + UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); + + playstatus->width = width; + playstatus->height = height; + + gtk_widget_set_size_request(widget, width*(playstatus->scaled ? cfg.scale_factor : 1), height*(playstatus->scaled ? cfg.scale_factor : 1)); +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_playstatus.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_playstatus.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,71 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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_SKINNED_PLAYSTATUS_H +#define AUDACIOUS_UI_SKINNED_PLAYSTATUS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_PLAYSTATUS(obj) GTK_CHECK_CAST (obj, ui_skinned_playstatus_get_type (), UiSkinnedPlaystatus) +#define UI_SKINNED_PLAYSTATUS_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_playstatus_get_type (), UiSkinnedPlaystatusClass) +#define UI_SKINNED_IS_PLAYSTATUS(obj) GTK_CHECK_TYPE (obj, ui_skinned_playstatus_get_type ()) + +typedef struct _UiSkinnedPlaystatus UiSkinnedPlaystatus; +typedef struct _UiSkinnedPlaystatusClass UiSkinnedPlaystatusClass; + +typedef enum { + STATUS_STOP, STATUS_PAUSE, STATUS_PLAY +} PStatus; + +struct _UiSkinnedPlaystatus { + GtkWidget widget; + + gint x, y, width, height; + gboolean scaled; + PStatus status; + gboolean buffering; +}; + +struct _UiSkinnedPlaystatusClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSkinnedPlaystatus *menurow); +}; + +GtkWidget* ui_skinned_playstatus_new (GtkWidget *fixed, gint x, gint y); +GtkType ui_skinned_playstatus_get_type(void); +void ui_skinned_playstatus_set_status(GtkWidget *widget, PStatus status); +void ui_skinned_playstatus_set_buffering(GtkWidget *widget, gboolean status); +void ui_skinned_playstatus_set_size(GtkWidget *widget, gint width, gint height); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_PLAYSTATUS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_textbox.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_textbox.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,871 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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. + */ + +#include "ui_skinned_textbox.h" + +#include + +#include "main.h" +#include "util.h" +#include "strings.h" + +#define UI_SKINNED_TEXTBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_textbox_get_type(), UiSkinnedTextboxPrivate)) +typedef struct _UiSkinnedTextboxPrivate UiSkinnedTextboxPrivate; + +#define TEXTBOX_SCROLL_SMOOTH_TIMEOUT 30 +#define TEXTBOX_SCROLL_WAIT 80 + +enum { + CLICKED, + DOUBLE_CLICKED, + RIGHT_CLICKED, + DOUBLED, + REDRAW, + LAST_SIGNAL +}; + +struct _UiSkinnedTextboxPrivate { + SkinPixmapId skin_index; + gboolean scaled; + gboolean scroll_back; + gint nominal_y, nominal_height; + gint scroll_timeout; + gint font_ascent, font_descent; + PangoFontDescription *font; + gchar *fontname; + gchar *pixbuf_text; + gint skin_id; + gint drag_x, drag_off, offset; + gboolean is_scrollable, is_dragging; + gint pixbuf_width; + GdkPixbuf *pixbuf; + gboolean scroll_allowed, scroll_enabled; + gint scroll_dummy; + gint move_x, move_y; +}; + +static void ui_skinned_textbox_class_init (UiSkinnedTextboxClass *klass); +static void ui_skinned_textbox_init (UiSkinnedTextbox *textbox); +static void ui_skinned_textbox_destroy (GtkObject *object); +static void ui_skinned_textbox_realize (GtkWidget *widget); +static void ui_skinned_textbox_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_skinned_textbox_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_skinned_textbox_expose (GtkWidget *widget, GdkEventExpose *event); +static gboolean ui_skinned_textbox_button_press (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_textbox_button_release (GtkWidget *widget, GdkEventButton *event); +static gboolean ui_skinned_textbox_motion_notify (GtkWidget *widget, GdkEventMotion *event); +static void ui_skinned_textbox_toggle_scaled (UiSkinnedTextbox *textbox); +static void ui_skinned_textbox_redraw (UiSkinnedTextbox *textbox); +static gboolean ui_skinned_textbox_should_scroll (UiSkinnedTextbox *textbox); +static void textbox_generate_xfont_pixmap (UiSkinnedTextbox *textbox, const gchar *pixmaptext); +static gboolean textbox_scroll (gpointer data); +static void textbox_generate_pixmap (UiSkinnedTextbox *textbox); +static void textbox_handle_special_char (gchar *c, gint * x, gint * y); + +static GtkWidgetClass *parent_class = NULL; +static guint textbox_signals[LAST_SIGNAL] = { 0 }; + +GType ui_skinned_textbox_get_type() { + static GType textbox_type = 0; + if (!textbox_type) { + static const GTypeInfo textbox_info = { + sizeof (UiSkinnedTextboxClass), + NULL, + NULL, + (GClassInitFunc) ui_skinned_textbox_class_init, + NULL, + NULL, + sizeof (UiSkinnedTextbox), + 0, + (GInstanceInitFunc) ui_skinned_textbox_init, + }; + textbox_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedTextbox_", &textbox_info, 0); + } + + return textbox_type; +} + +static void ui_skinned_textbox_class_init(UiSkinnedTextboxClass *klass) { + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = G_OBJECT_CLASS(klass); + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_skinned_textbox_destroy; + + widget_class->realize = ui_skinned_textbox_realize; + widget_class->expose_event = ui_skinned_textbox_expose; + widget_class->size_request = ui_skinned_textbox_size_request; + widget_class->size_allocate = ui_skinned_textbox_size_allocate; + widget_class->button_press_event = ui_skinned_textbox_button_press; + widget_class->button_release_event = ui_skinned_textbox_button_release; + widget_class->motion_notify_event = ui_skinned_textbox_motion_notify; + + klass->clicked = NULL; + klass->double_clicked = NULL; + klass->right_clicked = NULL; + klass->scaled = ui_skinned_textbox_toggle_scaled; + klass->redraw = ui_skinned_textbox_redraw; + + textbox_signals[CLICKED] = + g_signal_new ("clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedTextboxClass, clicked), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + textbox_signals[DOUBLE_CLICKED] = + g_signal_new ("double-clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedTextboxClass, double_clicked), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + textbox_signals[RIGHT_CLICKED] = + g_signal_new ("right-clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedTextboxClass, right_clicked), NULL, NULL, + gtk_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + + textbox_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedTextboxClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + textbox_signals[REDRAW] = + g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSkinnedTextboxClass, redraw), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (gobject_class, sizeof (UiSkinnedTextboxPrivate)); +} + +static void ui_skinned_textbox_init(UiSkinnedTextbox *textbox) { + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + priv->move_x = 0; + priv->move_y = 0; +} + +GtkWidget* ui_skinned_textbox_new(GtkWidget *fixed, gint x, gint y, gint w, gboolean allow_scroll, SkinPixmapId si) { + UiSkinnedTextbox *textbox = g_object_new (ui_skinned_textbox_get_type (), NULL); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + textbox->height = aud_active_skin->properties.textbox_bitmap_font_height; + textbox->x = x; + textbox->y = y; + textbox->text = g_strdup(""); + textbox->width = w; + priv->scroll_allowed = allow_scroll; + priv->scroll_enabled = TRUE; + priv->skin_index = si; + priv->nominal_y = y; + priv->nominal_height = textbox->height; + priv->scroll_timeout = 0; + priv->scroll_dummy = 0; + + priv->scaled = FALSE; + + gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(textbox), textbox->x, textbox->y); + + return GTK_WIDGET(textbox); +} + +static void ui_skinned_textbox_destroy(GtkObject *object) { + UiSkinnedTextbox *textbox; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_SKINNED_IS_TEXTBOX (object)); + + textbox = UI_SKINNED_TEXTBOX (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_skinned_textbox_realize(GtkWidget *widget) { + UiSkinnedTextbox *textbox; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_SKINNED_IS_TEXTBOX(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + textbox = UI_SKINNED_TEXTBOX(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK; + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + + widget->style = gtk_style_attach(widget->style, widget->window); + + gdk_window_set_user_data(widget->window, widget); +} + +static void ui_skinned_textbox_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + requisition->width = textbox->width*(priv->scaled ? cfg.scale_factor : 1); + requisition->height = textbox->height*(priv->scaled ? cfg.scale_factor : 1 ); +} + +static void ui_skinned_textbox_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + widget->allocation = *allocation; + widget->allocation.x *= (priv->scaled ? cfg.scale_factor : 1); + widget->allocation.y *= (priv->scaled ? cfg.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + + if (textbox->x + priv->move_x - widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1) <3); + priv->move_x = 0; + if (textbox->y + priv->move_y - widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1) <3); + priv->move_y = 0; + textbox->x = widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1); + textbox->y = widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1); + + if (textbox->width - (guint) (widget->allocation.width / (priv->scaled ? cfg.scale_factor : 1)) > 2) { + textbox->width = (guint) (widget->allocation.width / (priv->scaled ? cfg.scale_factor : 1)); + if (priv->pixbuf_text) g_free(priv->pixbuf_text); + priv->pixbuf_text = NULL; + priv->offset = 0; + gtk_widget_set_size_request(widget, textbox->width, textbox->height); + gtk_widget_queue_draw(GTK_WIDGET(textbox)); + } +} + +static gboolean ui_skinned_textbox_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_TEXTBOX (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + g_return_val_if_fail (textbox->width > 0 && textbox->height > 0, FALSE); + + GdkPixbuf *obj = NULL; + gint cw; + + if (textbox->text && (!priv->pixbuf_text || strcmp(textbox->text, priv->pixbuf_text))) + textbox_generate_pixmap(textbox); + + if (priv->pixbuf) { + if (skin_get_id() != priv->skin_id) { + priv->skin_id = skin_get_id(); + textbox_generate_pixmap(textbox); + } + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, textbox->width, textbox->height); + + if (cfg.twoway_scroll) { // twoway scroll + cw = priv->pixbuf_width - priv->offset; + if (cw > textbox->width) + cw = textbox->width; + gdk_pixbuf_copy_area(priv->pixbuf, priv->offset, 0, cw, textbox->height, obj, 0, 0); + if (cw < textbox->width) + gdk_pixbuf_copy_area(priv->pixbuf, 0, 0, textbox->width - cw, textbox->height, + obj, textbox->width - cw, textbox->height); + } else { // oneway scroll + int cw1, cw2; + + if (priv->offset >= priv->pixbuf_width) + priv->offset = 0; + + if (priv->pixbuf_width - priv->offset > textbox->width) { // case1 + cw1 = textbox->width; + gdk_pixbuf_copy_area(priv->pixbuf, priv->offset, 0, cw1, textbox->height, + obj, 0, 0); + } else { // case 2 + cw1 = priv->pixbuf_width - priv->offset; + gdk_pixbuf_copy_area(priv->pixbuf, priv->offset, 0, cw1, textbox->height, obj, 0, 0); + cw2 = textbox->width - cw1; + gdk_pixbuf_copy_area(priv->pixbuf, 0, 0, cw2, textbox->height, obj, cw1, 0); + } + } + + ui_skinned_widget_draw(widget, obj, textbox->width, textbox->height, priv->scaled); + + g_object_unref(obj); + } + + return FALSE; +} + +static gboolean ui_skinned_textbox_button_press(GtkWidget *widget, GdkEventButton *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_TEXTBOX (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (event->type == GDK_BUTTON_PRESS) { + textbox = UI_SKINNED_TEXTBOX(widget); + if (event->button == 3 && !g_signal_has_handler_pending(widget, textbox_signals[RIGHT_CLICKED], 0, TRUE)) + return FALSE; + else if (event->button == 1) { + if (priv->scroll_allowed) { + if ((priv->pixbuf_width > textbox->width) && priv->is_scrollable) { + priv->is_dragging = TRUE; + priv->drag_off = priv->offset; + priv->drag_x = event->x; + } + } else + g_signal_emit(widget, textbox_signals[CLICKED], 0); + + } else if (event->button == 3) { + g_signal_emit(widget, textbox_signals[RIGHT_CLICKED], 0, event); + } else + priv->is_dragging = FALSE; + } else if (event->type == GDK_2BUTTON_PRESS) { + if (event->button == 1) { + if (g_signal_has_handler_pending(widget, textbox_signals[DOUBLE_CLICKED], 0, TRUE)) + g_signal_emit(widget, textbox_signals[DOUBLE_CLICKED], 0); + else + return FALSE; + } + } + + return TRUE; +} + +static gboolean ui_skinned_textbox_button_release(GtkWidget *widget, GdkEventButton *event) { + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(widget); + + if (event->button == 1) { + priv->is_dragging = FALSE; + } + + return TRUE; +} + +static gboolean ui_skinned_textbox_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_SKINNED_IS_TEXTBOX (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(widget); + + if (priv->is_dragging) { + if (priv->scroll_allowed && + priv->pixbuf_width > textbox->width) { + priv->offset = priv->drag_off - (event->x - priv->drag_x); + + while (priv->offset < 0) + priv->offset = 0; + + while (priv->offset > (priv->pixbuf_width - textbox->width)) + priv->offset = (priv->pixbuf_width - textbox->width); + + gtk_widget_queue_draw(widget); + } + } + + return TRUE; +} + +static void ui_skinned_textbox_toggle_scaled(UiSkinnedTextbox *textbox) { + GtkWidget *widget = GTK_WIDGET (textbox); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + priv->scaled = !priv->scaled; + + gtk_widget_set_size_request(widget, textbox->width*(priv->scaled ? cfg.scale_factor : 1 ), + textbox->height*(priv->scaled ? cfg.scale_factor : 1 )); + + gtk_widget_queue_draw(GTK_WIDGET(textbox)); +} + +static void ui_skinned_textbox_redraw(UiSkinnedTextbox *textbox) { + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (priv->move_x || priv->move_y) + gtk_fixed_move(GTK_FIXED(gtk_widget_get_parent(GTK_WIDGET(textbox))), GTK_WIDGET(textbox), + textbox->x+priv->move_x, textbox->y+priv->move_y); + + gtk_widget_queue_draw(GTK_WIDGET(textbox)); +} + +static gboolean ui_skinned_textbox_should_scroll(UiSkinnedTextbox *textbox) { + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (!priv->scroll_allowed) + return FALSE; + + if (priv->font) { + gint width; + text_get_extents(priv->fontname, textbox->text, &width, NULL, NULL, NULL); + + if (width <= textbox->width) + return FALSE; + else + return TRUE; + } + + if (g_utf8_strlen(textbox->text, -1) * aud_active_skin->properties.textbox_bitmap_font_width > textbox->width) + return TRUE; + + return FALSE; +} + +void ui_skinned_textbox_set_xfont(GtkWidget *widget, gboolean use_xfont, const gchar * fontname) { + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + gint ascent, descent; + + g_return_if_fail(textbox != NULL); + + if (priv->font) { + pango_font_description_free(priv->font); + priv->font = NULL; + } + + textbox->y = priv->nominal_y; + textbox->height = priv->nominal_height; + + /* Make sure the pixmap is regenerated */ + if (priv->pixbuf_text) { + g_free(priv->pixbuf_text); + priv->pixbuf_text = NULL; + } + + if (!use_xfont || strlen(fontname) == 0) + return; + + priv->font = pango_font_description_from_string(fontname); + priv->fontname = g_strdup(fontname); + + text_get_extents(fontname, + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz ", + NULL, NULL, &ascent, &descent); + priv->font_ascent = ascent; + priv->font_descent = descent; + + + if (priv->font == NULL) + return; + + textbox->height = priv->font_ascent; + if (textbox->height > priv->nominal_height) + textbox->y -= (textbox->height - priv->nominal_height) / 2; + else + textbox->height = priv->nominal_height; +} + +void ui_skinned_textbox_set_text(GtkWidget *widget, const gchar *text) { + g_return_if_fail(text != NULL); + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (!strcmp(textbox->text, text)) + return; + if (textbox->text) + g_free(textbox->text); + + textbox->text = str_assert_utf8(text); + priv->scroll_back = FALSE; + gtk_widget_queue_draw(GTK_WIDGET(textbox)); +} + +static void textbox_generate_xfont_pixmap(UiSkinnedTextbox *textbox, const gchar *pixmaptext) { + /* FIXME: should operate directly on priv->pixbuf, it shouldn't use pixmap */ + gint length, i; + GdkGC *gc, *maskgc; + GdkColor *c, pattern; + GdkBitmap *mask; + PangoLayout *layout; + gint width; + GdkPixmap *pixmap; + + g_return_if_fail(textbox != NULL); + g_return_if_fail(pixmaptext != NULL); + g_return_if_fail(textbox->height > 0); + + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + length = g_utf8_strlen(pixmaptext, -1); + + text_get_extents(priv->fontname, pixmaptext, &width, NULL, NULL, NULL); + + priv->pixbuf_width = MAX(width, textbox->width); + pixmap = gdk_pixmap_new(mainwin->window, priv->pixbuf_width, + textbox->height, + gdk_rgb_get_visual()->depth); + gc = gdk_gc_new(pixmap); + c = skin_get_color(aud_active_skin, SKIN_TEXTBG); + for (i = 0; i < textbox->height; i++) { + gdk_gc_set_foreground(gc, &c[6 * i / textbox->height]); + gdk_draw_line(pixmap, gc, 0, i, priv->pixbuf_width, i); + } + + mask = gdk_pixmap_new(mainwin->window, priv->pixbuf_width, textbox->height, 1); + maskgc = gdk_gc_new(mask); + pattern.pixel = 0; + gdk_gc_set_foreground(maskgc, &pattern); + + gdk_draw_rectangle(mask, maskgc, TRUE, 0, 0, priv->pixbuf_width, textbox->height); + pattern.pixel = 1; + gdk_gc_set_foreground(maskgc, &pattern); + + gdk_gc_set_foreground(gc, skin_get_color(aud_active_skin, SKIN_TEXTFG)); + + layout = gtk_widget_create_pango_layout(mainwin, pixmaptext); + pango_layout_set_font_description(layout, priv->font); + + gdk_draw_layout(pixmap, gc, 0, (priv->font_descent / 2), layout); + g_object_unref(layout); + + g_object_unref(maskgc); + + gdk_gc_set_clip_mask(gc, mask); + c = skin_get_color(aud_active_skin, SKIN_TEXTFG); + for (i = 0; i < textbox->height; i++) { + gdk_gc_set_foreground(gc, &c[6 * i / textbox->height]); + gdk_draw_line(pixmap, gc, 0, i, priv->pixbuf_width, i); + } + priv->pixbuf = gdk_pixbuf_get_from_drawable(NULL, pixmap, gdk_colormap_get_system(), 0, 0, 0, 0, priv->pixbuf_width, textbox->height); + g_object_unref(mask); + g_object_unref(gc); +} + +static gboolean textbox_scroll(gpointer data) { + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(data); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (!priv->is_dragging) { + if (priv->scroll_dummy < TEXTBOX_SCROLL_WAIT) + priv->scroll_dummy++; + else { + if(cfg.twoway_scroll) { + if (priv->scroll_back) + priv->offset -= 1; + else + priv->offset += 1; + + if (priv->offset >= (priv->pixbuf_width - textbox->width)) { + priv->scroll_back = TRUE; + priv->scroll_dummy = 0; + priv->offset = priv->pixbuf_width - textbox->width; + } + if (priv->offset <= 0) { + priv->scroll_back = FALSE; + priv->scroll_dummy = 0; + priv->offset = 0; + } + } + else { // oneway scroll + priv->scroll_back = FALSE; + priv->offset += 1; + } + gtk_widget_queue_draw(GTK_WIDGET(textbox)); + } + } + return TRUE; +} + +static void textbox_generate_pixmap(UiSkinnedTextbox *textbox) { + gint length, i, x, y, wl; + gchar *pixmaptext; + gchar *tmp, *stxt; + + g_return_if_fail(textbox != NULL); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + if (priv->pixbuf) { + g_object_unref(priv->pixbuf); + priv->pixbuf = NULL; + } + + /* + * Don't reset the offset if only text after the last '(' has + * changed. This is a hack to avoid visual noice on vbr files + * where we guess the length. + */ + if (!(priv->pixbuf_text && strrchr(textbox->text, '(') && + !strncmp(priv->pixbuf_text, textbox->text, + strrchr(textbox->text, '(') - textbox->text))) + priv->offset = 0; + + g_free(priv->pixbuf_text); + priv->pixbuf_text = g_strdup(textbox->text); + + /* + * wl is the number of (partial) letters visible. Only makes + * sense when using skinned font. + */ + wl = textbox->width / 5; + if (wl * 5 != textbox->width) + wl++; + + length = g_utf8_strlen(textbox->text, -1); + + priv->is_scrollable = FALSE; + + priv->is_scrollable = ui_skinned_textbox_should_scroll(textbox); + + if (priv->is_scrollable) { + if(!cfg.twoway_scroll) { + pixmaptext = g_strdup_printf("%s *** ", priv->pixbuf_text); + length += 5; + } else + pixmaptext = g_strdup(priv->pixbuf_text); + } else + if (!priv->font && length <= wl) { + gint pad = wl - length; + gchar *padchars = g_strnfill(pad, ' '); + + pixmaptext = g_strconcat(priv->pixbuf_text, padchars, NULL); + g_free(padchars); + length += pad; + } else + pixmaptext = g_strdup(priv->pixbuf_text); + + if (priv->is_scrollable) { + if (priv->scroll_enabled && !priv->scroll_timeout) { + gint tag; + tag = TEXTBOX_SCROLL_SMOOTH_TIMEOUT; + priv->scroll_timeout = g_timeout_add(tag, textbox_scroll, textbox); + } + } else { + if (priv->scroll_timeout) { + g_source_remove(priv->scroll_timeout); + priv->scroll_timeout = 0; + } + priv->offset = 0; + } + + if (priv->font) { + textbox_generate_xfont_pixmap(textbox, pixmaptext); + g_free(pixmaptext); + return; + } + + priv->pixbuf_width = length * aud_active_skin->properties.textbox_bitmap_font_width; + priv->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, + priv->pixbuf_width, aud_active_skin->properties.textbox_bitmap_font_height); + + for (tmp = stxt = g_utf8_strup(pixmaptext, -1), i = 0; + tmp != NULL && i < length; i++, tmp = g_utf8_next_char(tmp)) { + gchar c = *tmp; + x = y = -1; + if (c >= 'A' && c <= 'Z') { + x = aud_active_skin->properties.textbox_bitmap_font_width * (c - 'A'); + y = 0; + } + else if (c >= '0' && c <= '9') { + x = aud_active_skin->properties.textbox_bitmap_font_width * (c - '0'); + y = aud_active_skin->properties.textbox_bitmap_font_height; + } + else + textbox_handle_special_char(tmp, &x, &y); + + skin_draw_pixbuf(GTK_WIDGET(textbox), aud_active_skin, + priv->pixbuf, priv->skin_index, + x, y, i * aud_active_skin->properties.textbox_bitmap_font_width, 0, + aud_active_skin->properties.textbox_bitmap_font_width, + aud_active_skin->properties.textbox_bitmap_font_height); + } + g_free(stxt); + g_free(pixmaptext); +} + +void ui_skinned_textbox_set_scroll(GtkWidget *widget, gboolean scroll) { + g_return_if_fail(widget != NULL); + UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(widget); + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); + + priv->scroll_enabled = scroll; + if (priv->scroll_enabled && priv->is_scrollable && priv->scroll_allowed) { + gint tag; + tag = TEXTBOX_SCROLL_SMOOTH_TIMEOUT; + if (priv->scroll_timeout) { + g_source_remove(priv->scroll_timeout); + priv->scroll_timeout = 0; + } + priv->scroll_timeout = g_timeout_add(tag, textbox_scroll, textbox); + + } else { + + if (priv->scroll_timeout) { + g_source_remove(priv->scroll_timeout); + priv->scroll_timeout = 0; + } + + priv->offset = 0; + gtk_widget_queue_draw(GTK_WIDGET(textbox)); + } +} + +static void textbox_handle_special_char(gchar *c, gint * x, gint * y) { + gint tx, ty; + + switch (*c) { + case '"': + tx = 26; + ty = 0; + break; + case '\r': + tx = 10; + ty = 1; + break; + case ':': + case ';': + tx = 12; + ty = 1; + break; + case '(': + tx = 13; + ty = 1; + break; + case ')': + tx = 14; + ty = 1; + break; + case '-': + tx = 15; + ty = 1; + break; + case '`': + case '\'': + tx = 16; + ty = 1; + break; + case '!': + tx = 17; + ty = 1; + break; + case '_': + tx = 18; + ty = 1; + break; + case '+': + tx = 19; + ty = 1; + break; + case '\\': + tx = 20; + ty = 1; + break; + case '/': + tx = 21; + ty = 1; + break; + case '[': + tx = 22; + ty = 1; + break; + case ']': + tx = 23; + ty = 1; + break; + case '^': + tx = 24; + ty = 1; + break; + case '&': + tx = 25; + ty = 1; + break; + case '%': + tx = 26; + ty = 1; + break; + case '.': + case ',': + tx = 27; + ty = 1; + break; + case '=': + tx = 28; + ty = 1; + break; + case '$': + tx = 29; + ty = 1; + break; + case '#': + tx = 30; + ty = 1; + break; + case '?': + tx = 3; + ty = 2; + break; + case '*': + tx = 4; + ty = 2; + break; + default: + tx = 29; + ty = 0; + break; + } + + const gchar *change[] = {"Ą", "A", "Ę", "E", "Ć", "C", "Ł", "L", "Ó", "O", "Ś", "S", "Ż", "Z", "Ź", "Z", + "Ń", "N", "Ü", "U", NULL}; + int i; + for (i = 0; change[i]; i+=2) { + if (!strncmp(c, change[i], strlen(change[i]))) { + tx = (*change[i+1] - 'A'); + break; + } + } + + /* those are commonly included into skins */ + if (!strncmp(c, "Å", strlen("Å"))) { + tx = 0; + ty = 2; + } else if (!strncmp(c, "Ö", strlen("Ö"))) { + tx = 1; + ty = 2; + } else if (!strncmp(c, "Ä", strlen("Ä"))) { + tx = 2; + ty = 2; + } + + *x = tx * aud_active_skin->properties.textbox_bitmap_font_width; + *y = ty * aud_active_skin->properties.textbox_bitmap_font_height; +} + +void ui_skinned_textbox_move_relative(GtkWidget *widget, gint x, gint y) { + UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(widget); + priv->move_x += x; + priv->move_y += y; +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_textbox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_textbox.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,71 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Tomasz Moń + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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_SKINNED_TEXTBOX_H +#define AUDACIOUS_UI_SKINNED_TEXTBOX_H + +#include +#include "ui_skin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SKINNED_TEXTBOX(obj) GTK_CHECK_CAST (obj, ui_skinned_textbox_get_type (), UiSkinnedTextbox) +#define UI_SKINNED_TEXTBOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_textbox_get_type (), UiSkinnedTextboxClass) +#define UI_SKINNED_IS_TEXTBOX(obj) GTK_CHECK_TYPE (obj, ui_skinned_textbox_get_type ()) + +typedef struct _UiSkinnedTextbox UiSkinnedTextbox; +typedef struct _UiSkinnedTextboxClass UiSkinnedTextboxClass; + +struct _UiSkinnedTextbox { + GtkWidget widget; + + gint x, y, width, height; + gchar *text; +}; + +struct _UiSkinnedTextboxClass { + GtkWidgetClass parent_class; + void (* clicked) (UiSkinnedTextbox *textbox); + void (* double_clicked) (UiSkinnedTextbox *textbox); + void (* right_clicked) (UiSkinnedTextbox *textbox); + void (* scaled) (UiSkinnedTextbox *textbox); + void (* redraw) (UiSkinnedTextbox *textbox); +}; + +GtkWidget* ui_skinned_textbox_new (GtkWidget *fixed, gint x, gint y, gint w, gboolean allow_scroll, SkinPixmapId si); +GtkType ui_skinned_textbox_get_type(void); +void ui_skinned_textbox_set_xfont(GtkWidget *widget, gboolean use_xfont, const gchar * fontname); +void ui_skinned_textbox_set_text(GtkWidget *widget, const gchar *text); +void ui_skinned_textbox_set_scroll(GtkWidget *widget, gboolean scroll); +void ui_skinned_textbox_move_relative(GtkWidget *widget, gint x, gint y); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SKINNED_TEXTBOX_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_window.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_window.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,286 @@ +/* + * Audacious: A cross-platform multimedia player + * Copyright (c) 2007 William Pitcock + * + * 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 "platform/smartinclude.h" +#include "ui_skin.h" + +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "ui_dock.h" +#include "ui_skinned_window.h" +#include "ui_playlist.h" + +static void ui_skinned_window_class_init(SkinnedWindowClass *klass); +static void ui_skinned_window_init(GtkWidget *widget); +static GtkWindowClass *parent = NULL; + +GType +ui_skinned_window_get_type(void) +{ + static GType window_type = 0; + + if (!window_type) + { + static const GTypeInfo window_info = + { + sizeof (SkinnedWindowClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ui_skinned_window_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (SkinnedWindow), + 0, /* n_preallocs */ + (GInstanceInitFunc) ui_skinned_window_init + }; + + window_type = + g_type_register_static (GTK_TYPE_WINDOW, "SkinnedWindow_", + &window_info, 0); + } + + return window_type; +} + +static void +ui_skinned_window_map(GtkWidget *widget) +{ + (* GTK_WIDGET_CLASS (parent)->map) (widget); + + SkinnedWindow *window = SKINNED_WINDOW(widget); + if (window->type == WINDOW_MAIN) + gtk_widget_shape_combine_mask(widget, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + cfg.player_shaded), 0, 0); + else if (window->type == WINDOW_EQ) + gtk_widget_shape_combine_mask(widget, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + cfg.equalizer_shaded), 0, 0); + + gtk_window_set_keep_above(GTK_WINDOW(widget), cfg.always_on_top); +} + +static gboolean +ui_skinned_window_motion_notify_event(GtkWidget *widget, + GdkEventMotion *event) +{ + if (dock_is_moving(GTK_WINDOW(widget))) + dock_move_motion(GTK_WINDOW(widget), event); + + return FALSE; +} + +static gboolean ui_skinned_window_focus_in(GtkWidget *widget, GdkEventFocus *focus) { + gboolean val = GTK_WIDGET_CLASS (parent)->focus_in_event (widget, focus); + gtk_widget_queue_draw(widget); + return val; +} + +static gboolean ui_skinned_window_focus_out(GtkWidget *widget, GdkEventFocus *focus) { + gboolean val = GTK_WIDGET_CLASS (parent)->focus_out_event (widget, focus); + gtk_widget_queue_draw(widget); + return val; +} + +static gboolean ui_skinned_window_button_press(GtkWidget *widget, GdkEventButton *event) { + if (event->button == 1 && event->type == GDK_BUTTON_PRESS && + (cfg.easy_move || cfg.equalizer_shaded || (event->y / cfg.scale_factor) < 14)) { + dock_move_press(get_dock_window_list(), GTK_WINDOW(widget), + event, SKINNED_WINDOW(widget)->type == WINDOW_MAIN ? TRUE : FALSE); + } + + return TRUE; +} + +static gboolean ui_skinned_window_button_release(GtkWidget *widget, GdkEventButton *event) { + if (dock_is_moving(GTK_WINDOW(widget))) + dock_move_release(GTK_WINDOW(widget)); + + return TRUE; +} + +static gboolean ui_skinned_window_expose(GtkWidget *widget, GdkEventExpose *event) { + SkinnedWindow *window = SKINNED_WINDOW(widget); + + GdkPixbuf *obj = NULL; + + gint width = 0, height = 0; + switch (window->type) { + case WINDOW_MAIN: + width = aud_active_skin->properties.mainwin_width; + height = aud_active_skin->properties.mainwin_height; + break; + case WINDOW_EQ: + width = 275 * (cfg.scaled ? cfg.scale_factor : 1); + height = 116 * (cfg.scaled ? cfg.scale_factor : 1) ; + break; + case WINDOW_PLAYLIST: + width = playlistwin_get_width(); + height = cfg.playlist_height; + break; + default: + return FALSE; + } + obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); + + gboolean focus = gtk_window_has_toplevel_focus(GTK_WINDOW(widget)); + + switch (window->type) { + case WINDOW_MAIN: + skin_draw_pixbuf(widget, aud_active_skin, obj,SKIN_MAIN, 0, 0, 0, 0, width, height); + skin_draw_mainwin_titlebar(aud_active_skin, obj, cfg.player_shaded, focus || !cfg.dim_titlebar); + break; + case WINDOW_EQ: + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQMAIN, 0, 0, 0, 0, width, height); + if (focus || !cfg.dim_titlebar) { + if (!cfg.equalizer_shaded) + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQMAIN, 0, 134, 0, 0, width, 14); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQ_EX, 0, 0, 0, 0, width, 14); + } else { + if (!cfg.equalizer_shaded) + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQMAIN, 0, 149, 0, 0, width, 14); + else + skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQ_EX, 0, 15, 0, 0, width, 14); + } + break; + case WINDOW_PLAYLIST: + focus |= !cfg.dim_titlebar; + if (cfg.playlist_shaded) { + skin_draw_playlistwin_shaded(aud_active_skin, obj, width, focus); + } else { + skin_draw_playlistwin_frame(aud_active_skin, obj, width, cfg.playlist_height, focus); + } + break; + } + + ui_skinned_widget_draw(GTK_WIDGET(window), obj, width, height, + window->type != WINDOW_PLAYLIST && cfg.scaled); + + g_object_unref(obj); + + return FALSE; +} + +static void +ui_skinned_window_class_init(SkinnedWindowClass *klass) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) klass; + + parent = gtk_type_class(gtk_window_get_type()); + + widget_class->motion_notify_event = ui_skinned_window_motion_notify_event; + widget_class->expose_event = ui_skinned_window_expose; + widget_class->focus_in_event = ui_skinned_window_focus_in; + widget_class->focus_out_event = ui_skinned_window_focus_out; + widget_class->button_press_event = ui_skinned_window_button_press; + widget_class->button_release_event = ui_skinned_window_button_release; + widget_class->map = ui_skinned_window_map; +} + +void +ui_skinned_window_hide(SkinnedWindow *window) +{ + g_return_if_fail(SKINNED_CHECK_WINDOW(window)); + + gtk_window_get_position(GTK_WINDOW(window), &window->x, &window->y); + gtk_widget_hide(GTK_WIDGET(window)); +} + +void +ui_skinned_window_show(SkinnedWindow *window) +{ + g_return_if_fail(SKINNED_CHECK_WINDOW(window)); + + gtk_window_move(GTK_WINDOW(window), window->x, window->y); + gtk_widget_show_all(GTK_WIDGET(window)); +} + +static void +ui_skinned_window_init(GtkWidget *widget) +{ + SkinnedWindow *window; + window = SKINNED_WINDOW(widget); + window->x = -1; + window->y = -1; +} + +GtkWidget * +ui_skinned_window_new(const gchar *wmclass_name) +{ + GtkWidget *widget = g_object_new(ui_skinned_window_get_type(), NULL); + GtkWindow *window = GTK_WINDOW(widget); + + window->type = SKINNED_WINDOW_TYPE; + + if (wmclass_name) + gtk_window_set_wmclass(GTK_WINDOW(widget), wmclass_name, "Audacious"); + + gtk_widget_add_events(GTK_WIDGET(widget), + GDK_FOCUS_CHANGE_MASK | GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_SCROLL_MASK | GDK_KEY_PRESS_MASK | + GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK); + gtk_widget_realize(GTK_WIDGET(widget)); + + set_dock_window_list(dock_window_set_decorated(get_dock_window_list(), + GTK_WINDOW(widget), + cfg.show_wm_decorations)); + gtk_widget_set_app_paintable(GTK_WIDGET(widget), TRUE); + gdk_window_set_back_pixmap(widget->window, NULL, FALSE); + gtk_widget_shape_combine_mask(widget, NULL, 0, 0); + + if (!strcmp(wmclass_name, "player")) + SKINNED_WINDOW(widget)->type = WINDOW_MAIN; + if (!strcmp(wmclass_name, "equalizer")) + SKINNED_WINDOW(widget)->type = WINDOW_EQ; + if (!strcmp(wmclass_name, "playlist")) + SKINNED_WINDOW(widget)->type = WINDOW_PLAYLIST; + + /* 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 */ + SKINNED_WINDOW(widget)->fixed = gtk_fixed_new(); + gtk_container_add(GTK_CONTAINER(widget), GTK_WIDGET(SKINNED_WINDOW(widget)->fixed)); + return widget; +} + +void ui_skinned_window_draw_all(GtkWidget *widget) { + if (SKINNED_WINDOW(widget)->type == WINDOW_MAIN) + mainwin_refresh_hints(); + + gtk_widget_queue_draw(widget); + GList *iter; + for (iter = GTK_FIXED (SKINNED_WINDOW(widget)->fixed)->children; iter; iter = g_list_next (iter)) { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + GtkWidget *child = child_data->widget; + gtk_widget_queue_draw(child); + } +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinned_window.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinned_window.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Audacious: A cross-platform multimedia player + * Copyright (c) 2007 William Pitcock + * + * 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_SKINNED_WINDOW_H +#define AUDACIOUS_UI_SKINNED_WINDOW_H + +#define SKINNED_WINDOW(obj) GTK_CHECK_CAST (obj, ui_skinned_window_get_type (), SkinnedWindow) +#define SKINNED_WINDOW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_window_get_type (), SkinnedWindowClass) +#define SKINNED_CHECK_WINDOW(obj) GTK_CHECK_TYPE (obj, ui_skinned_window_get_type ()) +#define SKINNED_TYPE_WINDOW (ui_skinned_window_get_type()) + +#ifdef GDK_WINDOWING_QUARTZ +# define SKINNED_WINDOW_TYPE GTK_WINDOW_POPUP +#else +# define SKINNED_WINDOW_TYPE GTK_WINDOW_TOPLEVEL +#endif + +enum { + WINDOW_MAIN, + WINDOW_EQ, + WINDOW_PLAYLIST +}; + +typedef struct _SkinnedWindow SkinnedWindow; +typedef struct _SkinnedWindowClass SkinnedWindowClass; + +struct _SkinnedWindow +{ + GtkWindow window; + + GtkWidget *canvas; + gint x,y; + + gint type; + GtkWidget *fixed; +}; + +struct _SkinnedWindowClass +{ + GtkWindowClass parent_class; +}; + +extern GType ui_skinned_window_get_type(void); +extern GtkWidget *ui_skinned_window_new(const gchar *wmclass_name); +extern void ui_skinned_window_draw_all(GtkWidget *widget); + +#endif /* AUDACIOUS_UI_SKINNED_WINDOW_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinselector.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinselector.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,404 @@ +/* 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 "ui_skinselector.h" + +#include +#include +#include + +#include "platform/smartinclude.h" + +#include +#include + +#include "main.h" +#include "ui_skin.h" +#include "util.h" + +#define EXTENSION_TARGETS 7 + +static gchar *ext_targets[EXTENSION_TARGETS] = { "bmp", "xpm", "png", "svg", + "gif", "jpg", "jpeg" }; + +#define THUMBNAIL_WIDTH 90 +#define THUMBNAIL_HEIGHT 40 + + +enum SkinViewCols { + SKIN_VIEW_COL_PREVIEW, + SKIN_VIEW_COL_FORMATTEDNAME, + SKIN_VIEW_COL_NAME, + SKIN_VIEW_N_COLS +}; + + +GList *skinlist = NULL; + + + +static gchar * +get_thumbnail_filename(const gchar * path) +{ + gchar *basename, *pngname, *thumbname; + + g_return_val_if_fail(path != NULL, NULL); + + basename = g_path_get_basename(path); + pngname = g_strconcat(basename, ".png", NULL); + + thumbname = g_build_filename(aud_paths[BMP_PATH_SKIN_THUMB_DIR], + pngname, NULL); + + g_free(basename); + g_free(pngname); + + return thumbname; +} + + +static GdkPixbuf * +skin_get_preview(const gchar * path) +{ + GdkPixbuf *preview = NULL; + gchar *dec_path, *preview_path; + gboolean is_archive = FALSE; + gint i = 0; + gchar buf[60]; /* gives us lots of room */ + + if (file_is_archive(path)) + { + if (!(dec_path = archive_decompress(path))) + return NULL; + + is_archive = TRUE; + } + else + { + dec_path = g_strdup(path); + } + + for (i = 0; i < EXTENSION_TARGETS; i++) + { + sprintf(buf, "main.%s", ext_targets[i]); + + if ((preview_path = find_path_recursively(dec_path, buf)) != NULL) + break; + } + + if (preview_path) + { + preview = gdk_pixbuf_new_from_file(preview_path, NULL); + g_free(preview_path); + } + + if (is_archive) + del_directory(dec_path); + + g_free(dec_path); + + return preview; +} + + +static GdkPixbuf * +skin_get_thumbnail(const gchar * path) +{ + GdkPixbuf *scaled = NULL; + GdkPixbuf *preview; + gchar *thumbname; + + g_return_val_if_fail(path != NULL, NULL); + + if (g_str_has_suffix(path, "thumbs")) + return NULL; + + thumbname = get_thumbnail_filename(path); + + if (g_file_test(thumbname, G_FILE_TEST_EXISTS)) { + scaled = gdk_pixbuf_new_from_file(thumbname, NULL); + g_free(thumbname); + return scaled; + } + + if (!(preview = skin_get_preview(path))) { + g_free(thumbname); + return NULL; + } + + scaled = gdk_pixbuf_scale_simple(preview, + THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, + GDK_INTERP_BILINEAR); + g_object_unref(preview); + + gdk_pixbuf_save(scaled, thumbname, "png", NULL, NULL); + g_free(thumbname); + + return scaled; +} + +static void +skinlist_add(const gchar * filename) +{ + SkinNode *node; + gchar *basename; + + g_return_if_fail(filename != NULL); + + node = g_slice_new0(SkinNode); + node->path = g_strdup(filename); + + basename = g_path_get_basename(filename); + + if (file_is_archive(filename)) { + node->name = archive_basename(basename); + node->desc = _("Archived Winamp 2.x skin"); + g_free(basename); + } + else { + node->name = basename; + node->desc = _("Unarchived Winamp 2.x skin"); + } + + skinlist = g_list_prepend(skinlist, node); +} + +static gboolean +scan_skindir_func(const gchar * path, const gchar * basename, gpointer data) +{ + if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) { + if (file_is_archive(path)) { + skinlist_add(path); + } + } + else if (g_file_test(path, G_FILE_TEST_IS_DIR)) { + skinlist_add(path); + } + + return FALSE; +} + +static void +scan_skindir(const gchar * path) +{ + GError *error = NULL; + + g_return_if_fail(path != NULL); + + if (path[0] == '.') + return; + + if (!dir_foreach(path, scan_skindir_func, NULL, &error)) { + g_warning("Failed to open directory (%s): %s", path, error->message); + g_error_free(error); + return; + } +} + +static gint +skinlist_compare_func(gconstpointer a, gconstpointer b) +{ + g_return_val_if_fail(a != NULL && SKIN_NODE(a)->name != NULL, 1); + g_return_val_if_fail(b != NULL && SKIN_NODE(b)->name != NULL, 1); + return strcasecmp(SKIN_NODE(a)->name, SKIN_NODE(b)->name); +} + +static void +skin_free_func(gpointer data) +{ + g_return_if_fail(data != NULL); + g_free(SKIN_NODE(data)->name); + g_free(SKIN_NODE(data)->path); + g_slice_free(SkinNode, data); +} + + +static void +skinlist_clear(void) +{ + if (!skinlist) + return; + + g_list_foreach(skinlist, (GFunc) skin_free_func, NULL); + g_list_free(skinlist); + skinlist = NULL; +} + +void +skinlist_update(void) +{ + gchar *skinsdir; + + skinlist_clear(); + + scan_skindir(aud_paths[BMP_PATH_USER_SKIN_DIR]); + scan_skindir(DATA_DIR G_DIR_SEPARATOR_S "Skins"); + + skinsdir = getenv("SKINSDIR"); + if (skinsdir) { + gchar **dir_list = g_strsplit(skinsdir, ":", 0); + gchar **dir; + + for (dir = dir_list; *dir; dir++) + scan_skindir(*dir); + g_strfreev(dir_list); + } + + skinlist = g_list_sort(skinlist, skinlist_compare_func); + + g_assert(skinlist != NULL); +} + +void +skin_view_update(GtkTreeView * treeview, GtkWidget * refresh_button) +{ + GtkTreeSelection *selection = NULL; + GtkListStore *store; + GtkTreeIter iter, iter_current_skin; + gboolean have_current_skin = FALSE; + GtkTreePath *path; + + GdkPixbuf *thumbnail; + gchar *formattedname; + gchar *name; + GList *entry; + + gtk_widget_set_sensitive(GTK_WIDGET(treeview), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(refresh_button), FALSE); + + store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview)); + + gtk_list_store_clear(store); + + skinlist_update(); + + for (entry = skinlist; entry; entry = g_list_next(entry)) { + thumbnail = skin_get_thumbnail(SKIN_NODE(entry->data)->path); + + formattedname = g_strdup_printf("%s\n%s", + SKIN_NODE(entry->data)->name, SKIN_NODE(entry->data)->desc); + name = SKIN_NODE(entry->data)->name; + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + SKIN_VIEW_COL_PREVIEW, thumbnail, + SKIN_VIEW_COL_FORMATTEDNAME, formattedname, + SKIN_VIEW_COL_NAME, name, -1); + if (thumbnail) + g_object_unref(thumbnail); + g_free(formattedname); + + if (g_strstr_len(aud_active_skin->path, + strlen(aud_active_skin->path), name) ) { + iter_current_skin = iter; + have_current_skin = TRUE; + } + } + + if (have_current_skin) { + selection = gtk_tree_view_get_selection(treeview); + gtk_tree_selection_select_iter(selection, &iter_current_skin); + + path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), + &iter_current_skin); + gtk_tree_view_scroll_to_cell(treeview, path, NULL, TRUE, 0.5, 0.5); + gtk_tree_path_free(path); + } + + gtk_widget_set_sensitive(GTK_WIDGET(treeview), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(refresh_button), TRUE); +} + + +static void +skin_view_on_cursor_changed(GtkTreeView * treeview, + gpointer data) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + GList *node; + gchar *name; + gchar *comp = NULL; + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + + gtk_tree_model_get(model, &iter, SKIN_VIEW_COL_NAME, &name, -1); + + for (node = skinlist; node; node = g_list_next(node)) { + comp = SKIN_NODE(node->data)->path; + if (g_strrstr(comp, name)) + break; + } + + g_free(name); + + aud_active_skin_load(comp); +} + + +void +skin_view_realize(GtkTreeView * treeview) +{ + GtkListStore *store; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeSelection *selection; + + gtk_widget_show_all(GTK_WIDGET(treeview)); + + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); + + store = gtk_list_store_new(SKIN_VIEW_N_COLS, GDK_TYPE_PIXBUF, + G_TYPE_STRING , G_TYPE_STRING); + gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store)); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_spacing(column, 16); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), + GTK_TREE_VIEW_COLUMN(column)); + + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_set_attributes(column, renderer, "pixbuf", + SKIN_VIEW_COL_PREVIEW, NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_set_attributes(column, renderer, "markup", + SKIN_VIEW_COL_FORMATTEDNAME, NULL); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); + + g_signal_connect(treeview, "cursor-changed", + G_CALLBACK(skin_view_on_cursor_changed), NULL); +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_skinselector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_skinselector.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,45 @@ +/* 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. + */ + +#ifndef AUDACIOUS_UI_SKINSELECTOR_H +#define AUDACIOUS_UI_SKINSELECTOR_H + +#include +#include + +#define SKIN_NODE(x) ((SkinNode *)(x)) +struct _SkinNode { + gchar *name; + gchar *desc; + gchar *path; + GTime *time; +}; + +typedef struct _SkinNode SkinNode; + +extern GList *skinlist; + +void skinlist_update(); +void skin_view_realize(GtkTreeView * treeview); +void skin_view_update(GtkTreeView * treeview, GtkWidget * refresh_button); + +#endif /* AUDACIOUS_UI_SKINSELECTOR_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_svis.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_svis.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,550 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Audacious development team. + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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. + */ + +#include "ui_skin.h" +#include "ui_svis.h" +#include "ui_vis.h" +#include "main.h" +#include "util.h" +#include "strings.h" +#include "playback.h" +#include +#include +#include +#include +#include + +#define UI_TYPE_SVIS (ui_svis_get_type()) + +static gint svis_redraw_delays[] = { 1, 2, 4, 8 }; + +/* FIXME: Are the svis_scope_colors correct? */ +static guint8 svis_scope_colors[] = { 20, 19, 18, 19, 20 }; +static guint8 svis_vu_normal_colors[] = { 17, 17, 17, 12, 12, 12, 2, 2 }; + +#define DRAW_DS_PIXEL(ptr,value) \ + *(ptr) = (value); \ + *((ptr) + 1) = (value); \ + *((ptr) + 76) = (value); \ + *((ptr) + 77) = (value); + +#define SVIS_HEIGHT 5 +#define SVIS_WIDTH 38 + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_svis_class_init (UiSVisClass *klass); +static void ui_svis_init (UiSVis *svis); +static void ui_svis_destroy (GtkObject *object); +static void ui_svis_realize (GtkWidget *widget); +static void ui_svis_unrealize (GtkWidget *widget); +static void ui_svis_map (GtkWidget *widget); +static void ui_svis_unmap (GtkWidget *widget); +static void ui_svis_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_svis_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_svis_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_svis_toggle_scaled (UiSVis *svis); + +static GtkWidgetClass *parent_class = NULL; +static guint vis_signals[LAST_SIGNAL] = { 0 }; + +GType ui_svis_get_type() { + static GType vis_type = 0; + if (!vis_type) { + static const GTypeInfo vis_info = { + sizeof (UiSVisClass), + NULL, + NULL, + (GClassInitFunc) ui_svis_class_init, + NULL, + NULL, + sizeof (UiSVis), + 0, + (GInstanceInitFunc) ui_svis_init, + }; + vis_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSVis_", &vis_info, 0); + } + + return vis_type; +} + +static void ui_svis_class_init(UiSVisClass *klass) { + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_svis_destroy; + + widget_class->realize = ui_svis_realize; + widget_class->unrealize = ui_svis_unrealize; + widget_class->map = ui_svis_map; + widget_class->unmap = ui_svis_unmap; + widget_class->expose_event = ui_svis_expose; + widget_class->size_request = ui_svis_size_request; + widget_class->size_allocate = ui_svis_size_allocate; + + klass->scaled = ui_svis_toggle_scaled; + + vis_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiSVisClass, scaled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_svis_init(UiSVis *svis) { + +} + +GtkWidget* ui_svis_new(GtkWidget *fixed, gint x, gint y) { + UiSVis *svis = g_object_new (ui_svis_get_type (), NULL); + + svis->x = x; + svis->y = y; + + svis->width = SVIS_WIDTH; + svis->height = SVIS_HEIGHT; + + svis->fixed = fixed; + svis->scaled = FALSE; + + svis->visible_window = TRUE; + svis->event_window = NULL; + + gtk_fixed_put(GTK_FIXED(svis->fixed), GTK_WIDGET(svis), svis->x, svis->y); + + return GTK_WIDGET(svis); +} + +static void ui_svis_destroy(GtkObject *object) { + UiSVis *svis; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_IS_SVIS (object)); + + svis = UI_SVIS (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_svis_realize(GtkWidget *widget) { + UiSVis *svis; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_IS_SVIS(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + svis = UI_SVIS(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; + + if (svis->visible_window) + { + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + attributes.wclass = GDK_INPUT_OUTPUT; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + GTK_WIDGET_UNSET_FLAGS(widget, GTK_NO_WINDOW); + gdk_window_set_user_data(widget->window, widget); + } + else + { + widget->window = gtk_widget_get_parent_window (widget); + g_object_ref (widget->window); + + attributes.wclass = GDK_INPUT_ONLY; + attributes_mask = GDK_WA_X | GDK_WA_Y; + svis->event_window = gdk_window_new (widget->window, &attributes, attributes_mask); + GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW); + gdk_window_set_user_data(svis->event_window, widget); + } + + widget->style = gtk_style_attach(widget->style, widget->window); +} + +static void ui_svis_unrealize(GtkWidget *widget) { + UiSVis *svis; + svis = UI_SVIS(widget); + + if ( svis->event_window != NULL ) + { + gdk_window_set_user_data( svis->event_window , NULL ); + gdk_window_destroy( svis->event_window ); + svis->event_window = NULL; + } + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static void ui_svis_map(GtkWidget *widget) +{ + UiSVis *svis; + svis = UI_SVIS(widget); + + if (svis->event_window != NULL) + gdk_window_show (svis->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->map) + (* GTK_WIDGET_CLASS (parent_class)->map) (widget); +} + +static void ui_svis_unmap (GtkWidget *widget) +{ + UiSVis *svis; + svis = UI_SVIS(widget); + + if (svis->event_window != NULL) + gdk_window_hide (svis->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->unmap) + (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget); +} + +static void ui_svis_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiSVis *svis = UI_SVIS(widget); + + requisition->width = svis->width * (svis->scaled ? cfg.scale_factor : 1); + requisition->height = svis->height*(svis->scaled ? cfg.scale_factor : 1); +} + +static void ui_svis_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiSVis *svis = UI_SVIS (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (svis->scaled ? cfg.scale_factor : 1 ); + widget->allocation.y *= (svis->scaled ? cfg.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + { + if (svis->event_window != NULL) + gdk_window_move_resize(svis->event_window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + else + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + } + + svis->x = widget->allocation.x/(svis->scaled ? cfg.scale_factor : 1); + svis->y = widget->allocation.y/(svis->scaled ? cfg.scale_factor : 1); +} + +static gboolean ui_svis_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_IS_SVIS (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiSVis *svis = UI_SVIS (widget); + + gint x, y, h; + guchar svis_color[24][3]; + guchar rgb_data[SVIS_WIDTH * 2 * SVIS_HEIGHT * 2], *ptr, c; + guint32 colors[24]; + GdkRgbCmap *cmap; + + if (!GTK_WIDGET_VISIBLE(widget)) + return FALSE; + + if (!svis->visible_window) + return FALSE; + + skin_get_viscolor(aud_active_skin, svis_color); + for (y = 0; y < 24; y++) { + colors[y] = + svis_color[y][0] << 16 | svis_color[y][1] << 8 | svis_color[y][2]; + } + cmap = gdk_rgb_cmap_new(colors, 24); + + if (!cfg.scaled) { + memset(rgb_data, 0, SVIS_WIDTH * SVIS_HEIGHT); + if (cfg.vis_type == VIS_ANALYZER && !playback_get_paused() && playback_get_playing()){ + for(y=0; y < SVIS_HEIGHT; y++){ + if (cfg.analyzer_type == ANALYZER_BARS){ + for(x=0;x< SVIS_WIDTH; x++){ + if(svis->data[x] > y << 1) + { + rgb_data[x*3+ (SVIS_HEIGHT - y) * SVIS_WIDTH] = 23; + rgb_data[x*3+1 + (SVIS_HEIGHT - y) * SVIS_WIDTH] = 23; + + } + } + } + else{ + for(x=0;x< SVIS_WIDTH; x++){ + if(svis->data[x] > y << 1) + { + rgb_data[x + (SVIS_HEIGHT - y) * SVIS_WIDTH] = 23; + } + } + } + } + } + else if (cfg.vis_type == VIS_VOICEPRINT){ + switch (cfg.vu_mode) { + case VU_NORMAL: + for (y = 0; y < 2; y++) { + ptr = rgb_data + ((y * 3) * 38); + h = (svis->data[y] * 7) / 37; + for (x = 0; x < h; x++, ptr += 5) { + c = svis_vu_normal_colors[x]; + *(ptr) = c; + *(ptr + 1) = c; + *(ptr + 2) = c; + *(ptr + 38) = c; + *(ptr + 39) = c; + *(ptr + 40) = c; + } + } + break; + case VU_SMOOTH: + for (y = 0; y < 2; y++) { + ptr = rgb_data + ((y * 3) * SVIS_WIDTH); + for (x = 0; x < svis->data[y]; x++, ptr++) { + c = 17 - ((x * 15) / 37); + *(ptr) = c; + *(ptr + 38) = c; + } + } + break; + } + } + else if (cfg.vis_type == VIS_SCOPE) { + for (x = 0; x < 38; x++) { + h = svis->data[x << 1] / 3; + ptr = rgb_data + ((4 - h) * 38) + x; + *ptr = svis_scope_colors[h]; + } + } + + } + else { /*svis scaling, this needs some work, since a lot of stuff is hardcoded --majeru*/ + + memset(rgb_data, 0, SVIS_WIDTH * cfg.scale_factor * SVIS_HEIGHT * cfg.scale_factor); + if (cfg.vis_type == VIS_ANALYZER && !playback_get_paused() && playback_get_playing()){ + for(y=0; y < SVIS_HEIGHT; y++){ + if (cfg.analyzer_type == ANALYZER_BARS){ + for(x=0;x< SVIS_WIDTH; x++){ + if(svis->data[x] > y << 1) + { + ptr = rgb_data + x * 6 + (SVIS_HEIGHT * 2 - y * 2) * SVIS_WIDTH *2; + DRAW_DS_PIXEL(ptr, 23); + DRAW_DS_PIXEL(ptr + 2, 23); + } + } + } + else{ + for(x=0;x< SVIS_WIDTH; x++){ + if(svis->data[x] > y << 1) + { + ptr = rgb_data + x * 2 + (SVIS_HEIGHT * 2 - y * 2) * SVIS_WIDTH * 2; + DRAW_DS_PIXEL(ptr, 23); + } + } + } + } + } + else if (cfg.vis_type == VIS_VOICEPRINT){ + switch (cfg.vu_mode) { + case VU_NORMAL: + for (y = 0; y < 2; y++) { + ptr = rgb_data + ((y * 3) * 152); + h = (svis->data[y] * 8) / 37; + for (x = 0; x < h; x++, ptr += 10) { + c = svis_vu_normal_colors[x]; + DRAW_DS_PIXEL(ptr, c); + DRAW_DS_PIXEL(ptr + 2, c); + DRAW_DS_PIXEL(ptr + 4, c); + DRAW_DS_PIXEL(ptr + 152, c); + DRAW_DS_PIXEL(ptr + 154, c); + DRAW_DS_PIXEL(ptr + 156, c); + } + } + break; + case VU_SMOOTH: + for (y = 0; y < 2; y++) { + ptr = rgb_data + ((y * 3) * 152); + for (x = 0; x < svis->data[y]; x++, ptr += 2) { + c = 17 - ((x * 15) / 37); + DRAW_DS_PIXEL(ptr, c); + DRAW_DS_PIXEL(ptr + 152, c); + } + } + break; + } + } + else if (cfg.vis_type == VIS_SCOPE) { + for (x = 0; x < 38; x++) { + h = svis->data[x << 1] / 3; + ptr = rgb_data + ((4 - h) * 152) + (x << 1); + *ptr = svis_scope_colors[h]; + *(ptr + 1) = svis_scope_colors[h]; + *(ptr + 76) = svis_scope_colors[h]; + *(ptr + 77) = svis_scope_colors[h]; + } + } + + + } + + GdkPixmap *obj = NULL; + GdkGC *gc; + obj = gdk_pixmap_new(NULL, svis->width* ( svis->scaled ? cfg.scale_factor : 1), + svis->height*(svis->scaled ? cfg.scale_factor : 1), gdk_rgb_get_visual()->depth); + gc = gdk_gc_new(obj); + + if (!svis->scaled) { + gdk_draw_indexed_image(obj, gc, 0, 0, svis->width, svis->height, + GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data, + 38, cmap); + } else { + gdk_draw_indexed_image(obj, gc, + 0 << 1, 0 << 1, + svis->width << 1, svis->height << 1, + GDK_RGB_DITHER_NONE, (guchar *) rgb_data, + 76, cmap); + } + + gdk_rgb_cmap_free(cmap); + gdk_draw_drawable (widget->window, gc, obj, 0, 0, 0, 0, + svis->width*(svis->scaled ? cfg.scale_factor : 1), + svis->height*(svis->scaled ? cfg.scale_factor : 1)); + g_object_unref(obj); + g_object_unref(gc); + + return FALSE; +} + +static void ui_svis_toggle_scaled(UiSVis *svis) { + GtkWidget *widget = GTK_WIDGET (svis); + svis->scaled = !svis->scaled; + + gtk_widget_set_size_request(widget, svis->width* cfg.scale_factor, svis->height * cfg.scale_factor); + + gtk_widget_queue_draw(widget); +} + +void ui_svis_set_visible(GtkWidget *widget, gboolean window_is_visible) +{ + UiSVis *svis; + gboolean widget_is_visible; + + g_return_if_fail(UI_IS_SVIS(widget)); + + svis = UI_SVIS (widget); + widget_is_visible = GTK_WIDGET_VISIBLE(widget); + + svis->visible_window = window_is_visible; + + if (GTK_WIDGET_REALIZED (widget)) + { + if ( widget_is_visible ) + gtk_widget_hide(widget); + + gtk_widget_unrealize(widget); + gtk_widget_realize(widget); + + if ( widget_is_visible ) + gtk_widget_show(widget); + } + + if (widget_is_visible) + gtk_widget_queue_resize(widget); +} + +void ui_svis_clear_data(GtkWidget *widget) { + g_return_if_fail(UI_IS_SVIS(widget)); + + gint i; + UiSVis *svis = UI_SVIS (widget); + + for (i = 0; i < 75; i++) { + svis->data[i] = (cfg.vis_type == VIS_SCOPE) ? 6 : 0; + } +} + +void ui_svis_timeout_func(GtkWidget *widget, guchar * data) { + g_return_if_fail(UI_IS_SVIS(widget)); + + UiSVis *svis = UI_SVIS (widget); + static GTimer *timer = NULL; + gulong micros = 9999999; + gboolean falloff = FALSE; + gint i; + + if (!timer) { + timer = g_timer_new(); + g_timer_start(timer); + } + else { + g_timer_elapsed(timer, µs); + if (micros > 14000) + g_timer_reset(timer); + + } + + if (cfg.vis_type == VIS_VOICEPRINT) { + if (micros > 14000) + falloff = TRUE; + + for (i = 0; i < 2; i++) { + if (falloff || data) { + if (data && data[i] > svis->data[i]) + svis->data[i] = data[i]; + else if (falloff) { + if (svis->data[i] >= 2) + svis->data[i] -= 2; + else + svis->data[i] = 0; + } + } + + } + } + else if (data) { + for (i = 0; i < 75; i++) + svis->data[i] = data[i]; + } + + if (micros > 14000) { + if (!svis->refresh_delay) { + gtk_widget_queue_draw(widget); + svis->refresh_delay = svis_redraw_delays[cfg.vis_refresh]; + } + svis->refresh_delay--; + } +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_svis.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_svis.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 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_SVIS_H +#define AUDACIOUS_UI_SVIS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_SVIS(obj) GTK_CHECK_CAST (obj, ui_svis_get_type (), UiSVis) +#define UI_SVIS_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_svis_get_type (), UiSVisClass) +#define UI_IS_SVIS(obj) GTK_CHECK_TYPE (obj, ui_svis_get_type ()) + +typedef struct _UiSVis UiSVis; +typedef struct _UiSVisClass UiSVisClass; + +struct _UiSVis { + GtkWidget widget; + + gint x, y, width, height; + gint data[75]; + gint refresh_delay; + gboolean scaled; + GtkWidget *fixed; + gboolean visible_window; + GdkWindow *event_window; +}; + +struct _UiSVisClass { + GtkWidgetClass parent_class; + void (* scaled) (UiSVis *vis); +}; + +GtkWidget* ui_svis_new (GtkWidget *fixed, gint x, gint y); +GtkType ui_svis_get_type(void); +void ui_svis_clear_data(GtkWidget *widget); +void ui_svis_timeout_func(GtkWidget *widget, guchar * data); +void ui_svis_set_visible(GtkWidget *widget, gboolean window_is_visible); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_SVIS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_urlopener.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_urlopener.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,159 @@ +/* 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_urlopener.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_urlopener.h Sun Jul 06 17:55:40 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 */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_vis.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_vis.c Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,724 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 Audacious development team. + * + * Based on: + * BMP - Cross-platform multimedia player + * Copyright (C) 2003-2004 BMP development team. + * 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. + */ + +#include "ui_skin.h" +#include "ui_vis.h" +#include "main.h" +#include "util.h" +#include "playback.h" + +static const gfloat vis_afalloff_speeds[] = { 0.34, 0.5, 1.0, 1.3, 1.6 }; +static const gfloat vis_pfalloff_speeds[] = { 1.2, 1.3, 1.4, 1.5, 1.6 }; +static const gint vis_redraw_delays[] = { 1, 2, 4, 8 }; +static const guint8 vis_scope_colors[] = + { 21, 21, 20, 20, 19, 19, 18, 19, 19, 20, 20, 21, 21 }; +static guchar voiceprint_data[76*16]; + +enum { + DOUBLED, + LAST_SIGNAL +}; + +static void ui_vis_class_init (UiVisClass *klass); +static void ui_vis_init (UiVis *vis); +static void ui_vis_destroy (GtkObject *object); +static void ui_vis_realize (GtkWidget *widget); +static void ui_vis_unrealize (GtkWidget *widget); +static void ui_vis_map (GtkWidget *widget); +static void ui_vis_unmap (GtkWidget *widget); +static void ui_vis_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void ui_vis_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gboolean ui_vis_expose (GtkWidget *widget, GdkEventExpose *event); +static void ui_vis_toggle_scaled (UiVis *vis); + +static GtkWidgetClass *parent_class = NULL; +static guint vis_signals[LAST_SIGNAL] = { 0 }; + +GType ui_vis_get_type() { + static GType vis_type = 0; + if (!vis_type) { + static const GTypeInfo vis_info = { + sizeof (UiVisClass), + NULL, + NULL, + (GClassInitFunc) ui_vis_class_init, + NULL, + NULL, + sizeof (UiVis), + 0, + (GInstanceInitFunc) ui_vis_init, + }; + vis_type = g_type_register_static (GTK_TYPE_WIDGET, "UiVis_", &vis_info, 0); + } + + return vis_type; +} + +static void ui_vis_class_init(UiVisClass *klass) { + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = ui_vis_destroy; + + widget_class->realize = ui_vis_realize; + widget_class->unrealize = ui_vis_unrealize; + widget_class->map = ui_vis_map; + widget_class->unmap = ui_vis_unmap; + widget_class->expose_event = ui_vis_expose; + widget_class->size_request = ui_vis_size_request; + widget_class->size_allocate = ui_vis_size_allocate; + + klass->doubled = ui_vis_toggle_scaled; + + vis_signals[DOUBLED] = + g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (UiVisClass, doubled), NULL, NULL, + gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void ui_vis_init(UiVis *vis) { + memset(voiceprint_data, 0, 16*76); +} + +GtkWidget* ui_vis_new(GtkWidget *fixed, gint x, gint y, gint width) { + UiVis *vis = g_object_new (ui_vis_get_type (), NULL); + + vis->x = x; + vis->y = y; + + vis->width = width; + vis->height = 16; + + vis->fixed = fixed; + vis->scaled = FALSE; + + vis->visible_window = TRUE; + vis->event_window = NULL; + + gtk_fixed_put(GTK_FIXED(vis->fixed), GTK_WIDGET(vis), vis->x, vis->y); + + return GTK_WIDGET(vis); +} + +static void ui_vis_destroy(GtkObject *object) { + UiVis *vis; + + g_return_if_fail (object != NULL); + g_return_if_fail (UI_IS_VIS (object)); + + vis = UI_VIS (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void ui_vis_realize(GtkWidget *widget) { + UiVis *vis; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (UI_IS_VIS(widget)); + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + vis = UI_VIS(widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events(widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; + + if (vis->visible_window) + { + attributes.visual = gtk_widget_get_visual(widget); + attributes.colormap = gtk_widget_get_colormap(widget); + attributes.wclass = GDK_INPUT_OUTPUT; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); + GTK_WIDGET_UNSET_FLAGS(widget, GTK_NO_WINDOW); + gdk_window_set_user_data(widget->window, widget); + } + else + { + widget->window = gtk_widget_get_parent_window (widget); + g_object_ref (widget->window); + + attributes.wclass = GDK_INPUT_ONLY; + attributes_mask = GDK_WA_X | GDK_WA_Y; + vis->event_window = gdk_window_new (widget->window, &attributes, attributes_mask); + GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW); + gdk_window_set_user_data(vis->event_window, widget); + } + + widget->style = gtk_style_attach(widget->style, widget->window); +} + +static void ui_vis_unrealize(GtkWidget *widget) { + UiVis *vis; + vis = UI_VIS(widget); + + if ( vis->event_window != NULL ) + { + gdk_window_set_user_data( vis->event_window , NULL ); + gdk_window_destroy( vis->event_window ); + vis->event_window = NULL; + } + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static void ui_vis_map(GtkWidget *widget) +{ + UiVis *vis; + vis = UI_VIS(widget); + + if (vis->event_window != NULL) + gdk_window_show (vis->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->map) + (* GTK_WIDGET_CLASS (parent_class)->map) (widget); +} + +static void ui_vis_unmap (GtkWidget *widget) +{ + UiVis *vis; + vis = UI_VIS(widget); + + if (vis->event_window != NULL) + gdk_window_hide (vis->event_window); + + if (GTK_WIDGET_CLASS (parent_class)->unmap) + (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget); +} + +static void ui_vis_size_request(GtkWidget *widget, GtkRequisition *requisition) { + UiVis *vis = UI_VIS(widget); + + requisition->width = vis->width*(vis->scaled ? cfg.scale_factor : 1); + requisition->height = vis->height*(vis->scaled ? cfg.scale_factor : 1); +} + +static void ui_vis_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { + UiVis *vis = UI_VIS (widget); + + widget->allocation = *allocation; + widget->allocation.x *= (vis->scaled ? cfg.scale_factor : 1); + widget->allocation.y *= (vis->scaled ? cfg.scale_factor : 1); + if (GTK_WIDGET_REALIZED (widget)) + { + if (vis->event_window != NULL) + gdk_window_move_resize(vis->event_window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + else + gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); + } + + vis->x = widget->allocation.x/(vis->scaled ? cfg.scale_factor : 1); + vis->y = widget->allocation.y/(vis->scaled ? cfg.scale_factor : 1); +} + +static gboolean ui_vis_expose(GtkWidget *widget, GdkEventExpose *event) { + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (UI_IS_VIS (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + UiVis *vis = UI_VIS (widget); + + gint x, y, n, h = 0, h2; + gfloat delta; + guchar skin_col[2][3]; + guchar vis_color[24][3]; + guchar vis_voice_color[256][3], voice_c[3]; + guchar rgb_data[76 * 16 * 3 * 2 * 2], *ptr, c; + guint32 colors[24]; + GdkColor *fgc, *bgc; + GdkRgbCmap *cmap; + + if (!GTK_WIDGET_VISIBLE(widget)) + return FALSE; + + if (!vis->visible_window) + return FALSE; + + skin_get_viscolor(aud_active_skin, vis_color); + for (y = 0; y < 24; y++) { + colors[y] = + vis_color[y][0] << 16 | vis_color[y][1] << 8 | vis_color[y][2]; + } + cmap = gdk_rgb_cmap_new(colors, 24); + + if (!vis->scaled) { + if(cfg.vis_type == VIS_VOICEPRINT /*&& cfg.voiceprint_mode != VOICEPRINT_NORMAL*/){ + memset(rgb_data, 0, 76 * 16 * 3); + } + else{ + memset(rgb_data, 0, 76 * 16); + for (y = 1; y < 16; y += 2) { + ptr = rgb_data + (y * 76); + for (x = 0; x < 76; x += 2, ptr += 2) + *ptr = 1; + } + } + } + else{ + if(cfg.vis_type == VIS_VOICEPRINT /*&& cfg.voiceprint_mode != VOICEPRINT_NORMAL*/){ + memset(rgb_data, 0, 3 * 4 * 16 * 76); + } + else{ + memset(rgb_data, 0, (guint)(76 * cfg.scale_factor) * 32); + for (y = 1; y < 16; y += 2) { + ptr = rgb_data + (y * (guint)(76 * 4 * cfg.scale_factor)); + for (x = 0; x < 76; x += 2, ptr += 4) { + *ptr = 1; + *(ptr + 1) = 1; + *(ptr + (guint)(76 * cfg.scale_factor)) = 1; + *(ptr + (guint)(76 * cfg.scale_factor)+1) = 1; + } + } + } + } + if (cfg.vis_type == VIS_ANALYZER) { + for (x = 0; x < 75; x++) { + if (cfg.analyzer_type == ANALYZER_BARS && (x % 4) == 0) + h = vis->data[x >> 2]; + else if (cfg.analyzer_type == ANALYZER_LINES) + h = vis->data[x]; + if (h && (cfg.analyzer_type == ANALYZER_LINES || + (x % 4) != 3)) { + if (!vis->scaled) { + ptr = rgb_data + ((16 - h) * 76) + x; + switch (cfg.analyzer_mode) { + case ANALYZER_NORMAL: + for (y = 0; y < h; y++, ptr += 76) + *ptr = 18 - h + y; + break; + case ANALYZER_FIRE: + for (y = 0; y < h; y++, ptr += 76) + *ptr = y + 2; + break; + case ANALYZER_VLINES: + for (y = 0; y < h; y++, ptr += 76) + *ptr = 18 - h; + break; + } + } + else{ + ptr = rgb_data + ((16 - h) * (guint)(76 * 4 * cfg.scale_factor)) + (guint)(x * cfg.scale_factor); + switch (cfg.analyzer_mode) { + case ANALYZER_NORMAL: + for (y = 0; y < h; y++, ptr += (guint)(76 * 4 * cfg.scale_factor)) { + *ptr = 18 - h + y; + *(ptr + 1) = 18 - h + y; + *(ptr + (guint)(76 * cfg.scale_factor)) = 18 - h + y; + *(ptr + (guint)(76 * cfg.scale_factor)+1) = 18 - h + y; + } + break; + case ANALYZER_FIRE: + for (y = 0; y < h; y++, ptr += (guint)(76 * 4 * cfg.scale_factor)) { + *ptr = y + 2; + *(ptr + 1) = y + 2; + *(ptr + (guint)(76 * cfg.scale_factor)) = y + 2; + *(ptr + (guint)(76 * cfg.scale_factor)+1) = y + 2; + } + break; + case ANALYZER_VLINES: + for (y = 0; y < h; y++, ptr += (guint)(76 * 4 * cfg.scale_factor)) { + *ptr = 18 - h; + *(ptr + 1) = 18 - h; + *(ptr + (guint)(76 * cfg.scale_factor)) = 18 - h; + *(ptr + (guint)(76 * cfg.scale_factor)+1) = 18 - h; + } + + break; + } + } + } + } + if (cfg.analyzer_peaks) { + for (x = 0; x < 75; x++) { + if (cfg.analyzer_type == ANALYZER_BARS && (x % 4) == 0) + h = vis->peak[x >> 2]; + else if (cfg.analyzer_type == ANALYZER_LINES) + h = vis->peak[x]; + if (h && (cfg.analyzer_type == ANALYZER_LINES || (x % 4) != 3)){ + + if (!vis->scaled) { + rgb_data[(16 - h) * 76 + x] = 23; + } + else{ + ptr = rgb_data + (16 - h) * (guint)(76 * 4 * cfg.scale_factor) + (guint)(x * cfg.scale_factor); + *ptr = 23; + *(ptr + 1) = 23; + *(ptr + (guint)(76 * cfg.scale_factor)) = 23; + *(ptr + (guint)(76 * cfg.scale_factor)+1) = 23; + } + } + } + } + } + else if (cfg.vis_type == VIS_VOICEPRINT) { + if(!playback_get_paused() && playback_get_playing()){/*Don't scroll when it's paused or stopped*/ + for (y = 0; y < 16; y ++) + for (x = 75; x > 0; x--) + voiceprint_data[x + y * 76] = voiceprint_data[x-1+y*76]; + for(y=0;y<16;y++) + voiceprint_data[y * 76] = vis->data[y]; + } + if(playback_get_playing()){ /*Only draw the data if we're playing*/ + if(cfg.voiceprint_mode == VOICEPRINT_NORMAL){ + /* Create color gradient from the skin's background- and foreground color*/ + fgc = skin_get_color(aud_active_skin, SKIN_TEXTFG); + bgc = skin_get_color(aud_active_skin, SKIN_TEXTBG); + skin_col[0][0] = fgc->red >> 8; + skin_col[0][1] = fgc->green >> 8; + skin_col[0][2] = fgc->blue >> 8; + skin_col[1][0] = bgc->red >> 8; + skin_col[1][1] = bgc->green >> 8; + skin_col[1][2] = bgc->blue >> 8; + for(n=0;n<3;n++){ + for(x=0;x<256;x++){ + if(skin_col[0][n] > skin_col[1][n]){ + delta = (gfloat)(skin_col[0][n] - skin_col[1][n]) / 256.0; + vis_voice_color[x][n] = skin_col[1][n] + (gfloat)(delta * x); + } + else if(skin_col[0][n] == skin_col[1][n]){ + vis_voice_color[x][n] = skin_col[0][n]; + } + else{ + delta = (gfloat)(skin_col[1][n] - skin_col[0][n]) / 256.0; + vis_voice_color[x][n] = skin_col[1][n] - (gfloat)(delta * x); + } + } + } + } + for (y = 0; y < 16; y ++){ + for (x = 0; x < 76; x++){ + guint8 d = voiceprint_data[x + y*76]; + + if(cfg.voiceprint_mode == VOICEPRINT_NORMAL){ + voice_c[0] = vis_voice_color[d][0]; + voice_c[1] = vis_voice_color[d][1]; + voice_c[2] = vis_voice_color[d][2]; + } + else if(cfg.voiceprint_mode == VOICEPRINT_FIRE){ + voice_c[0] = d < 64 ? (d * 2) : 255; + voice_c[1] = d < 64 ? 0 : (d < 128 ? (d-64) * 2 : 255); + voice_c[2] = d < 128 ? 0 : (d-128) * 2; + /* Test for black->blue->green->red. Isn't pretty, though... + voice_c[0] = d > 192 ? (d - 192) << 2 : 0; + voice_c[1] = d > 64 ? (d < 128 ? (d - 64) << 2 : (d < 192 ? (192 - d) << 2 : 0)) : 0; + voice_c[2] = d < 64 ? d << 2 : (d < 128 ? (128 - d) << 2 : 0); + */ + } + else if(cfg.voiceprint_mode == VOICEPRINT_ICE){ + voice_c[0] = d; + voice_c[1] = d < 128 ? d * 2 : 255; + voice_c[2] = d < 64 ? d * 4 : 255; + } + if(!vis->scaled){ + for(n=0;n<3;n++) + rgb_data[x * 3 + y * 76*3+n] = voice_c[n]; + } + else{ + ptr = rgb_data + (guint)(x * 3 * cfg.scale_factor) + (guint) (y * 76 * 3 * cfg.scale_factor); + for(n=0;n<3;n++) + { + *(ptr + n) = voice_c[n]; + *(ptr + n + 3) = voice_c[n]; + *(ptr + (guint)(n + 76 * cfg.scale_factor * 3)) = voice_c[n]; + *(ptr + (guint)(n + 3 + 76 * cfg.scale_factor * 3)) = voice_c[n]; + } + } + } + } + } + } + if (cfg.vis_type == VIS_SCOPE) { + for (x = 0; x < 75; x++) { + switch (cfg.scope_mode) { + case SCOPE_DOT: + h = vis->data[x]; + if (!vis->scaled) { + ptr = rgb_data + ((14 - h) * 76) + x; + *ptr = vis_scope_colors[h + 1]; + }else{ + ptr = rgb_data + ((14 - h) * (guint)(76 * 4 * cfg.scale_factor)) + (guint)(x * cfg.scale_factor); + *ptr = vis_scope_colors[h + 1]; + *(ptr + 1) = vis_scope_colors[h + 1]; + *(ptr + (guint)(76 * cfg.scale_factor)) = vis_scope_colors[h + 1]; + *(ptr + (guint)(76 * cfg.scale_factor)+1) = vis_scope_colors[h + 1]; + } + break; + case SCOPE_LINE: + if (x != 74) { + h = 14 - vis->data[x]; + h2 = 14 - vis->data[x + 1]; + if (h > h2) { + y = h; + h = h2; + h2 = y; + } + if (!vis->scaled) { + ptr = rgb_data + (h * 76) + x; + for (y = h; y <= h2; y++, ptr += 76) + *ptr = vis_scope_colors[y - 2]; + } + else{ + ptr = rgb_data + (h * (guint)(76 * 4 * cfg.scale_factor)) + (guint)(x * cfg.scale_factor); + for (y = h; y <= h2; y++, ptr += (guint)(76 * 4 * cfg.scale_factor)) { + *ptr = vis_scope_colors[y - 2]; + *(ptr + 1) = vis_scope_colors[y - 2]; + *(ptr + (guint)(76 * cfg.scale_factor)) = vis_scope_colors[y - 2]; + *(ptr + (guint)(76 * cfg.scale_factor)+1) = vis_scope_colors[y - 2]; + } + } + } + else { + h = 14 - vis->data[x]; + if (!vis->scaled) { + ptr = rgb_data + (h * 76) + x; + *ptr = vis_scope_colors[h + 1]; + }else{ + ptr = rgb_data + (h * (guint)(76 * 4 * cfg.scale_factor)) + (guint)(x * cfg.scale_factor); + *ptr = vis_scope_colors[h + 1]; + *(ptr + 1) = vis_scope_colors[h + 1]; + *(ptr + (guint)(76 * cfg.scale_factor)) = vis_scope_colors[h + 1]; + *(ptr + (guint)(76 * cfg.scale_factor)+1) = vis_scope_colors[h + 1]; + } + } + break; + case SCOPE_SOLID: + h = 14 - vis->data[x]; + h2 = 8; + c = vis_scope_colors[(gint) vis->data[x]]; + if (h > h2) { + y = h; + h = h2; + h2 = y; + } + if (!vis->scaled) { + ptr = rgb_data + (h * 76) + x; + for (y = h; y <= h2; y++, ptr += 76) + *ptr = c; + }else{ + ptr = rgb_data + (h * (guint)(76 * 4 * cfg.scale_factor)) + (guint)(x * cfg.scale_factor); + for (y = h; y <= h2; y++, ptr += (guint)(76 * 4 * cfg.scale_factor)) { + *ptr = c; + *(ptr + 1) = c; + *(ptr + (guint)(76 * cfg.scale_factor)) = c; + *(ptr + (guint)(76 * cfg.scale_factor)+1) = c; + } + } + break; + } + } + } + + GdkPixmap *obj = NULL; + GdkGC *gc; + obj = gdk_pixmap_new(NULL, vis->width*(vis->scaled ? cfg.scale_factor : 1), vis->height*(vis->scaled ? cfg.scale_factor : 1), gdk_rgb_get_visual()->depth); + gc = gdk_gc_new(obj); + + if (!vis->scaled) { + if (cfg.vis_type == VIS_VOICEPRINT) { + gdk_draw_rgb_image(obj, gc, 0, 0, vis->width, vis->height, + GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data, + 76 * 3); + } else { + gdk_draw_indexed_image(obj, gc, 0, 0, vis->width, vis->height, + GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data, + 76 , cmap); + } + } else { + if (cfg.vis_type == VIS_VOICEPRINT) { + gdk_draw_rgb_image(obj, gc, 0 << 1, 0 << 1, + vis->width << 1, vis->height << 1, + GDK_RGB_DITHER_NONE, (guchar *) rgb_data, + 76 * 2 * 3); + } else { + gdk_draw_indexed_image(obj, gc, 0 << 1, 0 << 1, + vis->width << 1, vis->height << 1, + GDK_RGB_DITHER_NONE, (guchar *) rgb_data, + 76 * 2 , cmap); + } + } + + gdk_draw_drawable (widget->window, gc, obj, 0, 0, 0, 0, + vis->width*(vis->scaled ? cfg.scale_factor : 1), vis->height*(vis->scaled ? cfg.scale_factor : 1)); + g_object_unref(obj); + g_object_unref(gc); + gdk_rgb_cmap_free(cmap); + return FALSE; +} + +static void ui_vis_toggle_scaled(UiVis *vis) { + GtkWidget *widget = GTK_WIDGET (vis); + vis->scaled = !vis->scaled; + + gtk_widget_set_size_request(widget, vis->width*(vis->scaled ? cfg.scale_factor : 1), vis->height*(vis->scaled ? cfg.scale_factor : 1)); + + gtk_widget_queue_draw(GTK_WIDGET(vis)); +} + +void ui_vis_draw_pixel(GtkWidget *widget, guchar* texture, gint x, gint y, guint8 colour) { + UiVis *vis = UI_VIS (widget); + if (vis->scaled){ + texture[y * 76 + x] = colour; + texture[y * 76 + x + 1] = colour; + texture[y * 76 * 4 + x] = colour; + texture[y * 76 * 4 + x + 1] = colour; + } else { + texture[y * 76 + x] = colour; + } +} + +void ui_vis_set_visible(GtkWidget *widget, gboolean window_is_visible) +{ + UiVis *vis; + gboolean widget_is_visible; + + g_return_if_fail(UI_IS_VIS(widget)); + + vis = UI_VIS (widget); + widget_is_visible = GTK_WIDGET_VISIBLE(widget); + + vis->visible_window = window_is_visible; + + if (GTK_WIDGET_REALIZED (widget)) + { + if ( widget_is_visible ) + gtk_widget_hide(widget); + + gtk_widget_unrealize(widget); + gtk_widget_realize(widget); + + if ( widget_is_visible ) + gtk_widget_show(widget); + } + + if (widget_is_visible) + gtk_widget_queue_resize(widget); +} + +void ui_vis_clear_data(GtkWidget *widget) { + g_return_if_fail(UI_IS_VIS(widget)); + + gint i; + UiVis *vis = UI_VIS (widget); + + memset(voiceprint_data, 0, 16*76); + for (i = 0; i < 75; i++) { + vis->data[i] = (cfg.vis_type == VIS_SCOPE) ? 6 : 0; + vis->peak[i] = 0; + } +} + +void ui_vis_timeout_func(GtkWidget *widget, guchar * data) { + g_return_if_fail(UI_IS_VIS(widget)); + + UiVis *vis = UI_VIS (widget); + static GTimer *timer = NULL; + gulong micros = 9999999; + gboolean falloff = FALSE; + gint i; + + if (!timer) { + timer = g_timer_new(); + g_timer_start(timer); + } + else { + g_timer_elapsed(timer, µs); + if (micros > 14000) + g_timer_reset(timer); + } + if (cfg.vis_type == VIS_ANALYZER) { + if (micros > 14000) + falloff = TRUE; + if (data || falloff) { + for (i = 0; i < 75; i++) { + if (data && data[i] > vis->data[i]) { + vis->data[i] = data[i]; + if (vis->data[i] > vis->peak[i]) { + vis->peak[i] = vis->data[i]; + vis->peak_speed[i] = 0.01; + + } + else if (vis->peak[i] > 0.0) { + vis->peak[i] -= vis->peak_speed[i]; + vis->peak_speed[i] *= + vis_pfalloff_speeds[cfg.peaks_falloff]; + if (vis->peak[i] < vis->data[i]) + vis->peak[i] = vis->data[i]; + if (vis->peak[i] < 0.0) + vis->peak[i] = 0.0; + } + } + else if (falloff) { + if (vis->data[i] > 0.0) { + vis->data[i] -= + vis_afalloff_speeds[cfg.analyzer_falloff]; + if (vis->data[i] < 0.0) + vis->data[i] = 0.0; + } + if (vis->peak[i] > 0.0) { + vis->peak[i] -= vis->peak_speed[i]; + vis->peak_speed[i] *= + vis_pfalloff_speeds[cfg.peaks_falloff]; + if (vis->peak[i] < vis->data[i]) + vis->peak[i] = vis->data[i]; + if (vis->peak[i] < 0.0) + vis->peak[i] = 0.0; + } + } + } + } + } + else if (cfg.vis_type == VIS_VOICEPRINT && data){ + for(i = 0; i < 16; i++) + { + vis->data[i] = data[15 - i]; + } + } + else if (data) { + for (i = 0; i < 75; i++) + vis->data[i] = data[i]; + } + + if (micros > 14000) { + if (!vis->refresh_delay) { + gtk_widget_queue_draw(widget); + vis->refresh_delay = vis_redraw_delays[cfg.vis_refresh]; + } + vis->refresh_delay--; + } +} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/legacy/ui_vis.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audacious/legacy/ui_vis.h Sun Jul 06 17:55:40 2008 +0200 @@ -0,0 +1,98 @@ +/* + * Audacious - a cross-platform multimedia player + * Copyright (c) 2007 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_VIS_H +#define AUDACIOUS_UI_VIS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_VIS(obj) GTK_CHECK_CAST (obj, ui_vis_get_type (), UiVis) +#define UI_VIS_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_vis_get_type (), UiVisClass) +#define UI_IS_VIS(obj) GTK_CHECK_TYPE (obj, ui_vis_get_type ()) + +typedef enum { + VIS_ANALYZER, VIS_SCOPE, VIS_VOICEPRINT, VIS_OFF +} VisType; + +typedef enum { + ANALYZER_NORMAL, ANALYZER_FIRE, ANALYZER_VLINES +} AnalyzerMode; + +typedef enum { + ANALYZER_LINES, ANALYZER_BARS +} AnalyzerType; + +typedef enum { + SCOPE_DOT, SCOPE_LINE, SCOPE_SOLID +} ScopeMode; +typedef enum { + VOICEPRINT_NORMAL, VOICEPRINT_FIRE, VOICEPRINT_ICE +} VoiceprintMode; + + +typedef enum { + VU_NORMAL, VU_SMOOTH +} VUMode; + +typedef enum { + REFRESH_FULL, REFRESH_HALF, REFRESH_QUARTER, REFRESH_EIGTH +} RefreshRate; + +typedef enum { + FALLOFF_SLOWEST, FALLOFF_SLOW, FALLOFF_MEDIUM, FALLOFF_FAST, + FALLOFF_FASTEST +} FalloffSpeed; + +typedef struct _UiVis UiVis; +typedef struct _UiVisClass UiVisClass; + +struct _UiVis { + GtkWidget widget; + + gint x, y, width, height; + gfloat data[75], peak[75], peak_speed[75]; + gint refresh_delay; + gboolean scaled; + GtkWidget *fixed; + gboolean visible_window; + GdkWindow *event_window; +}; + +struct _UiVisClass { + GtkWidgetClass parent_class; + void (* doubled) (UiVis *vis); +}; + +GtkWidget* ui_vis_new (GtkWidget *fixed, gint x, gint y, gint width); +GtkType ui_vis_get_type(void); +void ui_vis_set_vis(GtkWidget *widget, gint num); +void ui_vis_clear_data(GtkWidget *widget); +void ui_vis_timeout_func(GtkWidget *widget, guchar * data); +void ui_vis_set_visible(GtkWidget *widget, gboolean window_is_visible); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDACIOUS_UI_VIS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/main.c --- a/src/audacious/main.c Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/main.c Sun Jul 06 17:55:40 2008 +0200 @@ -58,8 +58,8 @@ #include "playlist.h" #include "pluginenum.h" #include "signals.h" -#include "ui_manager.h" -#include "ui_skin.h" +#include "legacy/ui_manager.h" +#include "legacy/ui_skin.h" #include "util.h" #include "vfs.h" diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/main.h --- a/src/audacious/main.h Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/main.h Sun Jul 06 17:55:40 2008 +0200 @@ -27,7 +27,7 @@ #define AUDACIOUS_MAIN_H #ifdef _AUDACIOUS_CORE -# include "ui_main.h" +# include "legacy/ui_main.h" # ifdef USE_DBUS # include "dbus-service.h" # endif diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/playlist.c --- a/src/audacious/playlist.c Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/playlist.c Sun Jul 06 17:55:40 2008 +0200 @@ -61,7 +61,7 @@ #include "playlist_evmessages.h" #include "pluginenum.h" #include "strings.h" -#include "ui_playlist.h" +#include "legacy/ui_playlist.h" #include "util.h" #include "vfs.h" diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/pluginenum.c --- a/src/audacious/pluginenum.c Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/pluginenum.c Sun Jul 06 17:55:40 2008 +0200 @@ -55,7 +55,7 @@ #include "vfs_buffered_file.h" #include "volumecontrol.h" -#include "ui_fileinfo.h" +#include "legacy/ui_fileinfo.h" #include "ui_fileinfopopup.h" #include "ui_plugin_menu.h" #include "ui_preferences.h" diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_about.c --- a/src/audacious/ui_about.c Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_albumart.c --- a/src/audacious/ui_albumart.c Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_credits.c --- a/src/audacious/ui_credits.c Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_credits.h --- a/src/audacious/ui_credits.h Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_dock.c --- a/src/audacious/ui_dock.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,531 +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. - */ - -#include "ui_dock.h" - -#include -#include -#include "main.h" -#include "ui_skinned_window.h" - -#include "platform/smartinclude.h" - -static GList *dock_window_list = NULL; - -struct _DockedWindow { - GtkWindow *w; - gint offset_x, offset_y; -}; - -typedef struct _DockedWindow DockedWindow; - - -static gint -docked_list_compare(DockedWindow * a, DockedWindow * b) -{ - if (a->w == b->w) - return 0; - return 1; -} - -static void -snap_edge(gint * x, gint * y, gint w, gint h, gint bx, gint by, - gint bw, gint bh) -{ - gint sd = cfg.snap_distance; - - if ((*x + w > bx - sd) && (*x + w < bx + sd) && - (*y > by - h - sd) && (*y < by + bh + sd)) { - *x = bx - w; - if ((*y > by - sd) && (*y < by + sd)) - *y = by; - if ((*y + h > by + bh - sd) && (*y + h < by + bh + sd)) - *y = by + bh - h; - } - if ((*x > bx + bw - sd) && (*x < bx + bw + sd) && - (*y > by - h - sd) && (*y < by + bh + sd)) { - *x = bx + bw; - if ((*y > by - sd) && (*y < by + sd)) - *y = by; - if ((*y + h > by + bh - sd) && (*y + h < by + bh + sd)) - *y = by + bh - h; - } -} - -static void -snap(gint * x, gint * y, gint w, gint h, gint bx, gint by, gint bw, gint bh) -{ - snap_edge(x, y, w, h, bx, by, bw, bh); - snap_edge(y, x, h, w, by, bx, bh, bw); -} - -static void -calc_snap_offset(GList * dlist, GList * wlist, gint x, gint y, - gint * off_x, gint * off_y) -{ - gint nx, ny, nw, nh, sx, sy, sw, sh; - GtkWindow *w; - GList *dnode, *wnode; - DockedWindow temp, *dw; - - - *off_x = 0; - *off_y = 0; - - if (!cfg.snap_windows) - return; - - /* - * FIXME: Why not break out of the loop when we find someting - * to snap to? - */ - for (dnode = dlist; dnode; dnode = g_list_next(dnode)) { - dw = dnode->data; - gtk_window_get_size(dw->w, &nw, &nh); - - nx = dw->offset_x + *off_x + x; - ny = dw->offset_y + *off_y + y; - - /* Snap to screen edges */ - if (abs(nx) < cfg.snap_distance) - *off_x -= nx; - if (abs(ny) < cfg.snap_distance) - *off_y -= ny; - if (abs(nx + nw - gdk_screen_width()) < cfg.snap_distance) - *off_x -= nx + nw - gdk_screen_width(); - if (abs(ny + nh - gdk_screen_height()) < cfg.snap_distance) - *off_y -= ny + nh - gdk_screen_height(); - - /* Snap to other windows */ - for (wnode = wlist; wnode; wnode = g_list_next(wnode)) { - temp.w = wnode->data; - if (g_list_find_custom - (dlist, &temp, (GCompareFunc) docked_list_compare)) - /* These windows are already docked */ - continue; - - w = GTK_WINDOW(wnode->data); - gtk_window_get_position(w, &sx, &sy); - gtk_window_get_size(w, &sw, &sh); - - nx = dw->offset_x + *off_x + x; - ny = dw->offset_y + *off_y + y; - - snap(&nx, &ny, nw, nh, sx, sy, sw, sh); - - *off_x += nx - (dw->offset_x + *off_x + x); - *off_y += ny - (dw->offset_y + *off_y + y); - } - } -} - - -static gboolean -is_docked(gint a_x, gint a_y, gint a_w, gint a_h, - gint b_x, gint b_y, gint b_w, gint b_h) -{ - if (((a_x == b_x + b_w) || (a_x + a_w == b_x)) && - (b_y + b_h >= a_y) && (b_y <= a_y + a_h)) - return TRUE; - - if (((a_y == b_y + b_h) || (a_y + a_h == b_y)) && - (b_x >= a_x - b_w) && (b_x <= a_x + a_w)) - return TRUE; - - return FALSE; -} - -/* - * Builds a list of all windows that are docked to the window "w". - * Recursively adds all windows that are docked to the windows that are - * docked to "w" and so on... - * FIXME: init_off_? ? - */ - -static GList * -get_docked_list(GList * dlist, GList * wlist, GtkWindow * w, - gint init_off_x, gint init_off_y) -{ - GList *node; - DockedWindow *dwin, temp; - gint w_x, w_y, w_width, w_height; - gint t_x, t_y, t_width, t_height; - - - gtk_window_get_position(w, &w_x, &w_y); - gtk_window_get_size(w, &w_width, &w_height); - if (!dlist) { - dwin = g_new0(DockedWindow, 1); - dwin->w = w; - dlist = g_list_append(dlist, dwin); - } - - for (node = wlist; node; node = g_list_next(node)) { - temp.w = node->data; - if (g_list_find_custom - (dlist, &temp, (GCompareFunc) docked_list_compare)) - continue; - - gtk_window_get_position(GTK_WINDOW(node->data), &t_x, &t_y); - gtk_window_get_size(GTK_WINDOW(node->data), &t_width, &t_height); - if (is_docked - (w_x, w_y, w_width, w_height, t_x, t_y, t_width, t_height)) { - dwin = g_new0(DockedWindow, 1); - dwin->w = node->data; - - dwin->offset_x = t_x - w_x + init_off_x; - dwin->offset_y = t_y - w_y + init_off_y; - - dlist = g_list_append(dlist, dwin); - - dlist = - get_docked_list(dlist, wlist, dwin->w, dwin->offset_x, - dwin->offset_y); - } - } - return dlist; -} - -static void -free_docked_list(GList * dlist) -{ - GList *node; - - for (node = dlist; node; node = g_list_next(node)) - g_free(node->data); - g_list_free(dlist); -} - -static void -docked_list_move(GList * list, gint x, gint y) -{ - GList *node; - DockedWindow *dw; - - for (node = list; node; node = g_list_next(node)) { - dw = node->data; - gtk_window_move(dw->w, x + dw->offset_x, y + dw->offset_y); - - SkinnedWindow *window = SKINNED_WINDOW(dw->w); - if (window) { - switch(window->type) { - - case WINDOW_MAIN: - cfg.player_x = x + dw->offset_x; - cfg.player_y = y + dw->offset_y; - break; - case WINDOW_EQ: - cfg.equalizer_x = x + dw->offset_x; - cfg.equalizer_y = y + dw->offset_y; - break; - case WINDOW_PLAYLIST: - cfg.playlist_x = x + dw->offset_x; - cfg.playlist_y = y + dw->offset_y; - break; - } - - window->x = x + dw->offset_x; - window->y = y + dw->offset_y; - } - } -} - -static GList * -shade_move_list(GList * list, GtkWindow * widget, gint offset) -{ - gint x, y, w, h; - GList *node; - DockedWindow *dw; - - gtk_window_get_position(widget, &x, &y); - gtk_window_get_size(widget, &w, &h); - - - for (node = list; node;) { - gint dx, dy, dwidth, dheight; - - dw = node->data; - gtk_window_get_position(dw->w, &dx, &dy); - gtk_window_get_size(dw->w, &dwidth, &dheight); - if (is_docked(x, y, w, h, dx, dy, dwidth, dheight) && - ((dx + dwidth) > x && dx < (x + w))) { - list = g_list_remove_link(list, node); - g_list_free_1(node); - - node = list = shade_move_list(list, dw->w, offset); - } - else - node = g_list_next(node); - } - gtk_window_move(widget, x, y + offset); - return list; -} - -/* - * Builds a list of the windows in the list of DockedWindows "winlist" - * that are docked to the top or bottom of the window, and recursively - * adds all windows that are docked to the top or bottom of that window, - * and so on... - * Note: The data in "winlist" is not copied. - */ -static GList * -find_shade_list(GtkWindow * widget, GList * winlist, GList * shade_list) -{ - gint x, y, w, h; - gint dx, dy, dwidth, dheight; - GList *node; - - gtk_window_get_position(widget, &x, &y); - gtk_window_get_size(widget, &w, &h); - for (node = winlist; node; node = g_list_next(node)) { - DockedWindow *dw = node->data; - if (g_list_find_custom - (shade_list, dw, (GCompareFunc) docked_list_compare)) - continue; - gtk_window_get_position(dw->w, &dx, &dy); - gtk_window_get_size(dw->w, &dwidth, &dheight); - - /* FIXME. Is the is_docked() necessary? */ - if (is_docked(x, y, w, h, dx, dy, dwidth, dheight) && - ((dx + dwidth) > x && dx < (x + w))) { - shade_list = g_list_append(shade_list, dw); - shade_list = find_shade_list(dw->w, winlist, shade_list); - } - } - return shade_list; -} - -void -dock_window_resize(GtkWindow * widget, gint new_w, gint new_h, gint w, gint h) -{ - gdk_window_set_hints(GTK_WIDGET(widget)->window, 0, 0, MIN(w, new_w), - MIN(h, new_h), MAX(w, new_w), MAX(h, new_h), - GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); - gdk_window_resize(GTK_WIDGET(widget)->window, new_w, new_h); - gdk_window_set_hints(GTK_WIDGET(widget)->window, 0, 0, new_w, new_h, - new_w, new_h, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); -} - -void -dock_shade(GList * window_list, GtkWindow * widget, gint new_h) -{ - gint x, y, w, h, off_y, orig_off_y; - GList *node, *docked_list, *slist; - DockedWindow *dw; - - gtk_window_get_position(widget, &x, &y); - gtk_window_get_size(widget, &w, &h); - - if (cfg.show_wm_decorations) { - dock_window_resize(widget, w, new_h, w, h); - return; - } - - docked_list = get_docked_list(NULL, window_list, widget, 0, 0); - slist = find_shade_list(widget, docked_list, NULL); - - off_y = new_h - h; - do { - orig_off_y = off_y; - for (node = slist; node; node = g_list_next(node)) { - gint dx, dy, dwidth, dheight; - - dw = node->data; - if (dw->w == widget) - continue; - gtk_window_get_position(dw->w, &dx, &dy); - gtk_window_get_size(dw->w, &dwidth, &dheight); - if ((dy >= y) && ((dy + off_y + dheight) > gdk_screen_height())) - off_y -= (dy + off_y + dheight) - gdk_screen_height(); - else if ((dy >= y) && ((dy + dheight) == gdk_screen_height())) - off_y = 0; - - if (((dy >= y) && ((dy + off_y) < 0))) - off_y -= dy + off_y; - if ((dy < y) && ((dy + (off_y - (new_h - h))) < 0)) - off_y -= dy + (off_y - (new_h - h)); - } - } while (orig_off_y != off_y); - if (slist) { - GList *mlist = g_list_copy(slist); - - /* Remove this widget from the list */ - for (node = mlist; node; node = g_list_next(node)) { - dw = node->data; - if (dw->w == widget) { - mlist = g_list_remove_link(mlist, node); - g_list_free_1(node); - break; - } - } - for (node = mlist; node;) { - GList *temp; - gint dx, dy, dwidth, dheight; - - dw = node->data; - - gtk_window_get_position(dw->w, &dx, &dy); - gtk_window_get_size(dw->w, &dwidth, &dheight); - /* - * Find windows that are directly docked to this window, - * move it, and any windows docked to that window again - */ - if (is_docked(x, y, w, h, dx, dy, dwidth, dheight) && - ((dx + dwidth) > x && dx < (x + w))) { - mlist = g_list_remove_link(mlist, node); - g_list_free_1(node); - if (dy > y) - temp = shade_move_list(mlist, dw->w, off_y); - else if (off_y - (new_h - h) != 0) - temp = shade_move_list(mlist, dw->w, off_y - (new_h - h)); - else - temp = mlist; - node = mlist = temp; - } - else - node = g_list_next(node); - } - g_list_free(mlist); - } - g_list_free(slist); - free_docked_list(docked_list); - gtk_window_move(widget, x, y + off_y - (new_h - h)); - dock_window_resize(widget, w, new_h, w, h); -} - -void -dock_move_press(GList * window_list, GtkWindow * w, - GdkEventButton * event, gboolean move_list) -{ - gint mx, my; - DockedWindow *dwin; - - if (cfg.show_wm_decorations) - return; - - gtk_window_present(w); - mx = event->x; - my = event->y; - gtk_object_set_data(GTK_OBJECT(w), "move_offset_x", GINT_TO_POINTER(mx)); - gtk_object_set_data(GTK_OBJECT(w), "move_offset_y", GINT_TO_POINTER(my)); - if (move_list) - gtk_object_set_data(GTK_OBJECT(w), "docked_list", - get_docked_list(NULL, window_list, w, 0, 0)); - else { - dwin = g_new0(DockedWindow, 1); - dwin->w = w; - gtk_object_set_data(GTK_OBJECT(w), "docked_list", - g_list_append(NULL, dwin)); - } - gtk_object_set_data(GTK_OBJECT(w), "window_list", window_list); - gtk_object_set_data(GTK_OBJECT(w), "is_moving", GINT_TO_POINTER(1)); -} - -void -dock_move_motion(GtkWindow * w, GdkEventMotion * event) -{ - gint offset_x, offset_y, x, y; - GList *dlist; - GList *window_list; - - if (!gtk_object_get_data(GTK_OBJECT(w), "is_moving")) - return; - - offset_x = - GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(w), "move_offset_x")); - offset_y = - GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(w), "move_offset_y")); - dlist = gtk_object_get_data(GTK_OBJECT(w), "docked_list"); - window_list = gtk_object_get_data(GTK_OBJECT(w), "window_list"); - - x = event->x_root - offset_x; - y = event->y_root - offset_y; - - calc_snap_offset(dlist, window_list, x, y, &offset_x, &offset_y); - x += offset_x; - y += offset_y; - - docked_list_move(dlist, x, y); -} - -void -dock_move_release(GtkWindow * w) -{ - GList *dlist; - gtk_object_remove_data(GTK_OBJECT(w), "is_moving"); - gtk_object_remove_data(GTK_OBJECT(w), "move_offset_x"); - gtk_object_remove_data(GTK_OBJECT(w), "move_offset_y"); - if ((dlist = gtk_object_get_data(GTK_OBJECT(w), "docked_list")) != NULL) - free_docked_list(dlist); - gtk_object_remove_data(GTK_OBJECT(w), "docked_list"); - gtk_object_remove_data(GTK_OBJECT(w), "window_list"); -} - -gboolean -dock_is_moving(GtkWindow * w) -{ - if (gtk_object_get_data(GTK_OBJECT(w), "is_moving")) - return TRUE; - return FALSE; -} - -GList * -dock_add_window(GList * list, GtkWindow * window) -{ - return g_list_append(list, window); -} - -GList * -dock_remove_window(GList * list, GtkWindow * window) -{ - return g_list_remove(list, window); -} - -GList * -dock_window_set_decorated(GList * list, GtkWindow * window, - gboolean decorated) -{ - if (gtk_window_get_decorated(window) == decorated) - return list; - - if (decorated) - list = dock_remove_window(list, window); - else - list = dock_add_window(list, window); - - gtk_window_set_decorated(window, decorated); - - return list; -} - -GList * -get_dock_window_list() { - return dock_window_list; -} - -void -set_dock_window_list(GList * list) { - dock_window_list = list; -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_dock.h --- a/src/audacious/ui_dock.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +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_DOCK_H -#define AUDACIOUS_UI_DOCK_H - -#include -#include - -void dock_set_uposition(GtkWindow * widget, gint x, gint y); -GList *dock_add_window(GList * window_list, GtkWindow * window); -GList *dock_remove_window(GList * window_list, GtkWindow * window); -void dock_move_press(GList * window_list, GtkWindow * w, - GdkEventButton * event, gboolean move_list); -void dock_move_motion(GtkWindow * w, GdkEventMotion * event); -void dock_move_release(GtkWindow * w); -void dock_get_widget_pos(GtkWindow * w, gint * x, gint * y); -gboolean dock_is_moving(GtkWindow * w); -void dock_shade(GList * window_list, GtkWindow * widget, gint new_h); - -GList *dock_window_set_decorated(GList * list, GtkWindow * window, - gboolean decorated); -void dock_window_resize(GtkWindow * widget, gint new_w, gint new_h, gint w, gint h); - -GList *get_dock_window_list(); -void set_dock_window_list(GList * list); - -#endif /* AUDACIOUS_UI_DOCK_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_equalizer.c --- a/src/audacious/ui_equalizer.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1521 +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. - */ - -/*#define AUD_DEBUG*/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "ui_equalizer.h" - -#include -#include -#include -#include -#include -#include - -#include "platform/smartinclude.h" -#include "ui_skin.h" -#include "input.h" -#include "main.h" -#include "ui_manager.h" -#include "actions-equalizer.h" -#include "playlist.h" -#include "ui_playlist.h" -#include "util.h" -#include "output.h" -#include "equalizer_flow.h" - -#include "rcfile.h" -#include "vfs.h" - -#include "images/audacious_eq.xpm" - -#include "ui_dock.h" -#include "ui_skinned_window.h" -#include "ui_skinned_button.h" -#include "ui_skinned_horizontal_slider.h" -#include "ui_skinned_equalizer_slider.h" -#include "ui_skinned_equalizer_graph.h" - -enum PresetViewCols { - PRESET_VIEW_COL_NAME, - PRESET_VIEW_N_COLS -}; - -struct _EqualizerPreset { - gchar *name; - gfloat preamp, bands[AUD_EQUALIZER_NBANDS]; -}; - -typedef struct _EqualizerPreset EqualizerPreset; - - -GtkWidget *equalizerwin; -GtkWidget *equalizerwin_graph; - -static GtkWidget *equalizerwin_load_window = NULL; -static GtkWidget *equalizerwin_load_auto_window = NULL; -static GtkWidget *equalizerwin_save_window = NULL; -static GtkWidget *equalizerwin_save_entry = NULL; -static GtkWidget *equalizerwin_save_auto_window = NULL; -static GtkWidget *equalizerwin_save_auto_entry = NULL; -static GtkWidget *equalizerwin_delete_window = NULL; -static GtkWidget *equalizerwin_delete_auto_window = NULL; - -static GtkWidget *equalizerwin_on, *equalizerwin_auto; - -static GtkWidget *equalizerwin_close, *equalizerwin_presets, *equalizerwin_shade; -static GtkWidget *equalizerwin_preamp,*equalizerwin_bands[AUD_EQUALIZER_NBANDS]; -static GtkWidget *equalizerwin_volume, *equalizerwin_balance; - -static GList *equalizer_presets = NULL, *equalizer_auto_presets = NULL; - -EqualizerPreset * -equalizer_preset_new(const gchar * name) -{ - EqualizerPreset *preset = g_new0(EqualizerPreset, 1); - preset->name = g_strdup(name); - return preset; -} - -void -equalizer_preset_free(EqualizerPreset * preset) -{ - if (!preset) - return; - - g_free(preset->name); - g_free(preset); -} - -void -equalizerwin_set_scaled(gboolean ds) -{ - gint height; - - if (cfg.equalizer_shaded) - height = 14; - else - height = 116; - - if (cfg.scaled) { - dock_window_resize(GTK_WINDOW(equalizerwin), 275 * cfg.scale_factor, - height * cfg.scale_factor, 275 * cfg.scale_factor, height * cfg.scale_factor); - } else { - dock_window_resize(GTK_WINDOW(equalizerwin), 275, height, 275, height); - } - - GList *iter; - for (iter = GTK_FIXED (SKINNED_WINDOW(equalizerwin)->fixed)->children; iter; iter = g_list_next (iter)) { - GtkFixedChild *child_data = (GtkFixedChild *) iter->data; - GtkWidget *child = child_data->widget; - g_signal_emit_by_name(child, "toggle-scaled"); - } - gtk_widget_shape_combine_mask(equalizerwin, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + cfg.equalizer_shaded), 0, 0); -} - -void -equalizerwin_set_shade_menu_cb(gboolean shaded) -{ - cfg.equalizer_shaded = shaded; - - if (shaded) { - dock_shade(get_dock_window_list(), GTK_WINDOW(equalizerwin), - 14 * EQUALIZER_SCALE_FACTOR); - ui_skinned_set_push_button_data(equalizerwin_shade, -1, 3, -1, 47); - ui_skinned_button_set_skin_index1(equalizerwin_shade, SKIN_EQ_EX); - ui_skinned_set_push_button_data(equalizerwin_close, 11, 38, 11, 47); - ui_skinned_button_set_skin_index(equalizerwin_close, SKIN_EQ_EX); - gtk_widget_show(equalizerwin_volume); - gtk_widget_show(equalizerwin_balance); - } - else { - dock_shade(get_dock_window_list(), GTK_WINDOW(equalizerwin), - 116 * EQUALIZER_SCALE_FACTOR); - ui_skinned_set_push_button_data(equalizerwin_shade, -1, 137, -1, 38); - ui_skinned_button_set_skin_index1(equalizerwin_shade, SKIN_EQMAIN); - ui_skinned_set_push_button_data(equalizerwin_close, 0, 116, 0, 125); - ui_skinned_button_set_skin_index(equalizerwin_close, SKIN_EQMAIN); - gtk_widget_hide(equalizerwin_volume); - gtk_widget_hide(equalizerwin_balance); - } - - gtk_widget_shape_combine_mask(equalizerwin, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + cfg.equalizer_shaded), 0, 0); -} - -static void -equalizerwin_set_shade(gboolean shaded) -{ - GtkAction *action = gtk_action_group_get_action( - toggleaction_group_others , "roll up equalizer" ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , shaded ); -} - -static void -equalizerwin_shade_toggle(void) -{ - equalizerwin_set_shade(!cfg.equalizer_shaded); -} - -void -equalizerwin_eq_changed(void) -{ - gint i; - - cfg.equalizer_preamp = ui_skinned_equalizer_slider_get_position(equalizerwin_preamp); - for (i = 0; i < AUD_EQUALIZER_NBANDS; i++) - cfg.equalizer_bands[i] = ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i]); - - output_set_eq(cfg.equalizer_active, cfg.equalizer_preamp, - cfg.equalizer_bands); - - gtk_widget_queue_draw(equalizerwin_graph); -} - -static void -equalizerwin_on_pushed(void) -{ - cfg.equalizer_active = UI_SKINNED_BUTTON(equalizerwin_on)->inside; - equalizerwin_eq_changed(); -} - -static void -equalizerwin_presets_pushed(void) -{ - GdkModifierType modmask; - gint x, y; - - gdk_window_get_pointer(NULL, &x, &y, &modmask); - ui_manager_popup_menu_show(GTK_MENU(equalizerwin_presets_menu), x, y, 1, GDK_CURRENT_TIME); -} - -static void -equalizerwin_auto_pushed(void) -{ - cfg.equalizer_autoload = UI_SKINNED_BUTTON(equalizerwin_auto)->inside; -} - -gboolean -equalizerwin_press(GtkWidget * widget, GdkEventButton * event, - gpointer callback_data) -{ - if (event->button == 1 && event->type == GDK_2BUTTON_PRESS - && event->y < 14) { - equalizerwin_set_shade(!cfg.equalizer_shaded); - if (dock_is_moving(GTK_WINDOW(equalizerwin))) - dock_move_release(GTK_WINDOW(equalizerwin)); - return TRUE; - } - if (event->button == 3) { - /* - * Pop up the main menu a few pixels down to avoid - * anything to be selected initially. - */ - ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), event->x_root, - event->y_root + 2, 3, event->time); - return TRUE; - } - - return FALSE; -} - -static gboolean -equalizerwin_keypress(GtkWidget * widget, - GdkEventKey * event, - gpointer data) -{ - if (event->keyval == GDK_Tab && event->state & GDK_CONTROL_MASK) { - if (cfg.playlist_visible) - gtk_window_present(GTK_WINDOW(playlistwin)); - else if (cfg.player_visible) - gtk_window_present(GTK_WINDOW(mainwin)); - return TRUE; - } - - if (!cfg.equalizer_shaded) { - gtk_widget_event(mainwin, (GdkEvent *) event); - return TRUE; - } - - switch (event->keyval) { - case GDK_Left: - case GDK_KP_Left: - mainwin_set_balance_diff(-4); - break; - case GDK_Right: - case GDK_KP_Right: - mainwin_set_balance_diff(4); - break; - default: - gtk_widget_event(mainwin, (GdkEvent *) event); - break; - } - - return FALSE; -} - -static void -equalizerwin_close_cb(void) -{ - equalizerwin_show(FALSE); -} - -static gboolean -equalizerwin_delete(GtkWidget * widget, - gpointer data) -{ - equalizerwin_show(FALSE); - return TRUE; -} - -static GList * -equalizerwin_read_presets(const gchar * basename) -{ - gchar *filename, *name; - RcFile *rcfile; - GList *list = NULL; - gint i, p = 0; - EqualizerPreset *preset; - - /* START mod: add check for the default presets locate in system path ({prefix}/share/audacious) - by Massimo Cavalleri (submax) */ - - filename = g_build_filename(aud_paths[BMP_PATH_USER_DIR], basename, NULL); - - if ((rcfile = aud_rcfile_open(filename)) == NULL) { - g_free(filename); - // DATA_DIR = "{prefix}/share/audacious" ; example is "/usr/share/audacious" - filename = g_build_filename(DATA_DIR, basename, NULL); - if ((rcfile = aud_rcfile_open(filename)) == NULL) { - g_free(filename); - return NULL; - } - } - - // END mod - - g_free(filename); - - for (;;) { - gchar section[32]; - - g_snprintf(section, sizeof(section), "Preset%d", p++); - if (aud_rcfile_read_string(rcfile, "Presets", section, &name)) { - preset = g_new0(EqualizerPreset, 1); - preset->name = name; - aud_rcfile_read_float(rcfile, name, "Preamp", &preset->preamp); - for (i = 0; i < AUD_EQUALIZER_NBANDS; i++) { - gchar band[16]; - g_snprintf(band, sizeof(band), "Band%d", i); - aud_rcfile_read_float(rcfile, name, band, &preset->bands[i]); - } - list = g_list_prepend(list, preset); - } - else - break; - } - list = g_list_reverse(list); - aud_rcfile_free(rcfile); - return list; -} - -gint -equalizerwin_volume_frame_cb(gint pos) -{ - if (equalizerwin_volume) { - gint x; - if (pos < 32) - x = 1; - else if (pos < 63) - x = 4; - else - x = 7; - - UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_volume)->knob_nx = x; - UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_volume)->knob_px = x; - } - return 1; -} - -static void -equalizerwin_volume_motion_cb(GtkWidget *widget, gint pos) -{ - gint v = (gint) rint(pos * 100 / 94.0); - mainwin_adjust_volume_motion(v); - mainwin_set_volume_slider(v); -} - -static void -equalizerwin_volume_release_cb(GtkWidget *widget, gint pos) -{ - mainwin_adjust_volume_release(); -} - -static gint -equalizerwin_balance_frame_cb(gint pos) -{ - if (equalizerwin_balance) { - gint x; - if (pos < 13) - x = 11; - else if (pos < 26) - x = 14; - else - x = 17; - - UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_balance)->knob_nx = x; - UI_SKINNED_HORIZONTAL_SLIDER(equalizerwin_balance)->knob_px = x; - } - - return 1; -} - -static void -equalizerwin_balance_motion_cb(GtkWidget *widget, gint pos) -{ - gint b; - pos = MIN(pos, 38); /* The skin uses a even number of pixels - for the balance-slider *sigh* */ - b = (gint) rint((pos - 19) * 100 / 19.0); - mainwin_adjust_balance_motion(b); - mainwin_set_balance_slider(b); -} - -static void -equalizerwin_balance_release_cb(GtkWidget *widget, gint pos) -{ - mainwin_adjust_balance_release(); -} - -void -equalizerwin_set_balance_slider(gint percent) -{ - ui_skinned_horizontal_slider_set_position(equalizerwin_balance, - (gint) rint((percent * 19 / 100.0) + 19)); -} - -void -equalizerwin_set_volume_slider(gint percent) -{ - ui_skinned_horizontal_slider_set_position(equalizerwin_volume, - (gint) rint(percent * 94 / 100.0)); -} - -static void -equalizerwin_create_widgets(void) -{ - gint i; - - equalizerwin_on = ui_skinned_button_new(); - ui_skinned_toggle_button_setup(equalizerwin_on, SKINNED_WINDOW(equalizerwin)->fixed, - 14, 18, 25, 12, 10, 119, 128, 119, 69, 119, 187, 119, SKIN_EQMAIN); - g_signal_connect(equalizerwin_on, "clicked", equalizerwin_on_pushed, NULL); - UI_SKINNED_BUTTON(equalizerwin_on)->inside = cfg.equalizer_active; - - equalizerwin_auto = ui_skinned_button_new(); - ui_skinned_toggle_button_setup(equalizerwin_auto, SKINNED_WINDOW(equalizerwin)->fixed, - 39, 18, 33, 12, 35, 119, 153, 119, 94, 119, 212, 119, SKIN_EQMAIN); - g_signal_connect(equalizerwin_auto, "clicked", equalizerwin_auto_pushed, NULL); - UI_SKINNED_BUTTON(equalizerwin_auto)->inside = cfg.equalizer_autoload; - - equalizerwin_presets = ui_skinned_button_new(); - ui_skinned_push_button_setup(equalizerwin_presets, SKINNED_WINDOW(equalizerwin)->fixed, - 217, 18, 44, 12, 224, 164, 224, 176, SKIN_EQMAIN); - g_signal_connect(equalizerwin_presets, "clicked", equalizerwin_presets_pushed, NULL ); - - equalizerwin_close = ui_skinned_button_new(); - ui_skinned_push_button_setup(equalizerwin_close, SKINNED_WINDOW(equalizerwin)->fixed, - 264, 3, 9, 9, 0, 116, 0, 125, SKIN_EQMAIN); - g_signal_connect(equalizerwin_close, "clicked", equalizerwin_close_cb, NULL ); - - equalizerwin_shade = ui_skinned_button_new(); - ui_skinned_push_button_setup(equalizerwin_shade, SKINNED_WINDOW(equalizerwin)->fixed, - 254, 3, 9, 9, 254, 137, 1, 38, SKIN_EQMAIN); - ui_skinned_button_set_skin_index2(equalizerwin_shade, SKIN_EQ_EX); - g_signal_connect(equalizerwin_shade, "clicked", equalizerwin_shade_toggle, NULL ); - - equalizerwin_graph = ui_skinned_equalizer_graph_new(SKINNED_WINDOW(equalizerwin)->fixed, 86, 17); - - equalizerwin_preamp = ui_skinned_equalizer_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, 21, 38); - ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, cfg.equalizer_preamp); - - for (i = 0; i < AUD_EQUALIZER_NBANDS; i++) { - equalizerwin_bands[i] = - ui_skinned_equalizer_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, 78 + (i * 18), 38); - ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], cfg.equalizer_bands[i]); - } - - equalizerwin_volume = - ui_skinned_horizontal_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, - 61, 4, 97, 8, 1, 30, 1, 30, 3, 7, 4, 61, 0, 94, - equalizerwin_volume_frame_cb, SKIN_EQ_EX); - g_signal_connect(equalizerwin_volume, "motion", G_CALLBACK(equalizerwin_volume_motion_cb), NULL); - g_signal_connect(equalizerwin_volume, "release", G_CALLBACK(equalizerwin_volume_release_cb), NULL); - - - equalizerwin_balance = - ui_skinned_horizontal_slider_new(SKINNED_WINDOW(equalizerwin)->fixed, - 164, 4, 42, 8, 11, 30, 11, 30, 3, 7, 4, 164, 0, 39, - equalizerwin_balance_frame_cb, SKIN_EQ_EX); - g_signal_connect(equalizerwin_balance, "motion", G_CALLBACK(equalizerwin_balance_motion_cb), NULL); - g_signal_connect(equalizerwin_balance, "release", G_CALLBACK(equalizerwin_balance_release_cb), NULL); -} - - -static void -equalizerwin_create_window(void) -{ - GdkPixbuf *icon; - gint width, height; - - width = 275; - height = cfg.equalizer_shaded ? 14 : 116; - - equalizerwin = ui_skinned_window_new("equalizer"); - gtk_window_set_title(GTK_WINDOW(equalizerwin), _("Audacious Equalizer")); - gtk_window_set_role(GTK_WINDOW(equalizerwin), "equalizer"); - gtk_window_set_resizable(GTK_WINDOW(equalizerwin), FALSE); - - if (cfg.scaled && cfg.eq_scaled_linked) { - width *= cfg.scale_factor; - height *= cfg.scale_factor; - } - - gtk_widget_set_size_request(equalizerwin, width, height); - - /* this will hide only mainwin. it's annoying! yaz */ - gtk_window_set_transient_for(GTK_WINDOW(equalizerwin), - GTK_WINDOW(mainwin)); - gtk_window_set_skip_taskbar_hint(GTK_WINDOW(equalizerwin), TRUE); - - icon = gdk_pixbuf_new_from_xpm_data((const gchar **) audacious_eq_icon); - gtk_window_set_icon(GTK_WINDOW(equalizerwin), icon); - g_object_unref(icon); - - gtk_widget_set_app_paintable(equalizerwin, TRUE); - - if (cfg.equalizer_x != -1 && cfg.save_window_position) - gtk_window_move(GTK_WINDOW(equalizerwin), - cfg.equalizer_x, cfg.equalizer_y); - - g_signal_connect(equalizerwin, "delete_event", - G_CALLBACK(equalizerwin_delete), NULL); - g_signal_connect(equalizerwin, "button_press_event", - G_CALLBACK(equalizerwin_press), NULL); - g_signal_connect(equalizerwin, "key_press_event", - G_CALLBACK(equalizerwin_keypress), NULL); -} - -void -equalizerwin_create(void) -{ - equalizer_presets = equalizerwin_read_presets("eq.preset"); - equalizer_auto_presets = equalizerwin_read_presets("eq.auto_preset"); - - equalizerwin_create_window(); - - gtk_window_add_accel_group( GTK_WINDOW(equalizerwin) , ui_manager_get_accel_group() ); - - equalizerwin_create_widgets(); -} - - -void -equalizerwin_show(gboolean show) -{ - GtkAction *action = gtk_action_group_get_action( - toggleaction_group_others , "show equalizer" ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , show ); - - if (show) - equalizerwin_real_show(); - else - equalizerwin_real_hide(); -} - -void -equalizerwin_real_show(void) -{ - gtk_window_move(GTK_WINDOW(equalizerwin), cfg.equalizer_x, cfg.equalizer_y); - if (cfg.scaled && cfg.eq_scaled_linked) - gtk_widget_set_size_request(equalizerwin, 275 * cfg.scale_factor, - ((cfg.equalizer_shaded ? 14 : 116) * cfg.scale_factor)); - else - gtk_widget_set_size_request(equalizerwin, 275, - (cfg.equalizer_shaded ? 14 : 116)); - cfg.equalizer_visible = TRUE; - UI_SKINNED_BUTTON(mainwin_eq)->inside = TRUE; - gtk_widget_show_all(equalizerwin); - - if (!cfg.equalizer_shaded) { - gtk_widget_hide(equalizerwin_volume); - gtk_widget_hide(equalizerwin_balance); - } - else { - ui_skinned_set_push_button_data(equalizerwin_shade, -1, 3, -1, 47); - ui_skinned_button_set_skin_index1(equalizerwin_shade, SKIN_EQ_EX); - ui_skinned_set_push_button_data(equalizerwin_close, 11, 38, 11, 47); - ui_skinned_button_set_skin_index(equalizerwin_close, SKIN_EQ_EX); - } - - gtk_window_present(GTK_WINDOW(equalizerwin)); -} - -void -equalizerwin_real_hide(void) -{ - /* - * This function should only be called from the - * main menu signal handler - */ - gtk_widget_hide(equalizerwin); - cfg.equalizer_visible = FALSE; - UI_SKINNED_BUTTON(mainwin_eq)->inside = FALSE; - gtk_widget_queue_draw(mainwin_eq); -} - -static EqualizerPreset * -equalizerwin_find_preset(GList * list, const gchar * name) -{ - GList *node = list; - EqualizerPreset *preset; - - while (node) { - preset = node->data; - if (!strcasecmp(preset->name, name)) - return preset; - node = g_list_next(node); - } - return NULL; -} - -static void -equalizerwin_write_preset_file(GList * list, const gchar * basename) -{ - gchar *filename, *tmp; - gint i, p; - EqualizerPreset *preset; - RcFile *rcfile; - GList *node; - - rcfile = aud_rcfile_new(); - p = 0; - for (node = list; node; node = g_list_next(node)) { - preset = node->data; - tmp = g_strdup_printf("Preset%d", p++); - aud_rcfile_write_string(rcfile, "Presets", tmp, preset->name); - g_free(tmp); - aud_rcfile_write_float(rcfile, preset->name, "Preamp", - preset->preamp); - for (i = 0; i < 10; i++) { - tmp = g_strdup_printf("Band%d\n", i); - aud_rcfile_write_float(rcfile, preset->name, tmp, - preset->bands[i]); - g_free(tmp); - } - } - - filename = g_build_filename(aud_paths[BMP_PATH_USER_DIR], basename, NULL); - aud_rcfile_write(rcfile, filename); - aud_rcfile_free(rcfile); - g_free(filename); -} - -static gboolean -equalizerwin_load_preset(GList * list, const gchar * name) -{ - EqualizerPreset *preset; - gint i; - - if ((preset = equalizerwin_find_preset(list, name)) != NULL) { - ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, preset->preamp); - for (i = 0; i < 10; i++) - ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], preset->bands[i]); - equalizerwin_eq_changed(); - return TRUE; - } - return FALSE; -} - -static GList * -equalizerwin_save_preset(GList * list, const gchar * name, - const gchar * filename) -{ - gint i; - EqualizerPreset *preset; - - if (!(preset = equalizerwin_find_preset(list, name))) { - preset = g_new0(EqualizerPreset, 1); - preset->name = g_strdup(name); - list = g_list_append(list, preset); - } - - preset->preamp = ui_skinned_equalizer_slider_get_position(equalizerwin_preamp); - for (i = 0; i < 10; i++) - preset->bands[i] = ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i]); - - equalizerwin_write_preset_file(list, filename); - - return list; -} - -static GList * -equalizerwin_delete_preset(GList * list, gchar * name, gchar * filename) -{ - EqualizerPreset *preset; - GList *node; - - if (!(preset = equalizerwin_find_preset(list, name))) - return list; - - if (!(node = g_list_find(list, preset))) - return list; - - list = g_list_remove_link(list, node); - equalizer_preset_free(preset); - g_list_free_1(node); - - equalizerwin_write_preset_file(list, filename); - - return list; -} - -static void -equalizerwin_delete_selected_presets(GtkTreeView *view, gchar *filename) -{ - gchar *text; - - GtkTreeSelection *selection = gtk_tree_view_get_selection(view); - GtkTreeModel *model = gtk_tree_view_get_model(view); - - /* - * first we are making a list of the selected rows, then we convert this - * list into a list of GtkTreeRowReferences, so that when you delete an - * item you can still access the other items - * finally we iterate through all GtkTreeRowReferences, convert them to - * GtkTreeIters and delete those one after the other - */ - - GList *list = gtk_tree_selection_get_selected_rows(selection, &model); - GList *rrefs = NULL; - GList *litr; - - for (litr = list; litr; litr = litr->next) - { - GtkTreePath *path = litr->data; - rrefs = g_list_append(rrefs, gtk_tree_row_reference_new(model, path)); - } - - for (litr = rrefs; litr; litr = litr->next) - { - GtkTreeRowReference *ref = litr->data; - GtkTreePath *path = gtk_tree_row_reference_get_path(ref); - GtkTreeIter iter; - gtk_tree_model_get_iter(model, &iter, path); - - gtk_tree_model_get(model, &iter, 0, &text, -1); - - if (!strcmp(filename, "eq.preset")) - equalizer_presets = equalizerwin_delete_preset(equalizer_presets, text, filename); - else if (!strcmp(filename, "eq.auto_preset")) - equalizer_auto_presets = equalizerwin_delete_preset(equalizer_auto_presets, text, filename); - - gtk_list_store_remove(GTK_LIST_STORE(model), &iter); - } -} - -static GList * -import_winamp_eqf(VFSFile * file) -{ - gchar header[31]; - gchar bands[11]; - gint i = 0; - EqualizerPreset *preset = NULL; - GList *list = NULL; - GtkWidget *dialog; - gchar *realfn; - gchar preset_name[0xb4]; - - vfs_fread(header, 1, 31, file); - if (strncmp(header, "Winamp EQ library file v1.1", 27)) goto error; - - AUDDBG("The EQF header is OK\n"); - - if (vfs_fseek(file, 0x1f, SEEK_SET) == -1) goto error; - - while (vfs_fread(preset_name, 1, 0xb4, file) == 0xb4) { - AUDDBG("The preset name is '%s'\n", preset_name); - vfs_fseek(file, 0x4d, SEEK_CUR); /* unknown crap --asphyx */ - if (vfs_fread(bands, 1, 11, file) != 11) break; - - preset = equalizer_preset_new(preset_name); - /*this was divided by 63, but shouldn't it be 64? --majeru*/ - preset->preamp = EQUALIZER_MAX_GAIN - ((bands[10] * EQUALIZER_MAX_GAIN * 2) / 64.0); - - for (i = 0; i < 10; i++) - preset->bands[i] = EQUALIZER_MAX_GAIN - ((bands[i] * EQUALIZER_MAX_GAIN * 2) / 64.0); - - list = g_list_prepend(list, preset); - } - - list = g_list_reverse(list); - if (list == NULL) goto error; - - return list; - -error: - realfn = g_filename_from_uri(file->uri, NULL, NULL); - dialog = gtk_message_dialog_new (GTK_WINDOW(mainwin), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - _("Error importing Winamp EQF file '%s'"), - realfn); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - g_free(realfn); - return NULL; -} - -static void -free_cb (gpointer data, gpointer user_data) -{ - equalizer_preset_free((EqualizerPreset*)data); -} - -static void -equalizerwin_read_winamp_eqf(VFSFile * file) -{ - GList *presets; - gint i; - - if ((presets = import_winamp_eqf(file)) == NULL) - return; - - /* just get the first preset --asphyx */ - EqualizerPreset *preset = (EqualizerPreset*)presets->data; - ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, - preset->preamp); - - for (i = 0; i < 10; i++) - ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], - preset->bands[i]); - - g_list_foreach(presets, free_cb, NULL); - g_list_free(presets); - - equalizerwin_eq_changed(); -} - -static void -equalizerwin_read_aud_preset(RcFile * rcfile) -{ - gfloat val; - gint i; - - if (aud_rcfile_read_float(rcfile, "Equalizer preset", "Preamp", &val)) - ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, val); - for (i = 0; i < 10; i++) { - gchar tmp[7]; - g_snprintf(tmp, sizeof(tmp), "Band%d", i); - if (aud_rcfile_read_float(rcfile, "Equalizer preset", tmp, &val)) - ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], val); - } - equalizerwin_eq_changed(); -} - -static void -equalizerwin_save_ok(GtkWidget * widget, gpointer data) -{ - const gchar *text; - - text = gtk_entry_get_text(GTK_ENTRY(equalizerwin_save_entry)); - if (strlen(text) != 0) - equalizer_presets = - equalizerwin_save_preset(equalizer_presets, text, "eq.preset"); - gtk_widget_destroy(equalizerwin_save_window); -} - -static void -equalizerwin_save_select(GtkTreeView *treeview, GtkTreePath *path, - GtkTreeViewColumn *col, gpointer data) -{ - gchar *text; - - GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); - GtkTreeModel *model; - GtkTreeIter iter; - - if (selection) - { - if (gtk_tree_selection_get_selected(selection, &model, &iter)) - { - gtk_tree_model_get(model, &iter, 0, &text, -1); - gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_entry), text); - equalizerwin_save_ok(NULL, NULL); - - g_free(text); - } - } -} - -static void -equalizerwin_load_ok(GtkWidget *widget, gpointer data) -{ - gchar *text; - - GtkTreeView* view = GTK_TREE_VIEW(data); - GtkTreeSelection *selection = gtk_tree_view_get_selection(view); - GtkTreeModel *model; - GtkTreeIter iter; - - if (selection) - { - if (gtk_tree_selection_get_selected(selection, &model, &iter)) - { - gtk_tree_model_get(model, &iter, 0, &text, -1); - equalizerwin_load_preset(equalizer_presets, text); - - g_free(text); - } - } - gtk_widget_destroy(equalizerwin_load_window); -} - -static void -equalizerwin_load_select(GtkTreeView *treeview, GtkTreePath *path, - GtkTreeViewColumn *col, gpointer data) -{ - equalizerwin_load_ok(NULL, treeview); -} - -static void -equalizerwin_delete_delete(GtkWidget *widget, gpointer data) -{ - equalizerwin_delete_selected_presets(GTK_TREE_VIEW(data), "eq.preset"); -} - -static void -equalizerwin_save_auto_ok(GtkWidget *widget, gpointer data) -{ - const gchar *text; - - text = gtk_entry_get_text(GTK_ENTRY(equalizerwin_save_auto_entry)); - if (strlen(text) != 0) - equalizer_auto_presets = - equalizerwin_save_preset(equalizer_auto_presets, text, - "eq.auto_preset"); - gtk_widget_destroy(equalizerwin_save_auto_window); -} - -static void -equalizerwin_save_auto_select(GtkTreeView *treeview, GtkTreePath *path, - GtkTreeViewColumn *col, gpointer data) -{ - gchar *text; - - GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); - GtkTreeModel *model; - GtkTreeIter iter; - - if (selection) - { - if (gtk_tree_selection_get_selected(selection, &model, &iter)) - { - gtk_tree_model_get(model, &iter, 0, &text, -1); - gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_auto_entry), text); - equalizerwin_save_auto_ok(NULL, NULL); - - g_free(text); - } - } -} - -static void -equalizerwin_load_auto_ok(GtkWidget *widget, gpointer data) -{ - gchar *text; - - GtkTreeView *view = GTK_TREE_VIEW(data); - GtkTreeSelection *selection = gtk_tree_view_get_selection(view); - GtkTreeModel *model; - GtkTreeIter iter; - - if (selection) - { - if (gtk_tree_selection_get_selected(selection, &model, &iter)) - { - gtk_tree_model_get(model, &iter, 0, &text, -1); - equalizerwin_load_preset(equalizer_auto_presets, text); - - g_free(text); - } - } - gtk_widget_destroy(equalizerwin_load_auto_window); -} - -static void -equalizerwin_load_auto_select(GtkTreeView *treeview, GtkTreePath *path, - GtkTreeViewColumn *col, gpointer data) -{ - equalizerwin_load_auto_ok(NULL, treeview); -} - -static void -equalizerwin_delete_auto_delete(GtkWidget *widget, gpointer data) -{ - equalizerwin_delete_selected_presets(GTK_TREE_VIEW(data), "eq.auto_preset"); -} - - -static void -load_preset_file(const gchar *filename) -{ - RcFile *rcfile; - - if ((rcfile = aud_rcfile_open(filename)) != NULL) { - equalizerwin_read_aud_preset(rcfile); - aud_rcfile_free(rcfile); - } -} - -static VFSFile * -open_vfs_file(const gchar *filename, const gchar *mode) -{ - VFSFile *file; - GtkWidget *dialog; - - if (!(file = vfs_fopen(filename, mode))) { - dialog = gtk_message_dialog_new (GTK_WINDOW (mainwin), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - "Error loading file '%s'", - filename); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - } - - return file; -} - -static void -load_winamp_file(const gchar * filename) -{ - VFSFile *file; - - if (!(file = open_vfs_file(filename, "rb"))) - return; - - equalizerwin_read_winamp_eqf(file); - vfs_fclose(file); -} - -static void -import_winamp_file(const gchar * filename) -{ - VFSFile *file; - GList *list; - - if (!(file = open_vfs_file(filename, "rb")) || - !(list = import_winamp_eqf(file))) - return; - - equalizer_presets = g_list_concat(equalizer_presets, list); - equalizerwin_write_preset_file(equalizer_presets, "eq.preset"); - - vfs_fclose(file); -} - -static void -save_preset_file(const gchar * filename) -{ - RcFile *rcfile; - gint i; - - rcfile = aud_rcfile_new(); - aud_rcfile_write_float(rcfile, "Equalizer preset", "Preamp", - ui_skinned_equalizer_slider_get_position(equalizerwin_preamp)); - - for (i = 0; i < 10; i++) { - gchar tmp[7]; - g_snprintf(tmp, sizeof(tmp), "Band%d", i); - aud_rcfile_write_float(rcfile, "Equalizer preset", tmp, - ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i])); - } - - aud_rcfile_write(rcfile, filename); - aud_rcfile_free(rcfile); -} - -static void -save_winamp_file(const gchar * filename) -{ - VFSFile *file; - - gchar name[257]; - gint i; - guchar bands[11]; - - if (!(file = open_vfs_file(filename, "wb"))) - return; - - vfs_fwrite("Winamp EQ library file v1.1\x1a!--", 1, 31, file); - - memset(name, 0, 257); - g_strlcpy(name, "Entry1", 257); - vfs_fwrite(name, 1, 257, file); - - for (i = 0; i < 10; i++) - bands[i] = 63 - (((ui_skinned_equalizer_slider_get_position(equalizerwin_bands[i]) + EQUALIZER_MAX_GAIN) * 63) / EQUALIZER_MAX_GAIN / 2); - bands[10] = 63 - (((ui_skinned_equalizer_slider_get_position(equalizerwin_preamp) + EQUALIZER_MAX_GAIN) * 63) / EQUALIZER_MAX_GAIN / 2); - vfs_fwrite(bands, 1, 11, file); - - vfs_fclose(file); -} - -static GtkWidget * -equalizerwin_create_list_window(GList *preset_list, - const gchar *title, - GtkWidget **window, - GtkSelectionMode sel_mode, - GtkWidget **entry, - const gchar *action_name, - GCallback action_func, - GCallback select_row_func) -{ - GtkWidget *vbox, *scrolled_window, *bbox, *view; - GtkWidget *button_cancel, *button_action; - GList *node; - - GtkListStore *store; - GtkTreeIter iter; - GtkTreeModel *model; - GtkCellRenderer *renderer; - GtkTreeSelection *selection; - GtkTreeSortable *sortable; - - - - *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(*window), title); - gtk_window_set_type_hint(GTK_WINDOW(*window), GDK_WINDOW_TYPE_HINT_DIALOG); - gtk_window_set_default_size(GTK_WINDOW(*window), 350, 300); - gtk_window_set_position(GTK_WINDOW(*window), GTK_WIN_POS_CENTER); - gtk_container_set_border_width(GTK_CONTAINER(*window), 10); - gtk_window_set_transient_for(GTK_WINDOW(*window), - GTK_WINDOW(equalizerwin)); - g_signal_connect(*window, "destroy", - G_CALLBACK(gtk_widget_destroyed), window); - - vbox = gtk_vbox_new(FALSE, 10); - gtk_container_add(GTK_CONTAINER(*window), vbox); - - scrolled_window = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - - - /* fill the store with the names of all available presets */ - store = gtk_list_store_new(1, G_TYPE_STRING); - for (node = preset_list; node; node = g_list_next(node)) - { - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - 0, ((EqualizerPreset*)node->data)->name, - -1); - } - model = GTK_TREE_MODEL(store); - - - sortable = GTK_TREE_SORTABLE(store); - gtk_tree_sortable_set_sort_column_id(sortable, 0, GTK_SORT_ASCENDING); - - - view = gtk_tree_view_new(); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, - _("Presets"), renderer, - "text", 0, NULL); - gtk_tree_view_set_model(GTK_TREE_VIEW(view), model); - g_object_unref(model); - - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); - gtk_tree_selection_set_mode(selection, sel_mode); - - - - - gtk_container_add(GTK_CONTAINER(scrolled_window), view); - gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0); - - if (entry) { - *entry = gtk_entry_new(); - g_signal_connect(*entry, "activate", action_func, NULL); - gtk_box_pack_start(GTK_BOX(vbox), *entry, 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), 5); - gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); - - button_cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); - g_signal_connect_swapped(button_cancel, "clicked", - G_CALLBACK(gtk_widget_destroy), - GTK_OBJECT(*window)); - gtk_box_pack_start(GTK_BOX(bbox), button_cancel, TRUE, TRUE, 0); - - button_action = gtk_button_new_from_stock(action_name); - g_signal_connect(button_action, "clicked", G_CALLBACK(action_func), view); - GTK_WIDGET_SET_FLAGS(button_action, GTK_CAN_DEFAULT); - - if (select_row_func) - g_signal_connect(view, "row-activated", G_CALLBACK(select_row_func), NULL); - - - gtk_box_pack_start(GTK_BOX(bbox), button_action, TRUE, TRUE, 0); - - gtk_widget_grab_default(button_action); - - - gtk_widget_show_all(*window); - - return *window; -} - -void -equalizerwin_load_auto_preset(const gchar * filename) -{ - gchar *presetfilename, *directory; - RcFile *rcfile; - - g_return_if_fail(filename != NULL); - - if (!cfg.equalizer_autoload) - return; - - presetfilename = g_strconcat(filename, ".", cfg.eqpreset_extension, NULL); - - /* First try to find a per file preset file */ - if (strlen(cfg.eqpreset_extension) > 0 && - (rcfile = aud_rcfile_open(presetfilename)) != NULL) { - g_free(presetfilename); - equalizerwin_read_aud_preset(rcfile); - aud_rcfile_free(rcfile); - return; - } - - g_free(presetfilename); - - directory = g_path_get_dirname(filename); - presetfilename = g_build_filename(directory, cfg.eqpreset_default_file, - NULL); - g_free(directory); - - /* Try to find a per directory preset file */ - if (strlen(cfg.eqpreset_default_file) > 0 && - (rcfile = aud_rcfile_open(presetfilename)) != NULL) { - equalizerwin_read_aud_preset(rcfile); - aud_rcfile_free(rcfile); - } - else if (!equalizerwin_load_preset - (equalizer_auto_presets, g_basename(filename))) { - /* Fall back to the oldstyle auto presets */ - equalizerwin_load_preset(equalizer_presets, "Default"); - } - - g_free(presetfilename); -} - -void -equalizerwin_set_preamp(gfloat preamp) -{ - ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, preamp); - equalizerwin_eq_changed(); -} - -void -equalizerwin_set_band(gint band, gfloat value) -{ - g_return_if_fail(band >= 0 && band < 10); - ui_skinned_equalizer_slider_set_position(equalizerwin_bands[band], value); -} - -gfloat -equalizerwin_get_preamp(void) -{ - return ui_skinned_equalizer_slider_get_position(equalizerwin_preamp); -} - -gfloat -equalizerwin_get_band(gint band) -{ - g_return_val_if_fail(band >= 0 && band < 10, 0.0); - return ui_skinned_equalizer_slider_get_position(equalizerwin_bands[band]); -} - -void -action_equ_load_preset(void) -{ - if (equalizerwin_load_window) { - gtk_window_present(GTK_WINDOW(equalizerwin_load_window)); - return; - } - - equalizerwin_create_list_window(equalizer_presets, - Q_("Load preset"), - &equalizerwin_load_window, - GTK_SELECTION_SINGLE, NULL, - GTK_STOCK_OK, - G_CALLBACK(equalizerwin_load_ok), - G_CALLBACK(equalizerwin_load_select)); -} - -void -action_equ_load_auto_preset(void) -{ - if (equalizerwin_load_auto_window) { - gtk_window_present(GTK_WINDOW(equalizerwin_load_auto_window)); - return; - } - - equalizerwin_create_list_window(equalizer_auto_presets, - Q_("Load auto-preset"), - &equalizerwin_load_auto_window, - GTK_SELECTION_SINGLE, NULL, - GTK_STOCK_OK, - G_CALLBACK(equalizerwin_load_auto_ok), - G_CALLBACK(equalizerwin_load_auto_select)); -} - -void -action_equ_load_default_preset(void) -{ - equalizerwin_load_preset(equalizer_presets, "Default"); -} - -void -action_equ_zero_preset(void) -{ - gint i; - - ui_skinned_equalizer_slider_set_position(equalizerwin_preamp, 0); - for (i = 0; i < 10; i++) - ui_skinned_equalizer_slider_set_position(equalizerwin_bands[i], 0); - - equalizerwin_eq_changed(); -} - -void -action_equ_load_preset_file(void) -{ - GtkWidget *dialog; - gchar *file_uri; - - dialog = make_filebrowser(Q_("Load equalizer preset"), FALSE); - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); - load_preset_file(file_uri); - g_free(file_uri); - } - gtk_widget_destroy(dialog); -} - -void -action_equ_load_preset_eqf(void) -{ - GtkWidget *dialog; - gchar *file_uri; - - dialog = make_filebrowser(Q_("Load equalizer preset"), FALSE); - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); - load_winamp_file(file_uri); - g_free(file_uri); - } - gtk_widget_destroy(dialog); -} - -void -action_equ_import_winamp_presets(void) -{ - GtkWidget *dialog; - gchar *file_uri; - - dialog = make_filebrowser(Q_("Load equalizer preset"), FALSE); - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); - import_winamp_file(file_uri); - g_free(file_uri); - } - gtk_widget_destroy(dialog); -} - -void -action_equ_save_preset(void) -{ - if (equalizerwin_save_window) { - gtk_window_present(GTK_WINDOW(equalizerwin_save_window)); - return; - } - - equalizerwin_create_list_window(equalizer_presets, - Q_("Save preset"), - &equalizerwin_save_window, - GTK_SELECTION_SINGLE, - &equalizerwin_save_entry, - GTK_STOCK_OK, - G_CALLBACK(equalizerwin_save_ok), - G_CALLBACK(equalizerwin_save_select)); -} - -void -action_equ_save_auto_preset(void) -{ - gchar *name; - Playlist *playlist = playlist_get_active(); - - if (equalizerwin_save_auto_window) - gtk_window_present(GTK_WINDOW(equalizerwin_save_auto_window)); - else - equalizerwin_create_list_window(equalizer_auto_presets, - Q_("Save auto-preset"), - &equalizerwin_save_auto_window, - GTK_SELECTION_SINGLE, - &equalizerwin_save_auto_entry, - GTK_STOCK_OK, - G_CALLBACK(equalizerwin_save_auto_ok), - G_CALLBACK(equalizerwin_save_auto_select)); - - name = playlist_get_filename(playlist, playlist_get_position(playlist)); - if (name) { - gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_auto_entry), - g_basename(name)); - g_free(name); - } -} - -void -action_equ_save_default_preset(void) -{ - equalizer_presets = - equalizerwin_save_preset(equalizer_presets, Q_("Default"), "eq.preset"); -} - -void -action_equ_save_preset_file(void) -{ - GtkWidget *dialog; - gchar *file_uri; - gchar *songname; - Playlist *playlist = playlist_get_active(); - - dialog = make_filebrowser(Q_("Save equalizer preset"), TRUE); - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); - save_preset_file(file_uri); - g_free(file_uri); - } - - songname = playlist_get_filename(playlist, playlist_get_position(playlist)); - if (songname) { - gchar *eqname = g_strdup_printf("%s.%s", songname, - cfg.eqpreset_extension); - g_free(songname); - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), - eqname); - g_free(eqname); - } - - gtk_widget_destroy(dialog); -} - -void -action_equ_save_preset_eqf(void) -{ - GtkWidget *dialog; - gchar *file_uri; - - dialog = make_filebrowser(Q_("Save equalizer preset"), TRUE); - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); - save_winamp_file(file_uri); - g_free(file_uri); - } - gtk_widget_destroy(dialog); -} - -void -action_equ_delete_preset(void) -{ - if (equalizerwin_delete_window) { - gtk_window_present(GTK_WINDOW(equalizerwin_delete_window)); - return; - } - - equalizerwin_create_list_window(equalizer_presets, - Q_("Delete preset"), - &equalizerwin_delete_window, - GTK_SELECTION_EXTENDED, NULL, - GTK_STOCK_DELETE, - G_CALLBACK(equalizerwin_delete_delete), - NULL); -} - -void -action_equ_delete_auto_preset(void) -{ - if (equalizerwin_delete_auto_window) { - gtk_window_present(GTK_WINDOW(equalizerwin_delete_auto_window)); - return; - } - - equalizerwin_create_list_window(equalizer_auto_presets, - Q_("Delete auto-preset"), - &equalizerwin_delete_auto_window, - GTK_SELECTION_EXTENDED, NULL, - GTK_STOCK_DELETE, - G_CALLBACK(equalizerwin_delete_auto_delete), - NULL); -} - -void -equalizer_activate(gboolean active) -{ - cfg.equalizer_active = active; - UI_SKINNED_BUTTON(equalizerwin_on)->inside = active; - gtk_widget_queue_draw(equalizerwin_on); - - equalizerwin_eq_changed(); -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_equalizer.h --- a/src/audacious/ui_equalizer.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +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_EQUALIZER_H -#define AUDACIOUS_UI_EQUALIZER_H - -#include -#include - -#define EQUALIZER_SCALED (cfg.scaled && cfg.eq_scaled_linked) -#define EQUALIZER_SCALE_FACTOR (EQUALIZER_SCALED ? cfg.scale_factor : 1) - -#define EQUALIZER_HEIGHT ((cfg.equalizer_shaded ? 14 : 116) * (EQUALIZER_SCALE_FACTOR)) -#define EQUALIZER_WIDTH (275 * EQUALIZER_SCALE_FACTOR) - -#define EQUALIZER_DEFAULT_POS_X 20 -#define EQUALIZER_DEFAULT_POS_Y 136 - -#define EQUALIZER_DEFAULT_DIR_PRESET "dir_default.preset" -#define EQUALIZER_DEFAULT_PRESET_EXT "preset" - -void equalizerwin_set_scaled(gboolean ds); -void equalizerwin_set_shade_menu_cb(gboolean shaded); -void draw_equalizer_window(gboolean force); -void equalizerwin_create(void); -void equalizerwin_show(gboolean show); -void equalizerwin_real_show(void); -void equalizerwin_real_hide(void); -void equalizerwin_load_auto_preset(const gchar * filename); -void equalizerwin_set_volume_slider(gint percent); -void equalizerwin_set_balance_slider(gint percent); -void equalizerwin_eq_changed(void); -void equalizerwin_set_preamp(gfloat preamp); -void equalizerwin_set_band(gint band, gfloat value); -gfloat equalizerwin_get_preamp(void); -gfloat equalizerwin_get_band(gint band); - -gboolean equalizerwin_has_focus(void); - -extern GtkWidget *equalizerwin; -extern GtkWidget *equalizerwin_graph; -extern gboolean equalizerwin_focus; - -void equalizer_activate(gboolean active); - -#endif /* AUDACIOUS_UI_EQUALIZER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_fileinfo.c --- a/src/audacious/ui_fileinfo.c Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_fileinfo.h --- a/src/audacious/ui_fileinfo.h Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_fileinfopopup.c --- a/src/audacious/ui_fileinfopopup.c Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/ui_fileinfopopup.c Sun Jul 06 17:55:40 2008 +0200 @@ -33,7 +33,7 @@ #include "playback.h" #include "strings.h" #include "ui_fileinfopopup.h" -#include "ui_fileinfo.h" +#include "legacy/ui_fileinfo.h" static void filepopup_entry_set_text(GtkWidget *filepopup_win, const gchar *entry_name, diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_fileopener.c --- a/src/audacious/ui_fileopener.c Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/ui_fileopener.c Sun Jul 06 17:55:40 2008 +0200 @@ -27,7 +27,7 @@ #include "main.h" #include "playback.h" #include "strings.h" -#include "ui_playlist.h" +#include "legacy/ui_playlist.h" static void filebrowser_add_files(GtkFileChooser * browser, diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_hints.c --- a/src/audacious/ui_hints.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +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. - */ - -#include "ui_hints.h" - -#include -#include - -#include "ui_equalizer.h" -#include "ui_main.h" -#include "ui_playlist.h" - -#include "platform/smartinclude.h" - -void -hint_set_always(gboolean always) -{ - gtk_window_set_keep_above(GTK_WINDOW(mainwin), always); - gtk_window_set_keep_above(GTK_WINDOW(equalizerwin), always); - gtk_window_set_keep_above(GTK_WINDOW(playlistwin), always); -} - -void -hint_set_sticky(gboolean sticky) -{ - if (sticky) { - gtk_window_stick(GTK_WINDOW(mainwin)); - gtk_window_stick(GTK_WINDOW(equalizerwin)); - gtk_window_stick(GTK_WINDOW(playlistwin)); - } - else { - gtk_window_unstick(GTK_WINDOW(mainwin)); - gtk_window_unstick(GTK_WINDOW(equalizerwin)); - gtk_window_unstick(GTK_WINDOW(playlistwin)); - } -} - diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_hints.h --- a/src/audacious/ui_hints.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +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_HINTS_H -#define AUDACIOUS_UI_HINTS_H - -#include -#include - -void hint_set_always(gboolean always); -void hint_set_sticky(gboolean sticky); - -#endif /* AUDACIOUS_UI_HINTS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_jumptotrack.c --- a/src/audacious/ui_jumptotrack.c Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_jumptotrack.h --- a/src/audacious/ui_jumptotrack.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +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. - */ - -#ifndef AUDACIOUS_UI_JUMPTOTRACK_H -#define AUDACIOUS_UI_JUMPTOTRACK_H - -extern void ui_jump_to_track_update(GtkWidget * widget, gpointer user_data); -extern void ui_jump_to_track(void); -extern void ui_jump_to_track_hide(void); - -#endif /* AUDACIOUS_UI_JUMPTOTRACK_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_jumptotrack_cache.c --- a/src/audacious/ui_jumptotrack_cache.c Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_jumptotrack_cache.h --- a/src/audacious/ui_jumptotrack_cache.h Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_legacy.c --- a/src/audacious/ui_legacy.c Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/ui_legacy.c Sun Jul 06 17:55:40 2008 +0200 @@ -64,15 +64,15 @@ #include "playlist.h" #include "pluginenum.h" #include "signals.h" -#include "ui_skin.h" -#include "ui_equalizer.h" -#include "ui_fileinfo.h" -#include "ui_hints.h" -#include "ui_main.h" -#include "ui_manager.h" -#include "ui_playlist.h" +#include "legacy/ui_skin.h" +#include "legacy/ui_equalizer.h" +#include "legacy/ui_fileinfo.h" +#include "legacy/ui_hints.h" +#include "legacy/ui_main.h" +#include "legacy/ui_manager.h" +#include "legacy/ui_playlist.h" #include "ui_preferences.h" -#include "ui_skinselector.h" +#include "legacy/ui_skinselector.h" #include "util.h" #include "libSAD.h" diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_main.c --- a/src/audacious/ui_main.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2850 +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 -#include -#include -#include -#include - -/* GDK including */ -#include "platform/smartinclude.h" - -#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 "configdb.h" -#include "dnd.h" -#include "input.h" -#include "main.h" -#include "playback.h" -#include "playlist.h" -#include "pluginenum.h" -#include "strings.h" -#include "ui_credits.h" -#include "ui_dock.h" -#include "ui_equalizer.h" -#include "ui_fileinfo.h" -#include "ui_fileopener.h" -#include "ui_hints.h" -#include "ui_jumptotrack.h" -#include "ui_main_evlisteners.h" -#include "ui_manager.h" -#include "ui_playlist.h" -#include "ui_preferences.h" -#include "ui_skinselector.h" -#include "ui_urlopener.h" -#include "util.h" -#include "visualization.h" - -#include "ui_skinned_window.h" -#include "ui_skinned_button.h" -#include "ui_skinned_textbox.h" -#include "ui_skinned_number.h" -#include "ui_skinned_horizontal_slider.h" -#include "ui_skinned_menurow.h" -#include "ui_skinned_playstatus.h" -#include "ui_skinned_monostereo.h" -#include "ui_skinned_playlist.h" - -static GTimeVal cb_time; -static const int TRISTATE_THRESHOLD = 200; - -enum { - MAINWIN_SEEK_REV = -1, - MAINWIN_SEEK_NIL, - MAINWIN_SEEK_FWD -}; - -GtkWidget *mainwin = NULL; - -static gint balance; - -static GtkWidget *mainwin_jtt = NULL; - -static gint seek_state = MAINWIN_SEEK_NIL; -static gint seek_initial_pos = 0; - -static GtkWidget *mainwin_menubtn; -static GtkWidget *mainwin_minimize, *mainwin_shade, *mainwin_close; - -static GtkWidget *mainwin_rew, *mainwin_fwd; -static GtkWidget *mainwin_eject; -static GtkWidget *mainwin_play, *mainwin_pause, *mainwin_stop; - -static GtkWidget *mainwin_shuffle, *mainwin_repeat; -GtkWidget *mainwin_eq, *mainwin_pl; - -GtkWidget *mainwin_info; -GtkWidget *mainwin_stime_min, *mainwin_stime_sec; - -static GtkWidget *mainwin_rate_text, *mainwin_freq_text, *mainwin_othertext; - -GtkWidget *mainwin_playstatus; - -GtkWidget *mainwin_minus_num, *mainwin_10min_num, *mainwin_min_num; -GtkWidget *mainwin_10sec_num, *mainwin_sec_num; - -GtkWidget *mainwin_vis; -GtkWidget *mainwin_svis; - -GtkWidget *mainwin_sposition = NULL; - -static GtkWidget *mainwin_menurow; -static GtkWidget *mainwin_volume, *mainwin_balance; -GtkWidget *mainwin_position; - -static GtkWidget *mainwin_monostereo; -static GtkWidget *mainwin_srew, *mainwin_splay, *mainwin_spause; -static GtkWidget *mainwin_sstop, *mainwin_sfwd, *mainwin_seject, *mainwin_about; - -static gint mainwin_timeout_id; - -static gboolean mainwin_info_text_locked = FALSE; -static guint mainwin_volume_release_timeout = 0; - -static int ab_position_a = -1; -static int ab_position_b = -1; - -static void mainwin_refresh_visible(void); -static gint mainwin_idle_func(gpointer data); - -static void set_timer_mode_menu_cb(TimerMode mode); -static void set_timer_mode(TimerMode mode); -static void change_timer_mode(void); - -static void mainwin_position_motion_cb(GtkWidget *widget, gint pos); -static void mainwin_position_release_cb(GtkWidget *widget, gint pos); - -static void set_scaled(gboolean scaled); -static void mainwin_eq_pushed(gboolean toggled); -static void mainwin_pl_pushed(gboolean toggled); - -static void -mainwin_set_title_scroll(gboolean scroll) -{ - cfg.autoscroll = scroll; - ui_skinned_textbox_set_scroll(mainwin_info, cfg.autoscroll); -} - - -void -mainwin_set_always_on_top(gboolean always) -{ - GtkAction *action = gtk_action_group_get_action(toggleaction_group_others, - "view always on top"); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , always ); -} - -static void -mainwin_set_shade(gboolean shaded) -{ - GtkAction *action = gtk_action_group_get_action(toggleaction_group_others, - "roll up player"); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , shaded ); -} - -static void -mainwin_set_shade_menu_cb(gboolean shaded) -{ - cfg.player_shaded = shaded; - - if (shaded) { - dock_shade(get_dock_window_list(), GTK_WINDOW(mainwin), - MAINWIN_SHADED_HEIGHT * MAINWIN_SCALE_FACTOR); - } else { - gint height = !aud_active_skin->properties.mainwin_height ? MAINWIN_HEIGHT : - aud_active_skin->properties.mainwin_height; - - dock_shade(get_dock_window_list(), GTK_WINDOW(mainwin), height * MAINWIN_SCALE_FACTOR); - } - - mainwin_refresh_hints(); - ui_skinned_set_push_button_data(mainwin_shade, 0, cfg.player_shaded ? 27 : 18, 9, cfg.player_shaded ? 27 : 18); - gtk_widget_shape_combine_mask(mainwin, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + cfg.player_shaded), 0, 0); -} - -static void -mainwin_vis_set_refresh(RefreshRate rate) -{ - cfg.vis_refresh = rate; -} - -static void -mainwin_vis_set_afalloff(FalloffSpeed speed) -{ - cfg.analyzer_falloff = speed; -} - -static void -mainwin_vis_set_pfalloff(FalloffSpeed speed) -{ - cfg.peaks_falloff = speed; -} - -static void -mainwin_vis_set_analyzer_mode(AnalyzerMode mode) -{ - cfg.analyzer_mode = mode; -} - -static void -mainwin_vis_set_analyzer_type(AnalyzerType mode) -{ - cfg.analyzer_type = mode; -} - -void -mainwin_vis_set_type(VisType mode) -{ - GtkAction *action; - - switch ( mode ) - { - case VIS_ANALYZER: - action = gtk_action_group_get_action(radioaction_group_vismode, - "vismode analyzer"); - break; - case VIS_SCOPE: - action = gtk_action_group_get_action(radioaction_group_vismode, - "vismode scope"); - break; - case VIS_VOICEPRINT: - action = gtk_action_group_get_action(radioaction_group_vismode, - "vismode voiceprint"); - break; - case VIS_OFF: - default: - action = gtk_action_group_get_action(radioaction_group_vismode, - "vismode off"); - break; - } - - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , TRUE ); -} - -static void -mainwin_vis_set_type_menu_cb(VisType mode) -{ - cfg.vis_type = mode; - - if (mode == VIS_OFF) { - if (cfg.player_shaded) { - ui_svis_set_visible(mainwin_svis, FALSE); - ui_vis_set_visible(mainwin_vis, TRUE); - } else { - ui_svis_set_visible(mainwin_svis, TRUE); - ui_vis_set_visible(mainwin_vis, FALSE); - } - } - if (mode == VIS_ANALYZER || mode == VIS_SCOPE || mode == VIS_VOICEPRINT) { - if (cfg.player_shaded) { - ui_svis_clear_data(mainwin_svis); - ui_svis_set_visible(mainwin_svis, TRUE); - ui_vis_clear_data(mainwin_vis); - ui_vis_set_visible(mainwin_vis, FALSE); - } else { - ui_svis_clear_data(mainwin_svis); - ui_svis_set_visible(mainwin_svis, FALSE); - ui_vis_clear_data(mainwin_vis); - ui_vis_set_visible(mainwin_vis, TRUE); - } - } -} - -static void -mainwin_menubtn_cb(void) -{ - gint x, y; - gtk_window_get_position(GTK_WINDOW(mainwin), &x, &y); - ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), - x + 6 * MAINWIN_SCALE_FACTOR , - y + MAINWIN_SHADED_HEIGHT * MAINWIN_SCALE_FACTOR, - 1, GDK_CURRENT_TIME); -} - -void -mainwin_minimize_cb(void) -{ - if (!mainwin) - return; - - gtk_window_iconify(GTK_WINDOW(mainwin)); -} - -static void -mainwin_shade_toggle(void) -{ - mainwin_set_shade(!cfg.player_shaded); -} - -void -mainwin_quit_cb(void) -{ - if (mainwin_timeout_id) - g_source_remove(mainwin_timeout_id); - - aud_quit(); -} - -gboolean -mainwin_vis_cb(GtkWidget *widget, GdkEventButton *event) -{ - if (event->button == 1) { - cfg.vis_type++; - - if (cfg.vis_type > VIS_OFF) - cfg.vis_type = VIS_ANALYZER; - - mainwin_vis_set_type(cfg.vis_type); - } else if (event->button == 3) { - ui_manager_popup_menu_show(GTK_MENU(mainwin_visualization_menu), - event->x_root, event->y_root, 3, - event->time); - } - return TRUE; -} - -static void -mainwin_destroy(GtkWidget * widget, gpointer data) -{ - mainwin_quit_cb(); -} - -static gchar *mainwin_tb_old_text = NULL; - -void -mainwin_lock_info_text(const gchar * text) -{ - if (mainwin_info_text_locked != TRUE) - mainwin_tb_old_text = g_strdup(aud_active_skin->properties.mainwin_othertext_is_status ? - UI_SKINNED_TEXTBOX(mainwin_othertext)->text : UI_SKINNED_TEXTBOX(mainwin_info)->text); - - mainwin_info_text_locked = TRUE; - if (aud_active_skin->properties.mainwin_othertext_is_status) - ui_skinned_textbox_set_text(mainwin_othertext, text); - else - ui_skinned_textbox_set_text(mainwin_info, text); -} - -void -mainwin_release_info_text(void) -{ - mainwin_info_text_locked = FALSE; - - if (mainwin_tb_old_text != NULL) - { - if (aud_active_skin->properties.mainwin_othertext_is_status) - ui_skinned_textbox_set_text(mainwin_othertext, mainwin_tb_old_text); - else - ui_skinned_textbox_set_text(mainwin_info, mainwin_tb_old_text); - g_free(mainwin_tb_old_text); - mainwin_tb_old_text = NULL; - } -} - - -static gchar * -make_mainwin_title(const gchar * title) -{ - if (title) - return g_strdup_printf(_("%s - Audacious"), title); - else - return g_strdup(_("Audacious")); -} - -void -mainwin_set_song_title(const gchar * title) -{ - gchar *mainwin_title_text = make_mainwin_title(title); - gtk_window_set_title(GTK_WINDOW(mainwin), mainwin_title_text); - g_free(mainwin_title_text); -} - -static void -mainwin_refresh_visible(void) -{ - if (!aud_active_skin || !cfg.player_visible) - return; - - gtk_widget_show_all(mainwin); - - if (!aud_active_skin->properties.mainwin_text_visible) - gtk_widget_hide(mainwin_info); - - if (!aud_active_skin->properties.mainwin_vis_visible) - gtk_widget_hide(mainwin_vis); - - if (!aud_active_skin->properties.mainwin_menurow_visible) - gtk_widget_hide(mainwin_menurow); - - if (aud_active_skin->properties.mainwin_othertext) { - gtk_widget_hide(mainwin_rate_text); - gtk_widget_hide(mainwin_freq_text); - gtk_widget_hide(mainwin_monostereo); - - if (!aud_active_skin->properties.mainwin_othertext_visible) - gtk_widget_hide(mainwin_othertext); - } else { - gtk_widget_hide(mainwin_othertext); - } - - if (!aud_active_skin->properties.mainwin_vis_visible) - gtk_widget_hide(mainwin_vis); - - if (!playback_get_playing()) { - gtk_widget_hide(mainwin_minus_num); - gtk_widget_hide(mainwin_10min_num); - gtk_widget_hide(mainwin_min_num); - gtk_widget_hide(mainwin_10sec_num); - gtk_widget_hide(mainwin_sec_num); - - gtk_widget_hide(mainwin_stime_min); - gtk_widget_hide(mainwin_stime_sec); - - gtk_widget_hide(mainwin_position); - gtk_widget_hide(mainwin_sposition); - } - - if (cfg.player_shaded) { - ui_svis_clear_data(mainwin_svis); - if (cfg.vis_type != VIS_OFF) - ui_svis_set_visible(mainwin_svis, TRUE); - else - ui_svis_set_visible(mainwin_svis, FALSE); - - ui_skinned_textbox_set_scroll(mainwin_info, FALSE); - if (!playback_get_playing()) { - gtk_widget_hide(mainwin_sposition); - gtk_widget_hide(mainwin_stime_min); - gtk_widget_hide(mainwin_stime_sec); - } - } else { - gtk_widget_hide(mainwin_srew); - gtk_widget_hide(mainwin_splay); - gtk_widget_hide(mainwin_spause); - gtk_widget_hide(mainwin_sstop); - gtk_widget_hide(mainwin_sfwd); - gtk_widget_hide(mainwin_seject); - gtk_widget_hide(mainwin_stime_min); - gtk_widget_hide(mainwin_stime_sec); - gtk_widget_hide(mainwin_svis); - gtk_widget_hide(mainwin_sposition); - ui_vis_clear_data(mainwin_vis); - if (cfg.vis_type != VIS_OFF) - ui_vis_set_visible(mainwin_vis, TRUE); - else - ui_vis_set_visible(mainwin_vis, FALSE); - - ui_skinned_textbox_set_scroll(mainwin_info, cfg.autoscroll); - } -} - -void -mainwin_refresh_hints(void) -{ - /* positioning and size attributes */ - if (aud_active_skin->properties.mainwin_vis_x && aud_active_skin->properties.mainwin_vis_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_vis), aud_active_skin->properties.mainwin_vis_x, - aud_active_skin->properties.mainwin_vis_y); - - if (aud_active_skin->properties.mainwin_vis_width) - gtk_widget_set_size_request(mainwin_vis, aud_active_skin->properties.mainwin_vis_width * MAINWIN_SCALE_FACTOR, - UI_VIS(mainwin_vis)->height* MAINWIN_SCALE_FACTOR); - - if (aud_active_skin->properties.mainwin_text_x && aud_active_skin->properties.mainwin_text_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_info), aud_active_skin->properties.mainwin_text_x, - aud_active_skin->properties.mainwin_text_y); - - if (aud_active_skin->properties.mainwin_text_width) { - UI_SKINNED_TEXTBOX(mainwin_info)->width = aud_active_skin->properties.mainwin_text_width; - gtk_widget_set_size_request(mainwin_info, aud_active_skin->properties.mainwin_text_width * MAINWIN_SCALE_FACTOR, - UI_SKINNED_TEXTBOX(mainwin_info)->height * MAINWIN_SCALE_FACTOR ); - } - - if (aud_active_skin->properties.mainwin_infobar_x && aud_active_skin->properties.mainwin_infobar_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_othertext), aud_active_skin->properties.mainwin_infobar_x, - aud_active_skin->properties.mainwin_infobar_y); - - if (aud_active_skin->properties.mainwin_number_0_x && aud_active_skin->properties.mainwin_number_0_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_minus_num), aud_active_skin->properties.mainwin_number_0_x, - aud_active_skin->properties.mainwin_number_0_y); - - if (aud_active_skin->properties.mainwin_number_1_x && aud_active_skin->properties.mainwin_number_1_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_10min_num), aud_active_skin->properties.mainwin_number_1_x, - aud_active_skin->properties.mainwin_number_1_y); - - if (aud_active_skin->properties.mainwin_number_2_x && aud_active_skin->properties.mainwin_number_2_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_min_num), aud_active_skin->properties.mainwin_number_2_x, - aud_active_skin->properties.mainwin_number_2_y); - - if (aud_active_skin->properties.mainwin_number_3_x && aud_active_skin->properties.mainwin_number_3_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_10sec_num), aud_active_skin->properties.mainwin_number_3_x, - aud_active_skin->properties.mainwin_number_3_y); - - if (aud_active_skin->properties.mainwin_number_4_x && aud_active_skin->properties.mainwin_number_4_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_sec_num), aud_active_skin->properties.mainwin_number_4_x, - aud_active_skin->properties.mainwin_number_4_y); - - if (aud_active_skin->properties.mainwin_playstatus_x && aud_active_skin->properties.mainwin_playstatus_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), mainwin_playstatus, aud_active_skin->properties.mainwin_playstatus_x, - aud_active_skin->properties.mainwin_playstatus_y); - - if (aud_active_skin->properties.mainwin_volume_x && aud_active_skin->properties.mainwin_volume_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_volume), aud_active_skin->properties.mainwin_volume_x, - aud_active_skin->properties.mainwin_volume_y); - - if (aud_active_skin->properties.mainwin_balance_x && aud_active_skin->properties.mainwin_balance_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_balance), aud_active_skin->properties.mainwin_balance_x, - aud_active_skin->properties.mainwin_balance_y); - - if (aud_active_skin->properties.mainwin_position_x && aud_active_skin->properties.mainwin_position_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_position), aud_active_skin->properties.mainwin_position_x, - aud_active_skin->properties.mainwin_position_y); - - if (aud_active_skin->properties.mainwin_previous_x && aud_active_skin->properties.mainwin_previous_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), mainwin_rew, aud_active_skin->properties.mainwin_previous_x, - aud_active_skin->properties.mainwin_previous_y); - - if (aud_active_skin->properties.mainwin_play_x && aud_active_skin->properties.mainwin_play_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_play), aud_active_skin->properties.mainwin_play_x, - aud_active_skin->properties.mainwin_play_y); - - if (aud_active_skin->properties.mainwin_pause_x && aud_active_skin->properties.mainwin_pause_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_pause), aud_active_skin->properties.mainwin_pause_x, - aud_active_skin->properties.mainwin_pause_y); - - if (aud_active_skin->properties.mainwin_stop_x && aud_active_skin->properties.mainwin_stop_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_stop), aud_active_skin->properties.mainwin_stop_x, - aud_active_skin->properties.mainwin_stop_y); - - if (aud_active_skin->properties.mainwin_next_x && aud_active_skin->properties.mainwin_next_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_fwd), aud_active_skin->properties.mainwin_next_x, - aud_active_skin->properties.mainwin_next_y); - - if (aud_active_skin->properties.mainwin_eject_x && aud_active_skin->properties.mainwin_eject_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_eject), aud_active_skin->properties.mainwin_eject_x, - aud_active_skin->properties.mainwin_eject_y); - - if (aud_active_skin->properties.mainwin_eqbutton_x && aud_active_skin->properties.mainwin_eqbutton_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_eq), aud_active_skin->properties.mainwin_eqbutton_x, - aud_active_skin->properties.mainwin_eqbutton_y); - - if (aud_active_skin->properties.mainwin_plbutton_x && aud_active_skin->properties.mainwin_plbutton_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_pl), aud_active_skin->properties.mainwin_plbutton_x, - aud_active_skin->properties.mainwin_plbutton_y); - - if (aud_active_skin->properties.mainwin_shuffle_x && aud_active_skin->properties.mainwin_shuffle_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_shuffle), aud_active_skin->properties.mainwin_shuffle_x, - aud_active_skin->properties.mainwin_shuffle_y); - - if (aud_active_skin->properties.mainwin_repeat_x && aud_active_skin->properties.mainwin_repeat_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_repeat), aud_active_skin->properties.mainwin_repeat_x, - aud_active_skin->properties.mainwin_repeat_y); - - if (aud_active_skin->properties.mainwin_about_x && aud_active_skin->properties.mainwin_about_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_about), aud_active_skin->properties.mainwin_about_x, - aud_active_skin->properties.mainwin_about_y); - - if (aud_active_skin->properties.mainwin_minimize_x && aud_active_skin->properties.mainwin_minimize_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_minimize), cfg.player_shaded ? 244 : aud_active_skin->properties.mainwin_minimize_x, - cfg.player_shaded ? 3 : aud_active_skin->properties.mainwin_minimize_y); - - if (aud_active_skin->properties.mainwin_shade_x && aud_active_skin->properties.mainwin_shade_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_shade), cfg.player_shaded ? 254 : aud_active_skin->properties.mainwin_shade_x, - cfg.player_shaded ? 3 : aud_active_skin->properties.mainwin_shade_y); - - if (aud_active_skin->properties.mainwin_close_x && aud_active_skin->properties.mainwin_close_y) - gtk_fixed_move(GTK_FIXED(SKINNED_WINDOW(mainwin)->fixed), GTK_WIDGET(mainwin_close), cfg.player_shaded ? 264 : aud_active_skin->properties.mainwin_close_x, - cfg.player_shaded ? 3 : aud_active_skin->properties.mainwin_close_y); - - mainwin_refresh_visible(); - - /* window size, mainwinWidth && mainwinHeight properties */ - if (aud_active_skin->properties.mainwin_height && aud_active_skin->properties.mainwin_width) - { - dock_window_resize(GTK_WINDOW(mainwin), cfg.player_shaded ? MAINWIN_SHADED_WIDTH * MAINWIN_SCALE_FACTOR : aud_active_skin->properties.mainwin_width * MAINWIN_SCALE_FACTOR, - cfg.player_shaded ? MAINWIN_SHADED_HEIGHT * MAINWIN_SCALE_FACTOR : aud_active_skin->properties.mainwin_height * MAINWIN_SCALE_FACTOR, - aud_active_skin->properties.mainwin_width * MAINWIN_SCALE_FACTOR, - aud_active_skin->properties.mainwin_height * MAINWIN_SCALE_FACTOR); - - gdk_flush(); - } -} - -void -mainwin_set_song_info(gint bitrate, - gint frequency, - gint n_channels) -{ - gchar *text; - gchar *title; - Playlist *playlist = playlist_get_active(); - - GDK_THREADS_ENTER(); - if (bitrate != -1) { - bitrate /= 1000; - - if (bitrate < 1000) { - /* Show bitrate in 1000s */ - text = g_strdup_printf("%3d", bitrate); - } - else { - /* Show bitrate in 100,000s */ - text = g_strdup_printf("%2dH", bitrate / 100); - } - ui_skinned_textbox_set_text(mainwin_rate_text, text); - g_free(text); - } - else - ui_skinned_textbox_set_text(mainwin_rate_text, _("VBR")); - - /* Show sampling frequency in kHz */ - text = g_strdup_printf("%2d", frequency / 1000); - ui_skinned_textbox_set_text(mainwin_freq_text, text); - g_free(text); - - ui_skinned_monostereo_set_num_channels(mainwin_monostereo, n_channels); - - if (!playback_get_paused() && mainwin_playstatus != NULL) - ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PLAY); - - if (aud_active_skin && aud_active_skin->properties.mainwin_othertext) - { - if (bitrate != -1) - text = g_strdup_printf("%d kbps, %0.1f kHz, %s", - bitrate, - (gfloat) frequency / 1000, - (n_channels > 1) ? _("stereo") : _("mono")); - else - text = g_strdup_printf("VBR, %0.1f kHz, %s", - (gfloat) frequency / 1000, - (n_channels > 1) ? _("stereo") : _("mono")); - - ui_skinned_textbox_set_text(mainwin_othertext, text); - g_free(text); - } - - title = playlist_get_info_text(playlist); - mainwin_set_song_title(title); - g_free(title); - GDK_THREADS_LEAVE(); -} - -void -mainwin_clear_song_info(void) -{ - if (!mainwin) - return; - - /* clear title */ - mainwin_set_song_title(NULL); - - /* clear sampling parameters */ - playback_set_sample_params(0, 0, 0); - - UI_SKINNED_HORIZONTAL_SLIDER(mainwin_position)->pressed = FALSE; - UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->pressed = FALSE; - - /* clear sampling parameter displays */ - ui_skinned_textbox_set_text(mainwin_rate_text, " "); - ui_skinned_textbox_set_text(mainwin_freq_text, " "); - ui_skinned_monostereo_set_num_channels(mainwin_monostereo, 0); - - if (mainwin_playstatus != NULL) - ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_STOP); - - mainwin_refresh_visible(); - - playlistwin_hide_timer(); - ui_vis_clear_data(mainwin_vis); - ui_svis_clear_data(mainwin_svis); -} - -void -mainwin_disable_seekbar(void) -{ - if (!mainwin) - return; - - gtk_widget_hide(mainwin_position); - gtk_widget_hide(mainwin_sposition); -} - -static gboolean -mainwin_mouse_button_release(GtkWidget * widget, - GdkEventButton * event, - gpointer callback_data) -{ - if (dock_is_moving(GTK_WINDOW(mainwin))) { - dock_move_release(GTK_WINDOW(mainwin)); - } - - return FALSE; -} - -void -mainwin_scrolled(GtkWidget *widget, GdkEventScroll *event, - gpointer callback_data) -{ - Playlist *playlist = playlist_get_active(); - - switch (event->direction) { - case GDK_SCROLL_UP: - mainwin_set_volume_diff(cfg.mouse_change); - break; - case GDK_SCROLL_DOWN: - mainwin_set_volume_diff(-cfg.mouse_change); - break; - case GDK_SCROLL_LEFT: - if (playlist_get_current_length(playlist) != -1) - playback_seek(CLAMP(playback_get_time() - 1000, - 0, playlist_get_current_length(playlist)) / 1000); - break; - case GDK_SCROLL_RIGHT: - if (playlist_get_current_length(playlist) != -1) - playback_seek(CLAMP(playback_get_time() + 1000, - 0, playlist_get_current_length(playlist)) / 1000); - break; - } -} - -static gboolean -mainwin_widget_contained(GdkEventButton *event, int x, int y, int w, int h) -{ - if ((event->x > x && event->y > y) && - (event->x < x+w && event->y < y+h)) - return TRUE; - - return FALSE; -} - -static gboolean -mainwin_mouse_button_press(GtkWidget * widget, - GdkEventButton * event, - gpointer callback_data) -{ - if (cfg.scaled) { - /* - * A hack to make scaling transparent to callbacks. - * We should make a copy of this data instead of - * tampering with the data we get from gtk+ - */ - event->x /= cfg.scale_factor; - event->y /= cfg.scale_factor; - } - - if (event->button == 1 && event->type == GDK_2BUTTON_PRESS && event->y < 14) { - mainwin_set_shade(!cfg.player_shaded); - if (dock_is_moving(GTK_WINDOW(mainwin))) - dock_move_release(GTK_WINDOW(mainwin)); - return TRUE; - } - - if (event->button == 3) { - /* Pop up playback menu if right clicked over playback-control widgets, - * otherwise popup general menu - */ - if (mainwin_widget_contained(event, aud_active_skin->properties.mainwin_position_x, - aud_active_skin->properties.mainwin_position_y, 248, 10) || - mainwin_widget_contained(event, aud_active_skin->properties.mainwin_previous_x, - aud_active_skin->properties.mainwin_previous_y, 23, 18) || - mainwin_widget_contained(event, aud_active_skin->properties.mainwin_play_x, - aud_active_skin->properties.mainwin_play_y, 23, 18) || - mainwin_widget_contained(event, aud_active_skin->properties.mainwin_pause_x, - aud_active_skin->properties.mainwin_pause_y, 23, 18) || - mainwin_widget_contained(event, aud_active_skin->properties.mainwin_stop_x, - aud_active_skin->properties.mainwin_stop_y, 23, 18) || - mainwin_widget_contained(event, aud_active_skin->properties.mainwin_next_x, - aud_active_skin->properties.mainwin_next_y, 23, 18)) - { - - ui_manager_popup_menu_show(GTK_MENU(mainwin_playback_menu), - event->x_root, - event->y_root, 3, event->time); - } else { - /* - * Pop up the main menu a few pixels down. - * This will avoid that anything is selected - * if one right-clicks to focus the window - * without raising it. - * - ***MD I think the above is stupid, people don't expect this - * - */ - ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), - event->x_root, - event->y_root, 3, event->time); - } - return TRUE; - } - - return FALSE; -} - -static gboolean -mainwin_keypress(GtkWidget * grab_widget, - GdkEventKey * event, - gpointer data) -{ - Playlist *playlist = playlist_get_active(); - - switch (event->keyval) { - - case GDK_Up: - case GDK_KP_Up: - case GDK_KP_8: - mainwin_set_volume_diff(2); - break; - case GDK_Down: - case GDK_KP_Down: - case GDK_KP_2: - mainwin_set_volume_diff(-2); - break; - case GDK_Left: - case GDK_KP_Left: - case GDK_KP_7: - if (playlist_get_current_length(playlist) != -1) - playback_seek(CLAMP - (playback_get_time() - 5000, 0, - playlist_get_current_length(playlist)) / 1000); - break; - case GDK_Right: - case GDK_KP_Right: - case GDK_KP_9: - if (playlist_get_current_length(playlist) != -1) - playback_seek(CLAMP - (playback_get_time() + 5000, 0, - playlist_get_current_length(playlist)) / 1000); - break; - case GDK_KP_4: - playlist_prev(playlist); - break; - case GDK_KP_6: - playlist_next(playlist); - break; - case GDK_KP_Insert: - ui_jump_to_track(); - break; - case GDK_Return: - case GDK_KP_Enter: - case GDK_KP_5: - mainwin_play_pushed(); - break; - case GDK_space: - playback_pause(); - break; - case GDK_Escape: - mainwin_minimize_cb(); - break; - case GDK_Tab: - if (event->state & GDK_CONTROL_MASK) { - if (cfg.equalizer_visible) - gtk_window_present(GTK_WINDOW(equalizerwin)); - else if (cfg.playlist_visible) - gtk_window_present(GTK_WINDOW(playlistwin)); - } - break; - case GDK_c: - if (event->state & GDK_CONTROL_MASK) { - Playlist *playlist = playlist_get_active(); - gint pos = playlist_get_position(playlist); - gchar *title = playlist_get_songtitle(playlist, pos); - - if (title != NULL) { - GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - gtk_clipboard_set_text(clip, title, -1); - gtk_clipboard_store(clip); - } - - return TRUE; - } - return FALSE; - default: - return FALSE; - } - - return TRUE; -} - -static void -mainwin_jump_to_time_cb(GtkWidget * widget, - GtkWidget * entry) -{ - guint min = 0, sec = 0, params; - gint time; - Playlist *playlist = playlist_get_active(); - - params = sscanf(gtk_entry_get_text(GTK_ENTRY(entry)), "%u:%u", - &min, &sec); - if (params == 2) - time = (min * 60) + sec; - else if (params == 1) - time = min; - else - return; - - if (playlist_get_current_length(playlist) > -1 && - time <= (playlist_get_current_length(playlist) / 1000)) - { - playback_seek(time); - gtk_widget_destroy(mainwin_jtt); - } -} - - -void -mainwin_jump_to_time(void) -{ - GtkWidget *vbox, *hbox_new, *hbox_total; - GtkWidget *time_entry, *label, *bbox, *jump, *cancel; - GtkWidget *dialog; - guint tindex; - gchar time_str[10]; - - if (!playback_get_playing()) { - dialog = - gtk_message_dialog_new (GTK_WINDOW (mainwin), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - _("Can't jump to time when no track is being played.\n")); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - return; - } - - if (mainwin_jtt) { - gtk_window_present(GTK_WINDOW(mainwin_jtt)); - return; - } - - mainwin_jtt = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_type_hint(GTK_WINDOW(mainwin_jtt), - GDK_WINDOW_TYPE_HINT_DIALOG); - - gtk_window_set_title(GTK_WINDOW(mainwin_jtt), _("Jump to Time")); - gtk_window_set_position(GTK_WINDOW(mainwin_jtt), GTK_WIN_POS_CENTER); - gtk_window_set_transient_for(GTK_WINDOW(mainwin_jtt), - GTK_WINDOW(mainwin)); - - g_signal_connect(mainwin_jtt, "destroy", - G_CALLBACK(gtk_widget_destroyed), &mainwin_jtt); - gtk_container_border_width(GTK_CONTAINER(mainwin_jtt), 10); - - vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(mainwin_jtt), vbox); - - hbox_new = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox_new, TRUE, TRUE, 5); - - time_entry = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox_new), time_entry, FALSE, FALSE, 5); - g_signal_connect(time_entry, "activate", - G_CALLBACK(mainwin_jump_to_time_cb), time_entry); - - gtk_widget_set_size_request(time_entry, 70, -1); - label = gtk_label_new(_("minutes:seconds")); - gtk_box_pack_start(GTK_BOX(hbox_new), label, FALSE, FALSE, 5); - - hbox_total = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox_total, TRUE, TRUE, 5); - gtk_widget_show(hbox_total); - - /* FIXME: Disable display of current track length. It's not - updated when track changes */ -#if 0 - label = gtk_label_new(_("Track length:")); - gtk_box_pack_start(GTK_BOX(hbox_total), label, FALSE, FALSE, 5); - - len = playlist_get_current_length() / 1000; - g_snprintf(time_str, sizeof(time_str), "%u:%2.2u", len / 60, len % 60); - label = gtk_label_new(time_str); - - gtk_box_pack_start(GTK_BOX(hbox_total), label, FALSE, FALSE, 10); -#endif - - bbox = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(vbox), bbox, TRUE, TRUE, 0); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); - - cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); - GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); - gtk_container_add(GTK_CONTAINER(bbox), cancel); - g_signal_connect_swapped(cancel, "clicked", - G_CALLBACK(gtk_widget_destroy), mainwin_jtt); - - jump = gtk_button_new_from_stock(GTK_STOCK_JUMP_TO); - GTK_WIDGET_SET_FLAGS(jump, GTK_CAN_DEFAULT); - gtk_container_add(GTK_CONTAINER(bbox), jump); - g_signal_connect(jump, "clicked", - G_CALLBACK(mainwin_jump_to_time_cb), time_entry); - - tindex = playback_get_time() / 1000; - g_snprintf(time_str, sizeof(time_str), "%u:%2.2u", tindex / 60, - tindex % 60); - gtk_entry_set_text(GTK_ENTRY(time_entry), time_str); - - gtk_entry_select_region(GTK_ENTRY(time_entry), 0, strlen(time_str)); - - gtk_widget_show_all(mainwin_jtt); - - gtk_widget_grab_focus(time_entry); - gtk_widget_grab_default(jump); -} - -/* - * Rewritten 09/13/06: - * - * Remove all of this flaky iter/sourcelist/strsplit stuff. - * All we care about is the filepath. - * - * We can figure this out and easily pass it to g_filename_from_uri(). - * - nenolod - */ -void -mainwin_drag_data_received(GtkWidget * widget, - GdkDragContext * context, - gint x, - gint y, - GtkSelectionData * selection_data, - guint info, - guint time, - gpointer user_data) -{ - Playlist *playlist = playlist_get_active(); - - g_return_if_fail(selection_data != NULL); - g_return_if_fail(selection_data->data != NULL); - - if (str_has_prefix_nocase((gchar *) selection_data->data, "fonts:///")) - { - gchar *path = (gchar *) selection_data->data; - gchar *decoded = g_filename_from_uri(path, NULL, NULL); - - if (decoded == NULL) - return; - - cfg.playlist_font = g_strconcat(decoded, strrchr(cfg.playlist_font, ' '), NULL); - ui_skinned_playlist_set_font(cfg.playlist_font); - playlistwin_update_list(playlist); - - g_free(decoded); - - return; - } - - /* perhaps make suffix check case-insensitive -- desowin */ - if (str_has_prefix_nocase((char*)selection_data->data, "file:///")) { - if (str_has_suffix_nocase((char*)selection_data->data, ".wsz\r\n") || - str_has_suffix_nocase((char*)selection_data->data, ".zip\r\n")) { - on_skin_view_drag_data_received(GTK_WIDGET(user_data), context, x, y, selection_data, info, time, NULL); - return; - } - } - - playlist_clear(playlist); - playlist_add_url(playlist, (gchar *) selection_data->data); - playback_initiate(); -} - -static void -on_add_url_add_clicked(GtkWidget * widget, - GtkWidget * entry) -{ - const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry)); - if (text && *text) - playlist_add_url(playlist_get_active(), text); -} - -static void -on_add_url_ok_clicked(GtkWidget * widget, - GtkWidget * entry) -{ - Playlist *playlist = playlist_get_active(); - - const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry)); - if (text && *text) - { - playlist_clear(playlist); - playlist_add_url(playlist, text); - playback_initiate(); - } -} - -static void -on_visibility_warning_toggle(GtkToggleButton *tbt, gpointer unused) -{ - cfg.warn_about_win_visibility = !gtk_toggle_button_get_active(tbt); -} - -static void -on_visibility_warning_response(GtkDialog *dlg, gint r_id, gpointer unused) -{ - switch (r_id) - { - case GTK_RESPONSE_OK: - mainwin_show(TRUE); - break; - case GTK_RESPONSE_CANCEL: - default: - break; - } - gtk_widget_destroy(GTK_WIDGET(dlg)); -} - -void -mainwin_show_visibility_warning(void) -{ - if (cfg.warn_about_win_visibility) - { - GtkWidget *label, *checkbt, *vbox; - GtkWidget *warning_dlg = - gtk_dialog_new_with_buttons( _("Audacious - visibility warning") , - GTK_WINDOW(mainwin) , - GTK_DIALOG_DESTROY_WITH_PARENT , - _("Show main player window") , - GTK_RESPONSE_OK , _("Ignore") , - GTK_RESPONSE_CANCEL , NULL ); - - vbox = gtk_vbox_new( FALSE , 4 ); - gtk_container_set_border_width( GTK_CONTAINER(vbox) , 4 ); - gtk_box_pack_start( GTK_BOX(GTK_DIALOG(warning_dlg)->vbox) , vbox , TRUE , TRUE , 0 ); - label = gtk_label_new( _("Audacious has been started with all of its windows hidden.\n" - "You may want to show the player window again to control Audacious; " - "otherwise, you'll have to control it remotely via audtool or " - "enabled plugins (such as the statusicon plugin).") ); - gtk_label_set_line_wrap( GTK_LABEL(label) , TRUE ); - gtk_misc_set_alignment( GTK_MISC(label) , 0.0 , 0.0 ); - checkbt = gtk_check_button_new_with_label( _("Always ignore, show/hide is controlled remotely") ); - gtk_box_pack_start( GTK_BOX(vbox) , label , TRUE , TRUE , 0 ); - gtk_box_pack_start( GTK_BOX(vbox) , checkbt , TRUE , TRUE , 0 ); - g_signal_connect( G_OBJECT(checkbt) , "toggled" , - G_CALLBACK(on_visibility_warning_toggle) , NULL ); - g_signal_connect( G_OBJECT(warning_dlg) , "response" , - G_CALLBACK(on_visibility_warning_response) , NULL ); - gtk_widget_show_all(warning_dlg); - } -} - -static void -on_broken_gtk_engine_warning_toggle(GtkToggleButton *tbt, gpointer unused) -{ - cfg.warn_about_broken_gtk_engines = !gtk_toggle_button_get_active(tbt); -} - -void -ui_main_check_theme_engine(void) -{ - GtkSettings *settings; - GtkWidget *widget; - gchar *theme = NULL; - - widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_widget_ensure_style(widget); - - settings = gtk_settings_get_default(); - g_object_get(G_OBJECT(settings), "gtk-theme-name", &theme, NULL); - gtk_widget_destroy(widget); - - if (theme == NULL) - return; - - if (g_ascii_strcasecmp(theme, "Qt")) - { - g_free(theme); - return; - } - - if (cfg.warn_about_broken_gtk_engines) - { - gchar *msg; - GtkWidget *label, *checkbt, *vbox; - GtkWidget *warning_dlg = - gtk_dialog_new_with_buttons( _("Audacious - broken GTK engine usage warning") , - GTK_WINDOW(mainwin) , GTK_DIALOG_DESTROY_WITH_PARENT , - GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL ); - vbox = gtk_vbox_new( FALSE , 4 ); - gtk_container_set_border_width( GTK_CONTAINER(vbox) , 4 ); - gtk_box_pack_start( GTK_BOX(GTK_DIALOG(warning_dlg)->vbox) , vbox , - TRUE , TRUE , 0 ); - - msg = g_strdup_printf(_("Broken GTK engine in use\n\n" - "Audacious has detected that you are using a broken GTK engine.\n\n" - "The theme engine you are using, %s, is incompatible with some of the features " - "used by modern skins. The incompatible features have been disabled for this session.\n\n" - "To use these features, please consider using a different GTK theme engine."), theme); - label = gtk_label_new(msg); - gtk_label_set_use_markup(GTK_LABEL(label), TRUE); - g_free(msg); - - gtk_label_set_line_wrap( GTK_LABEL(label) , TRUE ); - gtk_misc_set_alignment( GTK_MISC(label) , 0.0 , 0.0 ); - checkbt = gtk_check_button_new_with_label( _("Do not display this warning again") ); - gtk_box_pack_start( GTK_BOX(vbox) , label , TRUE , TRUE , 0 ); - gtk_box_pack_start( GTK_BOX(vbox) , checkbt , TRUE , TRUE , 0 ); - g_signal_connect( G_OBJECT(checkbt) , "toggled" , - G_CALLBACK(on_broken_gtk_engine_warning_toggle) , NULL ); - g_signal_connect( G_OBJECT(warning_dlg) , "response" , - G_CALLBACK(gtk_widget_destroy) , NULL ); - gtk_widget_show_all(warning_dlg); - gtk_window_stick(GTK_WINDOW(warning_dlg)); - } - - cfg.disable_inline_gtk = TRUE; - - g_free(theme); -} - -void -mainwin_show_add_url_window(void) -{ - static GtkWidget *url_window = NULL; - - if (!url_window) { - url_window = - util_add_url_dialog_new(_("Enter location to play:"), - G_CALLBACK(on_add_url_ok_clicked), - G_CALLBACK(on_add_url_add_clicked)); - gtk_window_set_transient_for(GTK_WINDOW(url_window), - GTK_WINDOW(mainwin)); - g_signal_connect(url_window, "destroy", - G_CALLBACK(gtk_widget_destroyed), - &url_window); - } - - gtk_window_present(GTK_WINDOW(url_window)); -} - -static void -check_set( GtkActionGroup * action_group , - const gchar * action_name , - gboolean is_on ) -{ - /* check_set noew uses gtkaction */ - GtkAction *action = gtk_action_group_get_action( action_group , action_name ); - if ( action != NULL ) - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , is_on ); - return; -} - -void -mainwin_eject_pushed(void) -{ - run_filebrowser(TRUE); -} - -void -mainwin_rev_pushed(void) -{ - g_get_current_time(&cb_time); - - seek_initial_pos = ui_skinned_horizontal_slider_get_position(mainwin_position); - seek_state = MAINWIN_SEEK_REV; - mainwin_timeout_id = g_timeout_add(MAINWIN_UPDATE_INTERVAL, - (GSourceFunc) mainwin_idle_func, NULL); -} - -void -mainwin_rev_release(void) -{ - GTimeVal now_time; - GTimeVal delta_time; - gulong now_dur; - - g_get_current_time(&now_time); - - delta_time.tv_usec = now_time.tv_usec - cb_time.tv_usec; - delta_time.tv_sec = now_time.tv_sec - cb_time.tv_sec; - - now_dur = labs((delta_time.tv_sec * 1000) + (glong) (delta_time.tv_usec / 1000)); - - if ( now_dur <= TRISTATE_THRESHOLD ) - { - /* interpret as 'skip to previous song' */ - playlist_prev(playlist_get_active()); - } - else - { - /* interpret as 'seek' */ - mainwin_position_release_cb( mainwin_position, ui_skinned_horizontal_slider_get_position(mainwin_position) ); - } - - seek_state = MAINWIN_SEEK_NIL; - - g_source_remove(mainwin_timeout_id); - mainwin_timeout_id = 0; -} - -void -mainwin_fwd_pushed(void) -{ - g_get_current_time(&cb_time); - - seek_initial_pos = ui_skinned_horizontal_slider_get_position(mainwin_position); - seek_state = MAINWIN_SEEK_FWD; - mainwin_timeout_id = g_timeout_add(MAINWIN_UPDATE_INTERVAL, - (GSourceFunc) mainwin_idle_func, NULL); -} - -void -mainwin_fwd_release(void) -{ - GTimeVal now_time; - GTimeVal delta_time; - gulong now_dur; - - g_get_current_time(&now_time); - - delta_time.tv_usec = now_time.tv_usec - cb_time.tv_usec; - delta_time.tv_sec = now_time.tv_sec - cb_time.tv_sec; - - now_dur = labs((delta_time.tv_sec * 1000) + (glong) (delta_time.tv_usec / 1000)); - - if ( now_dur <= TRISTATE_THRESHOLD ) - { - /* interpret as 'skip to next song' */ - playlist_next(playlist_get_active()); - } - else - { - /* interpret as 'seek' */ - mainwin_position_release_cb( mainwin_position, ui_skinned_horizontal_slider_get_position(mainwin_position) ); - } - - seek_state = MAINWIN_SEEK_NIL; - - g_source_remove(mainwin_timeout_id); - mainwin_timeout_id = 0; -} - -void -mainwin_play_pushed(void) -{ - if (ab_position_a != -1) - playback_seek(ab_position_a / 1000); - if (playback_get_paused()) { - playback_pause(); - return; - } - - if (playlist_get_length(playlist_get_active())) - playback_initiate(); - else - mainwin_eject_pushed(); -} - -void -mainwin_stop_pushed(void) -{ - ip_data.stop = TRUE; - playback_stop(); - mainwin_clear_song_info(); - ab_position_a = ab_position_b = -1; - ip_data.stop = FALSE; -} - -void -mainwin_shuffle_pushed(gboolean toggled) -{ - check_set( toggleaction_group_others , "playback shuffle" , toggled ); -} - -void mainwin_shuffle_pushed_cb(void) { - mainwin_shuffle_pushed(UI_SKINNED_BUTTON(mainwin_shuffle)->inside); -} - -void -mainwin_repeat_pushed(gboolean toggled) -{ - check_set( toggleaction_group_others , "playback repeat" , toggled ); -} - -void mainwin_repeat_pushed_cb(void) { - mainwin_repeat_pushed(UI_SKINNED_BUTTON(mainwin_repeat)->inside); -} - -void mainwin_equalizer_pushed_cb(void) { - mainwin_eq_pushed(UI_SKINNED_BUTTON(mainwin_eq)->inside); -} - -void mainwin_playlist_pushed_cb(void) { - mainwin_pl_pushed(UI_SKINNED_BUTTON(mainwin_pl)->inside); -} - -void -mainwin_eq_pushed(gboolean toggled) -{ - equalizerwin_show(toggled); -} - -void -mainwin_pl_pushed(gboolean toggled) -{ - if (toggled) - playlistwin_show(); - else - playlistwin_hide(); -} - -gint -mainwin_spos_frame_cb(gint pos) -{ - if (mainwin_sposition) { - gint x = 0; - if (pos < 6) - x = 17; - else if (pos < 9) - x = 20; - else - x = 23; - - UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->knob_nx = x; - UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->knob_px = x; - } - return 1; -} - -void -mainwin_spos_motion_cb(GtkWidget *widget, gint pos) -{ - gint time; - gchar *time_msg; - Playlist *playlist = playlist_get_active(); - - pos--; - - time = ((playlist_get_current_length(playlist) / 1000) * pos) / 12; - - if (cfg.timer_mode == TIMER_REMAINING) { - time = (playlist_get_current_length(playlist) / 1000) - time; - time_msg = g_strdup_printf("-%2.2d", time / 60); - ui_skinned_textbox_set_text(mainwin_stime_min, time_msg); - g_free(time_msg); - } - else { - time_msg = g_strdup_printf(" %2.2d", time / 60); - ui_skinned_textbox_set_text(mainwin_stime_min, time_msg); - g_free(time_msg); - } - - time_msg = g_strdup_printf("%2.2d", time % 60); - ui_skinned_textbox_set_text(mainwin_stime_sec, time_msg); - g_free(time_msg); -} - -void -mainwin_spos_release_cb(GtkWidget *widget, gint pos) -{ - playback_seek(((playlist_get_current_length(playlist_get_active()) / 1000) * - (pos - 1)) / 12); -} - -void -mainwin_position_motion_cb(GtkWidget *widget, gint pos) -{ - gint length, time; - gchar *seek_msg; - - length = playlist_get_current_length(playlist_get_active()) / 1000; - time = (length * pos) / 219; - seek_msg = g_strdup_printf(_("Seek to: %d:%-2.2d/%d:%-2.2d (%d%%)"), - time / 60, time % 60, - length / 60, length % 60, - (length != 0) ? (time * 100) / length : 0); - mainwin_lock_info_text(seek_msg); - g_free(seek_msg); -} - -void -mainwin_position_release_cb(GtkWidget *widget, gint pos) -{ - gint length, time; - - length = playlist_get_current_length(playlist_get_active()) / 1000; - time = (length * pos) / 219; - playback_seek(time); - mainwin_release_info_text(); -} - -gint -mainwin_volume_frame_cb(gint pos) -{ - return (gint) rint((pos / 52.0) * 28); -} - -void -mainwin_adjust_volume_motion(gint v) -{ - gchar *volume_msg; - - volume_msg = g_strdup_printf(_("Volume: %d%%"), v); - mainwin_lock_info_text(volume_msg); - g_free(volume_msg); - - if (balance < 0) - input_set_volume(v, (v * (100 - abs(balance))) / 100); - else if (balance > 0) - input_set_volume((v * (100 - abs(balance))) / 100, v); - else - input_set_volume(v, v); -} - -void -mainwin_adjust_volume_release(void) -{ - mainwin_release_info_text(); -} - -void -mainwin_adjust_balance_motion(gint b) -{ - gchar *balance_msg; - gint v, pvl, pvr; - - balance = b; - input_get_volume(&pvl, &pvr); - v = MAX(pvl, pvr); - if (b < 0) { - balance_msg = g_strdup_printf(_("Balance: %d%% left"), -b); - input_set_volume(v, (gint) rint(((100 + b) / 100.0) * v)); - } - else if (b == 0) { - balance_msg = g_strdup_printf(_("Balance: center")); - input_set_volume(v, v); - } - else { /* b > 0 */ - balance_msg = g_strdup_printf(_("Balance: %d%% right"), b); - input_set_volume((gint) rint(((100 - b) / 100.0) * v), v); - } - mainwin_lock_info_text(balance_msg); - g_free(balance_msg); -} - -void -mainwin_adjust_balance_release(void) -{ - mainwin_release_info_text(); -} - -void -mainwin_set_volume_slider(gint percent) -{ - ui_skinned_horizontal_slider_set_position(mainwin_volume, (gint) rint((percent * 51) / 100.0)); -} - -void -mainwin_set_balance_slider(gint percent) -{ - ui_skinned_horizontal_slider_set_position(mainwin_balance, (gint) rint(((percent * 12) / 100.0) + 12)); -} - -void -mainwin_volume_motion_cb(GtkWidget *widget, gint pos) -{ - gint vol = (pos * 100) / 51; - mainwin_adjust_volume_motion(vol); - equalizerwin_set_volume_slider(vol); -} - -gboolean -mainwin_volume_release_cb(GtkWidget *widget, gint pos) -{ - mainwin_adjust_volume_release(); - return FALSE; -} - -gint -mainwin_balance_frame_cb(gint pos) -{ - return ((abs(pos - 12) * 28) / 13); -} - -void -mainwin_balance_motion_cb(GtkWidget *widget, gint pos) -{ - gint bal = ((pos - 12) * 100) / 12; - mainwin_adjust_balance_motion(bal); - equalizerwin_set_balance_slider(bal); -} - -void -mainwin_balance_release_cb(GtkWidget *widget, gint pos) -{ - mainwin_adjust_volume_release(); -} - -void -mainwin_set_volume_diff(gint diff) -{ - gint vl, vr, vol; - - input_get_volume(&vl, &vr); - vol = MAX(vl, vr); - vol = CLAMP(vol + diff, 0, 100); - - mainwin_adjust_volume_motion(vol); - mainwin_set_volume_slider(vol); - equalizerwin_set_volume_slider(vol); - - if (mainwin_volume_release_timeout) - g_source_remove(mainwin_volume_release_timeout); - mainwin_volume_release_timeout = - g_timeout_add(700, (GSourceFunc)(mainwin_volume_release_cb), NULL); -} - -void -mainwin_set_balance_diff(gint diff) -{ - gint b; - b = CLAMP(balance + diff, -100, 100); - mainwin_adjust_balance_motion(b); - mainwin_set_balance_slider(b); - equalizerwin_set_balance_slider(b); -} - -void -mainwin_show(gboolean show) -{ - if (show) - mainwin_real_show(); - else - mainwin_real_hide(); -} - -void -mainwin_real_show(void) -{ - cfg.player_visible = TRUE; - - check_set( toggleaction_group_others , "show player" , TRUE ); - - if (cfg.player_shaded) - ui_vis_clear_data(mainwin_vis); - - if (cfg.show_wm_decorations) { - if (cfg.player_x != -1 && cfg.save_window_position) - gtk_window_move(GTK_WINDOW(mainwin), cfg.player_x, cfg.player_y); - - gtk_widget_show(mainwin); - return; - } - - if (cfg.player_x != -1 && cfg.save_window_position) - gtk_window_move(GTK_WINDOW(mainwin), cfg.player_x, cfg.player_y); - - mainwin_refresh_hints(); - gtk_window_present(GTK_WINDOW(mainwin)); -} - -void -mainwin_real_hide(void) -{ - check_set( toggleaction_group_others , "show player", FALSE); - - if (cfg.player_shaded) - ui_svis_clear_data(mainwin_svis); - - gtk_widget_hide(mainwin); - - cfg.player_visible = FALSE; -} - - -void -mainwin_set_stopaftersong(gboolean stop) -{ - cfg.stopaftersong = stop; - check_set(toggleaction_group_others, "stop after current song", cfg.stopaftersong); -} - -void -mainwin_set_noplaylistadvance(gboolean no_advance) -{ - cfg.no_playlist_advance = no_advance; - check_set(toggleaction_group_others, "playback no playlist advance", cfg.no_playlist_advance); -} - -static void -mainwin_set_scaled(gboolean scaled) -{ - gint height; - - if (cfg.player_shaded) - height = MAINWIN_SHADED_HEIGHT; - else - height = aud_active_skin->properties.mainwin_height; - - dock_window_resize(GTK_WINDOW(mainwin), cfg.player_shaded ? MAINWIN_SHADED_WIDTH : aud_active_skin->properties.mainwin_width, - cfg.player_shaded ? MAINWIN_SHADED_HEIGHT : aud_active_skin->properties.mainwin_height, - aud_active_skin->properties.mainwin_width * cfg.scale_factor , aud_active_skin->properties.mainwin_height * cfg.scale_factor); - - GList *iter; - for (iter = GTK_FIXED (SKINNED_WINDOW(mainwin)->fixed)->children; iter; iter = g_list_next (iter)) { - GtkFixedChild *child_data = (GtkFixedChild *) iter->data; - GtkWidget *child = child_data->widget; - g_signal_emit_by_name(child, "toggle-scaled"); - } - - mainwin_refresh_hints(); - gtk_widget_shape_combine_mask(mainwin, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + cfg.player_shaded), 0, 0); -} - -void -set_scaled(gboolean scaled) -{ - cfg.scaled = scaled; - - mainwin_set_scaled(scaled); - - if (cfg.eq_scaled_linked) - equalizerwin_set_scaled(scaled); -} - - - -void -mainwin_general_menu_callback(gpointer data, - guint action, - GtkWidget * item) -{ - Playlist *playlist = playlist_get_active(); - - switch (action) { - case MAINWIN_GENERAL_PREFS: - show_prefs_window(); - break; - case MAINWIN_GENERAL_ABOUT: - show_about_window(); - break; - case MAINWIN_GENERAL_PLAYFILE: - run_filebrowser(FALSE); - break; - case MAINWIN_GENERAL_PLAYLOCATION: - mainwin_show_add_url_window(); - break; - case MAINWIN_GENERAL_FILEINFO: - ui_fileinfo_show_current(playlist); - break; - case MAINWIN_GENERAL_FOCUSPLWIN: - gtk_window_present(GTK_WINDOW(playlistwin)); - break; - case MAINWIN_GENERAL_SHOWMWIN: - mainwin_show(GTK_CHECK_MENU_ITEM(item)->active); - break; - case MAINWIN_GENERAL_SHOWPLWIN: - if (GTK_CHECK_MENU_ITEM(item)->active) - playlistwin_show(); - else - playlistwin_hide(); - break; - case MAINWIN_GENERAL_SHOWEQWIN: - if (GTK_CHECK_MENU_ITEM(item)->active) - equalizerwin_real_show(); - else - equalizerwin_real_hide(); - break; - case MAINWIN_GENERAL_PREV: - playlist_prev(playlist); - break; - case MAINWIN_GENERAL_PLAY: - mainwin_play_pushed(); - break; - case MAINWIN_GENERAL_PAUSE: - playback_pause(); - break; - case MAINWIN_GENERAL_STOP: - mainwin_stop_pushed(); - break; - case MAINWIN_GENERAL_NEXT: - playlist_next(playlist); - break; - case MAINWIN_GENERAL_BACK5SEC: - if (playback_get_playing() - && playlist_get_current_length(playlist) != -1) - playback_seek_relative(-5); - break; - case MAINWIN_GENERAL_FWD5SEC: - if (playback_get_playing() - && playlist_get_current_length(playlist) != -1) - playback_seek_relative(5); - break; - case MAINWIN_GENERAL_START: - playlist_set_position(playlist, 0); - break; - case MAINWIN_GENERAL_JTT: - mainwin_jump_to_time(); - break; - case MAINWIN_GENERAL_JTF: - ui_jump_to_track(); - break; - case MAINWIN_GENERAL_EXIT: - mainwin_quit_cb(); - break; - case MAINWIN_GENERAL_SETAB: - if (playlist_get_current_length(playlist) != -1) { - if (ab_position_a == -1) { - ab_position_a = playback_get_time(); - ab_position_b = -1; - mainwin_lock_info_text("'Loop-Point A Position' set."); - } else if (ab_position_b == -1) { - int time = playback_get_time(); - if (time > ab_position_a) - ab_position_b = time; - mainwin_release_info_text(); - } else { - ab_position_a = playback_get_time(); - ab_position_b = -1; - mainwin_lock_info_text("'Loop-Point A Position' reset."); - } - } - break; - case MAINWIN_GENERAL_CLEARAB: - if (playlist_get_current_length(playlist) != -1) { - ab_position_a = ab_position_b = -1; - mainwin_release_info_text(); - } - break; - case MAINWIN_GENERAL_NEW_PL: - { - Playlist *new_pl = playlist_new(); - playlist_add_playlist(new_pl); - playlist_select_playlist(new_pl); - } - break; - case MAINWIN_GENERAL_PREV_PL: - playlist_select_prev(); - break; - case MAINWIN_GENERAL_NEXT_PL: - playlist_select_next(); - break; - } -} - -static void -mainwin_mr_change(GtkWidget *widget, MenuRowItem i) -{ - switch (i) { - case MENUROW_OPTIONS: - mainwin_lock_info_text(_("Options Menu")); - break; - case MENUROW_ALWAYS: - if (UI_SKINNED_MENUROW(mainwin_menurow)->always_selected) - mainwin_lock_info_text(_("Disable 'Always On Top'")); - else - mainwin_lock_info_text(_("Enable 'Always On Top'")); - break; - case MENUROW_FILEINFOBOX: - mainwin_lock_info_text(_("File Info Box")); - break; - case MENUROW_SCALE: - if (UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected) - mainwin_lock_info_text(_("Disable 'GUI Scaling'")); - else - mainwin_lock_info_text(_("Enable 'GUI Scaling'")); - break; - case MENUROW_VISUALIZATION: - mainwin_lock_info_text(_("Visualization Menu")); - break; - case MENUROW_NONE: - break; - } -} - -static void -mainwin_mr_release(GtkWidget *widget, MenuRowItem i, GdkEventButton *event) -{ - switch (i) { - case MENUROW_OPTIONS: - ui_manager_popup_menu_show(GTK_MENU(mainwin_view_menu), - event->x_root, event->y_root, 1, - event->time); - break; - case MENUROW_ALWAYS: - gtk_toggle_action_set_active( - GTK_TOGGLE_ACTION(gtk_action_group_get_action( - toggleaction_group_others , "view always on top" )) , - UI_SKINNED_MENUROW(mainwin_menurow)->always_selected ); - break; - case MENUROW_FILEINFOBOX: - ui_fileinfo_show_current(playlist_get_active()); - break; - case MENUROW_SCALE: - gtk_toggle_action_set_active( - GTK_TOGGLE_ACTION(gtk_action_group_get_action( - toggleaction_group_others , "view scaled" )) , - UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected ); - break; - case MENUROW_VISUALIZATION: - ui_manager_popup_menu_show(GTK_MENU(mainwin_visualization_menu), - event->x_root, event->y_root, 1, - event->time); - break; - case MENUROW_NONE: - break; - } - mainwin_release_info_text(); -} - -void -run_no_output_device_dialog(gpointer hook_data, gpointer user_data) -{ - const gchar *markup = - N_("Couldn't open audio.\n\n" - "Please check that:\n" - "1. You have the correct output plugin selected.\n" - "2. No other programs is blocking the soundcard.\n" - "3. Your soundcard is configured properly.\n"); - - GDK_THREADS_ENTER(); - GtkWidget *dialog = - gtk_message_dialog_new_with_markup(GTK_WINDOW(mainwin), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _(markup)); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - GDK_THREADS_LEAVE(); -} - -static void -set_timer_mode(TimerMode mode) -{ - if (mode == TIMER_ELAPSED) - check_set(radioaction_group_viewtime, "view time elapsed", TRUE); - else - check_set(radioaction_group_viewtime, "view time remaining", TRUE); -} - -static void -set_timer_mode_menu_cb(TimerMode mode) -{ - cfg.timer_mode = mode; -} - -gboolean -change_timer_mode_cb(GtkWidget *widget, GdkEventButton *event) -{ - if (event->button == 1) { - change_timer_mode(); - } else if (event->button == 3) - return FALSE; - - return TRUE; -} - -static void change_timer_mode(void) { - if (cfg.timer_mode == TIMER_ELAPSED) - set_timer_mode(TIMER_REMAINING); - else - set_timer_mode(TIMER_ELAPSED); - if (playback_get_playing()) - mainwin_update_song_info(); -} - -static void -mainwin_playlist_prev(void) -{ - playlist_prev(playlist_get_active()); -} - -static void -mainwin_playlist_next(void) -{ - playlist_next(playlist_get_active()); -} - -void -mainwin_setup_menus(void) -{ - set_timer_mode(cfg.timer_mode); - - /* View menu */ - - check_set(toggleaction_group_others, "view always on top", cfg.always_on_top); - check_set(toggleaction_group_others, "view put on all workspaces", cfg.sticky); - check_set(toggleaction_group_others, "roll up player", cfg.player_shaded); - check_set(toggleaction_group_others, "roll up playlist editor", cfg.playlist_shaded); - check_set(toggleaction_group_others, "roll up equalizer", cfg.equalizer_shaded); - check_set(toggleaction_group_others, "view easy move", cfg.easy_move); - check_set(toggleaction_group_others, "view scaled", cfg.scaled); - - /* Songname menu */ - - check_set(toggleaction_group_others, "autoscroll songname", cfg.autoscroll); - check_set(toggleaction_group_others, "stop after current song", cfg.stopaftersong); - - /* Playback menu */ - - check_set(toggleaction_group_others, "playback repeat", cfg.repeat); - check_set(toggleaction_group_others, "playback shuffle", cfg.shuffle); - check_set(toggleaction_group_others, "playback no playlist advance", cfg.no_playlist_advance); - - /* Visualization menu */ - - switch ( cfg.vis_type ) - { - case VIS_ANALYZER: - check_set(radioaction_group_vismode, "vismode analyzer", TRUE); - break; - case VIS_SCOPE: - check_set(radioaction_group_vismode, "vismode scope", TRUE); - break; - case VIS_VOICEPRINT: - check_set(radioaction_group_vismode, "vismode voiceprint", TRUE); - break; - case VIS_OFF: - default: - check_set(radioaction_group_vismode, "vismode off", TRUE); - break; - } - - switch ( cfg.analyzer_mode ) - { - case ANALYZER_FIRE: - check_set(radioaction_group_anamode, "anamode fire", TRUE); - break; - case ANALYZER_VLINES: - check_set(radioaction_group_anamode, "anamode vertical lines", TRUE); - break; - case ANALYZER_NORMAL: - default: - check_set(radioaction_group_anamode, "anamode normal", TRUE); - break; - } - - switch ( cfg.analyzer_type ) - { - case ANALYZER_BARS: - check_set(radioaction_group_anatype, "anatype bars", TRUE); - break; - case ANALYZER_LINES: - default: - check_set(radioaction_group_anatype, "anatype lines", TRUE); - break; - } - - check_set(toggleaction_group_others, "anamode peaks", cfg.analyzer_peaks ); - - switch ( cfg.scope_mode ) - { - case SCOPE_LINE: - check_set(radioaction_group_scomode, "scomode line", TRUE); - break; - case SCOPE_SOLID: - check_set(radioaction_group_scomode, "scomode solid", TRUE); - break; - case SCOPE_DOT: - default: - check_set(radioaction_group_scomode, "scomode dot", TRUE); - break; - } - - switch ( cfg.voiceprint_mode ) - { - case VOICEPRINT_FIRE: - check_set(radioaction_group_vprmode, "vprmode fire", TRUE); - break; - case VOICEPRINT_ICE: - check_set(radioaction_group_vprmode, "vprmode ice", TRUE); - break; - case VOICEPRINT_NORMAL: - default: - check_set(radioaction_group_vprmode, "vprmode normal", TRUE); - break; - } - - switch ( cfg.vu_mode ) - { - case VU_SMOOTH: - check_set(radioaction_group_wshmode, "wshmode smooth", TRUE); - break; - case VU_NORMAL: - default: - check_set(radioaction_group_wshmode, "wshmode normal", TRUE); - break; - } - - switch ( cfg.vis_refresh ) - { - case REFRESH_HALF: - check_set(radioaction_group_refrate, "refrate half", TRUE); - break; - case REFRESH_QUARTER: - check_set(radioaction_group_refrate, "refrate quarter", TRUE); - break; - case REFRESH_EIGTH: - check_set(radioaction_group_refrate, "refrate eighth", TRUE); - break; - case REFRESH_FULL: - default: - check_set(radioaction_group_refrate, "refrate full", TRUE); - break; - } - - switch ( cfg.analyzer_falloff ) - { - case FALLOFF_SLOW: - check_set(radioaction_group_anafoff, "anafoff slow", TRUE); - break; - case FALLOFF_MEDIUM: - check_set(radioaction_group_anafoff, "anafoff medium", TRUE); - break; - case FALLOFF_FAST: - check_set(radioaction_group_anafoff, "anafoff fast", TRUE); - break; - case FALLOFF_FASTEST: - check_set(radioaction_group_anafoff, "anafoff fastest", TRUE); - break; - case FALLOFF_SLOWEST: - default: - check_set(radioaction_group_anafoff, "anafoff slowest", TRUE); - break; - } - - switch ( cfg.peaks_falloff ) - { - case FALLOFF_SLOW: - check_set(radioaction_group_peafoff, "peafoff slow", TRUE); - break; - case FALLOFF_MEDIUM: - check_set(radioaction_group_peafoff, "peafoff medium", TRUE); - break; - case FALLOFF_FAST: - check_set(radioaction_group_peafoff, "peafoff fast", TRUE); - break; - case FALLOFF_FASTEST: - check_set(radioaction_group_peafoff, "peafoff fastest", TRUE); - break; - case FALLOFF_SLOWEST: - default: - check_set(radioaction_group_peafoff, "peafoff slowest", TRUE); - break; - } - -} - -static void mainwin_info_double_clicked_cb(void) { - ui_fileinfo_show_current(playlist_get_active()); -} - -static void -mainwin_info_right_clicked_cb(GtkWidget *widget, GdkEventButton *event) -{ - ui_manager_popup_menu_show(GTK_MENU(mainwin_songname_menu), - event->x_root, event->y_root, 3, event->time); -} - -static void -mainwin_create_widgets(void) -{ - mainwin_menubtn = ui_skinned_button_new(); - ui_skinned_push_button_setup(mainwin_menubtn, SKINNED_WINDOW(mainwin)->fixed, - 6, 3, 9, 9, 0, 0, 0, 9, SKIN_TITLEBAR); - g_signal_connect(mainwin_menubtn, "clicked", mainwin_menubtn_cb, NULL ); - - mainwin_minimize = ui_skinned_button_new(); - ui_skinned_push_button_setup(mainwin_minimize, SKINNED_WINDOW(mainwin)->fixed, - 244, 3, 9, 9, 9, 0, 9, 9, SKIN_TITLEBAR); - g_signal_connect(mainwin_minimize, "clicked", mainwin_minimize_cb, NULL ); - - mainwin_shade = ui_skinned_button_new(); - ui_skinned_push_button_setup(mainwin_shade, SKINNED_WINDOW(mainwin)->fixed, - 254, 3, 9, 9, 0, - cfg.player_shaded ? 27 : 18, 9, cfg.player_shaded ? 27 : 18, SKIN_TITLEBAR); - g_signal_connect(mainwin_shade, "clicked", mainwin_shade_toggle, NULL ); - - mainwin_close = ui_skinned_button_new(); - ui_skinned_push_button_setup(mainwin_close, SKINNED_WINDOW(mainwin)->fixed, - 264, 3, 9, 9, 18, 0, 18, 9, SKIN_TITLEBAR); - g_signal_connect(mainwin_close, "clicked", mainwin_quit_cb, NULL ); - - mainwin_rew = ui_skinned_button_new(); - ui_skinned_push_button_setup(mainwin_rew, SKINNED_WINDOW(mainwin)->fixed, - 16, 88, 23, 18, 0, 0, 0, 18, SKIN_CBUTTONS); - g_signal_connect(mainwin_rew, "pressed", mainwin_rev_pushed, NULL); - g_signal_connect(mainwin_rew, "released", mainwin_rev_release, NULL); - - mainwin_fwd = ui_skinned_button_new(); - ui_skinned_push_button_setup(mainwin_fwd, SKINNED_WINDOW(mainwin)->fixed, - 108, 88, 22, 18, 92, 0, 92, 18, SKIN_CBUTTONS); - g_signal_connect(mainwin_fwd, "pressed", mainwin_fwd_pushed, NULL); - g_signal_connect(mainwin_fwd, "released", mainwin_fwd_release, NULL); - - mainwin_play = ui_skinned_button_new(); - ui_skinned_push_button_setup(mainwin_play, SKINNED_WINDOW(mainwin)->fixed, - 39, 88, 23, 18, 23, 0, 23, 18, SKIN_CBUTTONS); - g_signal_connect(mainwin_play, "clicked", mainwin_play_pushed, NULL ); - - mainwin_pause = ui_skinned_button_new(); - ui_skinned_push_button_setup(mainwin_pause, SKINNED_WINDOW(mainwin)->fixed, - 62, 88, 23, 18, 46, 0, 46, 18, SKIN_CBUTTONS); - g_signal_connect(mainwin_pause, "clicked", playback_pause, NULL ); - - mainwin_stop = ui_skinned_button_new(); - ui_skinned_push_button_setup(mainwin_stop, SKINNED_WINDOW(mainwin)->fixed, - 85, 88, 23, 18, 69, 0, 69, 18, SKIN_CBUTTONS); - g_signal_connect(mainwin_stop, "clicked", mainwin_stop_pushed, NULL ); - - mainwin_eject = ui_skinned_button_new(); - ui_skinned_push_button_setup(mainwin_eject, SKINNED_WINDOW(mainwin)->fixed, - 136, 89, 22, 16, 114, 0, 114, 16, SKIN_CBUTTONS); - g_signal_connect(mainwin_eject, "clicked", mainwin_eject_pushed, NULL); - - mainwin_srew = ui_skinned_button_new(); - ui_skinned_small_button_setup(mainwin_srew, SKINNED_WINDOW(mainwin)->fixed, 169, 4, 8, 7); - g_signal_connect(mainwin_srew, "clicked", mainwin_playlist_prev, NULL); - - mainwin_splay = ui_skinned_button_new(); - ui_skinned_small_button_setup(mainwin_splay, SKINNED_WINDOW(mainwin)->fixed, 177, 4, 10, 7); - g_signal_connect(mainwin_splay, "clicked", mainwin_play_pushed, NULL); - - mainwin_spause = ui_skinned_button_new(); - ui_skinned_small_button_setup(mainwin_spause, SKINNED_WINDOW(mainwin)->fixed, 187, 4, 10, 7); - g_signal_connect(mainwin_spause, "clicked", playback_pause, NULL); - - mainwin_sstop = ui_skinned_button_new(); - ui_skinned_small_button_setup(mainwin_sstop, SKINNED_WINDOW(mainwin)->fixed, 197, 4, 9, 7); - g_signal_connect(mainwin_sstop, "clicked", mainwin_stop_pushed, NULL); - - mainwin_sfwd = ui_skinned_button_new(); - ui_skinned_small_button_setup(mainwin_sfwd, SKINNED_WINDOW(mainwin)->fixed, 206, 4, 8, 7); - g_signal_connect(mainwin_sfwd, "clicked", mainwin_playlist_next, NULL); - - mainwin_seject = ui_skinned_button_new(); - ui_skinned_small_button_setup(mainwin_seject, SKINNED_WINDOW(mainwin)->fixed, 216, 4, 9, 7); - g_signal_connect(mainwin_seject, "clicked", mainwin_eject_pushed, NULL); - - mainwin_shuffle = ui_skinned_button_new(); - ui_skinned_toggle_button_setup(mainwin_shuffle, SKINNED_WINDOW(mainwin)->fixed, - 164, 89, 46, 15, 28, 0, 28, 15, 28, 30, 28, 45, SKIN_SHUFREP); - g_signal_connect(mainwin_shuffle, "clicked", mainwin_shuffle_pushed_cb, NULL); - - mainwin_repeat = ui_skinned_button_new(); - ui_skinned_toggle_button_setup(mainwin_repeat, SKINNED_WINDOW(mainwin)->fixed, - 210, 89, 28, 15, 0, 0, 0, 15, 0, 30, 0, 45, SKIN_SHUFREP); - g_signal_connect(mainwin_repeat, "clicked", mainwin_repeat_pushed_cb, NULL); - - mainwin_eq = ui_skinned_button_new(); - ui_skinned_toggle_button_setup(mainwin_eq, SKINNED_WINDOW(mainwin)->fixed, - 219, 58, 23, 12, 0, 61, 46, 61, 0, 73, 46, 73, SKIN_SHUFREP); - g_signal_connect(mainwin_eq, "clicked", mainwin_equalizer_pushed_cb, NULL); - UI_SKINNED_BUTTON(mainwin_eq)->inside = cfg.equalizer_visible; - - mainwin_pl = ui_skinned_button_new(); - ui_skinned_toggle_button_setup(mainwin_pl, SKINNED_WINDOW(mainwin)->fixed, - 242, 58, 23, 12, 23, 61, 69, 61, 23, 73, 69, 73, SKIN_SHUFREP); - g_signal_connect(mainwin_pl, "clicked", mainwin_playlist_pushed_cb, NULL); - UI_SKINNED_BUTTON(mainwin_pl)->inside = cfg.playlist_visible; - - mainwin_info = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 112, 27, 153, 1, SKIN_TEXT); - ui_skinned_textbox_set_scroll(mainwin_info, cfg.autoscroll); - ui_skinned_textbox_set_xfont(mainwin_info, !cfg.mainwin_use_bitmapfont, cfg.mainwin_font); - g_signal_connect(mainwin_info, "double-clicked", mainwin_info_double_clicked_cb, NULL); - g_signal_connect(mainwin_info, "right-clicked", G_CALLBACK(mainwin_info_right_clicked_cb), NULL); - - mainwin_othertext = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 112, 43, 153, 1, SKIN_TEXT); - - mainwin_rate_text = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 111, 43, 15, 0, SKIN_TEXT); - - mainwin_freq_text = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 156, 43, 10, 0, SKIN_TEXT); - - mainwin_menurow = ui_skinned_menurow_new(SKINNED_WINDOW(mainwin)->fixed, 10, 22, 304, 0, 304, 44, SKIN_TITLEBAR); - g_signal_connect(mainwin_menurow, "change", G_CALLBACK(mainwin_mr_change), NULL); - g_signal_connect(mainwin_menurow, "release", G_CALLBACK(mainwin_mr_release), NULL); - - mainwin_volume = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 107, 57, 68, - 13, 15, 422, 0, 422, 14, 11, 15, 0, 0, 51, - mainwin_volume_frame_cb, SKIN_VOLUME); - g_signal_connect(mainwin_volume, "motion", G_CALLBACK(mainwin_volume_motion_cb), NULL); - g_signal_connect(mainwin_volume, "release", G_CALLBACK(mainwin_volume_release_cb), NULL); - - mainwin_balance = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 177, 57, 38, - 13, 15, 422, 0, 422, 14, 11, 15, 9, 0, 24, - mainwin_balance_frame_cb, SKIN_BALANCE); - g_signal_connect(mainwin_balance, "motion", G_CALLBACK(mainwin_balance_motion_cb), NULL); - g_signal_connect(mainwin_balance, "release", G_CALLBACK(mainwin_balance_release_cb), NULL); - - mainwin_monostereo = ui_skinned_monostereo_new(SKINNED_WINDOW(mainwin)->fixed, 212, 41, SKIN_MONOSTEREO); - - mainwin_playstatus = ui_skinned_playstatus_new(SKINNED_WINDOW(mainwin)->fixed, 24, 28); - - mainwin_minus_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 36, 26, SKIN_NUMBERS); - g_signal_connect(mainwin_minus_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); - - mainwin_10min_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 48, 26, SKIN_NUMBERS); - g_signal_connect(mainwin_10min_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); - - mainwin_min_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 60, 26, SKIN_NUMBERS); - g_signal_connect(mainwin_min_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); - - mainwin_10sec_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 78, 26, SKIN_NUMBERS); - g_signal_connect(mainwin_10sec_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); - - mainwin_sec_num = ui_skinned_number_new(SKINNED_WINDOW(mainwin)->fixed, 90, 26, SKIN_NUMBERS); - g_signal_connect(mainwin_sec_num, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); - - mainwin_about = ui_skinned_button_new(); - ui_skinned_small_button_setup(mainwin_about, SKINNED_WINDOW(mainwin)->fixed, 247, 83, 20, 25); - g_signal_connect(mainwin_about, "clicked", show_about_window, NULL); - - mainwin_vis = ui_vis_new(SKINNED_WINDOW(mainwin)->fixed, 24, 43, 76); - g_signal_connect(mainwin_vis, "button-press-event", G_CALLBACK(mainwin_vis_cb), NULL); - mainwin_svis = ui_svis_new(SKINNED_WINDOW(mainwin)->fixed, 79, 5); - g_signal_connect(mainwin_svis, "button-press-event", G_CALLBACK(mainwin_vis_cb), NULL); - - mainwin_position = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 16, 72, 248, - 10, 248, 0, 278, 0, 29, 10, 10, 0, 0, 219, - NULL, SKIN_POSBAR); - g_signal_connect(mainwin_position, "motion", G_CALLBACK(mainwin_position_motion_cb), NULL); - g_signal_connect(mainwin_position, "release", G_CALLBACK(mainwin_position_release_cb), NULL); - - mainwin_sposition = ui_skinned_horizontal_slider_new(SKINNED_WINDOW(mainwin)->fixed, 226, 4, 17, - 7, 17, 36, 17, 36, 3, 7, 36, 0, 1, 13, - mainwin_spos_frame_cb, SKIN_TITLEBAR); - g_signal_connect(mainwin_sposition, "motion", G_CALLBACK(mainwin_spos_motion_cb), NULL); - g_signal_connect(mainwin_sposition, "release", G_CALLBACK(mainwin_spos_release_cb), NULL); - - mainwin_stime_min = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 130, 4, 15, FALSE, SKIN_TEXT); - g_signal_connect(mainwin_stime_min, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); - - mainwin_stime_sec = ui_skinned_textbox_new(SKINNED_WINDOW(mainwin)->fixed, 147, 4, 10, FALSE, SKIN_TEXT); - g_signal_connect(mainwin_stime_sec, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); - - - hook_associate("playback audio error", (void *) mainwin_stop_pushed, NULL); - hook_associate("playback audio error", (void *) run_no_output_device_dialog, NULL); - - hook_associate("playback seek", (HookFunction) mainwin_update_song_info, NULL); -} - -static void -mainwin_create_window(void) -{ - gint width, height; - - mainwin = ui_skinned_window_new("player"); - gtk_window_set_title(GTK_WINDOW(mainwin), _("Audacious")); - gtk_window_set_role(GTK_WINDOW(mainwin), "player"); - gtk_window_set_resizable(GTK_WINDOW(mainwin), FALSE); - - width = cfg.player_shaded ? MAINWIN_SHADED_WIDTH : aud_active_skin->properties.mainwin_width; - height = cfg.player_shaded ? MAINWIN_SHADED_HEIGHT : aud_active_skin->properties.mainwin_height; - - if (cfg.scaled) { - width *= cfg.scale_factor; - height *= cfg.scale_factor; - } - - gtk_widget_set_size_request(mainwin, width, height); - - if (cfg.player_x != -1 && cfg.save_window_position) - gtk_window_move(GTK_WINDOW(mainwin), cfg.player_x, cfg.player_y); - - g_signal_connect(mainwin, "destroy", G_CALLBACK(mainwin_destroy), NULL); - g_signal_connect(mainwin, "button_press_event", - G_CALLBACK(mainwin_mouse_button_press), NULL); - g_signal_connect(mainwin, "scroll_event", - G_CALLBACK(mainwin_scrolled), NULL); - g_signal_connect(mainwin, "button_release_event", - G_CALLBACK(mainwin_mouse_button_release), NULL); - - aud_drag_dest_set(mainwin); - - g_signal_connect(mainwin, "key_press_event", - G_CALLBACK(mainwin_keypress), NULL); - - ui_main_evlistener_init(); -} - -void -mainwin_create(void) -{ - mainwin_create_window(); - - gtk_window_add_accel_group( GTK_WINDOW(mainwin) , ui_manager_get_accel_group() ); - - mainwin_create_widgets(); -} - -gboolean -mainwin_update_song_info(void) -{ - if (!playback_get_playing()) - return FALSE; - - gint time = playback_get_time(); - gint length = playback_get_length(); - gint t; - gchar stime_prefix; - - if (ab_position_a != -1 && ab_position_b != -1 && time > ab_position_b) - playback_seek(ab_position_a/1000); - - if (length == -1 && cfg.timer_mode == TIMER_REMAINING) - cfg.timer_mode = TIMER_ELAPSED; - - playlistwin_set_time(time, length, cfg.timer_mode); - - if (cfg.timer_mode == TIMER_REMAINING) { - if (length != -1) { - ui_skinned_number_set_number(mainwin_minus_num, 11); - t = length - time; - stime_prefix = '-'; - } - else { - ui_skinned_number_set_number(mainwin_minus_num, 10); - t = time; - stime_prefix = ' '; - } - } - else { - ui_skinned_number_set_number(mainwin_minus_num, 10); - t = time; - stime_prefix = ' '; - } - t /= 1000; - - /* Show the time in the format HH:MM when we have more than 100 - * minutes. */ - if (t >= 100 * 60) - t /= 60; - ui_skinned_number_set_number(mainwin_10min_num, t / 600); - ui_skinned_number_set_number(mainwin_min_num, (t / 60) % 10); - ui_skinned_number_set_number(mainwin_10sec_num, (t / 10) % 6); - ui_skinned_number_set_number(mainwin_sec_num, t % 10); - - if (!UI_SKINNED_HORIZONTAL_SLIDER(mainwin_sposition)->pressed) { - gchar *time_str; - - time_str = g_strdup_printf("%c%2.2d", stime_prefix, t / 60); - ui_skinned_textbox_set_text(mainwin_stime_min, time_str); - g_free(time_str); - - time_str = g_strdup_printf("%2.2d", t % 60); - ui_skinned_textbox_set_text(mainwin_stime_sec, time_str); - g_free(time_str); - } - - time /= 1000; - length /= 1000; - if (length > 0) { - if (time > length) { - ui_skinned_horizontal_slider_set_position(mainwin_position, 219); - ui_skinned_horizontal_slider_set_position(mainwin_sposition, 13); - } - /* update the slider position ONLY if there is not a seek in progress */ - else if (seek_state == MAINWIN_SEEK_NIL) { - ui_skinned_horizontal_slider_set_position(mainwin_position, (time * 219) / length); - ui_skinned_horizontal_slider_set_position(mainwin_sposition, - ((time * 12) / length) + 1); - } - } - else { - ui_skinned_horizontal_slider_set_position(mainwin_position, 0); - ui_skinned_horizontal_slider_set_position(mainwin_sposition, 1); - } - - return TRUE; -} - -static gboolean -mainwin_idle_func(gpointer data) -{ - GDK_THREADS_ENTER(); - - /* tristate buttons seek */ - if ( seek_state != MAINWIN_SEEK_NIL ) - { - GTimeVal now_time; - GTimeVal delta_time; - gulong now_dur; - g_get_current_time(&now_time); - - delta_time.tv_usec = now_time.tv_usec - cb_time.tv_usec; - delta_time.tv_sec = now_time.tv_sec - cb_time.tv_sec; - - now_dur = labs((delta_time.tv_sec * 1000) + (glong) (delta_time.tv_usec / 1000)); - - if ( now_dur > TRISTATE_THRESHOLD ) - { - gint np; - if (seek_state == MAINWIN_SEEK_REV) - np = seek_initial_pos - labs((gulong)(now_dur/100)); /* seek back */ - else - np = seek_initial_pos + labs((gulong)(now_dur/100)); /* seek forward */ - - /* boundaries check */ - if (np < 0 ) - np = 0; - else if ( np > 219 ) - np = 219; - - ui_skinned_horizontal_slider_set_position( mainwin_position , np ); - mainwin_position_motion_cb( mainwin_position, np ); - } - } - - GDK_THREADS_LEAVE(); - return TRUE; -} - - -/* toggleactionentries actions */ - -void -action_anamode_peaks( GtkToggleAction * action ) -{ - cfg.analyzer_peaks = gtk_toggle_action_get_active( action ); -} - -void -action_autoscroll_songname( GtkToggleAction * action ) -{ - mainwin_set_title_scroll(gtk_toggle_action_get_active(action)); - playlistwin_set_sinfo_scroll(cfg.autoscroll); /* propagate scroll setting to playlistwin_sinfo */ -} - -void -action_playback_noplaylistadvance( GtkToggleAction * action ) -{ - cfg.no_playlist_advance = gtk_toggle_action_get_active( action ); -} - -void -action_playback_repeat( GtkToggleAction * action ) -{ - cfg.repeat = gtk_toggle_action_get_active( action ); - UI_SKINNED_BUTTON(mainwin_repeat)->inside = cfg.repeat; - gtk_widget_queue_draw(mainwin_repeat); -} - -void -action_playback_shuffle( GtkToggleAction * action ) -{ - cfg.shuffle = gtk_toggle_action_get_active( action ); - playlist_set_shuffle(cfg.shuffle); - UI_SKINNED_BUTTON(mainwin_shuffle)->inside = cfg.shuffle; - gtk_widget_queue_draw(mainwin_shuffle); -} - -void -action_stop_after_current_song( GtkToggleAction * action ) -{ - cfg.stopaftersong = gtk_toggle_action_get_active( action ); -} - -void -action_view_always_on_top( GtkToggleAction * action ) -{ - UI_SKINNED_MENUROW(mainwin_menurow)->always_selected = gtk_toggle_action_get_active( action ); - cfg.always_on_top = UI_SKINNED_MENUROW(mainwin_menurow)->always_selected; - gtk_widget_queue_draw(mainwin_menurow); - hint_set_always(cfg.always_on_top); -} - -void -action_view_scaled( GtkToggleAction * action ) -{ - UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected = gtk_toggle_action_get_active( action ); - gtk_widget_queue_draw(mainwin_menurow); - set_scaled(UI_SKINNED_MENUROW(mainwin_menurow)->scale_selected); - gdk_flush(); -} - -void -action_view_easymove( GtkToggleAction * action ) -{ - cfg.easy_move = gtk_toggle_action_get_active( action ); -} - -void -action_view_on_all_workspaces( GtkToggleAction * action ) -{ - cfg.sticky = gtk_toggle_action_get_active( action ); - hint_set_sticky(cfg.sticky); -} - -void -action_roll_up_equalizer( GtkToggleAction * action ) -{ - equalizerwin_set_shade_menu_cb(gtk_toggle_action_get_active(action)); -} - -void -action_roll_up_player( GtkToggleAction * action ) -{ - mainwin_set_shade_menu_cb(gtk_toggle_action_get_active(action)); -} - -void -action_roll_up_playlist_editor( GtkToggleAction * action ) -{ - playlistwin_set_shade(gtk_toggle_action_get_active(action)); -} - -void -action_show_equalizer( GtkToggleAction * action ) -{ - if (gtk_toggle_action_get_active(action)) - equalizerwin_real_show(); - else - equalizerwin_real_hide(); -} - -void -action_show_playlist_editor( GtkToggleAction * action ) -{ - if (gtk_toggle_action_get_active(action)) - playlistwin_show(); - else - playlistwin_hide(); -} - -void -action_show_player( GtkToggleAction * action ) -{ - mainwin_show(gtk_toggle_action_get_active(action)); -} - - -/* radioactionentries actions (one callback for each radio group) */ - -void -action_anafoff( GtkAction *action, GtkRadioAction *current ) -{ - mainwin_vis_set_afalloff(gtk_radio_action_get_current_value(current)); -} - -void -action_anamode( GtkAction *action, GtkRadioAction *current ) -{ - mainwin_vis_set_analyzer_mode(gtk_radio_action_get_current_value(current)); -} - -void -action_anatype( GtkAction *action, GtkRadioAction *current ) -{ - mainwin_vis_set_analyzer_type(gtk_radio_action_get_current_value(current)); -} - -void -action_peafoff( GtkAction *action, GtkRadioAction *current ) -{ - mainwin_vis_set_pfalloff(gtk_radio_action_get_current_value(current)); -} - -void -action_refrate( GtkAction *action, GtkRadioAction *current ) -{ - mainwin_vis_set_refresh(gtk_radio_action_get_current_value(current)); -} - -void -action_scomode( GtkAction *action, GtkRadioAction *current ) -{ - cfg.scope_mode = gtk_radio_action_get_current_value(current); -} - -void -action_vismode( GtkAction *action, GtkRadioAction *current ) -{ - mainwin_vis_set_type_menu_cb(gtk_radio_action_get_current_value(current)); -} - -void -action_vprmode( GtkAction *action, GtkRadioAction *current ) -{ - cfg.voiceprint_mode = gtk_radio_action_get_current_value(current); -} - -void -action_wshmode( GtkAction *action, GtkRadioAction *current ) -{ - cfg.vu_mode = gtk_radio_action_get_current_value(current); -} - -void -action_viewtime( GtkAction *action, GtkRadioAction *current ) -{ - set_timer_mode_menu_cb(gtk_radio_action_get_current_value(current)); -} - - -/* actionentries actions */ - -void -action_about_audacious( void ) -{ - show_about_window(); -} - -void -action_play_file( void ) -{ - run_filebrowser(TRUE); -} - -void -action_play_location( void ) -{ - mainwin_show_add_url_window(); -} - -void -action_ab_set( void ) -{ - Playlist *playlist = playlist_get_active(); - if (playlist_get_current_length(playlist) != -1) - { - if (ab_position_a == -1) - { - ab_position_a = playback_get_time(); - ab_position_b = -1; - mainwin_lock_info_text("LOOP-POINT A POSITION SET."); - } - else if (ab_position_b == -1) - { - int time = playback_get_time(); - if (time > ab_position_a) - ab_position_b = time; - mainwin_release_info_text(); - } - else - { - ab_position_a = playback_get_time(); - ab_position_b = -1; - mainwin_lock_info_text("LOOP-POINT A POSITION RESET."); - } - } -} - -void -action_ab_clear( void ) -{ - Playlist *playlist = playlist_get_active(); - if (playlist_get_current_length(playlist) != -1) - { - ab_position_a = ab_position_b = -1; - mainwin_release_info_text(); - } -} - -void -action_current_track_info( void ) -{ - ui_fileinfo_show_current(playlist_get_active()); -} - -void -action_jump_to_file( void ) -{ - ui_jump_to_track(); -} - -void -action_jump_to_playlist_start( void ) -{ - Playlist *playlist = playlist_get_active(); - playlist_set_position(playlist, 0); -} - -void -action_jump_to_time( void ) -{ - mainwin_jump_to_time(); -} - -void -action_playback_next( void ) -{ - Playlist *playlist = playlist_get_active(); - playlist_next(playlist); -} - -void -action_playback_previous( void ) -{ - Playlist *playlist = playlist_get_active(); - playlist_prev(playlist); -} - -void -action_playback_play( void ) -{ - mainwin_play_pushed(); -} - -void -action_playback_pause( void ) -{ - playback_pause(); -} - -void -action_playback_stop( void ) -{ - mainwin_stop_pushed(); -} - -void -action_preferences( void ) -{ - show_prefs_window(); -} - -void -action_quit( void ) -{ - mainwin_quit_cb(); -} - -void -util_menu_main_show( gint x , gint y , guint button , guint time ) -{ - /* convenience function that shows the main popup menu wherever requested */ - ui_manager_popup_menu_show( GTK_MENU(mainwin_general_menu), - x , y , button , time ); - return; -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_main.h --- a/src/audacious/ui_main.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,193 +0,0 @@ -/* 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. - */ - -#ifndef AUDACIOUS_UI_MAIN_H -#define AUDACIOUS_UI_MAIN_H - -#include - -#include "ui_vis.h" -#include "ui_svis.h" - -/* yes, main window size is fixed */ -#define MAINWIN_WIDTH (gint)275 -#define MAINWIN_HEIGHT (gint)116 -#define MAINWIN_TITLEBAR_HEIGHT (gint)14 -#define MAINWIN_SHADED_WIDTH MAINWIN_WIDTH -#define MAINWIN_SHADED_HEIGHT MAINWIN_TITLEBAR_HEIGHT -#define MAINWIN_SCALE_FACTOR (cfg.scaled ? cfg.scale_factor : 1) - -#define MAINWIN_UPDATE_INTERVAL 100 - -#define MAINWIN_DEFAULT_POS_X 20 -#define MAINWIN_DEFAULT_POS_Y 20 - -#define MAINWIN_DEFAULT_FONT "Sans Bold 9" - - -typedef enum { - TIMER_ELAPSED, - TIMER_REMAINING -} TimerMode; - -enum { - MAINWIN_GENERAL_ABOUT, - - MAINWIN_GENERAL_PLAYFILE, - MAINWIN_GENERAL_PLAYLOCATION, - - MAINWIN_GENERAL_FILEINFO, - MAINWIN_GENERAL_PREFS, - - MAINWIN_GENERAL_SHOWMWIN, - MAINWIN_GENERAL_SHOWPLWIN, - - MAINWIN_GENERAL_FOCUSMWIN, - MAINWIN_GENERAL_FOCUSPLWIN, - - MAINWIN_GENERAL_SHOWEQWIN, - MAINWIN_GENERAL_EXIT, - - MAINWIN_GENERAL_PREV, - MAINWIN_GENERAL_PLAY, - MAINWIN_GENERAL_PAUSE, - MAINWIN_GENERAL_STOP, - MAINWIN_GENERAL_NEXT, - MAINWIN_GENERAL_STOPFADE, - MAINWIN_GENERAL_BACK5SEC, - MAINWIN_GENERAL_FWD5SEC, - MAINWIN_GENERAL_START, - MAINWIN_GENERAL_BACK10, - MAINWIN_GENERAL_FWD10, - MAINWIN_GENERAL_JTT, - MAINWIN_GENERAL_JTF, - MAINWIN_GENERAL_QUEUE, - MAINWIN_GENERAL_CQUEUE, - MAINWIN_GENERAL_VOLUP, - MAINWIN_GENERAL_VOLDOWN, - MAINWIN_GENERAL_SETAB, - MAINWIN_GENERAL_CLEARAB, - - MAINWIN_GENERAL_NEXT_PL, - MAINWIN_GENERAL_PREV_PL, - MAINWIN_GENERAL_NEW_PL -}; - -extern GtkWidget *mainwin; -extern GtkWidget *err; - -extern gboolean mainwin_moving; -extern gboolean mainwin_focus; - -extern GtkWidget *mainwin_jtf; -extern GtkWidget *mainwin_eq, *mainwin_pl; -extern GtkWidget *mainwin_info; - -extern GtkWidget *mainwin_stime_min, *mainwin_stime_sec; - -extern GtkWidget *mainwin_vis; -extern GtkWidget *mainwin_svis; - -extern GtkWidget *mainwin_playstatus; - -extern GtkWidget *mainwin_minus_num, *mainwin_10min_num, *mainwin_min_num; -extern GtkWidget *mainwin_10sec_num, *mainwin_sec_num; - -extern GtkWidget *mainwin_position, *mainwin_sposition; - -void mainwin_create(void); - -void mainwin_lock_info_text(const gchar * text); -void mainwin_release_info_text(void); -void mainwin_play_pushed(void); -void mainwin_stop_pushed(void); -void mainwin_eject_pushed(void); - -void mainwin_rev_pushed(void); -void mainwin_rev_release(void); -void mainwin_fwd_pushed(void); -void mainwin_fwd_release(void); - -void mainwin_adjust_volume_motion(gint v); -void mainwin_adjust_volume_release(void); -void mainwin_adjust_balance_motion(gint b); -void mainwin_adjust_balance_release(void); -void mainwin_set_volume_slider(gint percent); -void mainwin_set_balance_slider(gint percent); - -void mainwin_vis_set_type(VisType mode); - -void mainwin_refresh_hints(void); -void mainwin_set_info_text(void); -void mainwin_set_song_info(gint rate, gint freq, gint nch); -void mainwin_clear_song_info(void); -void mainwin_set_stopaftersong(gboolean stop); -void mainwin_set_noplaylistadvance(gboolean no_advance); - -void mainwin_set_always_on_top(gboolean always); -void mainwin_set_volume_diff(gint diff); -void mainwin_set_balance_diff(gint diff); - -void mainwin_show(gboolean); -void mainwin_real_show(void); -void mainwin_real_hide(void); -void mainwin_move(gint x, gint y); -void mainwin_shuffle_pushed(gboolean toggled); -void mainwin_repeat_pushed(gboolean toggled); -void mainwin_disable_seekbar(void); -void mainwin_set_title(const gchar * text); -void mainwin_show_add_url_window(void); -void mainwin_minimize_cb(void); -void mainwin_general_menu_callback(gpointer cb_data, - guint action, - GtkWidget * widget); - -gboolean mainwin_update_song_info(void); -void mainwin_drag_data_received(GtkWidget * widget, - GdkDragContext * context, - gint x, - gint y, - GtkSelectionData * selection_data, - guint info, - guint time, - gpointer user_data); - -void mainwin_setup_menus(void); -gboolean change_timer_mode_cb(GtkWidget *widget, GdkEventButton *event); - -void mainwin_jump_to_file(void); -void mainwin_jump_to_time(void); - -void mainwin_ewmh_activate(void); - -void mainwin_show_visibility_warning(void); - -/* FIXME: placed here for now */ -void playback_get_sample_params(gint * bitrate, - gint * frequency, - gint * numchannels); - -void ui_main_check_theme_engine(void); - -void util_menu_main_show( gint x , gint y , guint button , guint time ); - -#endif /* AUDACIOUS_UI_MAIN_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_main_evlisteners.c --- a/src/audacious/ui_main_evlisteners.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,474 +0,0 @@ -/* - * Audacious - * Copyright (c) 2006-2007 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 "ui_playlist_evlisteners.h" - -#include -#include - -#include "hook.h" -#include "playback.h" -#include "playlist.h" -#include "playlist_evmessages.h" -#include "visualization.h" - -#include "ui_credits.h" -#include "ui_equalizer.h" -#include "ui_fileopener.h" -#include "ui_jumptotrack.h" -#include "ui_main.h" -#include "ui_playlist.h" -#include "ui_preferences.h" -#include "ui_skinned_playstatus.h" -#include "ui_skinned_textbox.h" -#include "ui_skinned_window.h" - -static gint song_info_timeout_source = 0; -static gint update_vis_timeout_source = 0; - -/* XXX: there has to be a better way than polling here! */ -/* also: where should this function go? should it stay here? --mf0102 */ -static gboolean -update_vis_func(gpointer unused) -{ - if (!playback_get_playing()) - return FALSE; - - input_update_vis(playback_get_time()); - - return TRUE; -} - -static void -ui_main_evlistener_title_change(gpointer hook_data, gpointer user_data) -{ - gchar *text = (gchar *) hook_data; - - ui_skinned_textbox_set_text(mainwin_info, text); - playlistwin_update_list(playlist_get_active()); -} - -static void -ui_main_evlistener_hide_seekbar(gpointer hook_data, gpointer user_data) -{ - mainwin_disable_seekbar(); -} - -static void -ui_main_evlistener_volume_change(gpointer hook_data, gpointer user_data) -{ - gint *h_vol = (gint *) hook_data; - gint vl, vr, b, v; - - vl = CLAMP(h_vol[0], 0, 100); - vr = CLAMP(h_vol[1], 0, 100); - v = MAX(vl, vr); - if (vl > vr) - b = (gint) rint(((gdouble) vr / vl) * 100) - 100; - else if (vl < vr) - b = 100 - (gint) rint(((gdouble) vl / vr) * 100); - else - b = 0; - - mainwin_set_volume_slider(v); - equalizerwin_set_volume_slider(v); - mainwin_set_balance_slider(b); - equalizerwin_set_balance_slider(b); -} - -static void -ui_main_evlistener_playback_initiate(gpointer hook_data, gpointer user_data) -{ - playback_initiate(); -} - -static void -ui_main_evlistener_playback_begin(gpointer hook_data, gpointer user_data) -{ - PlaylistEntry *entry = (PlaylistEntry*)hook_data; - g_return_if_fail(entry != NULL); - - equalizerwin_load_auto_preset(entry->filename); - hook_call("equalizer changed", NULL); - - ui_vis_clear_data(mainwin_vis); - ui_svis_clear_data(mainwin_svis); - mainwin_disable_seekbar(); - mainwin_update_song_info(); - - if (cfg.player_shaded) { - gtk_widget_show(mainwin_stime_min); - gtk_widget_show(mainwin_stime_sec); - gtk_widget_show(mainwin_sposition); - } else { - gtk_widget_show(mainwin_minus_num); - gtk_widget_show(mainwin_10min_num); - gtk_widget_show(mainwin_min_num); - gtk_widget_show(mainwin_10sec_num); - gtk_widget_show(mainwin_sec_num); - gtk_widget_show(mainwin_position); - } - - song_info_timeout_source = - g_timeout_add_seconds(1, (GSourceFunc) mainwin_update_song_info, NULL); - - update_vis_timeout_source = - g_timeout_add(10, (GSourceFunc) update_vis_func, NULL); - - vis_playback_start(); - - ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PLAY); -} - -static void -ui_main_evlistener_playback_stop(gpointer hook_data, gpointer user_data) -{ - if (song_info_timeout_source) - g_source_remove(song_info_timeout_source); - - vis_playback_stop(); - free_vis_data(); - - ui_skinned_playstatus_set_buffering(mainwin_playstatus, FALSE); -} - -static void -ui_main_evlistener_playback_pause(gpointer hook_data, gpointer user_data) -{ - ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PAUSE); -} - -static void -ui_main_evlistener_playback_unpause(gpointer hook_data, gpointer user_data) -{ - ui_skinned_playstatus_set_status(mainwin_playstatus, STATUS_PLAY); -} - -static void -ui_main_evlistener_playback_seek(gpointer hook_data, gpointer user_data) -{ - free_vis_data(); -} - -static void -ui_main_evlistener_playback_play_file(gpointer hook_data, gpointer user_data) -{ - if (cfg.random_skin_on_play) - skin_set_random_skin(); -} - -static void -ui_main_evlistener_playlist_end_reached(gpointer hook_data, gpointer user_data) -{ - mainwin_clear_song_info(); - - if (cfg.stopaftersong) - mainwin_set_stopaftersong(FALSE); -} - -static void -ui_main_evlistener_playlist_info_change(gpointer hook_data, gpointer user_data) -{ - PlaylistEventInfoChange *msg = (PlaylistEventInfoChange *) hook_data; - - mainwin_set_song_info(msg->bitrate, msg->samplerate, msg->channels); -} - -static void -ui_main_evlistener_mainwin_set_always_on_top(gpointer hook_data, gpointer user_data) -{ - gboolean *ontop = (gboolean*)hook_data; - mainwin_set_always_on_top(*ontop); -} - -static void -ui_main_evlistener_mainwin_show(gpointer hook_data, gpointer user_data) -{ - gboolean *show = (gboolean*)hook_data; - mainwin_show(*show); -} - -static void -ui_main_evlistener_equalizerwin_show(gpointer hook_data, gpointer user_data) -{ - gboolean *show = (gboolean*)hook_data; - equalizerwin_show(*show); -} - -static void -ui_main_evlistener_prefswin_show(gpointer hook_data, gpointer user_data) -{ - gboolean *show = (gboolean*)hook_data; - if (*show == TRUE) - show_prefs_window(); - else - hide_prefs_window(); -} - -static void -ui_main_evlistener_aboutwin_show(gpointer hook_data, gpointer user_data) -{ - gboolean *show = (gboolean*)hook_data; - if (*show == TRUE) - show_about_window(); - else - hide_about_window(); -} - - -static void -ui_main_evlistener_ui_jump_to_track_show(gpointer hook_data, gpointer user_data) -{ - gboolean *show = (gboolean*)hook_data; - if (*show == TRUE) - ui_jump_to_track(); - else - ui_jump_to_track_hide(); -} - -static void -ui_main_evlistener_filebrowser_show(gpointer hook_data, gpointer user_data) -{ - gboolean *play_button = (gboolean*)hook_data; - run_filebrowser(*play_button); -} - -static void -ui_main_evlistener_filebrowser_hide(gpointer hook_data, gpointer user_data) -{ - hide_filebrowser(); -} - -static void -ui_main_evlistener_visualization_timeout(gpointer hook_data, gpointer user_data) -{ - if (hook_data == NULL) { - if (cfg.player_shaded && cfg.player_visible) - ui_svis_timeout_func(mainwin_svis, NULL); - else - ui_vis_timeout_func(mainwin_vis, NULL); - return; - } - - VisNode *vis = (VisNode*) hook_data; - - guint8 intern_vis_data[512]; - gint16 mono_freq[2][256]; - gboolean mono_freq_calced = FALSE; - gint16 mono_pcm[2][512], stereo_pcm[2][512]; - gboolean mono_pcm_calced = FALSE, stereo_pcm_calced = FALSE; - gint i; - - if (cfg.vis_type == VIS_OFF) - return; - - if (cfg.vis_type == VIS_ANALYZER) { - /* Spectrum analyzer */ - /* 76 values */ - const gint long_xscale[] = - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, - 52, 53, 54, 55, 56, 57, 58, 61, 66, 71, 76, 81, 87, 93, - 100, 107, - 114, 122, 131, 140, 150, 161, 172, 184, 255 - }; - /* 20 values */ - const int short_xscale[] = - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 15, 20, 27, - 36, 47, 62, 82, 107, 141, 184, 255 - }; - const double y_scale = 3.60673760222; /* 20.0 / log(256) */ - const int *xscale; - gint j, y, max; - - if (!mono_freq_calced) - calc_mono_freq(mono_freq, vis->data, vis->nch); - - memset(intern_vis_data, 0, 75); - - if (cfg.analyzer_type == ANALYZER_BARS) { - if (cfg.player_shaded) { - max = 13; - } - else { - max = 19; - } - xscale = short_xscale; - } - else { - if (cfg.player_shaded) { - max = 37; - } - else { - max = 75; - } - xscale = long_xscale; - } - - for (i = 0; i < max; i++) { - for (j = xscale[i], y = 0; j < xscale[i + 1]; j++) { - if (mono_freq[0][j] > y) - y = mono_freq[0][j]; - } - y >>= 7; - if (y != 0) { - intern_vis_data[i] = log(y) * y_scale; - if (intern_vis_data[i] > 15) - intern_vis_data[i] = 15; - } - else - intern_vis_data[i] = 0; - } - - } - else if(cfg.vis_type == VIS_VOICEPRINT){ - if (cfg.player_shaded && cfg.player_visible) { - /* VU */ - gint vu, val; - - if (!stereo_pcm_calced) - calc_stereo_pcm(stereo_pcm, vis->data, vis->nch); - vu = 0; - for (i = 0; i < 512; i++) { - val = abs(stereo_pcm[0][i]); - if (val > vu) - vu = val; - } - intern_vis_data[0] = (vu * 37) >> 15; - if (intern_vis_data[0] > 37) - intern_vis_data[0] = 37; - if (vis->nch == 2) { - vu = 0; - for (i = 0; i < 512; i++) { - val = abs(stereo_pcm[1][i]); - if (val > vu) - vu = val; - } - intern_vis_data[1] = (vu * 37) >> 15; - if (intern_vis_data[1] > 37) - intern_vis_data[1] = 37; - } - else - intern_vis_data[1] = intern_vis_data[0]; - } - else { /*Voiceprint*/ - if (!mono_freq_calced) - calc_mono_freq(mono_freq, vis->data, vis->nch); - memset(intern_vis_data, 0, 256); - - /* For the values [0-16] we use the frequency that's 3/2 as much. - If we assume the 512 values calculated by calc_mono_freq to - cover 0-22kHz linearly we get a range of - [0-16] * 3/2 * 22000/512 = [0-1,031] Hz. - Most stuff above that is harmonics and we want to utilize the - 16 samples we have to the max[tm] - */ - for (i = 0; i < 50 ; i+=3){ - intern_vis_data[i/3] += (mono_freq[0][i/2] >> 5); - - /*Boost frequencies above 257Hz a little*/ - //if(i > 4 * 3) - // intern_vis_data[i/3] += 8; - } - } - } - else { /* (cfg.vis_type == VIS_SCOPE) */ - - /* Oscilloscope */ - gint pos, step; - - if (!mono_pcm_calced) - calc_mono_pcm(mono_pcm, vis->data, vis->nch); - - step = (vis->length << 8) / 74; - for (i = 0, pos = 0; i < 75; i++, pos += step) { - intern_vis_data[i] = ((mono_pcm[0][pos >> 8]) >> 12) + 7; - if (intern_vis_data[i] == 255) - intern_vis_data[i] = 0; - else if (intern_vis_data[i] > 12) - intern_vis_data[i] = 12; - /* Do not see the point of that? (comparison always false) -larne. - if (intern_vis_data[i] < 0) - intern_vis_data[i] = 0; */ - } - } - - if (cfg.player_shaded && cfg.player_visible) - ui_svis_timeout_func(mainwin_svis, intern_vis_data); - else - ui_vis_timeout_func(mainwin_vis, intern_vis_data); -} - -static void -ui_main_evlistener_config_save(gpointer hook_data, gpointer user_data) -{ - ConfigDb *db = (ConfigDb *) hook_data; - - if (SKINNED_WINDOW(mainwin)->x != -1 && - SKINNED_WINDOW(mainwin)->y != -1 ) - { - cfg_db_set_int(db, NULL, "player_x", SKINNED_WINDOW(mainwin)->x); - cfg_db_set_int(db, NULL, "player_y", SKINNED_WINDOW(mainwin)->y); - } - - cfg_db_set_bool(db, NULL, "mainwin_use_bitmapfont", - cfg.mainwin_use_bitmapfont); -} - -static void -ui_main_evlistener_equalizer_changed(gpointer hook_data, gpointer user_data) -{ - output_set_eq(cfg.equalizer_active, cfg.equalizer_preamp, - cfg.equalizer_bands); -} - -void -ui_main_evlistener_init(void) -{ - hook_associate("title change", ui_main_evlistener_title_change, NULL); - hook_associate("hide seekbar", ui_main_evlistener_hide_seekbar, NULL); - hook_associate("volume set", ui_main_evlistener_volume_change, NULL); - hook_associate("playback initiate", ui_main_evlistener_playback_initiate, NULL); - hook_associate("playback begin", ui_main_evlistener_playback_begin, NULL); - hook_associate("playback stop", ui_main_evlistener_playback_stop, NULL); - hook_associate("playback pause", ui_main_evlistener_playback_pause, NULL); - hook_associate("playback unpause", ui_main_evlistener_playback_unpause, NULL); - hook_associate("playback seek", ui_main_evlistener_playback_seek, NULL); - hook_associate("playback play file", ui_main_evlistener_playback_play_file, NULL); - hook_associate("playlist end reached", ui_main_evlistener_playlist_end_reached, NULL); - hook_associate("playlist info change", ui_main_evlistener_playlist_info_change, NULL); - hook_associate("mainwin set always on top", ui_main_evlistener_mainwin_set_always_on_top, NULL); - hook_associate("mainwin show", ui_main_evlistener_mainwin_show, NULL); - hook_associate("equalizerwin show", ui_main_evlistener_equalizerwin_show, NULL); - hook_associate("prefswin show", ui_main_evlistener_prefswin_show, NULL); - hook_associate("aboutwin show", ui_main_evlistener_aboutwin_show, NULL); - hook_associate("ui jump to track show", ui_main_evlistener_ui_jump_to_track_show, NULL); - hook_associate("filebrowser show", ui_main_evlistener_filebrowser_show, NULL); - hook_associate("filebrowser hide", ui_main_evlistener_filebrowser_hide, NULL); - hook_associate("visualization timeout", ui_main_evlistener_visualization_timeout, NULL); - hook_associate("config save", ui_main_evlistener_config_save, NULL); - - hook_associate("equalizer changed", ui_main_evlistener_equalizer_changed, NULL); -} - diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_main_evlisteners.h --- a/src/audacious/ui_main_evlisteners.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Audacious - * Copyright (c) 2006-2007 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 - -#ifndef AUDACIOUS_UI_MAIN_EVLISTENERS_H -#define AUDACIOUS_UI_MAIN_EVLISTENERS_H - -void ui_main_evlistener_init(void); - -#endif /* AUDACIOUS_UI_MAIN_EVLISTENERS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_manager.c --- a/src/audacious/ui_manager.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,872 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2007 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. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "ui_manager.h" -#include "actions-mainwin.h" -#include "actions-playlist.h" -#include "actions-equalizer.h" - -/* this header contains prototypes for plugin-available menu functions */ -#include "ui_plugin_menu.h" - -/* TODO ui_main.h is only included because ui_manager.c needs the values of - TimerMode enum; move that enum elsewhere so we can get rid of this include */ -#include "ui_main.h" - -#include "icons-stock.h" - -#include "sync-menu.h" - -static GtkUIManager *ui_manager = NULL; -static gboolean menu_created = FALSE; - - -/* toggle action entries */ - -static GtkToggleActionEntry toggleaction_entries_others[] = { - - { "autoscroll songname", NULL , N_("Autoscroll Songname"), NULL, - N_("Autoscroll Songname"), G_CALLBACK(action_autoscroll_songname) , FALSE }, - - { "stop after current song", NULL , N_("Stop after Current Song"), "M", - N_("Stop after Current Song"), G_CALLBACK(action_stop_after_current_song) , FALSE }, - - { "anamode peaks", NULL , N_("Peaks"), NULL, - N_("Peaks"), G_CALLBACK(action_anamode_peaks) , FALSE }, - - { "playback repeat", NULL , N_("Repeat"), "R", - N_("Repeat"), G_CALLBACK(action_playback_repeat) , FALSE }, - - { "playback shuffle", NULL , N_("Shuffle"), "S", - N_("Shuffle"), G_CALLBACK(action_playback_shuffle) , FALSE }, - - { "playback no playlist advance", NULL , N_("No Playlist Advance"), "N", - N_("No Playlist Advance"), G_CALLBACK(action_playback_noplaylistadvance) , FALSE }, - - { "show player", NULL , N_("Show Player"), "M", - N_("Show Player"), G_CALLBACK(action_show_player) , FALSE }, - - { "show playlist editor", NULL , N_("Show Playlist Editor"), "E", - N_("Show Playlist Editor"), G_CALLBACK(action_show_playlist_editor) , FALSE }, - - { "show equalizer", NULL , N_("Show Equalizer"), "G", - N_("Show Equalizer"), G_CALLBACK(action_show_equalizer) , FALSE }, - - { "view always on top", NULL , N_("Always on Top"), "O", - N_("Always on Top"), G_CALLBACK(action_view_always_on_top) , FALSE }, - - { "view put on all workspaces", NULL , N_("Put on All Workspaces"), "S", - N_("Put on All Workspaces"), G_CALLBACK(action_view_on_all_workspaces) , FALSE }, - - { "roll up player", NULL , N_("Roll up Player"), "W", - N_("Roll up Player"), G_CALLBACK(action_roll_up_player) , FALSE }, - - { "roll up playlist editor", NULL , N_("Roll up Playlist Editor"), "W", - N_("Roll up Playlist Editor"), G_CALLBACK(action_roll_up_playlist_editor) , FALSE }, - - { "roll up equalizer", NULL , N_("Roll up Equalizer"), "W", - N_("Roll up Equalizer"), G_CALLBACK(action_roll_up_equalizer) , FALSE }, - - { "view scaled", NULL , N_("Scale"), "D", - N_("DoubleSize"), G_CALLBACK(action_view_scaled) , FALSE }, - - { "view easy move", NULL , N_("Easy Move"), "E", - N_("Easy Move"), G_CALLBACK(action_view_easymove) , FALSE } -}; - - - -/* radio action entries */ - -static GtkRadioActionEntry radioaction_entries_vismode[] = { - { "vismode analyzer", NULL , N_("Analyzer"), NULL, N_("Analyzer"), VIS_ANALYZER }, - { "vismode scope", NULL , N_("Scope"), NULL, N_("Scope"), VIS_SCOPE }, - { "vismode voiceprint", NULL , N_("Voiceprint"), NULL, N_("Voiceprint"), VIS_VOICEPRINT }, - { "vismode off", NULL , N_("Off"), NULL, N_("Off"), VIS_OFF } -}; - -static GtkRadioActionEntry radioaction_entries_anamode[] = { - { "anamode normal", NULL , N_("Normal"), NULL, N_("Normal"), ANALYZER_NORMAL }, - { "anamode fire", NULL , N_("Fire"), NULL, N_("Fire"), ANALYZER_FIRE }, - { "anamode vertical lines", NULL , N_("Vertical Lines"), NULL, N_("Vertical Lines"), ANALYZER_VLINES } -}; - -static GtkRadioActionEntry radioaction_entries_anatype[] = { - { "anatype lines", NULL , N_("Lines"), NULL, N_("Lines"), ANALYZER_LINES }, - { "anatype bars", NULL , N_("Bars"), NULL, N_("Bars"), ANALYZER_BARS } -}; - -static GtkRadioActionEntry radioaction_entries_scomode[] = { - { "scomode dot", NULL , N_("Dot Scope"), NULL, N_("Dot Scope"), SCOPE_DOT }, - { "scomode line", NULL , N_("Line Scope"), NULL, N_("Line Scope"), SCOPE_LINE }, - { "scomode solid", NULL , N_("Solid Scope"), NULL, N_("Solid Scope"), SCOPE_SOLID } -}; - -static GtkRadioActionEntry radioaction_entries_vprmode[] = { - { "vprmode normal", NULL , N_("Normal"), NULL, N_("Normal"), VOICEPRINT_NORMAL }, - { "vprmode fire", NULL , N_("Fire"), NULL, N_("Fire"), VOICEPRINT_FIRE }, - { "vprmode ice", NULL , N_("Ice"), NULL, N_("Ice"), VOICEPRINT_ICE } -}; - -static GtkRadioActionEntry radioaction_entries_wshmode[] = { - { "wshmode normal", NULL , N_("Normal"), NULL, N_("Normal"), VU_NORMAL }, - { "wshmode smooth", NULL , N_("Smooth"), NULL, N_("Smooth"), VU_SMOOTH } -}; - -static GtkRadioActionEntry radioaction_entries_refrate[] = { - { "refrate full", NULL , N_("Full (~50 fps)"), NULL, N_("Full (~50 fps)"), REFRESH_FULL }, - { "refrate half", NULL , N_("Half (~25 fps)"), NULL, N_("Half (~25 fps)"), REFRESH_HALF }, - { "refrate quarter", NULL , N_("Quarter (~13 fps)"), NULL, N_("Quarter (~13 fps)"), REFRESH_QUARTER }, - { "refrate eighth", NULL , N_("Eighth (~6 fps)"), NULL, N_("Eighth (~6 fps)"), REFRESH_EIGTH } -}; - -static GtkRadioActionEntry radioaction_entries_anafoff[] = { - { "anafoff slowest", NULL , N_("Slowest"), NULL, N_("Slowest"), FALLOFF_SLOWEST }, - { "anafoff slow", NULL , N_("Slow"), NULL, N_("Slow"), FALLOFF_SLOW }, - { "anafoff medium", NULL , N_("Medium"), NULL, N_("Medium"), FALLOFF_MEDIUM }, - { "anafoff fast", NULL , N_("Fast"), NULL, N_("Fast"), FALLOFF_FAST }, - { "anafoff fastest", NULL , N_("Fastest"), NULL, N_("Fastest"), FALLOFF_FASTEST } -}; - -static GtkRadioActionEntry radioaction_entries_peafoff[] = { - { "peafoff slowest", NULL , N_("Slowest"), NULL, N_("Slowest"), FALLOFF_SLOWEST }, - { "peafoff slow", NULL , N_("Slow"), NULL, N_("Slow"), FALLOFF_SLOW }, - { "peafoff medium", NULL , N_("Medium"), NULL, N_("Medium"), FALLOFF_MEDIUM }, - { "peafoff fast", NULL , N_("Fast"), NULL, N_("Fast"), FALLOFF_FAST }, - { "peafoff fastest", NULL , N_("Fastest"), NULL, N_("Fastest"), FALLOFF_FASTEST } -}; - -static GtkRadioActionEntry radioaction_entries_viewtime[] = { - { "view time elapsed", NULL , N_("Time Elapsed"), "E", N_("Time Elapsed"), TIMER_ELAPSED }, - { "view time remaining", NULL , N_("Time Remaining"), "R", N_("Time Remaining"), TIMER_REMAINING } -}; - - - -/* normal actions */ - -static GtkActionEntry action_entries_playback[] = { - - { "playback", NULL, N_("Playback") }, - - { "playback play", GTK_STOCK_MEDIA_PLAY , N_("Play"), "X", - N_("Play"), G_CALLBACK(action_playback_play) }, - - { "playback pause", GTK_STOCK_MEDIA_PAUSE , N_("Pause"), "C", - N_("Pause"), G_CALLBACK(action_playback_pause) }, - - { "playback stop", GTK_STOCK_MEDIA_STOP , N_("Stop"), "V", - N_("Stop"), G_CALLBACK(action_playback_stop) }, - - { "playback previous", GTK_STOCK_MEDIA_PREVIOUS , N_("Previous"), "Z", - N_("Previous"), G_CALLBACK(action_playback_previous) }, - - { "playback next", GTK_STOCK_MEDIA_NEXT , N_("Next"), "B", - N_("Next"), G_CALLBACK(action_playback_next) } -}; - - -static GtkActionEntry action_entries_visualization[] = { - { "visualization", NULL, N_("Visualization") }, - { "vismode", NULL, N_("Visualization Mode") }, - { "anamode", NULL, N_("Analyzer Mode") }, - { "scomode", NULL, N_("Scope Mode") }, - { "vprmode", NULL, N_("Voiceprint Mode") }, - { "wshmode", NULL, N_("WindowShade VU Mode") }, - { "refrate", NULL, N_("Refresh Rate") }, - { "anafoff", NULL, N_("Analyzer Falloff") }, - { "peafoff", NULL, N_("Peaks Falloff") } -}; - -static GtkActionEntry action_entries_playlist[] = { - - { "playlist", NULL, N_("Playlist") }, - - { "playlist new", GTK_STOCK_NEW , N_("New Playlist"), "N", - N_("New Playlist"), G_CALLBACK(action_playlist_new) }, - - { "playlist select next", GTK_STOCK_MEDIA_NEXT, N_("Select Next Playlist"), "P", - N_("Select Next Playlist"), G_CALLBACK(action_playlist_next) }, - - { "playlist select previous", GTK_STOCK_MEDIA_PREVIOUS, N_("Select Previous Playlist"), "P", - N_("Select Previous Playlist"), G_CALLBACK(action_playlist_prev) }, - - { "playlist delete", GTK_STOCK_DELETE , N_("Delete Playlist"), "D", - N_("Delete Playlist"), G_CALLBACK(action_playlist_delete) }, - - { "playlist load", GTK_STOCK_OPEN, N_("Load List"), "O", - N_("Loads a playlist file into the selected playlist."), G_CALLBACK(action_playlist_load_list) }, - - { "playlist save", GTK_STOCK_SAVE, N_("Save List"), "S", - N_("Saves the selected playlist."), G_CALLBACK(action_playlist_save_list) }, - - { "playlist save default", GTK_STOCK_SAVE, N_("Save Default List"), "S", - N_("Saves the selected playlist to the default location."), - G_CALLBACK(action_playlist_save_default_list) }, - - { "playlist refresh", GTK_STOCK_REFRESH, N_("Refresh List"), "F5", - N_("Refreshes metadata associated with a playlist entry."), - G_CALLBACK(action_playlist_refresh_list) }, - - { "playlist manager", AUD_STOCK_PLAYLIST , N_("List Manager"), "P", - N_("Opens the playlist manager."), - G_CALLBACK(action_open_list_manager) } -}; - -static GtkActionEntry action_entries_view[] = { - - { "view", NULL, N_("View") } -}; - -static GtkActionEntry action_entries_playlist_add[] = { - { "playlist add url", GTK_STOCK_NETWORK, N_("Add Internet Address..."), "H", - N_("Adds a remote track to the playlist."), - G_CALLBACK(action_playlist_add_url) }, - - { "playlist add files", GTK_STOCK_ADD, N_("Add Files..."), "F", - N_("Adds files to the playlist."), - G_CALLBACK(action_playlist_add_files) }, -}; - -static GtkActionEntry action_entries_playlist_select[] = { - { "playlist search and select", GTK_STOCK_FIND, N_("Search and Select"), "F", - N_("Searches the playlist and selects playlist entries based on specific criteria."), - G_CALLBACK(action_playlist_search_and_select) }, - - { "playlist invert selection", NULL , N_("Invert Selection"), NULL, - N_("Inverts the selected and unselected entries."), - G_CALLBACK(action_playlist_invert_selection) }, - - { "playlist select all", NULL , N_("Select All"), "A", - N_("Selects all of the playlist entries."), - G_CALLBACK(action_playlist_select_all) }, - - { "playlist select none", NULL , N_("Select None"), "A", - N_("Deselects all of the playlist entries."), - G_CALLBACK(action_playlist_select_none) }, -}; - -static GtkActionEntry action_entries_playlist_delete[] = { - { "playlist remove all", GTK_STOCK_CLEAR, N_("Remove All"), NULL, - N_("Removes all entries from the playlist."), - G_CALLBACK(action_playlist_remove_all) }, - - { "playlist clear queue", GTK_STOCK_CLEAR, N_("Clear Queue"), "Q", - N_("Clears the queue associated with this playlist."), - G_CALLBACK(action_playlist_clear_queue) }, - - { "playlist remove unavailable", GTK_STOCK_DIALOG_ERROR , N_("Remove Unavailable Files"), NULL, - N_("Removes unavailable files from the playlist."), - G_CALLBACK(action_playlist_remove_unavailable) }, - - { "playlist remove dups menu", NULL , N_("Remove Duplicates") }, - - { "playlist remove dups by title", NULL , N_("By Title"), NULL, - N_("Removes duplicate entries from the playlist by title."), - G_CALLBACK(action_playlist_remove_dupes_by_title) }, - - { "playlist remove dups by filename", NULL , N_("By Filename"), NULL, - N_("Removes duplicate entries from the playlist by filename."), - G_CALLBACK(action_playlist_remove_dupes_by_filename) }, - - { "playlist remove dups by full path", NULL , N_("By Path + Filename"), NULL, - N_("Removes duplicate entries from the playlist by their full path."), - G_CALLBACK(action_playlist_remove_dupes_by_full_path) }, - - { "playlist remove unselected", GTK_STOCK_REMOVE, N_("Remove Unselected"), NULL, - N_("Remove unselected entries from the playlist."), - G_CALLBACK(action_playlist_remove_unselected) }, - - { "playlist remove selected", GTK_STOCK_REMOVE, N_("Remove Selected"), "Delete", - N_("Remove selected entries from the playlist."), - G_CALLBACK(action_playlist_remove_selected) }, -}; - -static GtkActionEntry action_entries_playlist_sort[] = { - { "playlist randomize list", AUD_STOCK_RANDOMIZEPL , N_("Randomize List"), "R", - N_("Randomizes the playlist."), - G_CALLBACK(action_playlist_randomize_list) }, - - { "playlist reverse list", GTK_STOCK_GO_UP , N_("Reverse List"), NULL, - N_("Reverses the playlist."), - G_CALLBACK(action_playlist_reverse_list) }, - - { "playlist sort menu", GTK_STOCK_GO_DOWN , N_("Sort List") }, - - { "playlist sort by title", NULL , N_("By Title"), NULL, - N_("Sorts the list by title."), - G_CALLBACK(action_playlist_sort_by_title) }, - - { "playlist sort by artist", NULL , N_("By Artist"), NULL, - N_("Sorts the list by artist."), - G_CALLBACK(action_playlist_sort_by_artist) }, - - { "playlist sort by filename", NULL , N_("By Filename"), NULL, - N_("Sorts the list by filename."), - G_CALLBACK(action_playlist_sort_by_filename) }, - - { "playlist sort by full path", NULL , N_("By Path + Filename"), NULL, - N_("Sorts the list by full pathname."), - G_CALLBACK(action_playlist_sort_by_full_path) }, - - { "playlist sort by date", NULL , N_("By Date"), NULL, - N_("Sorts the list by modification time."), - G_CALLBACK(action_playlist_sort_by_date) }, - - { "playlist sort by track number", NULL , N_("By Track Number"), NULL, - N_("Sorts the list by track number."), - G_CALLBACK(action_playlist_sort_by_track_number) }, - - { "playlist sort by playlist entry", NULL , N_("By Playlist Entry"), NULL, - N_("Sorts the list by playlist entry."), - G_CALLBACK(action_playlist_sort_by_playlist_entry) }, - - { "playlist sort selected menu", GTK_STOCK_GO_DOWN , N_("Sort Selected") }, - - { "playlist sort selected by title", NULL , N_("By Title"), NULL, - N_("Sorts the list by title."), - G_CALLBACK(action_playlist_sort_selected_by_title) }, - - { "playlist sort selected by artist", NULL, N_("By Artist"), NULL, - N_("Sorts the list by artist."), - G_CALLBACK(action_playlist_sort_selected_by_artist) }, - - { "playlist sort selected by filename", NULL , N_("By Filename"), NULL, - N_("Sorts the list by filename."), - G_CALLBACK(action_playlist_sort_selected_by_filename) }, - - { "playlist sort selected by full path", NULL , N_("By Path + Filename"), NULL, - N_("Sorts the list by full pathname."), - G_CALLBACK(action_playlist_sort_selected_by_full_path) }, - - { "playlist sort selected by date", NULL , N_("By Date"), NULL, - N_("Sorts the list by modification time."), - G_CALLBACK(action_playlist_sort_selected_by_date) }, - - { "playlist sort selected by track number", NULL , N_("By Track Number"), NULL, - N_("Sorts the list by track number."), - G_CALLBACK(action_playlist_sort_selected_by_track_number) }, - - { "playlist sort selected by playlist entry", NULL, N_("By Playlist Entry"), NULL, - N_("Sorts the list by playlist entry."), - G_CALLBACK(action_playlist_sort_selected_by_playlist_entry) }, -}; - -static GtkActionEntry action_entries_others[] = { - - { "dummy", NULL, "dummy" }, - - /* XXX Carbon support */ - { "file", NULL, N_("File") }, - { "help", NULL, N_("Help") }, - - { "plugins-menu", AUD_STOCK_PLUGIN, N_("Plugin Services") }, - - { "current track info", GTK_STOCK_INFO , N_("View Track Details"), "I", - N_("View track details"), G_CALLBACK(action_current_track_info) }, - - { "playlist track info", GTK_STOCK_INFO , N_("View Track Details"), "I", - N_("View track details"), G_CALLBACK(action_playlist_track_info) }, - - { "about audacious", GTK_STOCK_DIALOG_INFO , N_("About Audacious"), NULL, - N_("About Audacious"), G_CALLBACK(action_about_audacious) }, - - { "play file", GTK_STOCK_OPEN , N_("Play File"), "L", - N_("Load and play a file"), G_CALLBACK(action_play_file) }, - - { "play location", GTK_STOCK_NETWORK , N_("Play Location"), "L", - N_("Play media from the selected location"), G_CALLBACK(action_play_location) }, - - { "plugins", NULL , N_("Plugin services") }, - - { "preferences", GTK_STOCK_PREFERENCES , N_("Preferences"), "P", - N_("Open preferences window"), G_CALLBACK(action_preferences) }, - - { "quit", GTK_STOCK_QUIT , N_("_Quit"), NULL, - N_("Quit Audacious"), G_CALLBACK(action_quit) }, - - { "ab set", NULL , N_("Set A-B"), "A", - N_("Set A-B"), G_CALLBACK(action_ab_set) }, - - { "ab clear", NULL , N_("Clear A-B"), "A", - N_("Clear A-B"), G_CALLBACK(action_ab_clear) }, - - { "jump to playlist start", GTK_STOCK_GOTO_TOP , N_("Jump to Playlist Start"), "Z", - N_("Jump to Playlist Start"), G_CALLBACK(action_jump_to_playlist_start) }, - - { "jump to file", GTK_STOCK_JUMP_TO , N_("Jump to File"), "J", - N_("Jump to File"), G_CALLBACK(action_jump_to_file) }, - - { "jump to time", GTK_STOCK_JUMP_TO , N_("Jump to Time"), "J", - N_("Jump to Time"), G_CALLBACK(action_jump_to_time) }, - - { "queue toggle", AUD_STOCK_QUEUETOGGLE , N_("Queue Toggle"), "Q", - N_("Enables/disables the entry in the playlist's queue."), - G_CALLBACK(action_queue_toggle) }, -}; - - -static GtkActionEntry action_entries_equalizer[] = { - - { "equ preset load menu", NULL, N_("Load") }, - { "equ preset import menu", NULL, N_("Import") }, - { "equ preset save menu", NULL, N_("Save") }, - { "equ preset delete menu", NULL, N_("Delete") }, - - { "equ load preset", NULL, N_("Preset"), NULL, - N_("Load preset"), G_CALLBACK(action_equ_load_preset) }, - - { "equ load auto preset", NULL, N_("Auto-load preset"), NULL, - N_("Load auto-load preset"), G_CALLBACK(action_equ_load_auto_preset) }, - - { "equ load default preset", NULL, N_("Default"), NULL, - N_("Load default preset into equalizer"), G_CALLBACK(action_equ_load_default_preset) }, - - { "equ zero preset", NULL, N_("Zero"), NULL, - N_("Set equalizer preset levels to zero"), G_CALLBACK(action_equ_zero_preset) }, - - { "equ load preset file", NULL, N_("From file"), NULL, - N_("Load preset from file"), G_CALLBACK(action_equ_load_preset_file) }, - - { "equ load preset eqf", NULL, N_("From WinAMP EQF file"), NULL, - N_("Load preset from WinAMP EQF file"), G_CALLBACK(action_equ_load_preset_eqf) }, - - { "equ import winamp presets", NULL, N_("WinAMP Presets"), NULL, - N_("Import WinAMP presets"), G_CALLBACK(action_equ_import_winamp_presets) }, - - { "equ save preset", NULL, N_("Preset"), NULL, - N_("Save preset"), G_CALLBACK(action_equ_save_preset) }, - - { "equ save auto preset", NULL, N_("Auto-load preset"), NULL, - N_("Save auto-load preset"), G_CALLBACK(action_equ_save_auto_preset) }, - - { "equ save default preset", NULL, N_("Default"), NULL, - N_("Save default preset"), G_CALLBACK(action_equ_save_default_preset) }, - - { "equ save preset file", NULL, N_("To file"), NULL, - N_("Save preset to file"), G_CALLBACK(action_equ_save_preset_file) }, - - { "equ save preset eqf", NULL, N_("To WinAMP EQF file"), NULL, - N_("Save preset to WinAMP EQF file"), G_CALLBACK(action_equ_save_preset_eqf) }, - - { "equ delete preset", NULL, N_("Preset"), NULL, - N_("Delete preset"), G_CALLBACK(action_equ_delete_preset) }, - - { "equ delete auto preset", NULL, N_("Auto-load preset"), NULL, - N_("Delete auto-load preset"), G_CALLBACK(action_equ_delete_auto_preset) } -}; - - - -/* ***************************** */ - - -static GtkActionGroup * -ui_manager_new_action_group( const gchar * group_name ) -{ - GtkActionGroup *group = gtk_action_group_new( group_name ); - gtk_action_group_set_translation_domain( group , PACKAGE_NAME ); - return group; -} - -void -ui_manager_init ( void ) -{ - /* toggle actions */ - toggleaction_group_others = ui_manager_new_action_group("toggleaction_others"); - gtk_action_group_add_toggle_actions( - toggleaction_group_others , toggleaction_entries_others , - G_N_ELEMENTS(toggleaction_entries_others) , NULL ); - - /* radio actions */ - radioaction_group_anamode = ui_manager_new_action_group("radioaction_anamode"); - gtk_action_group_add_radio_actions( - radioaction_group_anamode , radioaction_entries_anamode , - G_N_ELEMENTS(radioaction_entries_anamode) , 0 , G_CALLBACK(action_anamode) , NULL ); - - radioaction_group_anatype = ui_manager_new_action_group("radioaction_anatype"); - gtk_action_group_add_radio_actions( - radioaction_group_anatype , radioaction_entries_anatype , - G_N_ELEMENTS(radioaction_entries_anatype) , 0 , G_CALLBACK(action_anatype) , NULL ); - - radioaction_group_scomode = ui_manager_new_action_group("radioaction_scomode"); - gtk_action_group_add_radio_actions( - radioaction_group_scomode , radioaction_entries_scomode , - G_N_ELEMENTS(radioaction_entries_scomode) , 0 , G_CALLBACK(action_scomode) , NULL ); - - radioaction_group_vprmode = ui_manager_new_action_group("radioaction_vprmode"); - gtk_action_group_add_radio_actions( - radioaction_group_vprmode , radioaction_entries_vprmode , - G_N_ELEMENTS(radioaction_entries_vprmode) , 0 , G_CALLBACK(action_vprmode) , NULL ); - - radioaction_group_wshmode = ui_manager_new_action_group("radioaction_wshmode"); - gtk_action_group_add_radio_actions( - radioaction_group_wshmode , radioaction_entries_wshmode , - G_N_ELEMENTS(radioaction_entries_wshmode) , 0 , G_CALLBACK(action_wshmode) , NULL ); - - radioaction_group_refrate = ui_manager_new_action_group("radioaction_refrate"); - gtk_action_group_add_radio_actions( - radioaction_group_refrate , radioaction_entries_refrate , - G_N_ELEMENTS(radioaction_entries_refrate) , 0 , G_CALLBACK(action_refrate) , NULL ); - - radioaction_group_anafoff = ui_manager_new_action_group("radioaction_anafoff"); - gtk_action_group_add_radio_actions( - radioaction_group_anafoff , radioaction_entries_anafoff , - G_N_ELEMENTS(radioaction_entries_anafoff) , 0 , G_CALLBACK(action_anafoff) , NULL ); - - radioaction_group_peafoff = ui_manager_new_action_group("radioaction_peafoff"); - gtk_action_group_add_radio_actions( - radioaction_group_peafoff , radioaction_entries_peafoff , - G_N_ELEMENTS(radioaction_entries_peafoff) , 0 , G_CALLBACK(action_peafoff) , NULL ); - - radioaction_group_vismode = ui_manager_new_action_group("radioaction_vismode"); - gtk_action_group_add_radio_actions( - radioaction_group_vismode , radioaction_entries_vismode , - G_N_ELEMENTS(radioaction_entries_vismode) , 0 , G_CALLBACK(action_vismode) , NULL ); - - radioaction_group_viewtime = ui_manager_new_action_group("radioaction_viewtime"); - gtk_action_group_add_radio_actions( - radioaction_group_viewtime , radioaction_entries_viewtime , - G_N_ELEMENTS(radioaction_entries_viewtime) , 0 , G_CALLBACK(action_viewtime) , NULL ); - - /* normal actions */ - action_group_playback = ui_manager_new_action_group("action_playback"); - gtk_action_group_add_actions( - action_group_playback , action_entries_playback , - G_N_ELEMENTS(action_entries_playback) , NULL ); - - action_group_playlist = ui_manager_new_action_group("action_playlist"); - gtk_action_group_add_actions( - action_group_playlist , action_entries_playlist , - G_N_ELEMENTS(action_entries_playlist) , NULL ); - - action_group_visualization = ui_manager_new_action_group("action_visualization"); - gtk_action_group_add_actions( - action_group_visualization , action_entries_visualization , - G_N_ELEMENTS(action_entries_visualization) , NULL ); - - action_group_view = ui_manager_new_action_group("action_view"); - gtk_action_group_add_actions( - action_group_view , action_entries_view , - G_N_ELEMENTS(action_entries_view) , NULL ); - - action_group_others = ui_manager_new_action_group("action_others"); - gtk_action_group_add_actions( - action_group_others , action_entries_others , - G_N_ELEMENTS(action_entries_others) , NULL ); - - action_group_playlist_add = ui_manager_new_action_group("action_playlist_add"); - gtk_action_group_add_actions( - action_group_playlist_add, action_entries_playlist_add, - G_N_ELEMENTS(action_entries_playlist_add), NULL ); - - action_group_playlist_select = ui_manager_new_action_group("action_playlist_select"); - gtk_action_group_add_actions( - action_group_playlist_select, action_entries_playlist_select, - G_N_ELEMENTS(action_entries_playlist_select), NULL ); - - action_group_playlist_delete = ui_manager_new_action_group("action_playlist_delete"); - gtk_action_group_add_actions( - action_group_playlist_delete, action_entries_playlist_delete, - G_N_ELEMENTS(action_entries_playlist_delete), NULL ); - - action_group_playlist_sort = ui_manager_new_action_group("action_playlist_sort"); - gtk_action_group_add_actions( - action_group_playlist_sort, action_entries_playlist_sort, - G_N_ELEMENTS(action_entries_playlist_sort), NULL ); - - action_group_equalizer = ui_manager_new_action_group("action_equalizer"); - gtk_action_group_add_actions( - action_group_equalizer, action_entries_equalizer, - G_N_ELEMENTS(action_entries_equalizer), NULL); - - /* ui */ - ui_manager = gtk_ui_manager_new(); - gtk_ui_manager_insert_action_group( ui_manager , toggleaction_group_others , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_anamode , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_anatype , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_scomode , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_vprmode , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_wshmode , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_refrate , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_anafoff , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_peafoff , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_vismode , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , radioaction_group_viewtime , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , action_group_playback , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , action_group_visualization , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , action_group_view , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , action_group_others , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_add , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_select , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_delete , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , action_group_playlist_sort , 0 ); - gtk_ui_manager_insert_action_group( ui_manager , action_group_equalizer , 0 ); - - return; -} - -#ifdef GDK_WINDOWING_QUARTZ -static GtkWidget *carbon_menubar; -#endif - -static void -ui_manager_create_menus_init_pmenu( gchar * path ) -{ - GtkWidget *plugins_menu_item = gtk_ui_manager_get_widget( ui_manager , path ); - if ( plugins_menu_item ) - { - /* initially set count of items under plugins_menu_item to 0 */ - g_object_set_data( G_OBJECT(plugins_menu_item) , "ic" , GINT_TO_POINTER(0) ); - /* and since it's 0, hide the plugins_menu_item */ - gtk_widget_hide( plugins_menu_item ); - } - return; -} - - -void -ui_manager_create_menus ( void ) -{ - GError *gerr = NULL; - - /* attach xml menu definitions */ - gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/mainwin.ui" , &gerr ); - - if ( gerr != NULL ) - { - g_critical( "Error creating UI: %s" , gerr->message ); - g_error_free( gerr ); - return; - } - - /* create GtkMenu widgets using path from xml definitions */ - mainwin_songname_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/songname-menu" ); - mainwin_visualization_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/visualization" ); - mainwin_playback_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/playback" ); - mainwin_playlist_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/playlist" ); - mainwin_view_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu/view" ); - mainwin_general_menu = ui_manager_get_popup_menu( ui_manager , "/mainwin-menus/main-menu" ); - - /* initialize plugins-menu for mainwin-menus */ - ui_manager_create_menus_init_pmenu( "/mainwin-menus/main-menu/plugins-menu" ); - -#ifdef GDK_WINDOWING_QUARTZ - gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/carbon-menubar.ui" , &gerr ); - - if ( gerr != NULL ) - { - g_critical( "Error creating UI: %s" , gerr->message ); - g_error_free( gerr ); - return; - } - - carbon_menubar = ui_manager_get_popup_menu( ui_manager , "/carbon-menubar/main-menu" ); - sync_menu_takeover_menu(GTK_MENU_SHELL(carbon_menubar)); -#endif - - gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/playlist.ui" , &gerr ); - - if ( gerr != NULL ) - { - g_critical( "Error creating UI: %s" , gerr->message ); - g_error_free( gerr ); - return; - } - - playlistwin_popup_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/playlist-rightclick-menu"); - - playlistwin_pladd_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/add-menu"); - playlistwin_pldel_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/del-menu"); - playlistwin_plsel_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/select-menu"); - playlistwin_plsort_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/misc-menu"); - playlistwin_pllist_menu = ui_manager_get_popup_menu(ui_manager, "/playlist-menus/playlist-menu"); - - /* initialize plugins-menu for playlist-menus */ - ui_manager_create_menus_init_pmenu( "/playlist-menus/playlist-menu/plugins-menu" ); - ui_manager_create_menus_init_pmenu( "/playlist-menus/add-menu/plugins-menu" ); - ui_manager_create_menus_init_pmenu( "/playlist-menus/del-menu/plugins-menu" ); - ui_manager_create_menus_init_pmenu( "/playlist-menus/select-menu/plugins-menu" ); - ui_manager_create_menus_init_pmenu( "/playlist-menus/misc-menu/plugins-menu" ); - ui_manager_create_menus_init_pmenu( "/playlist-menus/playlist-rightclick-menu/plugins-menu" ); - - gtk_ui_manager_add_ui_from_file( ui_manager , DATA_DIR "/ui/equalizer.ui" , &gerr ); - - if ( gerr != NULL ) - { - g_critical( "Error creating UI: %s" , gerr->message ); - g_error_free( gerr ); - return; - } - - equalizerwin_presets_menu = ui_manager_get_popup_menu(ui_manager, "/equalizer-menus/preset-menu"); - - menu_created = TRUE; - - return; -} - - -GtkAccelGroup * -ui_manager_get_accel_group ( void ) -{ - return gtk_ui_manager_get_accel_group( ui_manager ); -} - - -GtkWidget * -ui_manager_get_popup_menu ( GtkUIManager * self , const gchar * path ) -{ - GtkWidget *menu_item = gtk_ui_manager_get_widget( self , path ); - - if (GTK_IS_MENU_ITEM(menu_item)) - return gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)); - else - return NULL; -} - - -static void -menu_popup_pos_func (GtkMenu * menu , gint * x , gint * y , gboolean * push_in , gint * point ) -{ - GtkRequisition requisition; - gint screen_width; - gint screen_height; - - gtk_widget_size_request(GTK_WIDGET(menu), &requisition); - - screen_width = gdk_screen_width(); - screen_height = gdk_screen_height(); - - *x = CLAMP(point[0] - 2, 0, MAX(0, screen_width - requisition.width)); - *y = CLAMP(point[1] - 2, 0, MAX(0, screen_height - requisition.height)); - - *push_in = FALSE; -} - - -void -ui_manager_popup_menu_show ( GtkMenu * menu , gint x , gint y , guint button , guint time ) -{ - gint pos[2]; - pos[0] = x; - pos[1] = y; - - gtk_menu_popup( menu , NULL , NULL , - (GtkMenuPositionFunc) menu_popup_pos_func , pos , button , time ); -} - - - -/******************************/ -/* plugin-available functions */ - -#define _MP_GWID(y) gtk_ui_manager_get_widget( ui_manager , y ) - -static GtkWidget* -audacious_menu_plugin_menuwid( menu_id ) -{ - switch (menu_id) - { - case AUDACIOUS_MENU_MAIN: - return _MP_GWID("/mainwin-menus/main-menu/plugins-menu"); - case AUDACIOUS_MENU_PLAYLIST: - return _MP_GWID("/playlist-menus/playlist-menu/plugins-menu"); - case AUDACIOUS_MENU_PLAYLIST_RCLICK: - return _MP_GWID("/playlist-menus/playlist-rightclick-menu/plugins-menu"); - case AUDACIOUS_MENU_PLAYLIST_ADD: - return _MP_GWID("/playlist-menus/add-menu/plugins-menu"); - case AUDACIOUS_MENU_PLAYLIST_REMOVE: - return _MP_GWID("/playlist-menus/del-menu/plugins-menu"); - case AUDACIOUS_MENU_PLAYLIST_SELECT: - return _MP_GWID("/playlist-menus/select-menu/plugins-menu"); - case AUDACIOUS_MENU_PLAYLIST_MISC: - return _MP_GWID("/playlist-menus/misc-menu/plugins-menu"); - default: - return NULL; - } -} - - -gint -menu_plugin_item_add( gint menu_id , GtkWidget * item ) -{ - if ( menu_created ) - { - GtkWidget *plugins_menu = NULL; - GtkWidget *plugins_menu_item = audacious_menu_plugin_menuwid( menu_id ); - if ( plugins_menu_item ) - { - gint ic = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(plugins_menu_item),"ic")); - if ( ic == 0 ) /* no items under plugins_menu_item, create the submenu */ - { - plugins_menu = gtk_menu_new(); - gtk_menu_item_set_submenu( GTK_MENU_ITEM(plugins_menu_item), plugins_menu ); - } - else /* items available under plugins_menu_item, pick the existing submenu */ - { - plugins_menu = gtk_menu_item_get_submenu( GTK_MENU_ITEM(plugins_menu_item) ); - if ( !plugins_menu ) return -1; - } - gtk_menu_shell_append( GTK_MENU_SHELL(plugins_menu) , item ); - gtk_widget_show( plugins_menu_item ); - g_object_set_data( G_OBJECT(plugins_menu_item) , "ic" , GINT_TO_POINTER(++ic) ); - return 0; /* success */ - } - } - return -1; /* failure */ -} - - -gint -menu_plugin_item_remove( gint menu_id , GtkWidget * item ) -{ - if ( menu_created ) - { - GtkWidget *plugins_menu = NULL; - GtkWidget *plugins_menu_item = audacious_menu_plugin_menuwid( menu_id ); - if ( plugins_menu_item ) - { - gint ic = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(plugins_menu_item),"ic")); - if ( ic > 0 ) - { - plugins_menu = gtk_menu_item_get_submenu( GTK_MENU_ITEM(plugins_menu_item) ); - if ( plugins_menu ) - { - /* remove the plugin-added entry */ - gtk_container_remove( GTK_CONTAINER(plugins_menu) , item ); - g_object_set_data( G_OBJECT(plugins_menu_item) , "ic" , GINT_TO_POINTER(--ic) ); - if ( ic == 0 ) /* if the menu is empty now, destroy it */ - { - gtk_menu_item_remove_submenu( GTK_MENU_ITEM(plugins_menu_item) ); - gtk_widget_destroy( plugins_menu ); - gtk_widget_hide( plugins_menu_item ); - } - return 0; /* success */ - } - } - } - } - return -1; /* failure */ -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_manager.h --- a/src/audacious/ui_manager.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2007 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_MANAGER_H -#define AUDACIOUS_UI_MANAGER_H - -#include -#include -#include - -G_BEGIN_DECLS - -GtkWidget *mainwin_songname_menu; -GtkWidget *mainwin_general_menu; -GtkWidget *mainwin_visualization_menu; -GtkWidget *mainwin_playback_menu; -GtkWidget *mainwin_playlist_menu; -GtkWidget *mainwin_view_menu; - -GtkWidget *playlistwin_pladd_menu; -GtkWidget *playlistwin_pldel_menu; -GtkWidget *playlistwin_plsel_menu; -GtkWidget *playlistwin_plsort_menu; -GtkWidget *playlistwin_pllist_menu; -GtkWidget *playlistwin_popup_menu; - -GtkWidget *equalizerwin_presets_menu; - -GtkActionGroup *toggleaction_group_others; -GtkActionGroup *radioaction_group_anamode; /* Analyzer mode */ -GtkActionGroup *radioaction_group_anatype; /* Analyzer type */ -GtkActionGroup *radioaction_group_scomode; /* Scope mode */ -GtkActionGroup *radioaction_group_vprmode; /* Voiceprint mode */ -GtkActionGroup *radioaction_group_wshmode; /* WindowShade VU mode */ -GtkActionGroup *radioaction_group_refrate; /* Refresh rate */ -GtkActionGroup *radioaction_group_anafoff; /* Analyzer Falloff */ -GtkActionGroup *radioaction_group_peafoff; /* Peak Falloff */ -GtkActionGroup *radioaction_group_vismode; /* Visualization mode */ -GtkActionGroup *radioaction_group_viewtime; /* View time (remaining/elapsed) */ -GtkActionGroup *action_group_playback; -GtkActionGroup *action_group_visualization; -GtkActionGroup *action_group_view; -GtkActionGroup *action_group_others; -GtkActionGroup *action_group_playlist; -GtkActionGroup *action_group_playlist_add; -GtkActionGroup *action_group_playlist_select; -GtkActionGroup *action_group_playlist_delete; -GtkActionGroup *action_group_playlist_sort; -GtkActionGroup *action_group_equalizer; - - -void ui_manager_init ( void ); -void ui_manager_create_menus ( void ); -GtkAccelGroup * ui_manager_get_accel_group ( void ); -GtkWidget * ui_manager_get_popup_menu ( GtkUIManager * , const gchar * ); -void ui_manager_popup_menu_show( GtkMenu * , gint , gint , guint , guint ); -#define popup_menu_show(x1,x2,x3,x4,x5) ui_manager_popup_menu_show(x1,x2,x3,x4,x5) - -G_END_DECLS - -#endif /* AUDACIOUS_UI_MANAGER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_playlist.c --- a/src/audacious/ui_playlist.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1923 +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. - */ - -/* #define AUD_DEBUG 1 */ - -#include "ui_playlist.h" - -#include -#include -#include -#include -#include -#include - -#include "platform/smartinclude.h" - -#include -#include - -#include "actions-playlist.h" -#include "dnd.h" -#include "input.h" -#include "main.h" -#include "playback.h" -#include "playlist.h" -#include "playlist_container.h" -#include "strings.h" -#include "ui_dock.h" -#include "ui_equalizer.h" -#include "ui_fileinfo.h" -#include "ui_fileopener.h" -#include "ui_main.h" -#include "ui_manager.h" -#include "ui_playlist_evlisteners.h" -#include "ui_playlist_manager.h" -#include "util.h" -#include "config.h" - -#include "ui_skinned_window.h" -#include "ui_skinned_button.h" -#include "ui_skinned_textbox.h" -#include "ui_skinned_playlist_slider.h" -#include "ui_skinned_playlist.h" - -#include "icons-stock.h" -#include "images/audacious_playlist.xpm" - -GtkWidget *playlistwin; - -static GMutex *resize_mutex = NULL; - -static GtkWidget *playlistwin_list = NULL; -static GtkWidget *playlistwin_shade, *playlistwin_close; - -static gboolean playlistwin_hint_flag = FALSE; - -static GtkWidget *playlistwin_slider; -static GtkWidget *playlistwin_time_min, *playlistwin_time_sec; -static GtkWidget *playlistwin_info, *playlistwin_sinfo; -static GtkWidget *playlistwin_srew, *playlistwin_splay; -static GtkWidget *playlistwin_spause, *playlistwin_sstop; -static GtkWidget *playlistwin_sfwd, *playlistwin_seject; -static GtkWidget *playlistwin_sscroll_up, *playlistwin_sscroll_down; - -static void playlistwin_select_search_cbt_cb(GtkWidget *called_cbt, - gpointer other_cbt); -static gboolean playlistwin_select_search_kp_cb(GtkWidget *entry, - GdkEventKey *event, - gpointer searchdlg_win); - -static gboolean playlistwin_resizing = FALSE; -static gint playlistwin_resize_x, playlistwin_resize_y; - -gboolean -playlistwin_is_shaded(void) -{ - return cfg.playlist_shaded; -} - -gint -playlistwin_get_width(void) -{ - cfg.playlist_width /= PLAYLISTWIN_WIDTH_SNAP; - cfg.playlist_width *= PLAYLISTWIN_WIDTH_SNAP; - return cfg.playlist_width; -} - -gint -playlistwin_get_height_unshaded(void) -{ - cfg.playlist_height /= PLAYLISTWIN_HEIGHT_SNAP; - cfg.playlist_height *= PLAYLISTWIN_HEIGHT_SNAP; - return cfg.playlist_height; -} - -gint -playlistwin_get_height_shaded(void) -{ - return PLAYLISTWIN_SHADED_HEIGHT; -} - -gint -playlistwin_get_height(void) -{ - if (playlistwin_is_shaded()) - return playlistwin_get_height_shaded(); - else - return playlistwin_get_height_unshaded(); -} - -static void -playlistwin_update_info(Playlist *playlist) -{ - gchar *text, *sel_text, *tot_text; - gulong selection, total; - gboolean selection_more, total_more; - - playlist_get_total_time(playlist, &total, &selection, &total_more, &selection_more); - - if (selection > 0 || (selection == 0 && !selection_more)) { - if (selection > 3600) - sel_text = - g_strdup_printf("%lu:%-2.2lu:%-2.2lu%s", selection / 3600, - (selection / 60) % 60, selection % 60, - (selection_more ? "+" : "")); - else - sel_text = - g_strdup_printf("%lu:%-2.2lu%s", selection / 60, - selection % 60, (selection_more ? "+" : "")); - } - else - sel_text = g_strdup("?"); - if (total > 0 || (total == 0 && !total_more)) { - if (total > 3600) - tot_text = - g_strdup_printf("%lu:%-2.2lu:%-2.2lu%s", total / 3600, - (total / 60) % 60, total % 60, - total_more ? "+" : ""); - else - tot_text = - g_strdup_printf("%lu:%-2.2lu%s", total / 60, total % 60, - total_more ? "+" : ""); - } - else - tot_text = g_strdup("?"); - text = g_strconcat(sel_text, "/", tot_text, NULL); - ui_skinned_textbox_set_text(playlistwin_info, text ? text : ""); - g_free(text); - g_free(tot_text); - g_free(sel_text); -} - -static void -playlistwin_update_sinfo(Playlist *playlist) -{ - gchar *posstr, *timestr, *title, *info; - gint pos, time; - - pos = playlist_get_position(playlist); - title = playlist_get_songtitle(playlist, pos); - - if (!title) { - ui_skinned_textbox_set_text(playlistwin_sinfo, ""); - return; - } - - convert_title_text(title); - - time = playlist_get_songtime(playlist, pos); - - if (cfg.show_numbers_in_pl) - posstr = g_strdup_printf("%d. ", pos + 1); - else - posstr = g_strdup(""); - - if (time != -1) { - timestr = g_strdup_printf(" (%d:%-2.2d)", time / 60000, - (time / 1000) % 60); - } - else - timestr = g_strdup(""); - - info = g_strdup_printf("%s%s%s", posstr, title, timestr); - - g_free(posstr); - g_free(title); - g_free(timestr); - - ui_skinned_textbox_set_text(playlistwin_sinfo, info ? info : ""); - g_free(info); -} - -gboolean -playlistwin_item_visible(gint index) -{ - g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), FALSE); - - if (index >= UI_SKINNED_PLAYLIST(playlistwin_list)->first && - index < (UI_SKINNED_PLAYLIST(playlistwin_list)->first + UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible) ) { - return TRUE; - } - return FALSE; -} - -gint -playlistwin_list_get_visible_count(void) -{ - g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), -1); - - return UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible; -} - -gint -playlistwin_list_get_first(void) -{ - g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), -1); - - return UI_SKINNED_PLAYLIST(playlistwin_list)->first; -} - -gint -playlistwin_get_toprow(void) -{ - g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), -1); - - return (UI_SKINNED_PLAYLIST(playlistwin_list)->first); -} - -void -playlistwin_set_toprow(gint toprow) -{ - if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) - UI_SKINNED_PLAYLIST(playlistwin_list)->first = toprow; - g_cond_signal(cond_scan); - playlistwin_update_list(playlist_get_active()); -} - -void -playlistwin_update_list(Playlist *playlist) -{ - /* this can happen early on. just bail gracefully. */ - g_return_if_fail(playlistwin_list); - - playlistwin_update_info(playlist); - playlistwin_update_sinfo(playlist); - gtk_widget_queue_draw(playlistwin_list); - gtk_widget_queue_draw(playlistwin_slider); -} - -static void -playlistwin_set_geometry_hints(gboolean shaded) -{ - GdkGeometry geometry; - GdkWindowHints mask; - - geometry.min_width = PLAYLISTWIN_MIN_WIDTH; - geometry.max_width = G_MAXUINT16; - - geometry.width_inc = PLAYLISTWIN_WIDTH_SNAP; - geometry.height_inc = PLAYLISTWIN_HEIGHT_SNAP; - - if (shaded) { - geometry.min_height = PLAYLISTWIN_SHADED_HEIGHT; - geometry.max_height = PLAYLISTWIN_SHADED_HEIGHT; - geometry.base_height = PLAYLISTWIN_SHADED_HEIGHT; - } - else { - geometry.min_height = PLAYLISTWIN_MIN_HEIGHT; - geometry.max_height = G_MAXUINT16; - } - - mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE | GDK_HINT_RESIZE_INC; - - gtk_window_set_geometry_hints(GTK_WINDOW(playlistwin), - playlistwin, &geometry, mask); -} - -void -playlistwin_set_sinfo_font(gchar *font) -{ - gchar *tmp = NULL, *tmp2 = NULL; - - g_return_if_fail(font); - AUDDBG("Attempt to set font \"%s\"\n", font); - - tmp = g_strdup(font); - g_return_if_fail(tmp); - - *strrchr(tmp, ' ') = '\0'; - tmp2 = g_strdup_printf("%s 8", tmp); - g_return_if_fail(tmp2); - - ui_skinned_textbox_set_xfont(playlistwin_sinfo, !cfg.mainwin_use_bitmapfont, tmp2); - - g_free(tmp); - g_free(tmp2); -} - -void -playlistwin_set_sinfo_scroll(gboolean scroll) -{ - if(playlistwin_is_shaded()) - ui_skinned_textbox_set_scroll(playlistwin_sinfo, cfg.autoscroll); - else - ui_skinned_textbox_set_scroll(playlistwin_sinfo, FALSE); -} - -void -playlistwin_set_shade(gboolean shaded) -{ - cfg.playlist_shaded = shaded; - - if (shaded) { - playlistwin_set_sinfo_font(cfg.playlist_font); - playlistwin_set_sinfo_scroll(cfg.autoscroll); - gtk_widget_show(playlistwin_sinfo); - ui_skinned_set_push_button_data(playlistwin_shade, 128, 45, 150, 42); - ui_skinned_set_push_button_data(playlistwin_close, 138, 45, -1, -1); - } - else { - gtk_widget_hide(playlistwin_sinfo); - playlistwin_set_sinfo_scroll(FALSE); - ui_skinned_set_push_button_data(playlistwin_shade, 157, 3, 62, 42); - ui_skinned_set_push_button_data(playlistwin_close, 167, 3, -1, -1); - } - - dock_shade(get_dock_window_list(), GTK_WINDOW(playlistwin), - playlistwin_get_height()); - - playlistwin_set_geometry_hints(cfg.playlist_shaded); - - gtk_window_resize(GTK_WINDOW(playlistwin), - playlistwin_get_width(), - playlistwin_get_height()); -} - -static void -playlistwin_set_shade_menu(gboolean shaded) -{ - GtkAction *action = gtk_action_group_get_action( - toggleaction_group_others , "roll up playlist editor" ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , shaded ); - - playlistwin_set_shade(shaded); - playlistwin_update_list(playlist_get_active()); -} - -void -playlistwin_shade_toggle(void) -{ - playlistwin_set_shade_menu(!cfg.playlist_shaded); -} - -static gboolean -playlistwin_release(GtkWidget * widget, - GdkEventButton * event, - gpointer callback_data) -{ - playlistwin_resizing = FALSE; - return FALSE; -} - -void -playlistwin_scroll(gint num) -{ - if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) - UI_SKINNED_PLAYLIST(playlistwin_list)->first += num; - playlistwin_update_list(playlist_get_active()); -} - -void -playlistwin_scroll_up_pushed(void) -{ - playlistwin_scroll(-3); -} - -void -playlistwin_scroll_down_pushed(void) -{ - playlistwin_scroll(3); -} - -static void -playlistwin_select_all(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_select_all(playlist, TRUE); - if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { - UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected = 0; - UI_SKINNED_PLAYLIST(playlistwin_list)->prev_min = 0; - UI_SKINNED_PLAYLIST(playlistwin_list)->prev_max = playlist_get_length(playlist) - 1; - } - playlistwin_update_list(playlist); -} - -static void -playlistwin_select_none(void) -{ - playlist_select_all(playlist_get_active(), FALSE); - if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { - UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected = -1; - UI_SKINNED_PLAYLIST(playlistwin_list)->prev_min = -1; - } - playlistwin_update_list(playlist_get_active()); -} - -static void -playlistwin_select_search(void) -{ - Playlist *playlist = playlist_get_active(); - GtkWidget *searchdlg_win, *searchdlg_table; - GtkWidget *searchdlg_hbox, *searchdlg_logo, *searchdlg_helptext; - GtkWidget *searchdlg_entry_title, *searchdlg_label_title; - GtkWidget *searchdlg_entry_album, *searchdlg_label_album; - GtkWidget *searchdlg_entry_file_name, *searchdlg_label_file_name; - GtkWidget *searchdlg_entry_performer, *searchdlg_label_performer; - GtkWidget *searchdlg_checkbt_clearprevsel; - GtkWidget *searchdlg_checkbt_newplaylist; - GtkWidget *searchdlg_checkbt_autoenqueue; - gint result; - - /* create dialog */ - searchdlg_win = gtk_dialog_new_with_buttons( - _("Search entries in active playlist") , GTK_WINDOW(mainwin) , - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT , - GTK_STOCK_CANCEL , GTK_RESPONSE_REJECT , GTK_STOCK_OK , GTK_RESPONSE_ACCEPT , NULL ); - gtk_window_set_position(GTK_WINDOW(searchdlg_win), GTK_WIN_POS_CENTER); - - /* help text and logo */ - searchdlg_hbox = gtk_hbox_new( FALSE , 4 ); - searchdlg_logo = gtk_image_new_from_stock( GTK_STOCK_FIND , GTK_ICON_SIZE_DIALOG ); - searchdlg_helptext = gtk_label_new( _("Select entries in playlist by filling one or more " - "fields. Fields use regular expressions syntax, case-insensitive. If you don't know how " - "regular expressions work, simply insert a literal portion of what you're searching for.") ); - gtk_label_set_line_wrap( GTK_LABEL(searchdlg_helptext) , TRUE ); - gtk_box_pack_start( GTK_BOX(searchdlg_hbox) , searchdlg_logo , FALSE , FALSE , 0 ); - gtk_box_pack_start( GTK_BOX(searchdlg_hbox) , searchdlg_helptext , FALSE , FALSE , 0 ); - - /* title */ - searchdlg_label_title = gtk_label_new( _("Title: ") ); - searchdlg_entry_title = gtk_entry_new(); - gtk_misc_set_alignment( GTK_MISC(searchdlg_label_title) , 0 , 0.5 ); - g_signal_connect( G_OBJECT(searchdlg_entry_title) , "key-press-event" , - G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); - - /* album */ - searchdlg_label_album= gtk_label_new( _("Album: ") ); - searchdlg_entry_album= gtk_entry_new(); - gtk_misc_set_alignment( GTK_MISC(searchdlg_label_album) , 0 , 0.5 ); - g_signal_connect( G_OBJECT(searchdlg_entry_album) , "key-press-event" , - G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); - - /* artist */ - searchdlg_label_performer = gtk_label_new( _("Artist: ") ); - searchdlg_entry_performer = gtk_entry_new(); - gtk_misc_set_alignment( GTK_MISC(searchdlg_label_performer) , 0 , 0.5 ); - g_signal_connect( G_OBJECT(searchdlg_entry_performer) , "key-press-event" , - G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); - - /* file name */ - searchdlg_label_file_name = gtk_label_new( _("Filename: ") ); - searchdlg_entry_file_name = gtk_entry_new(); - gtk_misc_set_alignment( GTK_MISC(searchdlg_label_file_name) , 0 , 0.5 ); - g_signal_connect( G_OBJECT(searchdlg_entry_file_name) , "key-press-event" , - G_CALLBACK(playlistwin_select_search_kp_cb) , searchdlg_win ); - - /* some options that control behaviour */ - searchdlg_checkbt_clearprevsel = gtk_check_button_new_with_label( - _("Clear previous selection before searching") ); - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_clearprevsel) , TRUE ); - searchdlg_checkbt_autoenqueue = gtk_check_button_new_with_label( - _("Automatically toggle queue for matching entries") ); - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_autoenqueue) , FALSE ); - searchdlg_checkbt_newplaylist = gtk_check_button_new_with_label( - _("Create a new playlist with matching entries") ); - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(searchdlg_checkbt_newplaylist) , FALSE ); - g_signal_connect( G_OBJECT(searchdlg_checkbt_autoenqueue) , "clicked" , - G_CALLBACK(playlistwin_select_search_cbt_cb) , searchdlg_checkbt_newplaylist ); - g_signal_connect( G_OBJECT(searchdlg_checkbt_newplaylist) , "clicked" , - G_CALLBACK(playlistwin_select_search_cbt_cb) , searchdlg_checkbt_autoenqueue ); - - /* place fields in searchdlg_table */ - searchdlg_table = gtk_table_new( 8 , 2 , FALSE ); - gtk_table_set_row_spacing( GTK_TABLE(searchdlg_table) , 0 , 8 ); - gtk_table_set_row_spacing( GTK_TABLE(searchdlg_table) , 4 , 8 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_hbox , - 0 , 2 , 0 , 1 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_title , - 0 , 1 , 1 , 2 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_title , - 1 , 2 , 1 , 2 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_album, - 0 , 1 , 2 , 3 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_album, - 1 , 2 , 2 , 3 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_performer , - 0 , 1 , 3 , 4 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_performer , - 1 , 2 , 3 , 4 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_file_name , - 0 , 1 , 4 , 5 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_file_name , - 1 , 2 , 4 , 5 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_clearprevsel , - 0 , 2 , 5 , 6 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_autoenqueue , - 0 , 2 , 6 , 7 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 ); - gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_checkbt_newplaylist , - 0 , 2 , 7 , 8 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 1 ); - - gtk_container_set_border_width( GTK_CONTAINER(searchdlg_table) , 5 ); - gtk_container_add( GTK_CONTAINER(GTK_DIALOG(searchdlg_win)->vbox) , searchdlg_table ); - gtk_widget_show_all( searchdlg_win ); - result = gtk_dialog_run( GTK_DIALOG(searchdlg_win) ); - switch(result) - { - case GTK_RESPONSE_ACCEPT: - { - gint matched_entries_num = 0; - /* create a TitleInput tuple with user search data */ - Tuple *tuple = tuple_new(); - gchar *searchdata = NULL; - - searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_title) ); - AUDDBG("title=\"%s\"\n", searchdata); - tuple_associate_string(tuple, FIELD_TITLE, NULL, searchdata); - - searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_album) ); - AUDDBG("album=\"%s\"\n", searchdata); - tuple_associate_string(tuple, FIELD_ALBUM, NULL, searchdata); - - searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_performer) ); - AUDDBG("performer=\"%s\"\n", searchdata); - tuple_associate_string(tuple, FIELD_ARTIST, NULL, searchdata); - - searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_file_name) ); - AUDDBG("filename=\"%s\"\n", searchdata); - tuple_associate_string(tuple, FIELD_FILE_NAME, NULL, searchdata); - - /* check if previous selection should be cleared before searching */ - if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_clearprevsel)) == TRUE ) - playlistwin_select_none(); - /* now send this tuple to the real search function */ - matched_entries_num = playlist_select_search( playlist , tuple , 0 ); - /* we do not need the tuple and its data anymore */ - mowgli_object_unref(tuple); - playlistwin_update_list(playlist_get_active()); - /* check if a new playlist should be created after searching */ - if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_newplaylist)) == TRUE ) - playlist_new_from_selected(); - /* check if matched entries should be queued */ - else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(searchdlg_checkbt_autoenqueue)) == TRUE ) - playlist_queue(playlist_get_active()); - break; - } - default: - break; - } - /* done here :) */ - gtk_widget_destroy( searchdlg_win ); -} - -static void -playlistwin_inverse_selection(void) -{ - playlist_select_invert_all(playlist_get_active()); - if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { - UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected = -1; - UI_SKINNED_PLAYLIST(playlistwin_list)->prev_min = -1; - } - playlistwin_update_list(playlist_get_active()); -} - -static void -playlistwin_resize(gint width, gint height) -{ - gint tx, ty; - gint dx, dy; - - g_return_if_fail(width > 0 && height > 0); - - tx = (width - PLAYLISTWIN_MIN_WIDTH) / PLAYLISTWIN_WIDTH_SNAP; - tx = (tx * PLAYLISTWIN_WIDTH_SNAP) + PLAYLISTWIN_MIN_WIDTH; - if (tx < PLAYLISTWIN_MIN_WIDTH) - tx = PLAYLISTWIN_MIN_WIDTH; - - if (!cfg.playlist_shaded) - { - ty = (height - PLAYLISTWIN_MIN_HEIGHT) / PLAYLISTWIN_HEIGHT_SNAP; - ty = (ty * PLAYLISTWIN_HEIGHT_SNAP) + PLAYLISTWIN_MIN_HEIGHT; - if (ty < PLAYLISTWIN_MIN_HEIGHT) - ty = PLAYLISTWIN_MIN_HEIGHT; - } - else - ty = cfg.playlist_height; - - if (tx == cfg.playlist_width && ty == cfg.playlist_height) - return; - - /* difference between previous size and new size */ - dx = tx - cfg.playlist_width; - dy = ty - cfg.playlist_height; - - cfg.playlist_width = width = tx; - cfg.playlist_height = height = ty; - - g_mutex_lock(resize_mutex); - ui_skinned_playlist_resize_relative(playlistwin_list, dx, dy); - - ui_skinned_playlist_slider_move_relative(playlistwin_slider, dx); - ui_skinned_playlist_slider_resize_relative(playlistwin_slider, dy); - - playlistwin_update_sinfo(playlist_get_active()); - - ui_skinned_button_move_relative(playlistwin_shade, dx, 0); - ui_skinned_button_move_relative(playlistwin_close, dx, 0); - ui_skinned_textbox_move_relative(playlistwin_time_min, dx, dy); - ui_skinned_textbox_move_relative(playlistwin_time_sec, dx, dy); - ui_skinned_textbox_move_relative(playlistwin_info, dx, dy); - ui_skinned_button_move_relative(playlistwin_srew, dx, dy); - ui_skinned_button_move_relative(playlistwin_splay, dx, dy); - ui_skinned_button_move_relative(playlistwin_spause, dx, dy); - ui_skinned_button_move_relative(playlistwin_sstop, dx, dy); - ui_skinned_button_move_relative(playlistwin_sfwd, dx, dy); - ui_skinned_button_move_relative(playlistwin_seject, dx, dy); - ui_skinned_button_move_relative(playlistwin_sscroll_up, dx, dy); - ui_skinned_button_move_relative(playlistwin_sscroll_down, dx, dy); - - gtk_widget_set_size_request(playlistwin_sinfo, playlistwin_get_width() - 35, - aud_active_skin->properties.textbox_bitmap_font_height); - GList *iter; - for (iter = GTK_FIXED (SKINNED_WINDOW(playlistwin)->fixed)->children; iter; iter = g_list_next (iter)) { - GtkFixedChild *child_data = (GtkFixedChild *) iter->data; - GtkWidget *child = child_data->widget; - g_signal_emit_by_name(child, "redraw"); - } - g_mutex_unlock(resize_mutex); -} - -static void -playlistwin_motion(GtkWidget * widget, - GdkEventMotion * event, - gpointer callback_data) -{ - /* - * GDK2's resize is broken and doesn't really play nice, so we have - * to do all of this stuff by hand. - */ - if (playlistwin_resizing == TRUE) - { - if (event->x + playlistwin_resize_x != playlistwin_get_width() || - event->y + playlistwin_resize_y != playlistwin_get_height()) - { - playlistwin_resize(event->x + playlistwin_resize_x, - event->y + playlistwin_resize_y); - gdk_window_resize(playlistwin->window, - cfg.playlist_width, playlistwin_get_height()); - gdk_flush(); - } - } - else if (dock_is_moving(GTK_WINDOW(playlistwin))) - dock_move_motion(GTK_WINDOW(playlistwin), event); -} - -static void -playlistwin_show_filebrowser(void) -{ - run_filebrowser(FALSE); -} - -static void -playlistwin_fileinfo(void) -{ - Playlist *playlist = playlist_get_active(); - - /* Show the first selected file, or the current file if nothing is - * selected */ - GList *list = playlist_get_selected(playlist); - if (list) { - ui_fileinfo_show(playlist, GPOINTER_TO_INT(list->data)); - g_list_free(list); - } - else - ui_fileinfo_show_current(playlist); -} - -static void -show_playlist_save_error(GtkWindow *parent, - const gchar *filename) -{ - GtkWidget *dialog; - - g_return_if_fail(GTK_IS_WINDOW(parent)); - g_return_if_fail(filename); - - dialog = gtk_message_dialog_new(GTK_WINDOW(parent), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _("Error writing playlist \"%s\": %s"), - filename, strerror(errno)); - - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); -} - -static gboolean -show_playlist_overwrite_prompt(GtkWindow * parent, - const gchar * filename) -{ - GtkWidget *dialog; - gint result; - - g_return_val_if_fail(GTK_IS_WINDOW(parent), FALSE); - g_return_val_if_fail(filename != NULL, FALSE); - - dialog = gtk_message_dialog_new(GTK_WINDOW(parent), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - _("%s already exist. Continue?"), - filename); - - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ - result = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - - return (result == GTK_RESPONSE_YES); -} - -static void -show_playlist_save_format_error(GtkWindow * parent, - const gchar * filename) -{ - const gchar *markup = - N_("Unable to save playlist.\n\n" - "Unknown file type for '%s'.\n"); - - GtkWidget *dialog; - - g_return_if_fail(GTK_IS_WINDOW(parent)); - g_return_if_fail(filename != NULL); - - dialog = - gtk_message_dialog_new_with_markup(GTK_WINDOW(parent), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _(markup), - filename); - - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); -} - -static void -playlistwin_save_playlist(const gchar * filename) -{ - PlaylistContainer *plc; - gchar *ext = strrchr(filename, '.') + 1; - - plc = playlist_container_find(ext); - if (plc == NULL) { - show_playlist_save_format_error(GTK_WINDOW(playlistwin), filename); - return; - } - - str_replace_in(&cfg.playlist_path, g_path_get_dirname(filename)); - - if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) - if (!show_playlist_overwrite_prompt(GTK_WINDOW(playlistwin), filename)) - return; - - if (!playlist_save(playlist_get_active(), filename)) - show_playlist_save_error(GTK_WINDOW(playlistwin), filename); -} - -static void -playlistwin_load_playlist(const gchar * filename) -{ - const gchar *title; - Playlist *playlist = playlist_get_active(); - - g_return_if_fail(filename != NULL); - - str_replace_in(&cfg.playlist_path, g_path_get_dirname(filename)); - - playlist_clear(playlist); - mainwin_clear_song_info(); - - playlist_load(playlist, filename); - title = playlist_get_current_name(playlist); - if(!title || !title[0]) - playlist_set_current_name(playlist, filename); -} - -static gchar * -playlist_file_selection_load(const gchar * title, - const gchar * default_filename) -{ - GtkWidget *dialog; - gchar *filename; - - g_return_val_if_fail(title != NULL, NULL); - - dialog = make_filebrowser(title, FALSE); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), cfg.playlist_path); - if (default_filename) - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), default_filename); - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); /* centering */ - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - else - filename = NULL; - - gtk_widget_destroy(dialog); - return filename; -} - -static void -on_static_toggle(GtkToggleButton *button, gpointer data) -{ - Playlist *playlist = playlist_get_active(); - - playlist->attribute = - gtk_toggle_button_get_active(button) ? - playlist->attribute | PLAYLIST_STATIC : - playlist->attribute & ~PLAYLIST_STATIC; -} - -static void -on_relative_toggle(GtkToggleButton *button, gpointer data) -{ - Playlist *playlist = playlist_get_active(); - - playlist->attribute = - gtk_toggle_button_get_active(button) ? - playlist->attribute | PLAYLIST_USE_RELATIVE : - playlist->attribute & ~PLAYLIST_USE_RELATIVE; -} - -static gchar * -playlist_file_selection_save(const gchar * title, - const gchar * default_filename) -{ - GtkWidget *dialog; - gchar *filename; - GtkWidget *hbox; - GtkWidget *toggle, *toggle2; - - g_return_val_if_fail(title != NULL, NULL); - - dialog = make_filebrowser(title, TRUE); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), cfg.playlist_path); - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), default_filename); - - hbox = gtk_hbox_new(FALSE, 5); - - /* static playlist */ - toggle = gtk_check_button_new_with_label(_("Save as Static Playlist")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), - (playlist_get_active()->attribute & PLAYLIST_STATIC) ? TRUE : FALSE); - g_signal_connect(G_OBJECT(toggle), "toggled", G_CALLBACK(on_static_toggle), dialog); - gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, FALSE, 0); - - /* use relative path */ - toggle2 = gtk_check_button_new_with_label(_("Use Relative Path")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle2), - (playlist_get_active()->attribute & PLAYLIST_USE_RELATIVE) ? TRUE : FALSE); - g_signal_connect(G_OBJECT(toggle2), "toggled", G_CALLBACK(on_relative_toggle), dialog); - gtk_box_pack_start(GTK_BOX(hbox), toggle2, FALSE, FALSE, 0); - - gtk_widget_show_all(hbox); - gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), hbox); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - else - filename = NULL; - - gtk_widget_destroy(dialog); - return filename; -} - -void -playlistwin_select_playlist_to_load(const gchar * default_filename) -{ - gchar *filename = - playlist_file_selection_load(_("Load Playlist"), default_filename); - - if (filename) { - playlistwin_load_playlist(filename); - g_free(filename); - } -} - -static void -playlistwin_select_playlist_to_save(const gchar * default_filename) -{ - gchar *dot = NULL, *basename = NULL; - gchar *filename = - playlist_file_selection_save(_("Save Playlist"), default_filename); - - if (filename) { - /* Default extension */ - basename = g_path_get_basename(filename); - dot = strrchr(basename, '.'); - if( dot == NULL || dot == basename) { - gchar *oldname = filename; -#ifdef HAVE_XSPF_PLAYLIST - filename = g_strconcat(oldname, ".xspf", NULL); -#else - filename = g_strconcat(oldname, ".m3u", NULL); -#endif - g_free(oldname); - } - g_free(basename); - - playlistwin_save_playlist(filename); - g_free(filename); - } -} - -#define REGION_L(x1,x2,y1,y2) \ - (event->x >= (x1) && event->x < (x2) && \ - event->y >= cfg.playlist_height - (y1) && \ - event->y < cfg.playlist_height - (y2)) - -#define REGION_R(x1,x2,y1,y2) \ - (event->x >= playlistwin_get_width() - (x1) && \ - event->x < playlistwin_get_width() - (x2) && \ - event->y >= cfg.playlist_height - (y1) && \ - event->y < cfg.playlist_height - (y2)) - -static void -playlistwin_scrolled(GtkWidget * widget, - GdkEventScroll * event, - gpointer callback_data) -{ - if (event->direction == GDK_SCROLL_DOWN) - playlistwin_scroll(cfg.scroll_pl_by); - - if (event->direction == GDK_SCROLL_UP) - playlistwin_scroll(-cfg.scroll_pl_by); - - g_cond_signal(cond_scan); -} - -static gboolean -playlistwin_press(GtkWidget * widget, - GdkEventButton * event, - gpointer callback_data) -{ - gint xpos, ypos; - GtkRequisition req; - - gtk_window_get_position(GTK_WINDOW(playlistwin), &xpos, &ypos); - - if (event->button == 1 && !cfg.show_wm_decorations && - ((!cfg.playlist_shaded && - event->x > playlistwin_get_width() - 20 && - event->y > cfg.playlist_height - 20) || - (cfg.playlist_shaded && - event->x >= playlistwin_get_width() - 31 && - event->x < playlistwin_get_width() - 22))) { - - if (event->type != GDK_2BUTTON_PRESS && - event->type != GDK_3BUTTON_PRESS) { - playlistwin_resizing = TRUE; - playlistwin_resize_x = cfg.playlist_width - event->x; - playlistwin_resize_y = cfg.playlist_height - event->y; - } - } - else if (event->button == 1 && REGION_L(12, 37, 29, 11)) { - /* ADD button menu */ - gtk_widget_size_request(playlistwin_pladd_menu, &req); - ui_manager_popup_menu_show(GTK_MENU(playlistwin_pladd_menu), - xpos + 12, - (ypos + playlistwin_get_height()) - 8 - req.height, - event->button, - event->time); - } - else if (event->button == 1 && REGION_L(41, 66, 29, 11)) { - /* SUB button menu */ - gtk_widget_size_request(playlistwin_pldel_menu, &req); - ui_manager_popup_menu_show(GTK_MENU(playlistwin_pldel_menu), - xpos + 40, - (ypos + playlistwin_get_height()) - 8 - req.height, - event->button, - event->time); - } - else if (event->button == 1 && REGION_L(70, 95, 29, 11)) { - /* SEL button menu */ - gtk_widget_size_request(playlistwin_plsel_menu, &req); - ui_manager_popup_menu_show(GTK_MENU(playlistwin_plsel_menu), - xpos + 68, - (ypos + playlistwin_get_height()) - 8 - req.height, - event->button, - event->time); - } - else if (event->button == 1 && REGION_L(99, 124, 29, 11)) { - /* MISC button menu */ - gtk_widget_size_request(playlistwin_plsort_menu, &req); - ui_manager_popup_menu_show(GTK_MENU(playlistwin_plsort_menu), - xpos + 100, - (ypos + playlistwin_get_height()) - 8 - req.height, - event->button, - event->time); - } - else if (event->button == 1 && REGION_R(46, 23, 29, 11)) { - /* LIST button menu */ - gtk_widget_size_request(playlistwin_pllist_menu, &req); - ui_manager_popup_menu_show(GTK_MENU(playlistwin_pllist_menu), - xpos + playlistwin_get_width() - req.width - 12, - (ypos + playlistwin_get_height()) - 8 - req.height, - event->button, - event->time); - } - else if (event->button == 1 && event->type == GDK_BUTTON_PRESS && - (cfg.easy_move || event->y < 14)) - { - return FALSE; - } - else if (event->button == 1 && event->type == GDK_2BUTTON_PRESS - && event->y < 14) { - /* double click on title bar */ - playlistwin_shade_toggle(); - if (dock_is_moving(GTK_WINDOW(playlistwin))) - dock_move_release(GTK_WINDOW(playlistwin)); - return TRUE; - } - else if (event->button == 3) { - /* - * Pop up the main menu a few pixels down to avoid - * anything to be selected initially. - */ - ui_manager_popup_menu_show(GTK_MENU(mainwin_general_menu), event->x_root, - event->y_root + 2, 3, event->time); - } - - return TRUE; -} - -static gboolean -playlistwin_delete(GtkWidget * w, gpointer data) -{ - playlistwin_hide(); - return TRUE; -} - -static gboolean -playlistwin_keypress_up_down_handler(UiSkinnedPlaylist * pl, - gboolean up, guint state) -{ - Playlist *playlist = playlist_get_active(); - if ((!(pl->prev_selected || pl->first) && up) || - ((pl->prev_selected >= playlist_get_length(playlist) - 1) && !up)) - return FALSE; - - if ((state & GDK_MOD1_MASK) && (state & GDK_SHIFT_MASK)) - return FALSE; - if (!(state & GDK_MOD1_MASK)) - playlist_select_all(playlist, FALSE); - - if (pl->prev_selected == -1 || - (!playlistwin_item_visible(pl->prev_selected) && - !(state & GDK_SHIFT_MASK && pl->prev_min != -1))) { - pl->prev_selected = pl->first; - } - else if (state & GDK_SHIFT_MASK) { - if (pl->prev_min == -1) { - pl->prev_max = pl->prev_selected; - pl->prev_min = pl->prev_selected; - } - pl->prev_max += (up ? -1 : 1); - pl->prev_max = - CLAMP(pl->prev_max, 0, playlist_get_length(playlist) - 1); - - pl->first = MIN(pl->first, pl->prev_max); - pl->first = MAX(pl->first, pl->prev_max - - pl->num_visible + 1); - playlist_select_range(playlist, pl->prev_min, pl->prev_max, TRUE); - return TRUE; - } - else if (state & GDK_MOD1_MASK) { - if (up) - ui_skinned_playlist_move_up(pl); - else - ui_skinned_playlist_move_down(pl); - if (pl->prev_min < pl->first) - pl->first = pl->prev_min; - else if (pl->prev_max >= (pl->first + pl->num_visible)) - pl->first = pl->prev_max - pl->num_visible + 1; - return TRUE; - } - else if (up) - pl->prev_selected--; - else - pl->prev_selected++; - - pl->prev_selected = - CLAMP(pl->prev_selected, 0, playlist_get_length(playlist) - 1); - - if (pl->prev_selected < pl->first) - pl->first--; - else if (pl->prev_selected >= (pl->first + pl->num_visible)) - pl->first++; - - playlist_select_range(playlist, pl->prev_selected, pl->prev_selected, TRUE); - pl->prev_min = -1; - - return TRUE; -} - -/* FIXME: Handle the keys through menu */ - -static gboolean -playlistwin_keypress(GtkWidget * w, GdkEventKey * event, gpointer data) -{ - g_return_val_if_fail(UI_SKINNED_IS_PLAYLIST(playlistwin_list), FALSE); - Playlist *playlist = playlist_get_active(); - - guint keyval; - gboolean refresh = FALSE; - guint cur_pos; - - if (cfg.playlist_shaded) - return FALSE; - - switch (keyval = event->keyval) { - case GDK_KP_Up: - case GDK_KP_Down: - case GDK_Up: - case GDK_Down: - refresh = playlistwin_keypress_up_down_handler(UI_SKINNED_PLAYLIST(playlistwin_list), - keyval == GDK_Up - || keyval == GDK_KP_Up, - event->state); - break; - case GDK_Page_Up: - playlistwin_scroll(-UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible); - refresh = TRUE; - break; - case GDK_Page_Down: - playlistwin_scroll(UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible); - refresh = TRUE; - break; - case GDK_Home: - UI_SKINNED_PLAYLIST(playlistwin_list)->first = 0; - refresh = TRUE; - break; - case GDK_End: - UI_SKINNED_PLAYLIST(playlistwin_list)->first = - playlist_get_length(playlist) - UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible; - refresh = TRUE; - break; - case GDK_Return: - if (UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected > -1 - && playlistwin_item_visible(UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected)) { - playlist_set_position(playlist, UI_SKINNED_PLAYLIST(playlistwin_list)->prev_selected); - if (!playback_get_playing()) - playback_initiate(); - } - refresh = TRUE; - break; - case GDK_3: - if (event->state & GDK_CONTROL_MASK) - playlistwin_fileinfo(); - break; - case GDK_Delete: - if (event->state & GDK_CONTROL_MASK) - playlist_delete(playlist, TRUE); - else - playlist_delete(playlist, FALSE); - break; - case GDK_Insert: - if (event->state & GDK_MOD1_MASK) - mainwin_show_add_url_window(); - else - playlistwin_show_filebrowser(); - break; - case GDK_Left: - case GDK_KP_Left: - case GDK_KP_7: - if (playlist_get_current_length(playlist) != -1) - playback_seek(CLAMP - (playback_get_time() - 5000, 0, - playlist_get_current_length(playlist)) / 1000); - break; - case GDK_Right: - case GDK_KP_Right: - case GDK_KP_9: - if (playlist_get_current_length(playlist) != -1) - playback_seek(CLAMP - (playback_get_time() + 5000, 0, - playlist_get_current_length(playlist)) / 1000); - break; - case GDK_KP_4: - playlist_prev(playlist); - break; - case GDK_KP_6: - playlist_next(playlist); - break; - - case GDK_Escape: - mainwin_minimize_cb(); - break; - case GDK_Tab: - if (event->state & GDK_CONTROL_MASK) { - if (cfg.player_visible) - gtk_window_present(GTK_WINDOW(mainwin)); - else if (cfg.equalizer_visible) - gtk_window_present(GTK_WINDOW(equalizerwin)); - } - break; - case GDK_space: - cur_pos=playlist_get_position(playlist); - UI_SKINNED_PLAYLIST(playlistwin_list)->first = - cur_pos - (UI_SKINNED_PLAYLIST(playlistwin_list)->num_visible >> 1); - refresh = TRUE; - break; - default: - return FALSE; - } - - if (refresh) { - g_cond_signal(cond_scan); - playlistwin_update_list(playlist_get_active()); - } - - return TRUE; -} - -void -playlistwin_hide_timer(void) -{ - ui_skinned_textbox_set_text(playlistwin_time_min, " "); - ui_skinned_textbox_set_text(playlistwin_time_sec, " "); -} - -void -playlistwin_set_time(gint time, gint length, TimerMode mode) -{ - gchar *text, sign; - - if (mode == TIMER_REMAINING && length != -1) { - time = length - time; - sign = '-'; - } - else - sign = ' '; - - time /= 1000; - - if (time < 0) - time = 0; - if (time > 99 * 60) - time /= 60; - - text = g_strdup_printf("%c%-2.2d", sign, time / 60); - ui_skinned_textbox_set_text(playlistwin_time_min, text); - g_free(text); - - text = g_strdup_printf("%-2.2d", time % 60); - ui_skinned_textbox_set_text(playlistwin_time_sec, text); - g_free(text); -} - -static void -playlistwin_drag_motion(GtkWidget * widget, - GdkDragContext * context, - gint x, gint y, - GtkSelectionData * selection_data, - guint info, guint time, gpointer user_data) -{ - if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) { - UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion = TRUE; - UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion_x = x; - UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion_y = y; - } - playlistwin_update_list(playlist_get_active()); - playlistwin_hint_flag = TRUE; -} - -static void -playlistwin_drag_end(GtkWidget * widget, - GdkDragContext * context, gpointer user_data) -{ - if (UI_SKINNED_IS_PLAYLIST(playlistwin_list)) - UI_SKINNED_PLAYLIST(playlistwin_list)->drag_motion = FALSE; - playlistwin_hint_flag = FALSE; - playlistwin_update_list(playlist_get_active()); -} - -static void -playlistwin_drag_data_received(GtkWidget * widget, - GdkDragContext * context, - gint x, gint y, - GtkSelectionData * - selection_data, guint info, - guint time, gpointer user_data) -{ - gint pos; - Playlist *playlist = playlist_get_active(); - - g_return_if_fail(selection_data); - - if (!selection_data->data) { - g_message("Received no DND data!"); - return; - } - if (UI_SKINNED_IS_PLAYLIST(playlistwin_list) && - (x < playlistwin_get_width() - 20 || y < cfg.playlist_height - 38)) { - pos = y / UI_SKINNED_PLAYLIST(playlistwin_list)->fheight + UI_SKINNED_PLAYLIST(playlistwin_list)->first; - - pos = MIN(pos, playlist_get_length(playlist)); - playlist_ins_url(playlist, (gchar *) selection_data->data, pos); - } - else - playlist_add_url(playlist, (gchar *) selection_data->data); -} - -static void -local_playlist_prev(void) -{ - playlist_prev(playlist_get_active()); -} - -static void -local_playlist_next(void) -{ - playlist_next(playlist_get_active()); -} - -static void -playlistwin_create_widgets(void) -{ - /* This function creates the custom widgets used by the playlist editor */ - - /* text box for displaying song title in shaded mode */ - playlistwin_sinfo = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, - 4, 4, playlistwin_get_width() - 35, TRUE, SKIN_TEXT); - - playlistwin_set_sinfo_font(cfg.playlist_font); - - playlistwin_shade = ui_skinned_button_new(); - /* shade/unshade window push button */ - if (cfg.playlist_shaded) - ui_skinned_push_button_setup(playlistwin_shade, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 21, 3, - 9, 9, 128, 45, 150, 42, SKIN_PLEDIT); - else - ui_skinned_push_button_setup(playlistwin_shade, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 21, 3, - 9, 9, 157, 3, 62, 42, SKIN_PLEDIT); - - g_signal_connect(playlistwin_shade, "clicked", playlistwin_shade_toggle, NULL ); - - /* close window push button */ - playlistwin_close = ui_skinned_button_new(); - ui_skinned_push_button_setup(playlistwin_close, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 11, 3, 9, 9, - cfg.playlist_shaded ? 138 : 167, - cfg.playlist_shaded ? 45 : 3, 52, 42, SKIN_PLEDIT); - - g_signal_connect(playlistwin_close, "clicked", playlistwin_hide, NULL ); - - /* playlist list box */ - playlistwin_list = ui_skinned_playlist_new(SKINNED_WINDOW(playlistwin)->fixed, 12, 20, - playlistwin_get_width() - 31, - cfg.playlist_height - 58); - ui_skinned_playlist_set_font(cfg.playlist_font); - - /* playlist list box slider */ - playlistwin_slider = ui_skinned_playlist_slider_new(SKINNED_WINDOW(playlistwin)->fixed, playlistwin_get_width() - 15, - 20, cfg.playlist_height - 58); - - /* track time (minute) */ - playlistwin_time_min = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 82, - cfg.playlist_height - 15, 15, FALSE, SKIN_TEXT); - g_signal_connect(playlistwin_time_min, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); - - /* track time (second) */ - playlistwin_time_sec = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 64, - cfg.playlist_height - 15, 10, FALSE, SKIN_TEXT); - g_signal_connect(playlistwin_time_sec, "button-press-event", G_CALLBACK(change_timer_mode_cb), NULL); - - /* playlist information (current track length / total track length) */ - playlistwin_info = ui_skinned_textbox_new(SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 143, - cfg.playlist_height - 28, 90, FALSE, SKIN_TEXT); - - /* mini play control buttons at right bottom corner */ - - /* rewind button */ - playlistwin_srew = ui_skinned_button_new(); - ui_skinned_small_button_setup(playlistwin_srew, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 144, - cfg.playlist_height - 16, 8, 7); - g_signal_connect(playlistwin_srew, "clicked", local_playlist_prev, NULL); - - /* play button */ - playlistwin_splay = ui_skinned_button_new(); - ui_skinned_small_button_setup(playlistwin_splay, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 138, - cfg.playlist_height - 16, 10, 7); - g_signal_connect(playlistwin_splay, "clicked", mainwin_play_pushed, NULL); - - /* pause button */ - playlistwin_spause = ui_skinned_button_new(); - ui_skinned_small_button_setup(playlistwin_spause, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 128, - cfg.playlist_height - 16, 10, 7); - g_signal_connect(playlistwin_spause, "clicked", playback_pause, NULL); - - /* stop button */ - playlistwin_sstop = ui_skinned_button_new(); - ui_skinned_small_button_setup(playlistwin_sstop, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 118, - cfg.playlist_height - 16, 9, 7); - g_signal_connect(playlistwin_sstop, "clicked", mainwin_stop_pushed, NULL); - - /* forward button */ - playlistwin_sfwd = ui_skinned_button_new(); - ui_skinned_small_button_setup(playlistwin_sfwd, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 109, - cfg.playlist_height - 16, 8, 7); - g_signal_connect(playlistwin_sfwd, "clicked", local_playlist_next, NULL); - - /* eject button */ - playlistwin_seject = ui_skinned_button_new(); - ui_skinned_small_button_setup(playlistwin_seject, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 100, - cfg.playlist_height - 16, 9, 7); - g_signal_connect(playlistwin_seject, "clicked", mainwin_eject_pushed, NULL); - - playlistwin_sscroll_up = ui_skinned_button_new(); - ui_skinned_small_button_setup(playlistwin_sscroll_up, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 14, - cfg.playlist_height - 35, 8, 5); - g_signal_connect(playlistwin_sscroll_up, "clicked", playlistwin_scroll_up_pushed, NULL); - - playlistwin_sscroll_down = ui_skinned_button_new(); - ui_skinned_small_button_setup(playlistwin_sscroll_down, SKINNED_WINDOW(playlistwin)->fixed, - playlistwin_get_width() - 14, - cfg.playlist_height - 30, 8, 5); - g_signal_connect(playlistwin_sscroll_down, "clicked", playlistwin_scroll_down_pushed, NULL); - - ui_playlist_evlistener_init(); -} - -static void -selection_received(GtkWidget * widget, - GtkSelectionData * selection_data, gpointer data) -{ - if (selection_data->type == GDK_SELECTION_TYPE_STRING && - selection_data->length > 0) - playlist_add_url(playlist_get_active(), (gchar *) selection_data->data); -} - -static void -playlistwin_create_window(void) -{ - GdkPixbuf *icon; - - playlistwin = ui_skinned_window_new("playlist"); - gtk_window_set_title(GTK_WINDOW(playlistwin), _("Audacious Playlist Editor")); - gtk_window_set_role(GTK_WINDOW(playlistwin), "playlist"); - gtk_window_set_default_size(GTK_WINDOW(playlistwin), - playlistwin_get_width(), - playlistwin_get_height()); - gtk_window_set_resizable(GTK_WINDOW(playlistwin), TRUE); - playlistwin_set_geometry_hints(cfg.playlist_shaded); - - gtk_window_set_transient_for(GTK_WINDOW(playlistwin), - GTK_WINDOW(mainwin)); - gtk_window_set_skip_taskbar_hint(GTK_WINDOW(playlistwin), TRUE); - - icon = gdk_pixbuf_new_from_xpm_data((const gchar **) audacious_playlist_icon); - gtk_window_set_icon(GTK_WINDOW(playlistwin), icon); - g_object_unref(icon); - - if (cfg.playlist_x != -1 && cfg.save_window_position) - gtk_window_move(GTK_WINDOW(playlistwin), - cfg.playlist_x, cfg.playlist_y); - - gtk_widget_add_events(playlistwin, GDK_POINTER_MOTION_MASK | - GDK_FOCUS_CHANGE_MASK | GDK_BUTTON_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_SCROLL_MASK | GDK_VISIBILITY_NOTIFY_MASK); - gtk_widget_realize(playlistwin); - - g_signal_connect(playlistwin, "delete_event", - G_CALLBACK(playlistwin_delete), NULL); - g_signal_connect(playlistwin, "button_press_event", - G_CALLBACK(playlistwin_press), NULL); - g_signal_connect(playlistwin, "button_release_event", - G_CALLBACK(playlistwin_release), NULL); - g_signal_connect(playlistwin, "scroll_event", - G_CALLBACK(playlistwin_scrolled), NULL); - g_signal_connect(playlistwin, "motion_notify_event", - G_CALLBACK(playlistwin_motion), NULL); - - aud_drag_dest_set(playlistwin); - - /* DnD stuff */ - g_signal_connect(playlistwin, "drag-leave", - G_CALLBACK(playlistwin_drag_end), NULL); - g_signal_connect(playlistwin, "drag-data-delete", - G_CALLBACK(playlistwin_drag_end), NULL); - g_signal_connect(playlistwin, "drag-end", - G_CALLBACK(playlistwin_drag_end), NULL); - g_signal_connect(playlistwin, "drag-drop", - G_CALLBACK(playlistwin_drag_end), NULL); - g_signal_connect(playlistwin, "drag-data-received", - G_CALLBACK(playlistwin_drag_data_received), NULL); - g_signal_connect(playlistwin, "drag-motion", - G_CALLBACK(playlistwin_drag_motion), NULL); - - g_signal_connect(playlistwin, "key_press_event", - G_CALLBACK(playlistwin_keypress), NULL); - g_signal_connect(playlistwin, "selection_received", - G_CALLBACK(selection_received), NULL); -} - -void -playlistwin_create(void) -{ - resize_mutex = g_mutex_new(); - playlistwin_create_window(); - - playlistwin_create_widgets(); - playlistwin_update_info(playlist_get_active()); - - gtk_window_add_accel_group(GTK_WINDOW(playlistwin), ui_manager_get_accel_group()); -} - - -void -playlistwin_show(void) -{ - gtk_window_move(GTK_WINDOW(playlistwin), cfg.playlist_x, cfg.playlist_y); - GtkAction *action = gtk_action_group_get_action( - toggleaction_group_others , "show playlist editor" ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , TRUE ); - - cfg.playlist_visible = TRUE; - UI_SKINNED_BUTTON(mainwin_pl)->inside = TRUE; - gtk_widget_queue_draw(mainwin_pl); - - playlistwin_set_toprow(0); - playlist_check_pos_current(playlist_get_active()); - - gtk_widget_show_all(playlistwin); - if (!cfg.playlist_shaded) - gtk_widget_hide(playlistwin_sinfo); - gtk_window_present(GTK_WINDOW(playlistwin)); -} - -void -playlistwin_hide(void) -{ - GtkAction *action = gtk_action_group_get_action( - toggleaction_group_others , "show playlist editor" ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(action) , FALSE ); - - gtk_widget_hide(playlistwin); - cfg.playlist_visible = FALSE; - UI_SKINNED_BUTTON(mainwin_pl)->inside = FALSE; - gtk_widget_queue_draw(mainwin_pl); - - if ( cfg.player_visible ) - { - gtk_window_present(GTK_WINDOW(mainwin)); - gtk_widget_grab_focus(mainwin); - } -} - -void action_playlist_track_info(void) -{ - playlistwin_fileinfo(); -} - -void action_queue_toggle(void) -{ - playlist_queue(playlist_get_active()); -} - -void action_playlist_sort_by_playlist_entry(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort(playlist, PLAYLIST_SORT_PLAYLIST); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_by_track_number(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort(playlist, PLAYLIST_SORT_TRACK); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_by_title(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort(playlist, PLAYLIST_SORT_TITLE); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_by_artist(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort(playlist, PLAYLIST_SORT_ARTIST); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_by_full_path(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort(playlist, PLAYLIST_SORT_PATH); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_by_date(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort(playlist, PLAYLIST_SORT_DATE); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_by_filename(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort(playlist, PLAYLIST_SORT_FILENAME); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_selected_by_playlist_entry(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort_selected(playlist, PLAYLIST_SORT_PLAYLIST); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_selected_by_track_number(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort_selected(playlist, PLAYLIST_SORT_TRACK); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_selected_by_title(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort_selected(playlist, PLAYLIST_SORT_TITLE); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_selected_by_artist(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort_selected(playlist, PLAYLIST_SORT_ARTIST); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_selected_by_full_path(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort_selected(playlist, PLAYLIST_SORT_PATH); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_selected_by_date(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort_selected(playlist, PLAYLIST_SORT_DATE); - playlistwin_update_list(playlist); -} - -void action_playlist_sort_selected_by_filename(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_sort_selected(playlist, PLAYLIST_SORT_FILENAME); - playlistwin_update_list(playlist); -} - -void action_playlist_randomize_list(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_random(playlist); - playlistwin_update_list(playlist); -} - -void action_playlist_reverse_list(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_reverse(playlist); - playlistwin_update_list(playlist); -} - -void -action_playlist_clear_queue(void) -{ - playlist_clear_queue(playlist_get_active()); -} - -void -action_playlist_remove_unavailable(void) -{ - playlist_remove_dead_files(playlist_get_active()); -} - -void -action_playlist_remove_dupes_by_title(void) -{ - playlist_remove_duplicates(playlist_get_active(), PLAYLIST_DUPS_TITLE); -} - -void -action_playlist_remove_dupes_by_filename(void) -{ - playlist_remove_duplicates(playlist_get_active(), PLAYLIST_DUPS_FILENAME); -} - -void -action_playlist_remove_dupes_by_full_path(void) -{ - playlist_remove_duplicates(playlist_get_active(), PLAYLIST_DUPS_PATH); -} - -void -action_playlist_remove_all(void) -{ - playlist_clear(playlist_get_active()); - - /* XXX -- should this really be coupled here? -nenolod */ - mainwin_clear_song_info(); -} - -void -action_playlist_remove_selected(void) -{ - playlist_delete(playlist_get_active(), FALSE); -} - -void -action_playlist_remove_unselected(void) -{ - playlist_delete(playlist_get_active(), TRUE); -} - -void -action_playlist_add_files(void) -{ - run_filebrowser(FALSE); -} - -void -action_playlist_add_url(void) -{ - mainwin_show_add_url_window(); -} - -void -action_playlist_new( void ) -{ - Playlist *new_pl = playlist_new(); - playlist_add_playlist(new_pl); - playlist_select_playlist(new_pl); -} - -void -action_playlist_prev( void ) -{ - playlist_select_prev(); -} - -void -action_playlist_next( void ) -{ - playlist_select_next(); -} - -void -action_playlist_delete( void ) -{ - playlist_remove_playlist( playlist_get_active() ); -} - -void -action_playlist_save_list(void) -{ - Playlist *playlist = playlist_get_active(); - - playlistwin_select_playlist_to_save(playlist_get_current_name(playlist)); -} - -void -action_playlist_save_default_list(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_save(playlist, aud_paths[BMP_PATH_PLAYLIST_FILE]); -} - -void -action_playlist_load_list(void) -{ - Playlist *playlist = playlist_get_active(); - - playlistwin_select_playlist_to_load(playlist_get_current_name(playlist)); -} - -void -action_playlist_refresh_list(void) -{ - Playlist *playlist = playlist_get_active(); - - playlist_read_info_selection(playlist); - playlistwin_update_list(playlist); -} - -void -action_open_list_manager(void) -{ - playlist_manager_ui_show(); -} - -void -action_playlist_search_and_select(void) -{ - playlistwin_select_search(); -} - -void -action_playlist_invert_selection(void) -{ - playlistwin_inverse_selection(); -} - -void -action_playlist_select_none(void) -{ - playlistwin_select_none(); -} - -void -action_playlist_select_all(void) -{ - playlistwin_select_all(); -} - - -static void -playlistwin_select_search_cbt_cb(GtkWidget *called_cbt, gpointer other_cbt) -{ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(called_cbt)) == TRUE) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(other_cbt), FALSE); - return; -} - -static gboolean -playlistwin_select_search_kp_cb(GtkWidget *entry, GdkEventKey *event, - gpointer searchdlg_win) -{ - switch (event->keyval) - { - case GDK_Return: - if (gtk_im_context_filter_keypress (GTK_ENTRY (entry)->im_context, event)) { - GTK_ENTRY (entry)->need_im_reset = TRUE; - return TRUE; - } else { - gtk_dialog_response(GTK_DIALOG(searchdlg_win), GTK_RESPONSE_ACCEPT); - return TRUE; - } - default: - return FALSE; - } -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_playlist.h --- a/src/audacious/ui_playlist.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* 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. - */ - -#ifndef AUDACIOUS_UI_PLAYLIST_H -#define AUDACIOUS_UI_PLAYLIST_H - -#include - -#include "ui_main.h" -#include "playlist.h" - -#define PLAYLISTWIN_FRAME_TOP_HEIGHT 20 -#define PLAYLISTWIN_FRAME_BOTTOM_HEIGHT 38 -#define PLAYLISTWIN_FRAME_LEFT_WIDTH 12 -#define PLAYLISTWIN_FRAME_RIGHT_WIDTH 19 - -#define PLAYLISTWIN_MIN_WIDTH MAINWIN_WIDTH -#define PLAYLISTWIN_MIN_HEIGHT MAINWIN_HEIGHT -#define PLAYLISTWIN_WIDTH_SNAP 25 -#define PLAYLISTWIN_HEIGHT_SNAP 29 -#define PLAYLISTWIN_SHADED_HEIGHT MAINWIN_SHADED_HEIGHT -#define PLAYLISTWIN_WIDTH cfg.playlist_width -#define PLAYLISTWIN_HEIGHT \ - (cfg.playlist_shaded ? PLAYLISTWIN_SHADED_HEIGHT : cfg.playlist_height) - -#define PLAYLISTWIN_DEFAULT_WIDTH 275 -#define PLAYLISTWIN_DEFAULT_HEIGHT 232 -#define PLAYLISTWIN_DEFAULT_POS_X 295 -#define PLAYLISTWIN_DEFAULT_POS_Y 20 - -#define PLAYLISTWIN_DEFAULT_FONT "Sans Bold 8" - -gboolean playlistwin_is_shaded(void); -gint playlistwin_get_width(void); -gint playlistwin_get_height(void); -void playlistwin_update_list(Playlist *playlist); -gboolean playlistwin_item_visible(gint index); -gint playlistwin_get_toprow(void); -void playlistwin_set_toprow(gint top); -void playlistwin_set_shade_menu_cb(gboolean shaded); -void playlistwin_set_shade(gboolean shaded); -void playlistwin_shade_toggle(void); -void playlistwin_create(void); -void playlistwin_hide_timer(void); -void playlistwin_set_time(gint time, gint length, TimerMode mode); -void playlistwin_show(void); -void playlistwin_hide(void); -void playlistwin_scroll(gint num); -void playlistwin_scroll_up_pushed(void); -void playlistwin_scroll_down_pushed(void); -void playlistwin_select_playlist_to_load(const gchar * default_filename); -void playlistwin_set_sinfo_font(gchar *font); -void playlistwin_set_sinfo_scroll(gboolean scroll); -gint playlistwin_list_get_visible_count(void); -gint playlistwin_list_get_first(void); - -extern GtkWidget *playlistwin; - -extern gboolean playlistwin_focus; - -#endif /* AUDACIOUS_UI_PLAYLIST_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_playlist_evlisteners.c --- a/src/audacious/ui_playlist_evlisteners.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Audacious - * Copyright (c) 2006-2007 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 "ui_playlist_evlisteners.h" - -#include - -#include "hook.h" -#include "playlist.h" -#include "ui_playlist.h" -#include "ui_playlist_manager.h" - -static void -ui_playlist_evlistener_playlist_update(gpointer hook_data, gpointer user_data) -{ - Playlist *playlist = (Playlist *) hook_data; - if (playlist != NULL) - playlistwin_update_list(playlist); - - playlist_manager_update(); -} - -static void -ui_playlist_evlistener_playlistwin_show(gpointer hook_data, gpointer user_data) -{ - gboolean *show = (gboolean*)hook_data; - if (*show == TRUE) - playlistwin_show(); - else - playlistwin_hide(); -} - -void ui_playlist_evlistener_init(void) -{ - hook_associate("playlist update", ui_playlist_evlistener_playlist_update, NULL); - hook_associate("playlistwin show", ui_playlist_evlistener_playlistwin_show, NULL); -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_playlist_evlisteners.h --- a/src/audacious/ui_playlist_evlisteners.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Audacious - * Copyright (c) 2006-2007 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_PLAYLIST_EVLISTENERS_H -#define AUDACIOUS_UI_PLAYLIST_EVLISTENERS_H - -void ui_playlist_evlistener_init(void); - -#endif /* AUDACIOUS_UI_PLAYLIST_EVLISTENERS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_playlist_manager.c --- a/src/audacious/ui_playlist_manager.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,498 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2007 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 "ui_playlist_manager.h" -#include "ui_playlist.h" -#include "playlist.h" -#include "ui_main.h" - -#include -#include -#include -#include - - -#define DISABLE_MANAGER_UPDATE() g_object_set_data(G_OBJECT(listview),"opt1",GINT_TO_POINTER(1)) -#define ENABLE_MANAGER_UPDATE() g_object_set_data(G_OBJECT(listview),"opt1",GINT_TO_POINTER(0)) - - -static GtkWidget *playman_win = NULL; - - -/* in this enum, place the columns according to visualization order - (information not displayed in columns should be placed right before PLLIST_NUMCOLS) */ -enum -{ - PLLIST_COL_NAME = 0, - PLLIST_COL_ENTRIESNUM, - PLLIST_PLPOINTER, - PLLIST_TEXT_WEIGHT, - PLLIST_NUMCOLS -}; - - -static GtkTreeIter -playlist_manager_populate ( GtkListStore * store ) -{ - GList *playlists = NULL; - Playlist *active, *iter_playlist, *next_playlist; - GtkTreeIter iter, insert, next, active_iter; - gboolean valid, have_active_iter; - - active = playlist_get_active(); - playlists = playlist_get_playlists(); - valid = gtk_tree_model_get_iter_first( GTK_TREE_MODEL(store) , &iter ); - have_active_iter = FALSE; - while ( playlists != NULL ) - { - GList *entries = NULL; - gint entriesnum = 0; - gchar *pl_name = NULL; - Playlist *playlist = (Playlist*)playlists->data; - - if(playlist != active) //XXX the active playlist has been locked in playlist_new_from_selected() - PLAYLIST_LOCK(playlist); - - /* for each playlist, pick name and number of entries */ - pl_name = (gchar*)playlist_get_current_name( playlist ); - for (entries = playlist->entries; entries; entries = g_list_next(entries)) - entriesnum++; - - if(playlist != active) - PLAYLIST_UNLOCK(playlist); - - /* update the tree model conservatively */ - - if ( !valid ) - { - /* append */ - gtk_list_store_append( store , &insert ); - goto store_set; - } - - gtk_tree_model_get( GTK_TREE_MODEL(store) , &iter , - PLLIST_PLPOINTER , &iter_playlist , -1 ); - - if ( playlist == iter_playlist ) - { - /* already have - just update */ - insert = iter; - valid = gtk_tree_model_iter_next( GTK_TREE_MODEL(store) , &iter ); - goto store_set; - } - - /* handle movement/deletion/insertion of single elements */ - if ( gtk_tree_model_iter_next( GTK_TREE_MODEL(store) , &next ) ) - { - gtk_tree_model_get( GTK_TREE_MODEL(store) , &next , - PLLIST_PLPOINTER , &next_playlist , -1 ); - if ( playlist == next_playlist ) - { - /* remove */ - gtk_list_store_remove( store , &iter ); - iter = next; - valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter); - goto next_playlist; - } - } - - /* insert */ - gtk_list_store_insert_before( store , &insert , &iter ); - -store_set: - gtk_list_store_set( store, &insert, - PLLIST_COL_NAME , pl_name , - PLLIST_COL_ENTRIESNUM , entriesnum , - PLLIST_PLPOINTER , playlist , - PLLIST_TEXT_WEIGHT , playlist == active ? - PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL , - -1 ); - if ( !have_active_iter && playlist == active ) - { - active_iter = insert; - have_active_iter = TRUE; - } - -next_playlist: - playlists = g_list_next(playlists); - } - - while (valid) - { - /* remove any other elements */ - next = iter; - valid = gtk_tree_model_iter_next( GTK_TREE_MODEL(store) , &next ); - gtk_list_store_remove( store , &iter ); - iter = next; - } - - if ( !have_active_iter ) - gtk_tree_model_get_iter_first( GTK_TREE_MODEL(store) , &active_iter ); - - return active_iter; -} - - -static void -playlist_manager_cb_new ( gpointer listview ) -{ - GList *playlists = NULL; - Playlist *newpl = NULL; - GtkTreeIter iter; - GtkListStore *store; - gchar *pl_name = NULL; - - /* this ensures that playlist_manager_update() will - not perform update, since we're already doing it here */ - DISABLE_MANAGER_UPDATE(); - - newpl = playlist_new(); - pl_name = (gchar*)playlist_get_current_name( newpl ); - playlists = playlist_get_playlists(); - playlist_add_playlist( newpl ); - - store = (GtkListStore*)gtk_tree_view_get_model( GTK_TREE_VIEW(listview) ); - gtk_list_store_append( store , &iter ); - gtk_list_store_set( store, &iter, - PLLIST_COL_NAME , pl_name , - PLLIST_COL_ENTRIESNUM , 0 , - PLLIST_PLPOINTER , newpl , - PLLIST_TEXT_WEIGHT , PANGO_WEIGHT_NORMAL , - -1 ); - - ENABLE_MANAGER_UPDATE(); - - return; -} - - -static void -playlist_manager_cb_del ( gpointer listview ) -{ - GtkTreeSelection *listsel = gtk_tree_view_get_selection( GTK_TREE_VIEW(listview) ); - GtkTreeModel *store; - GtkTreeIter iter; - Playlist *active; - gboolean was_active; - - if ( gtk_tree_selection_get_selected( listsel , &store , &iter ) == TRUE ) - { - Playlist *playlist = NULL; - gtk_tree_model_get( store, &iter, PLLIST_PLPOINTER , &playlist , -1 ); - - active = playlist_get_active(); - was_active = ( playlist == active ); - - if ( gtk_tree_model_iter_n_children( store , NULL ) < 2 ) - { - /* let playlist_manager_update() handle the deletion of the last playlist */ - playlist_remove_playlist( playlist ); - } - else - { - gtk_list_store_remove( (GtkListStore*)store , &iter ); - /* this ensures that playlist_manager_update() will - not perform update, since we're already doing it here */ - DISABLE_MANAGER_UPDATE(); - playlist_remove_playlist( playlist ); - ENABLE_MANAGER_UPDATE(); - } - - if ( was_active && gtk_tree_model_get_iter_first( store , &iter ) ) - { - /* update bolded playlist */ - active = playlist_get_active(); - do { - gtk_tree_model_get( store , &iter , - PLLIST_PLPOINTER , &playlist , -1 ); - gtk_list_store_set( GTK_LIST_STORE(store) , &iter , - PLLIST_TEXT_WEIGHT , playlist == active ? - PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL , - -1 ); - } while ( gtk_tree_model_iter_next( store , &iter ) ); - } - } - - return; -} - - -static void -playlist_manager_cb_lv_dclick ( GtkTreeView * listview , GtkTreePath * path , - GtkTreeViewColumn * col , gpointer userdata ) -{ - GtkTreeModel *store; - GtkTreeIter iter; - Playlist *playlist = NULL, *active; - - store = gtk_tree_view_get_model( GTK_TREE_VIEW(listview) ); - if ( gtk_tree_model_get_iter( store , &iter , path ) == TRUE ) - { - gtk_tree_model_get( store , &iter , PLLIST_PLPOINTER , &playlist , -1 ); - DISABLE_MANAGER_UPDATE(); - playlist_select_playlist( playlist ); - ENABLE_MANAGER_UPDATE(); - } - - if ( gtk_tree_model_get_iter_first( store , &iter ) ) - { - /* update bolded playlist */ - active = playlist_get_active(); - do { - gtk_tree_model_get( store , &iter , - PLLIST_PLPOINTER , &playlist , -1 ); - gtk_list_store_set( GTK_LIST_STORE(store) , &iter , - PLLIST_TEXT_WEIGHT , playlist == active ? - PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL , - -1 ); - } while ( gtk_tree_model_iter_next( store , &iter ) ); - } - - return; -} - - -static void -playlist_manager_cb_lv_pmenu_rename ( GtkMenuItem *menuitem , gpointer lv ) -{ - GtkTreeSelection *listsel = gtk_tree_view_get_selection( GTK_TREE_VIEW(lv) ); - GtkTreeModel *store; - GtkTreeIter iter; - - if ( gtk_tree_selection_get_selected( listsel , &store , &iter ) == TRUE ) - { - GtkTreePath *path = gtk_tree_model_get_path( GTK_TREE_MODEL(store) , &iter ); - GtkCellRenderer *rndrname = g_object_get_data( G_OBJECT(lv) , "rn" ); - /* set the name renderer to editable and start editing */ - g_object_set( G_OBJECT(rndrname) , "editable" , TRUE , NULL ); - gtk_tree_view_set_cursor_on_cell( GTK_TREE_VIEW(lv) , path , - gtk_tree_view_get_column( GTK_TREE_VIEW(lv) , PLLIST_COL_NAME ) , rndrname , TRUE ); - gtk_tree_path_free( path ); - } -} - -static void -playlist_manager_cb_lv_name_edited ( GtkCellRendererText *cell , gchar *path_string , - gchar *new_text , gpointer listview ) -{ - /* this is currently used to change playlist names */ - GtkTreeModel *store = gtk_tree_view_get_model( GTK_TREE_VIEW(listview) ); - GtkTreeIter iter; - - if ( gtk_tree_model_get_iter_from_string( store , &iter , path_string ) == TRUE ) - { - Playlist *playlist = NULL; - gtk_tree_model_get( GTK_TREE_MODEL(store), &iter, PLLIST_PLPOINTER , &playlist , -1 ); - DISABLE_MANAGER_UPDATE(); - playlist_set_current_name( playlist , new_text ); - ENABLE_MANAGER_UPDATE(); - gtk_list_store_set( GTK_LIST_STORE(store), &iter, PLLIST_COL_NAME , new_text , -1 ); - } - /* set the renderer uneditable again */ - g_object_set( G_OBJECT(cell) , "editable" , FALSE , NULL ); -} - - -static gboolean -playlist_manager_cb_lv_btpress ( GtkWidget *lv , GdkEventButton *event ) -{ - if (( event->type == GDK_BUTTON_PRESS ) && ( event->button == 3 )) - { - GtkWidget *pmenu = (GtkWidget*)g_object_get_data( G_OBJECT(lv) , "menu" ); - gtk_menu_popup( GTK_MENU(pmenu) , NULL , NULL , NULL , NULL , - (event != NULL) ? event->button : 0, - event->time); - return TRUE; - } - - return FALSE; -} - - -static gboolean -playlist_manager_cb_keypress ( GtkWidget *win , GdkEventKey *event ) -{ - switch (event->keyval) - { - case GDK_Escape: - gtk_widget_destroy( playman_win ); - return TRUE; - default: - return FALSE; - } -} - - -void -playlist_manager_ui_show ( void ) -{ - GtkWidget *playman_vbox; - GtkWidget *playman_pl_lv, *playman_pl_lv_frame, *playman_pl_lv_sw; - GtkCellRenderer *playman_pl_lv_textrndr_name, *playman_pl_lv_textrndr_entriesnum; - GtkTreeViewColumn *playman_pl_lv_col_name, *playman_pl_lv_col_entriesnum; - GtkListStore *pl_store; - GtkWidget *playman_pl_lv_pmenu, *playman_pl_lv_pmenu_rename; - GtkWidget *playman_bbar_hbbox; - GtkWidget *playman_bbar_bt_new, *playman_bbar_bt_del, *playman_bbar_bt_close; - GdkGeometry playman_win_hints; - GtkTreeIter active_iter; - GtkTreePath *active_path; - - if ( playman_win != NULL ) - { - gtk_window_present( GTK_WINDOW(playman_win) ); - return; - } - - playman_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); - gtk_window_set_type_hint( GTK_WINDOW(playman_win), GDK_WINDOW_TYPE_HINT_DIALOG ); - gtk_window_set_transient_for( GTK_WINDOW(playman_win) , GTK_WINDOW(mainwin) ); - gtk_window_set_position( GTK_WINDOW(playman_win), GTK_WIN_POS_CENTER ); - gtk_window_set_title( GTK_WINDOW(playman_win), _("Playlist Manager") ); - gtk_container_set_border_width( GTK_CONTAINER(playman_win), 10 ); - g_signal_connect( G_OBJECT(playman_win) , "destroy" , - G_CALLBACK(gtk_widget_destroyed) , &playman_win ); - g_signal_connect( G_OBJECT(playman_win) , "key-press-event" , - G_CALLBACK(playlist_manager_cb_keypress) , NULL ); - playman_win_hints.min_width = 400; - playman_win_hints.min_height = 250; - gtk_window_set_geometry_hints( GTK_WINDOW(playman_win) , GTK_WIDGET(playman_win) , - &playman_win_hints , GDK_HINT_MIN_SIZE ); - - playman_vbox = gtk_vbox_new( FALSE , 10 ); - gtk_container_add( GTK_CONTAINER(playman_win) , playman_vbox ); - - /* current liststore model - ---------------------------------------------- - G_TYPE_STRING -> playlist name - G_TYPE_UINT -> number of entries in playlist - G_TYPE_POINTER -> playlist pointer (Playlist*) - PANGO_TYPE_WEIGHT -> font weight - ---------------------------------------------- - */ - pl_store = gtk_list_store_new( PLLIST_NUMCOLS , - G_TYPE_STRING , G_TYPE_UINT , G_TYPE_POINTER , PANGO_TYPE_WEIGHT ); - active_iter = playlist_manager_populate( pl_store ); - - playman_pl_lv_frame = gtk_frame_new( NULL ); - playman_pl_lv = gtk_tree_view_new_with_model( GTK_TREE_MODEL(pl_store) ); - - g_object_set_data( G_OBJECT(playman_win) , "lv" , playman_pl_lv ); - g_object_set_data( G_OBJECT(playman_pl_lv) , "opt1" , GINT_TO_POINTER(0) ); - playman_pl_lv_textrndr_entriesnum = gtk_cell_renderer_text_new(); /* uneditable */ - playman_pl_lv_textrndr_name = gtk_cell_renderer_text_new(); /* can become editable */ - g_object_set( G_OBJECT(playman_pl_lv_textrndr_entriesnum) , "weight-set" , TRUE , NULL ); - g_object_set( G_OBJECT(playman_pl_lv_textrndr_name) , "weight-set" , TRUE , NULL ); - g_signal_connect( G_OBJECT(playman_pl_lv_textrndr_name) , "edited" , - G_CALLBACK(playlist_manager_cb_lv_name_edited) , playman_pl_lv ); - g_object_set_data( G_OBJECT(playman_pl_lv) , "rn" , playman_pl_lv_textrndr_name ); - playman_pl_lv_col_name = gtk_tree_view_column_new_with_attributes( - _("Playlist") , playman_pl_lv_textrndr_name , - "text" , PLLIST_COL_NAME , - "weight", PLLIST_TEXT_WEIGHT , - NULL ); - gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(playman_pl_lv_col_name) , TRUE ); - gtk_tree_view_append_column( GTK_TREE_VIEW(playman_pl_lv), playman_pl_lv_col_name ); - playman_pl_lv_col_entriesnum = gtk_tree_view_column_new_with_attributes( - _("Entries") , playman_pl_lv_textrndr_entriesnum , - "text" , PLLIST_COL_ENTRIESNUM , - "weight", PLLIST_TEXT_WEIGHT , - NULL ); - gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(playman_pl_lv_col_entriesnum) , FALSE ); - gtk_tree_view_append_column( GTK_TREE_VIEW(playman_pl_lv), playman_pl_lv_col_entriesnum ); - playman_pl_lv_sw = gtk_scrolled_window_new( NULL , NULL ); - gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(playman_pl_lv_sw) , - GTK_POLICY_NEVER , GTK_POLICY_ALWAYS ); - gtk_container_add( GTK_CONTAINER(playman_pl_lv_sw) , playman_pl_lv ); - gtk_container_add( GTK_CONTAINER(playman_pl_lv_frame) , playman_pl_lv_sw ); - gtk_box_pack_start( GTK_BOX(playman_vbox) , playman_pl_lv_frame , TRUE , TRUE , 0 ); - - /* listview popup menu */ - playman_pl_lv_pmenu = gtk_menu_new(); - playman_pl_lv_pmenu_rename = gtk_menu_item_new_with_mnemonic( _( "_Rename" ) ); - g_signal_connect( G_OBJECT(playman_pl_lv_pmenu_rename) , "activate" , - G_CALLBACK(playlist_manager_cb_lv_pmenu_rename) , playman_pl_lv ); - gtk_menu_shell_append( GTK_MENU_SHELL(playman_pl_lv_pmenu) , playman_pl_lv_pmenu_rename ); - gtk_widget_show_all( playman_pl_lv_pmenu ); - g_object_set_data( G_OBJECT(playman_pl_lv) , "menu" , playman_pl_lv_pmenu ); - g_signal_connect_swapped( G_OBJECT(playman_win) , "destroy" , - G_CALLBACK(gtk_widget_destroy) , playman_pl_lv_pmenu ); - - /* button bar */ - playman_bbar_hbbox = gtk_hbutton_box_new(); - gtk_button_box_set_layout( GTK_BUTTON_BOX(playman_bbar_hbbox) , GTK_BUTTONBOX_END ); - gtk_button_box_set_spacing(GTK_BUTTON_BOX(playman_bbar_hbbox), 5); - playman_bbar_bt_close = gtk_button_new_from_stock( GTK_STOCK_CLOSE ); - playman_bbar_bt_del = gtk_button_new_from_stock( GTK_STOCK_DELETE ); - playman_bbar_bt_new = gtk_button_new_from_stock( GTK_STOCK_NEW ); - gtk_container_add( GTK_CONTAINER(playman_bbar_hbbox) , playman_bbar_bt_close ); - gtk_container_add( GTK_CONTAINER(playman_bbar_hbbox) , playman_bbar_bt_del ); - gtk_container_add( GTK_CONTAINER(playman_bbar_hbbox) , playman_bbar_bt_new ); - gtk_button_box_set_child_secondary( GTK_BUTTON_BOX(playman_bbar_hbbox) , - playman_bbar_bt_close , TRUE ); - gtk_box_pack_start( GTK_BOX(playman_vbox) , playman_bbar_hbbox , FALSE , FALSE , 0 ); - - g_signal_connect( G_OBJECT(playman_pl_lv) , "button-press-event" , - G_CALLBACK(playlist_manager_cb_lv_btpress) , NULL ); - g_signal_connect( G_OBJECT(playman_pl_lv) , "row-activated" , - G_CALLBACK(playlist_manager_cb_lv_dclick) , NULL ); - g_signal_connect_swapped( G_OBJECT(playman_bbar_bt_new) , "clicked" , - G_CALLBACK(playlist_manager_cb_new) , playman_pl_lv ); - g_signal_connect_swapped( G_OBJECT(playman_bbar_bt_del) , "clicked" , - G_CALLBACK(playlist_manager_cb_del) , playman_pl_lv ); - g_signal_connect_swapped( G_OBJECT(playman_bbar_bt_close) , "clicked" , - G_CALLBACK(gtk_widget_destroy) , playman_win ); - - /* have active playlist selected and scrolled to */ - active_path = gtk_tree_model_get_path( GTK_TREE_MODEL(pl_store) , - &active_iter ); - gtk_tree_view_set_cursor( GTK_TREE_VIEW(playman_pl_lv) , - active_path , NULL , FALSE ); - gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW(playman_pl_lv) , - active_path , NULL , TRUE , 0.5 , 0.0 ); - gtk_tree_path_free( active_path ); - - g_object_unref( pl_store ); - - gtk_widget_show_all( playman_win ); -} - - -void -playlist_manager_update ( void ) -{ - /* this function is called whenever there is a change in playlist, such as - playlist created/deleted or entry added/deleted in a playlist; if the playlist - manager is active, it should be updated to keep consistency of information */ - - /* CAREFUL! this currently locks/unlocks all the playlists */ - - if ( playman_win != NULL ) - { - GtkWidget *lv = (GtkWidget*)g_object_get_data( G_OBJECT(playman_win) , "lv" ); - if ( GPOINTER_TO_INT(g_object_get_data(G_OBJECT(lv),"opt1")) == 0 ) - { - GtkListStore *store = (GtkListStore*)gtk_tree_view_get_model( GTK_TREE_VIEW(lv) ); - playlist_manager_populate( store ); - } - return; - } - else - return; /* if the playlist manager is not active, simply return */ -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_playlist_manager.h --- a/src/audacious/ui_playlist_manager.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2007 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_PLAYLIST_MANAGER_H -#define AUDACIOUS_UI_PLAYLIST_MANAGER_H - -void playlist_manager_update ( void ); -void playlist_manager_ui_show ( void ); - -#endif /* AUDACIOUS_UI_PLAYLIST_MANAGER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_preferences.c --- a/src/audacious/ui_preferences.c Sun Jul 06 13:55:23 2008 +0200 +++ b/src/audacious/ui_preferences.c Sun Jul 06 17:55:40 2008 +0200 @@ -46,20 +46,20 @@ #include "visualization.h" #include "playlist.h" -#include "ui_skinned_textbox.h" #include "strings.h" #include "util.h" #include "dnd.h" #include "configdb.h" #include "preferences.h" -#include "ui_main.h" -#include "ui_playlist.h" -#include "ui_skinselector.h" +#include "legacy/ui_main.h" +#include "legacy/ui_playlist.h" +#include "legacy/ui_skinselector.h" #include "ui_preferences.h" -#include "ui_equalizer.h" -#include "ui_skinned_playlist.h" -#include "ui_skinned_window.h" +#include "legacy/ui_equalizer.h" +#include "legacy/ui_skinned_playlist.h" +#include "legacy/ui_skinned_textbox.h" +#include "legacy/ui_skinned_window.h" #include "build_stamp.h" diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skin.c --- a/src/audacious/ui_skin.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2048 +0,0 @@ -/* Audacious - * Copyright (C) 2005-2007 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. - */ - -/*#define AUD_DEBUG*/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -/* TODO: enforce default sizes! */ - -#include -#include -#include -#include -#include - -#include "ui_skin.h" -#include "ui_equalizer.h" -#include "main.h" -#include "ui_playlist.h" -#include "ui_skinselector.h" -#include "util.h" - -#include "debug.h" - -#include "platform/smartinclude.h" -#include "vfs.h" - -#include "ui_skinned_window.h" -#include "ui_skinned_button.h" -#include "ui_skinned_number.h" -#include "ui_skinned_horizontal_slider.h" -#include "ui_skinned_playstatus.h" - -#define EXTENSION_TARGETS 7 - -static gchar *ext_targets[EXTENSION_TARGETS] = -{ "bmp", "xpm", "png", "svg", "gif", "jpg", "jpeg" }; - -struct _SkinPixmapIdMapping { - SkinPixmapId id; - const gchar *name; - const gchar *alt_name; - gint width, height; -}; - -struct _SkinMaskInfo { - gint width, height; - gchar *inistr; -}; - -typedef struct _SkinPixmapIdMapping SkinPixmapIdMapping; -typedef struct _SkinMaskInfo SkinMaskInfo; - - -Skin *aud_active_skin = NULL; - -static gint skin_current_num; - -static SkinMaskInfo skin_mask_info[] = { - {275, 116, "Normal"}, - {275, 16, "WindowShade"}, - {275, 116, "Equalizer"}, - {275, 16, "EqualizerWS"} -}; - -static SkinPixmapIdMapping skin_pixmap_id_map[] = { - {SKIN_MAIN, "main", NULL, 0, 0}, - {SKIN_CBUTTONS, "cbuttons", NULL, 0, 0}, - {SKIN_SHUFREP, "shufrep", NULL, 0, 0}, - {SKIN_TEXT, "text", NULL, 0, 0}, - {SKIN_TITLEBAR, "titlebar", NULL, 0, 0}, - {SKIN_VOLUME, "volume", NULL, 0, 0}, - {SKIN_BALANCE, "balance", "volume", 0, 0}, - {SKIN_MONOSTEREO, "monoster", NULL, 0, 0}, - {SKIN_PLAYPAUSE, "playpaus", NULL, 0, 0}, - {SKIN_NUMBERS, "nums_ex", "numbers", 0, 0}, - {SKIN_POSBAR, "posbar", NULL, 0, 0}, - {SKIN_EQMAIN, "eqmain", NULL, 0, 0}, - {SKIN_PLEDIT, "pledit", NULL, 0, 0}, - {SKIN_EQ_EX, "eq_ex", NULL, 0, 0} -}; - -static guint skin_pixmap_id_map_size = G_N_ELEMENTS(skin_pixmap_id_map); - -static const guchar skin_default_viscolor[24][3] = { - {9, 34, 53}, - {10, 18, 26}, - {0, 54, 108}, - {0, 58, 116}, - {0, 62, 124}, - {0, 66, 132}, - {0, 70, 140}, - {0, 74, 148}, - {0, 78, 156}, - {0, 82, 164}, - {0, 86, 172}, - {0, 92, 184}, - {0, 98, 196}, - {0, 104, 208}, - {0, 110, 220}, - {0, 116, 232}, - {0, 122, 244}, - {0, 128, 255}, - {0, 128, 255}, - {0, 104, 208}, - {0, 80, 160}, - {0, 56, 112}, - {0, 32, 64}, - {200, 200, 200} -}; - -static gchar *original_gtk_theme = NULL; - -static GdkBitmap *skin_create_transparent_mask(const gchar *, - const gchar *, - const gchar *, - GdkWindow *, - gint, gint, gboolean); - -static void skin_set_default_vis_color(Skin * skin); - -void -skin_lock(Skin * skin) -{ - g_mutex_lock(skin->lock); -} - -void -skin_unlock(Skin * skin) -{ - g_mutex_unlock(skin->lock); -} - -gboolean -aud_active_skin_reload(void) -{ - AUDDBG("\n"); - return aud_active_skin_load(aud_active_skin->path); -} - -gboolean -aud_active_skin_load(const gchar * path) -{ - AUDDBG("%s\n", path); - g_return_val_if_fail(aud_active_skin != NULL, FALSE); - - if (!skin_load(aud_active_skin, path)) { - AUDDBG("loading failed\n"); - return FALSE; - } - - ui_skinned_window_draw_all(mainwin); - ui_skinned_window_draw_all(equalizerwin); - ui_skinned_window_draw_all(playlistwin); - - playlistwin_update_list(playlist_get_active()); - - SkinPixmap *pixmap; - pixmap = &aud_active_skin->pixmaps[SKIN_POSBAR]; - /* last 59 pixels of SKIN_POSBAR are knobs (normal and selected) */ - gtk_widget_set_size_request(mainwin_position, pixmap->width - 59, pixmap->height); - - return TRUE; -} - -void -skin_pixmap_free(SkinPixmap * p) -{ - g_return_if_fail(p != NULL); - g_return_if_fail(p->pixbuf != NULL); - - g_object_unref(p->pixbuf); - p->pixbuf = NULL; -} - -Skin * -skin_new(void) -{ - Skin *skin; - skin = g_new0(Skin, 1); - skin->lock = g_mutex_new(); - return skin; -} - -/** - * Frees the data associated for skin. - * - * Does not free skin itself or lock variable so that the skin can immediately - * populated with new skin data if needed. - */ -void -skin_free(Skin * skin) -{ - gint i; - - g_return_if_fail(skin != NULL); - - for (i = 0; i < SKIN_PIXMAP_COUNT; i++) - skin_pixmap_free(&skin->pixmaps[i]); - - for (i = 0; i < SKIN_MASK_COUNT; i++) { - if (skin->masks[i]) - g_object_unref(skin->masks[i]); - if (skin->scaled_masks[i]) - g_object_unref(skin->scaled_masks[i]); - - skin->masks[i] = NULL; - skin->scaled_masks[i] = NULL; - } - - for (i = 0; i < SKIN_COLOR_COUNT; i++) { - if (skin->colors[i]) - g_free(skin->colors[i]); - - skin->colors[i] = NULL; - } - - g_free(skin->path); - skin->path = NULL; - - skin_set_default_vis_color(skin); -} - -void -skin_destroy(Skin * skin) -{ - g_return_if_fail(skin != NULL); - skin_free(skin); - g_mutex_free(skin->lock); - g_free(skin); -} - -const SkinPixmapIdMapping * -skin_pixmap_id_lookup(guint id) -{ - guint i; - - for (i = 0; i < skin_pixmap_id_map_size; i++) { - if (id == skin_pixmap_id_map[i].id) { - return &skin_pixmap_id_map[i]; - } - } - - return NULL; -} - -const gchar * -skin_pixmap_id_to_name(SkinPixmapId id) -{ - guint i; - - for (i = 0; i < skin_pixmap_id_map_size; i++) { - if (id == skin_pixmap_id_map[i].id) - return skin_pixmap_id_map[i].name; - } - return NULL; -} - -static void -skin_set_default_vis_color(Skin * skin) -{ - memcpy(skin->vis_color, skin_default_viscolor, - sizeof(skin_default_viscolor)); -} - -/* - * I have rewritten this to take an array of possible targets, - * once we find a matching target we now return, instead of loop - * recursively. This allows for us to support many possible format - * targets for our skinning engine than just the original winamp - * formats. - * - * -- nenolod, 16 January 2006 - */ -gchar * -skin_pixmap_locate(const gchar * dirname, gchar ** basenames) -{ - gchar *filename; - gint i; - - for (i = 0; basenames[i]; i++) - if (!(filename = find_path_recursively(dirname, basenames[i]))) - g_free(filename); - else - return filename; - - /* can't find any targets -- sorry */ - return NULL; -} - -/** - * Creates possible file names for a pixmap. - * - * Basically this makes list of all possible file names that pixmap data - * can be found from by using the static ext_targets variable to get all - * possible extensions that pixmap file might have. - */ -static gchar ** -skin_pixmap_create_basenames(const SkinPixmapIdMapping * pixmap_id_mapping) -{ - gchar **basenames = g_malloc0(sizeof(gchar*) * (EXTENSION_TARGETS * 2 + 1)); - gint i, y; - - // Create list of all possible image formats that can be loaded - for (i = 0, y = 0; i < EXTENSION_TARGETS; i++, y++) - { - basenames[y] = - g_strdup_printf("%s.%s", pixmap_id_mapping->name, ext_targets[i]); - - if (pixmap_id_mapping->alt_name) - basenames[++y] = - g_strdup_printf("%s.%s", pixmap_id_mapping->alt_name, - ext_targets[i]); - } - - return basenames; -} - -/** - * Frees the data allocated by skin_pixmap_create_basenames - */ -static void -skin_pixmap_free_basenames(gchar ** basenames) -{ - int i; - for (i = 0; basenames[i] != NULL; i++) - { - g_free(basenames[i]); - basenames[i] = NULL; - } - g_free(basenames); -} - -/** - * Locates a pixmap file for skin. - */ -static gchar * -skin_pixmap_locate_basenames(const Skin * skin, - const SkinPixmapIdMapping * pixmap_id_mapping, - const gchar * path_p) -{ - gchar *filename = NULL; - const gchar *path = path_p ? path_p : skin->path; - gchar **basenames = skin_pixmap_create_basenames(pixmap_id_mapping); - - filename = skin_pixmap_locate(path, basenames); - - skin_pixmap_free_basenames(basenames); - - return filename; -} - - -static gboolean -skin_load_pixmap_id(Skin * skin, SkinPixmapId id, const gchar * path_p) -{ - const SkinPixmapIdMapping *pixmap_id_mapping; - gchar *filename; - SkinPixmap *pm = NULL; - - g_return_val_if_fail(skin != NULL, FALSE); - g_return_val_if_fail(id < SKIN_PIXMAP_COUNT, FALSE); - - pixmap_id_mapping = skin_pixmap_id_lookup(id); - g_return_val_if_fail(pixmap_id_mapping != NULL, FALSE); - - filename = skin_pixmap_locate_basenames(skin, pixmap_id_mapping, path_p); - - if (filename == NULL) - return FALSE; - - AUDDBG("loaded %s\n", filename); - - pm = &skin->pixmaps[id]; - GdkPixbuf *pix = gdk_pixbuf_new_from_file(filename, NULL); - pm->pixbuf = audacious_create_colorized_pixbuf(pix, cfg.colorize_r, cfg.colorize_g, cfg.colorize_b); - g_object_unref(pix); - pm->width = gdk_pixbuf_get_width(pm->pixbuf); - pm->height = gdk_pixbuf_get_height(pm->pixbuf); - pm->current_width = pm->width; - pm->current_height = pm->height; - - g_free(filename); - - return TRUE; -} - -void -skin_mask_create(Skin * skin, - const gchar * path, - gint id, - GdkWindow * window) -{ - skin->masks[id] = - skin_create_transparent_mask(path, "region.txt", - skin_mask_info[id].inistr, window, - skin_mask_info[id].width, - skin_mask_info[id].height, FALSE); - - skin->scaled_masks[id] = - skin_create_transparent_mask(path, "region.txt", - skin_mask_info[id].inistr, window, - skin_mask_info[id].width * 2, - skin_mask_info[id].height * 2, TRUE); -} - -static GdkBitmap * -create_default_mask(GdkWindow * parent, gint w, gint h) -{ - GdkBitmap *ret; - GdkGC *gc; - GdkColor pattern; - - ret = gdk_pixmap_new(parent, w, h, 1); - gc = gdk_gc_new(ret); - pattern.pixel = 1; - gdk_gc_set_foreground(gc, &pattern); - gdk_draw_rectangle(ret, gc, TRUE, 0, 0, w, h); - g_object_unref(gc); - - return ret; -} - -static void -skin_query_color(GdkColormap * cm, GdkColor * c) -{ -#ifdef GDK_WINDOWING_X11 - XColor xc = { 0,0,0,0,0,0 }; - - xc.pixel = c->pixel; - XQueryColor(GDK_COLORMAP_XDISPLAY(cm), GDK_COLORMAP_XCOLORMAP(cm), &xc); - c->red = xc.red; - c->green = xc.green; - c->blue = xc.blue; -#else - /* do nothing. see what breaks? */ -#endif -} - -static glong -skin_calc_luminance(GdkColor * c) -{ - return (0.212671 * c->red + 0.715160 * c->green + 0.072169 * c->blue); -} - -static void -skin_get_textcolors(GdkPixbuf * pix, GdkColor * bgc, GdkColor * fgc) -{ - /* - * Try to extract reasonable background and foreground colors - * from the font pixmap - */ - - GdkImage *gi; - GdkColormap *cm; - gint i; - - g_return_if_fail(pix != NULL); - - GdkPixmap *text = gdk_pixmap_new(NULL, gdk_pixbuf_get_width(pix), gdk_pixbuf_get_height(pix), gdk_rgb_get_visual()->depth); - gdk_draw_pixbuf(text, NULL, pix, 0, 0, 0, 0, gdk_pixbuf_get_width(pix), gdk_pixbuf_get_height(pix), - GDK_RGB_DITHER_NONE, 0, 0); - /* Get the first line of text */ - gi = gdk_drawable_get_image(text, 0, 0, 152, 6); - cm = gdk_colormap_get_system(); - - for (i = 0; i < 6; i++) { - GdkColor c; - gint x; - glong d, max_d; - - /* Get a pixel from the middle of the space character */ - bgc[i].pixel = gdk_image_get_pixel(gi, 151, i); - skin_query_color(cm, &bgc[i]); - - max_d = 0; - for (x = 1; x < 150; x++) { - c.pixel = gdk_image_get_pixel(gi, x, i); - skin_query_color(cm, &c); - - d = labs(skin_calc_luminance(&c) - skin_calc_luminance(&bgc[i])); - if (d > max_d) { - memcpy(&fgc[i], &c, sizeof(GdkColor)); - max_d = d; - } - } - } - g_object_unref(gi); - g_object_unref(text); -} - -gboolean -init_skins(const gchar * path) -{ - aud_active_skin = skin_new(); - - skin_parse_hints(aud_active_skin, NULL); - - /* create the windows if they haven't been created yet, needed for bootstrapping */ - if (mainwin == NULL) - { - mainwin_create(); - equalizerwin_create(); - playlistwin_create(); - } - - if (!aud_active_skin_load(path)) { - if (path != NULL) - AUDDBG("Unable to load skin (%s), trying default...\n", path); - else - AUDDBG("Skin not defined: trying default...\n"); - - /* can't load configured skin, retry with default */ - if (!aud_active_skin_load(BMP_DEFAULT_SKIN_PATH)) { - AUDDBG("Unable to load default skin (%s)! Giving up.\n", - BMP_DEFAULT_SKIN_PATH); - return FALSE; - } - } - - if (cfg.random_skin_on_play) - skinlist_update(); - - return TRUE; -} - -void cleanup_skins() -{ - skin_destroy(aud_active_skin); - aud_active_skin = NULL; -} - - -/* - * Opens and parses a skin's hints file. - * Hints files are somewhat like "scripts" in Winamp3/5. - * We'll probably add scripts to it next. - */ -void -skin_parse_hints(Skin * skin, gchar *path_p) -{ - gchar *filename, *tmp; - INIFile *inifile; - - path_p = path_p ? path_p : skin->path; - - skin->properties.mainwin_othertext = FALSE; - skin->properties.mainwin_vis_x = 24; - skin->properties.mainwin_vis_y = 43; - skin->properties.mainwin_vis_width = 76; - skin->properties.mainwin_text_x = 112; - skin->properties.mainwin_text_y = 27; - skin->properties.mainwin_text_width = 153; - skin->properties.mainwin_infobar_x = 112; - skin->properties.mainwin_infobar_y = 43; - skin->properties.mainwin_number_0_x = 36; - skin->properties.mainwin_number_0_y = 26; - skin->properties.mainwin_number_1_x = 48; - skin->properties.mainwin_number_1_y = 26; - skin->properties.mainwin_number_2_x = 60; - skin->properties.mainwin_number_2_y = 26; - skin->properties.mainwin_number_3_x = 78; - skin->properties.mainwin_number_3_y = 26; - skin->properties.mainwin_number_4_x = 90; - skin->properties.mainwin_number_4_y = 26; - skin->properties.mainwin_playstatus_x = 24; - skin->properties.mainwin_playstatus_y = 28; - skin->properties.mainwin_menurow_visible = TRUE; - skin->properties.mainwin_volume_x = 107; - skin->properties.mainwin_volume_y = 57; - skin->properties.mainwin_balance_x = 177; - skin->properties.mainwin_balance_y = 57; - skin->properties.mainwin_position_x = 16; - skin->properties.mainwin_position_y = 72; - skin->properties.mainwin_othertext_is_status = FALSE; - skin->properties.mainwin_othertext_visible = skin->properties.mainwin_othertext; - skin->properties.mainwin_text_visible = TRUE; - skin->properties.mainwin_vis_visible = TRUE; - skin->properties.mainwin_previous_x = 16; - skin->properties.mainwin_previous_y = 88; - skin->properties.mainwin_play_x = 39; - skin->properties.mainwin_play_y = 88; - skin->properties.mainwin_pause_x = 62; - skin->properties.mainwin_pause_y = 88; - skin->properties.mainwin_stop_x = 85; - skin->properties.mainwin_stop_y = 88; - skin->properties.mainwin_next_x = 108; - skin->properties.mainwin_next_y = 88; - skin->properties.mainwin_eject_x = 136; - skin->properties.mainwin_eject_y = 89; - skin->properties.mainwin_width = 275; - skin_mask_info[0].width = skin->properties.mainwin_width; - skin->properties.mainwin_height = 116; - skin_mask_info[0].height = skin->properties.mainwin_height; - skin->properties.mainwin_about_x = 247; - skin->properties.mainwin_about_y = 83; - skin->properties.mainwin_shuffle_x = 164; - skin->properties.mainwin_shuffle_y = 89; - skin->properties.mainwin_repeat_x = 210; - skin->properties.mainwin_repeat_y = 89; - skin->properties.mainwin_eqbutton_x = 219; - skin->properties.mainwin_eqbutton_y = 58; - skin->properties.mainwin_plbutton_x = 242; - skin->properties.mainwin_plbutton_y = 58; - skin->properties.textbox_bitmap_font_width = 5; - skin->properties.textbox_bitmap_font_height = 6; - skin->properties.mainwin_minimize_x = 244; - skin->properties.mainwin_minimize_y = 3; - skin->properties.mainwin_shade_x = 254; - skin->properties.mainwin_shade_y = 3; - skin->properties.mainwin_close_x = 264; - skin->properties.mainwin_close_y = 3; - - if (path_p == NULL) - return; - - filename = find_file_recursively(path_p, "skin.hints"); - - if (filename == NULL) - return; - - inifile = open_ini_file(filename); - if (!inifile) - return; - - tmp = read_ini_string(inifile, "skin", "mainwinOthertext"); - - if (tmp != NULL) - { - skin->properties.mainwin_othertext = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinVisX"); - - if (tmp != NULL) - { - skin->properties.mainwin_vis_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinVisY"); - - if (tmp != NULL) - { - skin->properties.mainwin_vis_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinVisWidth"); - - if (tmp != NULL) - { - skin->properties.mainwin_vis_width = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinTextX"); - - if (tmp != NULL) - { - skin->properties.mainwin_text_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinTextY"); - - if (tmp != NULL) - { - skin->properties.mainwin_text_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinTextWidth"); - - if (tmp != NULL) - { - skin->properties.mainwin_text_width = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinInfoBarX"); - - if (tmp != NULL) - { - skin->properties.mainwin_infobar_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinInfoBarY"); - - if (tmp != NULL) - { - skin->properties.mainwin_infobar_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNumber0X"); - - if (tmp != NULL) - { - skin->properties.mainwin_number_0_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNumber0Y"); - - if (tmp != NULL) - { - skin->properties.mainwin_number_0_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNumber1X"); - - if (tmp != NULL) - { - skin->properties.mainwin_number_1_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNumber1Y"); - - if (tmp != NULL) - { - skin->properties.mainwin_number_1_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNumber2X"); - - if (tmp != NULL) - { - skin->properties.mainwin_number_2_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNumber2Y"); - - if (tmp != NULL) - { - skin->properties.mainwin_number_2_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNumber3X"); - - if (tmp != NULL) - { - skin->properties.mainwin_number_3_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNumber3Y"); - - if (tmp != NULL) - { - skin->properties.mainwin_number_3_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNumber4X"); - - if (tmp != NULL) - { - skin->properties.mainwin_number_4_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNumber4Y"); - - if (tmp != NULL) - { - skin->properties.mainwin_number_4_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPlayStatusX"); - - if (tmp != NULL) - { - skin->properties.mainwin_playstatus_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPlayStatusY"); - - if (tmp != NULL) - { - skin->properties.mainwin_playstatus_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinMenurowVisible"); - - if (tmp != NULL) - { - skin->properties.mainwin_menurow_visible = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinVolumeX"); - - if (tmp != NULL) - { - skin->properties.mainwin_volume_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinVolumeY"); - - if (tmp != NULL) - { - skin->properties.mainwin_volume_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinBalanceX"); - - if (tmp != NULL) - { - skin->properties.mainwin_balance_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinBalanceY"); - - if (tmp != NULL) - { - skin->properties.mainwin_balance_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPositionX"); - - if (tmp != NULL) - { - skin->properties.mainwin_position_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPositionY"); - - if (tmp != NULL) - { - skin->properties.mainwin_position_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinOthertextIsStatus"); - - if (tmp != NULL) - { - skin->properties.mainwin_othertext_is_status = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinOthertextVisible"); - - if (tmp != NULL) - { - skin->properties.mainwin_othertext_visible = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinTextVisible"); - - if (tmp != NULL) - { - skin->properties.mainwin_text_visible = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinVisVisible"); - - if (tmp != NULL) - { - skin->properties.mainwin_vis_visible = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPreviousX"); - - if (tmp != NULL) - { - skin->properties.mainwin_previous_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPreviousY"); - - if (tmp != NULL) - { - skin->properties.mainwin_previous_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPlayX"); - - if (tmp != NULL) - { - skin->properties.mainwin_play_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPlayY"); - - if (tmp != NULL) - { - skin->properties.mainwin_play_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPauseX"); - - if (tmp != NULL) - { - skin->properties.mainwin_pause_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPauseY"); - - if (tmp != NULL) - { - skin->properties.mainwin_pause_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinStopX"); - - if (tmp != NULL) - { - skin->properties.mainwin_stop_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinStopY"); - - if (tmp != NULL) - { - skin->properties.mainwin_stop_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNextX"); - - if (tmp != NULL) - { - skin->properties.mainwin_next_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinNextY"); - - if (tmp != NULL) - { - skin->properties.mainwin_next_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinEjectX"); - - if (tmp != NULL) - { - skin->properties.mainwin_eject_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinEjectY"); - - if (tmp != NULL) - { - skin->properties.mainwin_eject_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinWidth"); - - if (tmp != NULL) - { - skin->properties.mainwin_width = atoi(tmp); - g_free(tmp); - } - - skin_mask_info[0].width = skin->properties.mainwin_width; - - tmp = read_ini_string(inifile, "skin", "mainwinHeight"); - - if (tmp != NULL) - { - skin->properties.mainwin_height = atoi(tmp); - g_free(tmp); - } - - skin_mask_info[0].height = skin->properties.mainwin_height; - - tmp = read_ini_string(inifile, "skin", "mainwinAboutX"); - - if (tmp != NULL) - { - skin->properties.mainwin_about_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinAboutY"); - - if (tmp != NULL) - { - skin->properties.mainwin_about_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinShuffleX"); - - if (tmp != NULL) - { - skin->properties.mainwin_shuffle_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinShuffleY"); - - if (tmp != NULL) - { - skin->properties.mainwin_shuffle_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinRepeatX"); - - if (tmp != NULL) - { - skin->properties.mainwin_repeat_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinRepeatY"); - - if (tmp != NULL) - { - skin->properties.mainwin_repeat_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinEQButtonX"); - - if (tmp != NULL) - { - skin->properties.mainwin_eqbutton_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinEQButtonY"); - - if (tmp != NULL) - { - skin->properties.mainwin_eqbutton_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPLButtonX"); - - if (tmp != NULL) - { - skin->properties.mainwin_plbutton_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinPLButtonY"); - - if (tmp != NULL) - { - skin->properties.mainwin_plbutton_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "textboxBitmapFontWidth"); - - if (tmp != NULL) - { - skin->properties.textbox_bitmap_font_width = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "textboxBitmapFontHeight"); - - if (tmp != NULL) - { - skin->properties.textbox_bitmap_font_height = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinMinimizeX"); - - if (tmp != NULL) - { - skin->properties.mainwin_minimize_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinMinimizeY"); - - if (tmp != NULL) - { - skin->properties.mainwin_minimize_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinShadeX"); - - if (tmp != NULL) - { - skin->properties.mainwin_shade_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinShadeY"); - - if (tmp != NULL) - { - skin->properties.mainwin_shade_y = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinCloseX"); - - if (tmp != NULL) - { - skin->properties.mainwin_close_x = atoi(tmp); - g_free(tmp); - } - - tmp = read_ini_string(inifile, "skin", "mainwinCloseY"); - - if (tmp != NULL) - { - skin->properties.mainwin_close_y = atoi(tmp); - g_free(tmp); - } - - if (filename != NULL) - g_free(filename); - - close_ini_file(inifile); -} - -static guint -hex_chars_to_int(gchar hi, gchar lo) -{ - /* - * Converts a value in the range 0x00-0xFF - * to a integer in the range 0-65535 - */ - gchar str[3]; - - str[0] = hi; - str[1] = lo; - str[2] = 0; - - return (CLAMP(strtol(str, NULL, 16), 0, 0xFF) << 8); -} - -static GdkColor * -skin_load_color(INIFile *inifile, - const gchar * section, const gchar * key, - gchar * default_hex) -{ - gchar *value; - GdkColor *color = NULL; - - if (inifile || default_hex) { - if (inifile) { - value = read_ini_string(inifile, section, key); - if (value == NULL) { - value = g_strdup(default_hex); - } - } else { - value = g_strdup(default_hex); - } - if (value) { - gchar *ptr = value; - gint len; - - color = g_new0(GdkColor, 1); - g_strstrip(value); - - if (value[0] == '#') - ptr++; - len = strlen(ptr); - /* - * The handling of incomplete values is done this way - * to maximize winamp compatibility - */ - if (len >= 6) { - color->red = hex_chars_to_int(*ptr, *(ptr + 1)); - ptr += 2; - } - if (len >= 4) { - color->green = hex_chars_to_int(*ptr, *(ptr + 1)); - ptr += 2; - } - if (len >= 2) - color->blue = hex_chars_to_int(*ptr, *(ptr + 1)); - - g_free(value); - } - } - return color; -} - - - -GdkBitmap * -skin_create_transparent_mask(const gchar * path, - const gchar * file, - const gchar * section, - GdkWindow * window, - gint width, - gint height, gboolean scale) -{ - GdkBitmap *mask = NULL; - GdkGC *gc = NULL; - GdkColor pattern; - GdkPoint *gpoints; - - gchar *filename = NULL; - INIFile *inifile = NULL; - gboolean created_mask = FALSE; - GArray *num, *point; - guint i, j; - gint k; - - if (path) - filename = find_file_recursively(path, file); - - /* filename will be null if path wasn't set */ - if (!filename) - return create_default_mask(window, width, height); - - inifile = open_ini_file(filename); - - if ((num = read_ini_array(inifile, section, "NumPoints")) == NULL) { - g_free(filename); - close_ini_file(inifile); - return NULL; - } - - if ((point = read_ini_array(inifile, section, "PointList")) == NULL) { - g_array_free(num, TRUE); - g_free(filename); - close_ini_file(inifile); - return NULL; - } - - close_ini_file(inifile); - - mask = gdk_pixmap_new(window, width, height, 1); - gc = gdk_gc_new(mask); - - pattern.pixel = 0; - gdk_gc_set_foreground(gc, &pattern); - gdk_draw_rectangle(mask, gc, TRUE, 0, 0, width, height); - pattern.pixel = 1; - gdk_gc_set_foreground(gc, &pattern); - - j = 0; - for (i = 0; i < num->len; i++) { - if ((int)(point->len - j) >= (g_array_index(num, gint, i) * 2)) { - created_mask = TRUE; - gpoints = g_new(GdkPoint, g_array_index(num, gint, i)); - for (k = 0; k < g_array_index(num, gint, i); k++) { - gpoints[k].x = - g_array_index(point, gint, j + k * 2) * (scale ? cfg.scale_factor : 1 ); - gpoints[k].y = - g_array_index(point, gint, - j + k * 2 + 1) * (scale ? cfg.scale_factor : 1); - } - j += k * 2; - gdk_draw_polygon(mask, gc, TRUE, gpoints, - g_array_index(num, gint, i)); - g_free(gpoints); - } - } - g_array_free(num, TRUE); - g_array_free(point, TRUE); - g_free(filename); - - if (!created_mask) - gdk_draw_rectangle(mask, gc, TRUE, 0, 0, width, height); - - g_object_unref(gc); - - return mask; -} - -void -skin_load_viscolor(Skin * skin, const gchar * path, const gchar * basename) -{ - VFSFile *file; - gint i, c; - gchar line[256], *filename; - GArray *a; - - g_return_if_fail(skin != NULL); - g_return_if_fail(path != NULL); - g_return_if_fail(basename != NULL); - - skin_set_default_vis_color(skin); - - filename = find_file_recursively(path, basename); - if (!filename) - return; - - if (!(file = vfs_fopen(filename, "r"))) { - g_free(filename); - return; - } - - g_free(filename); - - for (i = 0; i < 24; i++) { - if (vfs_fgets(line, 255, file)) { - a = string_to_garray(line); - if (a->len > 2) { - for (c = 0; c < 3; c++) - skin->vis_color[i][c] = g_array_index(a, gint, c); - } - g_array_free(a, TRUE); - } - else - break; - } - - vfs_fclose(file); -} - -static void -skin_numbers_generate_dash(Skin * skin) -{ - GdkPixbuf *pixbuf; - SkinPixmap *numbers; - - g_return_if_fail(skin != NULL); - - numbers = &skin->pixmaps[SKIN_NUMBERS]; - if (!numbers->pixbuf || numbers->current_width < 99) - return; - - pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, - 108, numbers->current_height); - - skin_draw_pixbuf(NULL, skin, pixbuf, SKIN_NUMBERS, 0, 0, 0, 0, 99, numbers->current_height); - skin_draw_pixbuf(NULL, skin, pixbuf, SKIN_NUMBERS, 90, 0, 99, 0, 9, numbers->current_height); - skin_draw_pixbuf(NULL, skin, pixbuf, SKIN_NUMBERS, 20, 6, 101, 6, 5, 1); - - g_object_unref(numbers->pixbuf); - - numbers->pixbuf = pixbuf; - numbers->current_width = 108; - numbers->width = 108; -} - -static gboolean -skin_load_pixmaps(Skin * skin, const gchar * path) -{ - GdkPixbuf *text_pb; - guint i; - gchar *filename; - INIFile *inifile; - - if(!skin) return FALSE; - if(!path) return FALSE; - - AUDDBG("Loading pixmaps in %s\n", path); - - for (i = 0; i < SKIN_PIXMAP_COUNT; i++) - if (!skin_load_pixmap_id(skin, i, path) && !cfg.allow_broken_skins) - return FALSE; - - text_pb = skin->pixmaps[SKIN_TEXT].pixbuf; - - if (text_pb) - skin_get_textcolors(text_pb, skin->textbg, skin->textfg); - - if (skin->pixmaps[SKIN_NUMBERS].pixbuf && - skin->pixmaps[SKIN_NUMBERS].width < 108 ) - skin_numbers_generate_dash(skin); - - filename = find_file_recursively(path, "pledit.txt"); - inifile = open_ini_file(filename); - - skin->colors[SKIN_PLEDIT_NORMAL] = - skin_load_color(inifile, "Text", "Normal", "#2499ff"); - skin->colors[SKIN_PLEDIT_CURRENT] = - skin_load_color(inifile, "Text", "Current", "#ffeeff"); - skin->colors[SKIN_PLEDIT_NORMALBG] = - skin_load_color(inifile, "Text", "NormalBG", "#0a120a"); - skin->colors[SKIN_PLEDIT_SELECTEDBG] = - skin_load_color(inifile, "Text", "SelectedBG", "#0a124a"); - - if (inifile) - close_ini_file(inifile); - - if (filename) - g_free(filename); - - skin_mask_create(skin, path, SKIN_MASK_MAIN, mainwin->window); - skin_mask_create(skin, path, SKIN_MASK_MAIN_SHADE, mainwin->window); - - skin_mask_create(skin, path, SKIN_MASK_EQ, equalizerwin->window); - skin_mask_create(skin, path, SKIN_MASK_EQ_SHADE, equalizerwin->window); - - skin_load_viscolor(skin, path, "viscolor.txt"); - - return TRUE; -} - -static void -skin_set_gtk_theme(GtkSettings * settings, Skin * skin) -{ - if (original_gtk_theme == NULL) - g_object_get(settings, "gtk-theme-name", &original_gtk_theme, NULL); - - /* the way GTK does things can be very broken. --nenolod */ - - gchar *tmp = g_strdup_printf("%s/.themes/aud-%s", g_get_home_dir(), - basename(skin->path)); - - gchar *troot = g_strdup_printf("%s/.themes", g_get_home_dir()); - g_mkdir_with_parents(troot, 0755); - g_free(troot); - - symlink(skin->path, tmp); - gtk_settings_set_string_property(settings, "gtk-theme-name", - basename(tmp), "audacious"); - g_free(tmp); -} - -/** - * Checks if all pixmap files exist that skin needs. - */ -static gboolean -skin_check_pixmaps(const Skin * skin, const gchar * skin_path) -{ - guint i; - for (i = 0; i < SKIN_PIXMAP_COUNT; i++) - { - gchar *filename = skin_pixmap_locate_basenames(skin, - skin_pixmap_id_lookup(i), - skin_path); - if (!filename) - return FALSE; - g_free(filename); - } - return TRUE; -} - -static gboolean -skin_load_nolock(Skin * skin, const gchar * path, gboolean force) -{ - GtkSettings *settings; - gchar *gtkrcpath; - gchar *newpath, *skin_path; - int archive = 0; - - AUDDBG("Attempt to load skin \"%s\"\n", path); - - g_return_val_if_fail(skin != NULL, FALSE); - g_return_val_if_fail(path != NULL, FALSE); - REQUIRE_LOCK(skin->lock); - - if (!g_file_test(path, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_DIR)) - return FALSE; - - if(force) AUDDBG("reloading forced!\n"); - if (!force && skin->path && !strcmp(skin->path, path)) { - AUDDBG("skin %s already loaded\n", path); - return FALSE; - } - - if (file_is_archive(path)) { - AUDDBG("Attempt to load archive\n"); - if (!(skin_path = archive_decompress(path))) { - AUDDBG("Unable to extract skin archive (%s)\n", path); - return FALSE; - } - archive = 1; - } else { - skin_path = g_strdup(path); - } - - // Check if skin path has all necessary files. - if (!cfg.allow_broken_skins && !skin_check_pixmaps(skin, skin_path)) { - if(archive) del_directory(skin_path); - g_free(skin_path); - AUDDBG("Skin path (%s) doesn't have all wanted pixmaps\n", skin_path); - return FALSE; - } - - // skin_free() frees skin->path and variable path can actually be skin->path - // and we want to get the path before possibly freeing it. - newpath = g_strdup(path); - skin_free(skin); - skin->path = newpath; - - memset(&(skin->properties), 0, sizeof(SkinProperties)); /* do it only if all tests above passed! --asphyx */ - - skin_current_num++; - - /* Parse the hints for this skin. */ - skin_parse_hints(skin, skin_path); - - if (!skin_load_pixmaps(skin, skin_path)) { - if(archive) del_directory(skin_path); - g_free(skin_path); - AUDDBG("Skin loading failed\n"); - return FALSE; - } - - /* restore gtk theme if changed by previous skin */ - settings = gtk_settings_get_default(); - - if (original_gtk_theme != NULL) { - gtk_settings_set_string_property(settings, "gtk-theme-name", - original_gtk_theme, "audacious"); - g_free(original_gtk_theme); - original_gtk_theme = NULL; - } - -#ifndef _WIN32 - if (!cfg.disable_inline_gtk && !archive) { - gtkrcpath = find_path_recursively(skin->path, "gtkrc"); - if (gtkrcpath != NULL) - skin_set_gtk_theme(settings, skin); - g_free(gtkrcpath); - } -#endif - - if(archive) del_directory(skin_path); - g_free(skin_path); - - gtk_widget_shape_combine_mask(mainwin, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + cfg.player_shaded), 0, 0); - gtk_widget_shape_combine_mask(equalizerwin, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + cfg.equalizer_shaded), 0, 0); - - return TRUE; -} - -void -skin_install_skin(const gchar * path) -{ - gchar *command; - - g_return_if_fail(path != NULL); - - command = g_strdup_printf("cp %s %s", - path, aud_paths[BMP_PATH_USER_SKIN_DIR]); - if (system(command)) { - AUDDBG("Unable to install skin (%s) into user directory (%s)\n", - path, aud_paths[BMP_PATH_USER_SKIN_DIR]); - } - g_free(command); -} - -static SkinPixmap * -skin_get_pixmap(Skin * skin, SkinPixmapId map_id) -{ - g_return_val_if_fail(skin != NULL, NULL); - g_return_val_if_fail(map_id < SKIN_PIXMAP_COUNT, NULL); - - return &skin->pixmaps[map_id]; -} - -gboolean -skin_load(Skin * skin, const gchar * path) -{ - gboolean ret; - - g_return_val_if_fail(skin != NULL, FALSE); - - if (!path) - return FALSE; - - skin_lock(skin); - ret = skin_load_nolock(skin, path, FALSE); - skin_unlock(skin); - - if(!ret) { - AUDDBG("loading failed\n"); - return FALSE; /* don't try to update anything if loading failed --asphyx */ - } - - SkinPixmap *pixmap = NULL; - pixmap = skin_get_pixmap(skin, SKIN_NUMBERS); - if (pixmap) { - ui_skinned_number_set_size(mainwin_minus_num, 9, pixmap->height); - ui_skinned_number_set_size(mainwin_10min_num, 9, pixmap->height); - ui_skinned_number_set_size(mainwin_min_num, 9, pixmap->height); - ui_skinned_number_set_size(mainwin_10sec_num, 9, pixmap->height); - ui_skinned_number_set_size(mainwin_sec_num, 9, pixmap->height); - } - - pixmap = skin_get_pixmap(skin, SKIN_MAIN); - if (pixmap && skin->properties.mainwin_height > pixmap->height) - skin->properties.mainwin_height = pixmap->height; - - pixmap = skin_get_pixmap(skin, SKIN_PLAYPAUSE); - if (pixmap) - ui_skinned_playstatus_set_size(mainwin_playstatus, 11, pixmap->height); - - pixmap = skin_get_pixmap(skin, SKIN_EQMAIN); - if (pixmap->height >= 313) - gtk_widget_show(equalizerwin_graph); - - return TRUE; -} - -gboolean -skin_reload_forced(void) -{ - gboolean error; - AUDDBG("\n"); - - skin_lock(aud_active_skin); - error = skin_load_nolock(aud_active_skin, aud_active_skin->path, TRUE); - skin_unlock(aud_active_skin); - - return error; -} - -void -skin_reload(Skin * skin) -{ - AUDDBG("\n"); - g_return_if_fail(skin != NULL); - skin_load_nolock(skin, skin->path, TRUE); -} - -GdkBitmap * -skin_get_mask(Skin * skin, SkinMaskId mi) -{ - GdkBitmap **masks; - - g_return_val_if_fail(skin != NULL, NULL); - g_return_val_if_fail(mi < SKIN_PIXMAP_COUNT, NULL); - - masks = cfg.scaled ? skin->scaled_masks : skin->masks; - return masks[mi]; -} - -GdkColor * -skin_get_color(Skin * skin, SkinColorId color_id) -{ - GdkColor *ret = NULL; - - g_return_val_if_fail(skin != NULL, NULL); - - switch (color_id) { - case SKIN_TEXTBG: - if (skin->pixmaps[SKIN_TEXT].pixbuf) - ret = skin->textbg; - else - ret = skin->def_textbg; - break; - case SKIN_TEXTFG: - if (skin->pixmaps[SKIN_TEXT].pixbuf) - ret = skin->textfg; - else - ret = skin->def_textfg; - break; - default: - if (color_id < SKIN_COLOR_COUNT) - ret = skin->colors[color_id]; - break; - } - return ret; -} - -void -skin_get_viscolor(Skin * skin, guchar vis_color[24][3]) -{ - gint i; - - g_return_if_fail(skin != NULL); - - for (i = 0; i < 24; i++) { - vis_color[i][0] = skin->vis_color[i][0]; - vis_color[i][1] = skin->vis_color[i][1]; - vis_color[i][2] = skin->vis_color[i][2]; - } -} - -gint -skin_get_id(void) -{ - return skin_current_num; -} - -void -skin_draw_pixbuf(GtkWidget *widget, Skin * skin, GdkPixbuf * pix, - SkinPixmapId pixmap_id, - gint xsrc, gint ysrc, gint xdest, gint ydest, - gint width, gint height) -{ - SkinPixmap *pixmap; - - g_return_if_fail(skin != NULL); - - pixmap = skin_get_pixmap(skin, pixmap_id); - g_return_if_fail(pixmap != NULL); - g_return_if_fail(pixmap->pixbuf != NULL); - - /* perhaps we should use transparency or resize widget? */ - if (xsrc+width > pixmap->width || ysrc+height > pixmap->height) { - if (widget) { - /* it's better to hide widget using SKIN_PLAYPAUSE/SKIN_POSBAR than display mess */ - if ((pixmap_id == SKIN_PLAYPAUSE && pixmap->width != 42) || pixmap_id == SKIN_POSBAR) { - gtk_widget_hide(widget); - return; - } - gint x, y; - x = -1; - y = -1; - - if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(mainwin)->fixed) { - GList *iter; - for (iter = GTK_FIXED (SKINNED_WINDOW(mainwin)->fixed)->children; iter; iter = g_list_next (iter)) { - GtkFixedChild *child_data = (GtkFixedChild *) iter->data; - if (child_data->widget == widget) { - x = child_data->x; - y = child_data->y; - break; - } - } - - if (x != -1 && y != -1) { - /* Some skins include SKIN_VOLUME and/or SKIN_BALANCE - without knobs */ - if (pixmap_id == SKIN_VOLUME || pixmap_id == SKIN_BALANCE) { - if (ysrc+height > 421 && xsrc+width <= pixmap->width) - return; - } - /* let's copy what's under widget */ - gdk_pixbuf_copy_area(skin_get_pixmap(aud_active_skin, SKIN_MAIN)->pixbuf, - x, y, width, height, pix, xdest, ydest); - - /* XMMS skins seems to have SKIN_MONOSTEREO with size 58x20 instead of 58x24 */ - if (pixmap_id == SKIN_MONOSTEREO) - height = pixmap->height/2; - } - } else if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(equalizerwin)->fixed) { - if (!(pixmap_id == SKIN_EQMAIN && ysrc == 314)) /* equalizer preamp on equalizer graph */ - gtk_widget_hide(widget); - } else if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(playlistwin)->fixed) { - /* I haven't seen any skin with substandard playlist */ - gtk_widget_hide(widget); - } - } else - return; - } - - width = MIN(width, pixmap->width - xsrc); - height = MIN(height, pixmap->height - ysrc); - gdk_pixbuf_copy_area(pixmap->pixbuf, xsrc, ysrc, width, height, - pix, xdest, ydest); -} - -void -skin_get_eq_spline_colors(Skin * skin, guint32 colors[19]) -{ - gint i; - GdkPixbuf *pixbuf; - SkinPixmap *eqmainpm; - guchar* pixels,*p; - guint rowstride, n_channels; - g_return_if_fail(skin != NULL); - - eqmainpm = &skin->pixmaps[SKIN_EQMAIN]; - if (eqmainpm->pixbuf && - eqmainpm->current_width >= 116 && eqmainpm->current_height >= 313) - pixbuf = eqmainpm->pixbuf; - else - return; - - if (!GDK_IS_PIXBUF(pixbuf)) - return; - - pixels = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - n_channels = gdk_pixbuf_get_n_channels (pixbuf); - for (i = 0; i < 19; i++) - { - p = pixels + rowstride * (i + 294) + 115 * n_channels; - colors[i] = (p[0] << 16) | (p[1] << 8) | p[2]; - /* should we really treat the Alpha channel? */ - /*if (n_channels == 4) - colors[i] = (colors[i] << 8) | p[3];*/ - } -} - - -static void -skin_draw_playlistwin_frame_top(Skin * skin, GdkPixbuf * pix, - gint width, gint height, gboolean focus) -{ - /* The title bar skin consists of 2 sets of 4 images, 1 set - * for focused state and the other for unfocused. The 4 images - * are: - * - * a. right corner (25,20) - * b. left corner (25,20) - * c. tiler (25,20) - * d. title (100,20) - * - * min allowed width = 100+25+25 = 150 - */ - - gint i, y, c; - - /* get y offset of the pixmap set to use */ - if (focus) - y = 0; - else - y = 21; - - /* left corner */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 0, y, 0, 0, 25, 20); - - /* titlebar title */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 26, y, - (width - 100) / 2, 0, 100, 20); - - /* titlebar right corner */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 153, y, - width - 25, 0, 25, 20); - - /* tile draw the remaining frame */ - - /* compute tile count */ - c = (width - (100 + 25 + 25)) / 25; - - for (i = 0; i < c / 2; i++) { - /* left of title */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, - 25 + i * 25, 0, 25, 20); - - /* right of title */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, - (width + 100) / 2 + i * 25, 0, 25, 20); - } - - if (c & 1) { - /* Odd tile count, so one remaining to draw. Here we split - * it into two and draw half on either side of the title */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, - ((c / 2) * 25) + 25, 0, 12, 20); - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 127, y, - (width / 2) + ((c / 2) * 25) + 50, 0, 13, 20); - } -} - -static void -skin_draw_playlistwin_frame_bottom(Skin * skin, GdkPixbuf * pix, - gint width, gint height, gboolean focus) -{ - /* The bottom frame skin consists of 1 set of 4 images. The 4 - * images are: - * - * a. left corner with menu buttons (125,38) - * b. visualization window (75,38) - * c. right corner with play buttons (150,38) - * d. frame tile (25,38) - * - * (min allowed width = 125+150+25=300 - */ - - gint i, c; - - /* bottom left corner (menu buttons) */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 0, 72, - 0, height - 38, 125, 38); - - c = (width - 275) / 25; - - /* draw visualization window, if width allows */ - if (c >= 3) { - c -= 3; - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 205, 0, - width - (150 + 75), height - 38, 75, 38); - } - - /* Bottom right corner (playbuttons etc) */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, - 126, 72, width - 150, height - 38, 150, 38); - - /* Tile draw the remaining undrawn portions */ - for (i = 0; i < c; i++) - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 179, 0, - 125 + i * 25, height - 38, 25, 38); -} - -static void -skin_draw_playlistwin_frame_sides(Skin * skin, GdkPixbuf * pix, - gint width, gint height, gboolean focus) -{ - /* The side frames consist of 2 tile images. 1 for the left, 1 for - * the right. - * a. left (12,29) - * b. right (19,29) - */ - - gint i; - - /* frame sides */ - for (i = 0; i < (height - (20 + 38)) / 29; i++) { - /* left */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 0, 42, - 0, 20 + i * 29, 12, 29); - - /* right */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 32, 42, - width - 19, 20 + i * 29, 19, 29); - } -} - - -void -skin_draw_playlistwin_frame(Skin * skin, GdkPixbuf * pix, - gint width, gint height, gboolean focus) -{ - skin_draw_playlistwin_frame_top(skin, pix, width, height, focus); - skin_draw_playlistwin_frame_bottom(skin, pix, width, height, focus); - skin_draw_playlistwin_frame_sides(skin, pix, width, height, focus); -} - - -void -skin_draw_playlistwin_shaded(Skin * skin, GdkPixbuf * pix, - gint width, gboolean focus) -{ - /* The shade mode titlebar skin consists of 4 images: - * a) left corner offset (72,42) size (25,14) - * b) right corner, focused offset (99,57) size (50,14) - * c) right corner, unfocused offset (99,42) size (50,14) - * d) bar tile offset (72,57) size (25,14) - */ - - gint i; - - /* left corner */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 72, 42, 0, 0, 25, 14); - - /* bar tile */ - for (i = 0; i < (width - 75) / 25; i++) - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 72, 57, - (i * 25) + 25, 0, 25, 14); - - /* right corner */ - skin_draw_pixbuf(NULL, skin, pix, SKIN_PLEDIT, 99, focus ? 42 : 57, - width - 50, 0, 50, 14); -} - - -void -skin_draw_mainwin_titlebar(Skin * skin, GdkPixbuf * pix, - gboolean shaded, gboolean focus) -{ - /* The titlebar skin consists of 2 sets of 2 images, one for for - * shaded and the other for unshaded mode, giving a total of 4. - * The images are exactly 275x14 pixels, aligned and arranged - * vertically on each other in the pixmap in the following order: - * - * a) unshaded, focused offset (27, 0) - * b) unshaded, unfocused offset (27, 15) - * c) shaded, focused offset (27, 29) - * d) shaded, unfocused offset (27, 42) - */ - - gint y_offset; - - if (shaded) { - if (focus) - y_offset = 29; - else - y_offset = 42; - } - else { - if (focus) - y_offset = 0; - else - y_offset = 15; - } - - skin_draw_pixbuf(NULL, skin, pix, SKIN_TITLEBAR, 27, y_offset, - 0, 0, aud_active_skin->properties.mainwin_width, MAINWIN_TITLEBAR_HEIGHT); -} - - -void -skin_set_random_skin(void) -{ - SkinNode *node; - guint32 randval; - - /* Get a random value to select the skin to use */ - randval = g_random_int_range(0, g_list_length(skinlist)); - node = g_list_nth(skinlist, randval)->data; - aud_active_skin_load(node->path); -} - - -void ui_skinned_widget_draw(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gboolean scale) { - g_return_if_fail(widget != NULL); - g_return_if_fail(obj != NULL); - - if (scale) { - gint s_width = width * cfg.scale_factor, - s_height = height * cfg.scale_factor; - GdkPixbuf *image = gdk_pixbuf_scale_simple(obj, s_width, s_height, GDK_INTERP_NEAREST); - gdk_draw_pixbuf(widget->window, NULL, image, 0, 0, 0, 0, s_width, s_height, GDK_RGB_DITHER_NONE, 0, 0); - g_object_unref(image); - } else { - gdk_draw_pixbuf(widget->window, NULL, obj, 0, 0, 0, 0, width, height, GDK_RGB_DITHER_NONE, 0, 0); - } -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skin.h --- a/src/audacious/ui_skin.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,247 +0,0 @@ -/* Audacious - * Copyright (C) 2005-2007 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. - */ - -#ifndef AUDACIOUS_UI_SKIN_H -#define AUDACIOUS_UI_SKIN_H - -#include -#include -#include - -#include "audconfig.h" - -#define BMP_DEFAULT_SKIN_PATH \ - DATA_DIR G_DIR_SEPARATOR_S "Skins" G_DIR_SEPARATOR_S "Default" - - -typedef enum { - SKIN_MAIN = 0, - SKIN_CBUTTONS, - SKIN_TITLEBAR, - SKIN_SHUFREP, - SKIN_TEXT, - SKIN_VOLUME, - SKIN_BALANCE, - SKIN_MONOSTEREO, - SKIN_PLAYPAUSE, - SKIN_NUMBERS, - SKIN_POSBAR, - SKIN_PLEDIT, - SKIN_EQMAIN, - SKIN_EQ_EX, - SKIN_PIXMAP_COUNT -} SkinPixmapId; - -typedef enum { - SKIN_MASK_MAIN = 0, - SKIN_MASK_MAIN_SHADE, - SKIN_MASK_EQ, - SKIN_MASK_EQ_SHADE, - SKIN_MASK_COUNT -} SkinMaskId; - -typedef enum { - SKIN_PLEDIT_NORMAL = 0, - SKIN_PLEDIT_CURRENT, - SKIN_PLEDIT_NORMALBG, - SKIN_PLEDIT_SELECTEDBG, - SKIN_TEXTBG, - SKIN_TEXTFG, - SKIN_COLOR_COUNT -} SkinColorId; - -typedef struct _SkinProperties { - /* this enables the othertext engine, not it's visibility -nenolod */ - gboolean mainwin_othertext; - - /* Vis properties */ - gint mainwin_vis_x; - gint mainwin_vis_y; - gint mainwin_vis_width; - gboolean mainwin_vis_visible; - - /* Text properties */ - gint mainwin_text_x; - gint mainwin_text_y; - gint mainwin_text_width; - gboolean mainwin_text_visible; - - /* Infobar properties */ - gint mainwin_infobar_x; - gint mainwin_infobar_y; - gboolean mainwin_othertext_visible; - - gint mainwin_number_0_x; - gint mainwin_number_0_y; - - gint mainwin_number_1_x; - gint mainwin_number_1_y; - - gint mainwin_number_2_x; - gint mainwin_number_2_y; - - gint mainwin_number_3_x; - gint mainwin_number_3_y; - - gint mainwin_number_4_x; - gint mainwin_number_4_y; - - gint mainwin_playstatus_x; - gint mainwin_playstatus_y; - - gint mainwin_volume_x; - gint mainwin_volume_y; - - gint mainwin_balance_x; - gint mainwin_balance_y; - - gint mainwin_position_x; - gint mainwin_position_y; - - gint mainwin_previous_x; - gint mainwin_previous_y; - - gint mainwin_play_x; - gint mainwin_play_y; - - gint mainwin_pause_x; - gint mainwin_pause_y; - - gint mainwin_stop_x; - gint mainwin_stop_y; - - gint mainwin_next_x; - gint mainwin_next_y; - - gint mainwin_eject_x; - gint mainwin_eject_y; - - gint mainwin_eqbutton_x; - gint mainwin_eqbutton_y; - - gint mainwin_plbutton_x; - gint mainwin_plbutton_y; - - gint mainwin_shuffle_x; - gint mainwin_shuffle_y; - - gint mainwin_repeat_x; - gint mainwin_repeat_y; - - gint mainwin_about_x; - gint mainwin_about_y; - - gint mainwin_minimize_x; - gint mainwin_minimize_y; - - gint mainwin_shade_x; - gint mainwin_shade_y; - - gint mainwin_close_x; - gint mainwin_close_y; - - gint mainwin_width; - gint mainwin_height; - - gboolean mainwin_menurow_visible; - gboolean mainwin_othertext_is_status; - - gint textbox_bitmap_font_width; - gint textbox_bitmap_font_height; -} SkinProperties; - -#define SKIN_PIXMAP(x) ((SkinPixmap *)(x)) -typedef struct _SkinPixmap { - GdkPixbuf *pixbuf; - - /* The real size of the pixmap */ - gint width, height; - - /* The size of the pixmap from the current skin, - which might be smaller */ - gint current_width, current_height; -} SkinPixmap; - - -#define SKIN(x) ((Skin *)(x)) -typedef struct _Skin { - GMutex *lock; - gchar *path; - gchar *def_path; - SkinPixmap pixmaps[SKIN_PIXMAP_COUNT]; - GdkColor textbg[6], def_textbg[6]; - GdkColor textfg[6], def_textfg[6]; - GdkColor *colors[SKIN_COLOR_COUNT]; - guchar vis_color[24][3]; - GdkBitmap *masks[SKIN_MASK_COUNT]; - GdkBitmap *scaled_masks[SKIN_MASK_COUNT]; - SkinProperties properties; -} Skin; - -extern Skin *aud_active_skin; - -gboolean init_skins(const gchar * path); -void cleanup_skins(void); - -gboolean aud_active_skin_load(const gchar * path); -gboolean aud_active_skin_reload(void); - -Skin *skin_new(void); -gboolean skin_load(Skin * skin, const gchar * path); -gboolean skin_reload_forced(void); -void skin_reload(Skin * skin); -void skin_free(Skin * skin); - -GdkBitmap *skin_get_mask(Skin * skin, SkinMaskId mi); -GdkColor *skin_get_color(Skin * skin, SkinColorId color_id); - -void skin_get_viscolor(Skin * skin, guchar vis_color[24][3]); -gint skin_get_id(void); -void skin_draw_pixbuf(GtkWidget *widget, Skin * skin, GdkPixbuf * pix, - SkinPixmapId pixmap_id, - gint xsrc, gint ysrc, gint xdest, gint ydest, - gint width, gint height); - -void skin_get_eq_spline_colors(Skin * skin, guint32 colors[19]); -void skin_install_skin(const gchar * path); - -void skin_draw_playlistwin_shaded(Skin * skin, GdkPixbuf * pix, - gint width, gboolean focus); -void skin_draw_playlistwin_frame(Skin * skin, GdkPixbuf * pix, - gint width, gint height, gboolean focus); - -void skin_draw_mainwin_titlebar(Skin * skin, GdkPixbuf * pix, - gboolean shaded, gboolean focus); - - -void skin_parse_hints(Skin * skin, gchar *path_p); - - -void skin_set_random_skin(void); - - -void ui_skinned_widget_draw(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gboolean scale); - -#endif /* AUDACIOUS_UI_SKIN_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_button.c --- a/src/audacious/ui_skinned_button.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,535 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * 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 "ui_skinned_button.h" -#include - -#define UI_SKINNED_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_button_get_type(), UiSkinnedButtonPrivate)) -typedef struct _UiSkinnedButtonPrivate UiSkinnedButtonPrivate; - -enum { - PRESSED, - RELEASED, - CLICKED, - DOUBLED, - REDRAW, - LAST_SIGNAL -}; - -struct _UiSkinnedButtonPrivate { - //Skinned part - GdkGC *gc; - gint w; - gint h; - SkinPixmapId skin_index1; - SkinPixmapId skin_index2; - gboolean scaled; - gint move_x, move_y; - - gint nx, ny, px, py; - //Toogle button needs also those - gint pnx, pny, ppx, ppy; -}; - - -static GtkWidgetClass *parent_class = NULL; -static void ui_skinned_button_class_init(UiSkinnedButtonClass *klass); -static void ui_skinned_button_init(UiSkinnedButton *button); -static void ui_skinned_button_destroy(GtkObject *object); -static void ui_skinned_button_realize(GtkWidget *widget); -static void ui_skinned_button_unrealize(GtkWidget *widget); -static void ui_skinned_button_map(GtkWidget *widget); -static void ui_skinned_button_unmap(GtkWidget *widget); -static void ui_skinned_button_size_request(GtkWidget *widget, GtkRequisition *requisition); -static gint ui_skinned_button_expose(GtkWidget *widget,GdkEventExpose *event); - -static void ui_skinned_button_size_allocate(GtkWidget *widget, GtkAllocation *allocation); -static void ui_skinned_button_update_state(UiSkinnedButton *button); - -static guint button_signals[LAST_SIGNAL] = { 0 }; -static gint ui_skinned_button_button_press(GtkWidget *widget, GdkEventButton *event); -static gint ui_skinned_button_button_release(GtkWidget *widget, GdkEventButton *event); -static void button_pressed(UiSkinnedButton *button); -static void button_released(UiSkinnedButton *button); -static void ui_skinned_button_pressed(UiSkinnedButton *button); -static void ui_skinned_button_released(UiSkinnedButton *button); -static void ui_skinned_button_clicked(UiSkinnedButton *button); -static void ui_skinned_button_set_pressed (UiSkinnedButton *button, gboolean pressed); - -static void ui_skinned_button_toggle_scaled(UiSkinnedButton *button); - -static gint ui_skinned_button_enter_notify(GtkWidget *widget, GdkEventCrossing *event); -static gint ui_skinned_button_leave_notify(GtkWidget *widget, GdkEventCrossing *event); -static void ui_skinned_button_redraw(UiSkinnedButton *button); - -GType ui_skinned_button_get_type() { - static GType button_type = 0; - if (!button_type) { - static const GTypeInfo button_info = { - sizeof (UiSkinnedButtonClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_button_class_init, - NULL, - NULL, - sizeof (UiSkinnedButton), - 0, - (GInstanceInitFunc) ui_skinned_button_init, - }; - button_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedButton_", &button_info, 0); - } - - return button_type; -} - -static void ui_skinned_button_class_init (UiSkinnedButtonClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_button_destroy; - - widget_class->realize = ui_skinned_button_realize; - widget_class->unrealize = ui_skinned_button_unrealize; - widget_class->map = ui_skinned_button_map; - widget_class->unmap = ui_skinned_button_unmap; - widget_class->expose_event = ui_skinned_button_expose; - widget_class->size_request = ui_skinned_button_size_request; - widget_class->size_allocate = ui_skinned_button_size_allocate; - widget_class->button_press_event = ui_skinned_button_button_press; - widget_class->button_release_event = ui_skinned_button_button_release; - widget_class->enter_notify_event = ui_skinned_button_enter_notify; - widget_class->leave_notify_event = ui_skinned_button_leave_notify; - - klass->pressed = button_pressed; - klass->released = button_released; - klass->clicked = NULL; - klass->scaled = ui_skinned_button_toggle_scaled; - klass->redraw = ui_skinned_button_redraw; - - button_signals[PRESSED] = - g_signal_new ("pressed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (UiSkinnedButtonClass, pressed), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - button_signals[RELEASED] = - g_signal_new ("released", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (UiSkinnedButtonClass, released), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - button_signals[CLICKED] = - g_signal_new ("clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedButtonClass, clicked), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - button_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedButtonClass, scaled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - button_signals[REDRAW] = - g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedButtonClass, redraw), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - g_type_class_add_private (gobject_class, sizeof (UiSkinnedButtonPrivate)); -} - -static void ui_skinned_button_init (UiSkinnedButton *button) { - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); - button->inside = FALSE; - button->type = TYPE_NOT_SET; - priv->move_x = 0; - priv->move_y = 0; - button->event_window = NULL; -} - -static void ui_skinned_button_destroy (GtkObject *object) { - UiSkinnedButton *button; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_BUTTON (object)); - - button = UI_SKINNED_BUTTON(object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_button_realize (GtkWidget *widget) { - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_BUTTON(widget)); - UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); - GdkWindowAttr attributes; - gint attributes_mask; - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; - - if (button->type == TYPE_SMALL || button->type == TYPE_NOT_SET) { - widget->window = gtk_widget_get_parent_window (widget); - g_object_ref (widget->window); - attributes.wclass = GDK_INPUT_ONLY; - attributes_mask = GDK_WA_X | GDK_WA_Y; - button->event_window = gdk_window_new (widget->window, &attributes, attributes_mask); - GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW); - gdk_window_set_user_data(button->event_window, widget); - } else { - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.event_mask |= GDK_EXPOSURE_MASK; - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - GTK_WIDGET_UNSET_FLAGS (widget, GTK_NO_WINDOW); - gdk_window_set_user_data(widget->window, widget); - } - - widget->style = gtk_style_attach(widget->style, widget->window); -} - -static void ui_skinned_button_unrealize (GtkWidget *widget) { - UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); - - if ( button->event_window != NULL ) - { - gdk_window_set_user_data( button->event_window , NULL ); - gdk_window_destroy( button->event_window ); - button->event_window = NULL; - } - - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); -} - -static void ui_skinned_button_map (GtkWidget *widget) -{ - UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); - - if (button->event_window != NULL) - gdk_window_show (button->event_window); - - if (GTK_WIDGET_CLASS (parent_class)->map) - (* GTK_WIDGET_CLASS (parent_class)->map) (widget); -} - -static void ui_skinned_button_unmap (GtkWidget *widget) -{ - UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); - - if (button->event_window != NULL) - gdk_window_hide (button->event_window); - - if (GTK_WIDGET_CLASS (parent_class)->unmap) - (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget); -} - -static void ui_skinned_button_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(widget); - requisition->width = priv->w*(priv->scaled ? cfg.scale_factor : 1); - requisition->height = priv->h*(priv->scaled ? cfg.scale_factor : 1); -} - -static void ui_skinned_button_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); - widget->allocation = *allocation; - widget->allocation.x = ceil(widget->allocation.x*(priv->scaled ? cfg.scale_factor : 1)); - widget->allocation.y = ceil(widget->allocation.y*(priv->scaled ? cfg.scale_factor : 1)); - - if (GTK_WIDGET_REALIZED (widget)) - { - if ( button->event_window != NULL ) - gdk_window_move_resize(button->event_window, ceil(allocation->x*(priv->scaled ? cfg.scale_factor : 1)), ceil(allocation->y*(priv->scaled ? cfg.scale_factor : 1)), allocation->width, allocation->height); - else - gdk_window_move_resize(widget->window, ceil(allocation->x*(priv->scaled ? cfg.scale_factor : 1)), ceil(allocation->y*(priv->scaled ? cfg.scale_factor : 1)), allocation->width, allocation->height); - } - - if (button->x + priv->move_x == ceil(widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1))) - priv->move_x = 0; - if (button->y + priv->move_y == ceil(widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1))) - priv->move_y = 0; - - button->x = ceil(widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1)); - button->y = ceil(widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1)); -} - -static gboolean ui_skinned_button_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_BUTTON (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedButton *button = UI_SKINNED_BUTTON (widget); - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); - g_return_val_if_fail (priv->w > 0 && priv->h > 0, FALSE); - - //TYPE_SMALL doesn't have its own face - if (button->type == TYPE_SMALL || button->type == TYPE_NOT_SET) - return FALSE; - - /* paranoia */ - if (button->event_window != NULL) - return FALSE; - - GdkPixbuf *obj; - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->w, priv->h); - - switch (button->type) { - case TYPE_PUSH: - skin_draw_pixbuf(widget, aud_active_skin, obj, - button->pressed ? priv->skin_index2 : priv->skin_index1, - button->pressed ? priv->px : priv->nx, - button->pressed ? priv->py : priv->ny, - 0, 0, priv->w, priv->h); - break; - case TYPE_TOGGLE: - if (button->inside) - skin_draw_pixbuf(widget, aud_active_skin, obj, - button->pressed ? priv->skin_index2 : priv->skin_index1, - button->pressed ? priv->ppx : priv->pnx, - button->pressed ? priv->ppy : priv->pny, - 0, 0, priv->w, priv->h); - else - skin_draw_pixbuf(widget, aud_active_skin, obj, - button->pressed ? priv->skin_index2 : priv->skin_index1, - button->pressed ? priv->px : priv->nx, - button->pressed ? priv->py : priv->ny, - 0, 0, priv->w, priv->h); - break; - default: - break; - } - - ui_skinned_widget_draw(widget, obj, priv->w, priv->h, priv->scaled); - g_object_unref(obj); - - return FALSE; -} - -GtkWidget* ui_skinned_button_new () { - UiSkinnedButton *button = g_object_new (ui_skinned_button_get_type (), NULL); - - return GTK_WIDGET(button); -} - -void ui_skinned_push_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, SkinPixmapId si) { - - UiSkinnedButton *sbutton = UI_SKINNED_BUTTON(button); - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(sbutton); - priv->w = w; - priv->h = h; - sbutton->x = x; - sbutton->y = y; - priv->nx = nx; - priv->ny = ny; - priv->px = px; - priv->py = py; - sbutton->type = TYPE_PUSH; - priv->skin_index1 = si; - priv->skin_index2 = si; - priv->scaled = FALSE; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(button), sbutton->x, sbutton->y); -} - -void ui_skinned_toggle_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, gint pnx, gint pny, gint ppx, gint ppy, SkinPixmapId si) { - - UiSkinnedButton *sbutton = UI_SKINNED_BUTTON(button); - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(sbutton); - priv->w = w; - priv->h = h; - sbutton->x = x; - sbutton->y = y; - priv->nx = nx; - priv->ny = ny; - priv->px = px; - priv->py = py; - priv->pnx = pnx; - priv->pny = pny; - priv->ppx = ppx; - priv->ppy = ppy; - sbutton->type = TYPE_TOGGLE; - priv->skin_index1 = si; - priv->skin_index2 = si; - priv->scaled = FALSE; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(button), sbutton->x, sbutton->y); -} - -void ui_skinned_small_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h) { - - UiSkinnedButton *sbutton = UI_SKINNED_BUTTON(button); - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(sbutton); - priv->w = w; - priv->h = h; - sbutton->x = x; - sbutton->y = y; - sbutton->type = TYPE_SMALL; - priv->scaled = FALSE; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(button), sbutton->x, sbutton->y); -} - -static void button_pressed(UiSkinnedButton *button) { - button->button_down = TRUE; - ui_skinned_button_update_state(button); -} - -static void button_released(UiSkinnedButton *button) { - button->button_down = FALSE; - if(button->hover) ui_skinned_button_clicked(button); - ui_skinned_button_update_state(button); -} - -static void ui_skinned_button_update_state(UiSkinnedButton *button) { - ui_skinned_button_set_pressed(button, button->button_down); -} - -static void ui_skinned_button_set_pressed (UiSkinnedButton *button, gboolean pressed) { - if (pressed != button->pressed) { - button->pressed = pressed; - gtk_widget_queue_draw(GTK_WIDGET(button)); - } -} - -static gboolean ui_skinned_button_button_press(GtkWidget *widget, GdkEventButton *event) { - UiSkinnedButton *button; - - if (event->type == GDK_BUTTON_PRESS) { - button = UI_SKINNED_BUTTON(widget); - - if (event->button == 1) - ui_skinned_button_pressed (button); - else if (event->button == 3) { - event->x = event->x + button->x; - event->y = event->y + button->y; - return FALSE; - } - } - - return TRUE; -} - -static gboolean ui_skinned_button_button_release(GtkWidget *widget, GdkEventButton *event) { - UiSkinnedButton *button; - if (event->button == 1) { - button = UI_SKINNED_BUTTON(widget); - ui_skinned_button_released(button); - } - return TRUE; -} - -static void ui_skinned_button_pressed(UiSkinnedButton *button) { - g_return_if_fail(UI_SKINNED_IS_BUTTON(button)); - g_signal_emit(button, button_signals[PRESSED], 0); -} - -static void ui_skinned_button_released(UiSkinnedButton *button) { - g_return_if_fail(UI_SKINNED_IS_BUTTON(button)); - g_signal_emit(button, button_signals[RELEASED], 0); -} - -static void ui_skinned_button_clicked(UiSkinnedButton *button) { - g_return_if_fail(UI_SKINNED_IS_BUTTON(button)); - button->inside = !button->inside; - g_signal_emit(button, button_signals[CLICKED], 0); -} - -static gboolean ui_skinned_button_enter_notify(GtkWidget *widget, GdkEventCrossing *event) { - UiSkinnedButton *button; - - button = UI_SKINNED_BUTTON(widget); - button->hover = TRUE; - if(button->button_down) ui_skinned_button_set_pressed(button, TRUE); - - return FALSE; -} - -static gboolean ui_skinned_button_leave_notify(GtkWidget *widget, GdkEventCrossing *event) { - UiSkinnedButton *button; - - button = UI_SKINNED_BUTTON (widget); - button->hover = FALSE; - if(button->button_down) ui_skinned_button_set_pressed(button, FALSE); - - return FALSE; -} - -static void ui_skinned_button_toggle_scaled(UiSkinnedButton *button) { - GtkWidget *widget = GTK_WIDGET (button); - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); - priv->scaled = !priv->scaled; - - gtk_widget_set_size_request(widget, priv->w*(priv->scaled ? cfg.scale_factor : 1), priv->h*(priv->scaled ? cfg.scale_factor : 1)); - - gtk_widget_queue_draw(widget); -} - -static void ui_skinned_button_redraw(UiSkinnedButton *button) { - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); - if (priv->move_x || priv->move_y) - gtk_fixed_move(GTK_FIXED(gtk_widget_get_parent(GTK_WIDGET(button))), GTK_WIDGET(button), - button->x+priv->move_x, button->y+priv->move_y); - - gtk_widget_queue_draw(GTK_WIDGET(button)); -} - - -void ui_skinned_set_push_button_data(GtkWidget *button, gint nx, gint ny, gint px, gint py) { - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE(button); - if (nx > -1) priv->nx = nx; - if (ny > -1) priv->ny = ny; - if (px > -1) priv->px = px; - if (py > -1) priv->py = py; - gtk_widget_queue_draw(button); -} - -void ui_skinned_button_set_skin_index(GtkWidget *button, SkinPixmapId si) { - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); - priv->skin_index1 = priv->skin_index2 = si; -} - -void ui_skinned_button_set_skin_index1(GtkWidget *button, SkinPixmapId si) { - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); - priv->skin_index1 = si; -} - -void ui_skinned_button_set_skin_index2(GtkWidget *button, SkinPixmapId si) { - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); - priv->skin_index2 = si; -} - -void ui_skinned_button_move_relative(GtkWidget *button, gint x, gint y) { - UiSkinnedButtonPrivate *priv = UI_SKINNED_BUTTON_GET_PRIVATE (button); - priv->move_x += x; - priv->move_y += y; -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_button.h --- a/src/audacious/ui_skinned_button.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * 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_SKINNED_BUTTON_H -#define AUDACIOUS_UI_SKINNED_BUTTON_H - -#include -#include "ui_skin.h" - -#define UI_SKINNED_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ui_skinned_button_get_type(), UiSkinnedButton)) -#define UI_SKINNED_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ui_skinned_button_get_type(), UiSkinnedButtonClass)) -#define UI_SKINNED_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ui_skinned_button_get_type())) - -typedef struct _UiSkinnedButton UiSkinnedButton; -typedef struct _UiSkinnedButtonClass UiSkinnedButtonClass; - -enum { - TYPE_NOT_SET, - TYPE_PUSH, - TYPE_TOGGLE, - TYPE_SMALL -}; - -struct _UiSkinnedButton { - GtkWidget widget; - - GdkWindow *event_window; - gboolean button_down; - gboolean pressed; - gboolean hover; - gboolean inside; - gint type; - gint x, y; -}; - -struct _UiSkinnedButtonClass { - GtkWidgetClass parent_class; - void (* pressed) (UiSkinnedButton *button); - void (* released) (UiSkinnedButton *button); - void (* clicked) (UiSkinnedButton *button); - void (* right_clicked) (UiSkinnedButton *button); - void (* scaled) (UiSkinnedButton *button); - void (* redraw) (UiSkinnedButton *button); -}; - -GType ui_skinned_button_get_type(void) G_GNUC_CONST; -GtkWidget* ui_skinned_button_new(); -void ui_skinned_push_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, SkinPixmapId si); -void ui_skinned_set_push_button_data(GtkWidget *button, gint nx, gint ny, gint px, gint py); -void ui_skinned_toggle_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h, gint nx, gint ny, gint px, gint py, gint pnx, gint pny, gint ppx, gint ppy, SkinPixmapId si); -void ui_skinned_small_button_setup(GtkWidget *button, GtkWidget *fixed, gint x, gint y, gint w, gint h); -void ui_skinned_button_set_skin_index(GtkWidget *button, SkinPixmapId si); -void ui_skinned_button_set_skin_index1(GtkWidget *button, SkinPixmapId si); -void ui_skinned_button_set_skin_index2(GtkWidget *button, SkinPixmapId si); -void ui_skinned_button_move_relative(GtkWidget *button, gint x, gint y); - -#endif /* AUDACIOUS_UI_SKINNED_BUTTON_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_equalizer_graph.c --- a/src/audacious/ui_skinned_equalizer_graph.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,307 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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 . - */ - -#include "ui_skin.h" -#include "ui_skinned_equalizer_graph.h" -#include "main.h" -#include "equalizer_flow.h" - -#define UI_TYPE_SKINNED_EQUALIZER_GRAPH (ui_skinned_equalizer_graph_get_type()) - -enum { - DOUBLED, - LAST_SIGNAL -}; - -static void ui_skinned_equalizer_graph_class_init (UiSkinnedEqualizerGraphClass *klass); -static void ui_skinned_equalizer_graph_init (UiSkinnedEqualizerGraph *equalizer_graph); -static void ui_skinned_equalizer_graph_destroy (GtkObject *object); -static void ui_skinned_equalizer_graph_realize (GtkWidget *widget); -static void ui_skinned_equalizer_graph_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_skinned_equalizer_graph_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_skinned_equalizer_graph_expose (GtkWidget *widget, GdkEventExpose *event); -static void ui_skinned_equalizer_graph_toggle_scaled (UiSkinnedEqualizerGraph *equalizer_graph); - -static GtkWidgetClass *parent_class = NULL; -static guint equalizer_graph_signals[LAST_SIGNAL] = { 0 }; - -GType ui_skinned_equalizer_graph_get_type() { - static GType equalizer_graph_type = 0; - if (!equalizer_graph_type) { - static const GTypeInfo equalizer_graph_info = { - sizeof (UiSkinnedEqualizerGraphClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_equalizer_graph_class_init, - NULL, - NULL, - sizeof (UiSkinnedEqualizerGraph), - 0, - (GInstanceInitFunc) ui_skinned_equalizer_graph_init, - }; - equalizer_graph_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedEqualizerGraph_", &equalizer_graph_info, 0); - } - - return equalizer_graph_type; -} - -static void ui_skinned_equalizer_graph_class_init(UiSkinnedEqualizerGraphClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_equalizer_graph_destroy; - - widget_class->realize = ui_skinned_equalizer_graph_realize; - widget_class->expose_event = ui_skinned_equalizer_graph_expose; - widget_class->size_request = ui_skinned_equalizer_graph_size_request; - widget_class->size_allocate = ui_skinned_equalizer_graph_size_allocate; - - klass->scaled = ui_skinned_equalizer_graph_toggle_scaled; - - equalizer_graph_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedEqualizerGraphClass, scaled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); -} - -static void ui_skinned_equalizer_graph_init(UiSkinnedEqualizerGraph *equalizer_graph) { - equalizer_graph->width = 113; - equalizer_graph->height = 19; -} - -GtkWidget* ui_skinned_equalizer_graph_new(GtkWidget *fixed, gint x, gint y) { - UiSkinnedEqualizerGraph *equalizer_graph = g_object_new (ui_skinned_equalizer_graph_get_type (), NULL); - - equalizer_graph->x = x; - equalizer_graph->y = y; - equalizer_graph->skin_index = SKIN_EQMAIN; - equalizer_graph->scaled = FALSE; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(equalizer_graph), equalizer_graph->x, equalizer_graph->y); - - return GTK_WIDGET(equalizer_graph); -} - -static void ui_skinned_equalizer_graph_destroy(GtkObject *object) { - UiSkinnedEqualizerGraph *equalizer_graph; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_EQUALIZER_GRAPH (object)); - - equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_equalizer_graph_realize(GtkWidget *widget) { - UiSkinnedEqualizerGraph *equalizer_graph; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_EQUALIZER_GRAPH(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - - widget->style = gtk_style_attach(widget->style, widget->window); - - gdk_window_set_user_data(widget->window, widget); -} - -static void ui_skinned_equalizer_graph_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedEqualizerGraph *equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH(widget); - - requisition->width = equalizer_graph->width*(equalizer_graph->scaled ? cfg.scale_factor : 1); - requisition->height = equalizer_graph->height*(equalizer_graph->scaled ? cfg.scale_factor : 1); -} - -static void ui_skinned_equalizer_graph_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedEqualizerGraph *equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH (widget); - - widget->allocation = *allocation; - widget->allocation.x *= (equalizer_graph->scaled ? cfg.scale_factor : 1); - widget->allocation.y *= (equalizer_graph->scaled ? cfg.scale_factor : 1); - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - - equalizer_graph->x = widget->allocation.x/(equalizer_graph->scaled ? cfg.scale_factor : 1); - equalizer_graph->y = widget->allocation.y/(equalizer_graph->scaled ? cfg.scale_factor : 1); -} - -void -init_spline(gfloat * x, gfloat * y, gint n, gfloat * y2) -{ - gint i, k; - gfloat p, qn, sig, un, *u; - - u = (gfloat *) g_malloc(n * sizeof(gfloat)); - - y2[0] = u[0] = 0.0; - - for (i = 1; i < n - 1; i++) { - sig = ((gfloat) x[i] - x[i - 1]) / ((gfloat) x[i + 1] - x[i - 1]); - p = sig * y2[i - 1] + 2.0; - y2[i] = (sig - 1.0) / p; - u[i] = - (((gfloat) y[i + 1] - y[i]) / (x[i + 1] - x[i])) - - (((gfloat) y[i] - y[i - 1]) / (x[i] - x[i - 1])); - u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; - } - qn = un = 0.0; - - y2[n - 1] = (un - qn * u[n - 2]) / (qn * y2[n - 2] + 1.0); - for (k = n - 2; k >= 0; k--) - y2[k] = y2[k] * y2[k + 1] + u[k]; - g_free(u); -} - -gfloat -eval_spline(gfloat xa[], gfloat ya[], gfloat y2a[], gint n, gfloat x) -{ - gint klo, khi, k; - gfloat h, b, a; - - klo = 0; - khi = n - 1; - while (khi - klo > 1) { - k = (khi + klo) >> 1; - if (xa[k] > x) - khi = k; - else - klo = k; - } - h = xa[khi] - xa[klo]; - a = (xa[khi] - x) / h; - b = (x - xa[klo]) / h; - return (a * ya[klo] + b * ya[khi] + - ((a * a * a - a) * y2a[klo] + - (b * b * b - b) * y2a[khi]) * (h * h) / 6.0); -} - -static gboolean ui_skinned_equalizer_graph_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_GRAPH (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedEqualizerGraph *equalizer_graph = UI_SKINNED_EQUALIZER_GRAPH (widget); - g_return_val_if_fail (equalizer_graph->width > 0 && equalizer_graph->height > 0, FALSE); - - GdkPixbuf *obj = NULL; - - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, equalizer_graph->width, equalizer_graph->height); - - guint32 cols[19], rowstride; - gint i, y, ymin, ymax, py = 0; - gfloat x[] = { 0, 11, 23, 35, 47, 59, 71, 83, 97, 109 }, yf[10]; - guchar* pixels, *p; - gint n_channels; - /* - * This avoids the init_spline() function to be inlined. - * Inlining the function caused troubles when compiling with - * `-O' (at least on FreeBSD). - */ - void (*__init_spline) (gfloat *, gfloat *, gint, gfloat *) = init_spline; - - skin_draw_pixbuf(widget, aud_active_skin, obj, equalizer_graph->skin_index, 0, 294, 0, 0, - equalizer_graph->width, equalizer_graph->height); - skin_draw_pixbuf(widget, aud_active_skin, obj, equalizer_graph->skin_index, 0, 314, - 0, 9 + ((cfg.equalizer_preamp * 9) / 20), - equalizer_graph->width, 1); - - skin_get_eq_spline_colors(aud_active_skin, cols); - - __init_spline(x, cfg.equalizer_bands, AUD_EQUALIZER_NBANDS, yf); - for (i = 0; i < 109; i++) { - y = 9 - - (gint) ((eval_spline(x, cfg.equalizer_bands, yf, AUD_EQUALIZER_NBANDS, i) * - 9.0) / EQUALIZER_MAX_GAIN); - if (y < 0) - y = 0; - if (y > 18) - y = 18; - if (!i) - py = y; - if (y < py) { - ymin = y; - ymax = py; - } - else { - ymin = py; - ymax = y; - } - py = y; - - pixels = gdk_pixbuf_get_pixels(obj); - rowstride = gdk_pixbuf_get_rowstride(obj); - n_channels = gdk_pixbuf_get_n_channels(obj); - - for (y = ymin; y <= ymax; y++) - { - p = pixels + (y * rowstride) + (( i + 2) * n_channels); - p[0] = (cols[y] & 0xff0000) >> 16; - p[1] = (cols[y] & 0x00ff00) >> 8; - p[2] = (cols[y] & 0x0000ff); - /* do we really need to treat the alpha channel? */ - /*if (n_channels == 4) - p[3] = cols[y] >> 24;*/ - } - } - - ui_skinned_widget_draw(widget, obj, equalizer_graph->width, equalizer_graph->height, equalizer_graph->scaled); - - g_object_unref(obj); - - return FALSE; -} - -static void ui_skinned_equalizer_graph_toggle_scaled(UiSkinnedEqualizerGraph *equalizer_graph) { - GtkWidget *widget = GTK_WIDGET (equalizer_graph); - - equalizer_graph->scaled = !equalizer_graph->scaled; - gtk_widget_set_size_request(widget, equalizer_graph->width*(equalizer_graph->scaled ? cfg.scale_factor : 1), - equalizer_graph->height*(equalizer_graph->scaled ? cfg.scale_factor : 1)); - - gtk_widget_queue_draw(GTK_WIDGET(equalizer_graph)); -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_equalizer_graph.h --- a/src/audacious/ui_skinned_equalizer_graph.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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_SKINNED_EQUALIZER_GRAPH_H -#define AUDACIOUS_UI_SKINNED_EQUALIZER_GRAPH_H - -#include -#include "ui_skin.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SKINNED_EQUALIZER_GRAPH(obj) GTK_CHECK_CAST (obj, ui_skinned_equalizer_graph_get_type (), UiSkinnedEqualizerGraph) -#define UI_SKINNED_EQUALIZER_GRAPH_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_equalizer_graph_get_type (), UiSkinnedEqualizerGraphClass) -#define UI_SKINNED_IS_EQUALIZER_GRAPH(obj) GTK_CHECK_TYPE (obj, ui_skinned_equalizer_graph_get_type ()) - -typedef struct _UiSkinnedEqualizerGraph UiSkinnedEqualizerGraph; -typedef struct _UiSkinnedEqualizerGraphClass UiSkinnedEqualizerGraphClass; - -struct _UiSkinnedEqualizerGraph { - GtkWidget widget; - - gint x, y, width, height; - SkinPixmapId skin_index; - gboolean scaled; -}; - -struct _UiSkinnedEqualizerGraphClass { - GtkWidgetClass parent_class; - void (* scaled) (UiSkinnedEqualizerGraph *eq_graph); -}; - -GtkWidget* ui_skinned_equalizer_graph_new(GtkWidget *fixed, gint x, gint y); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SKINNED_EQUALIZER_GRAPH_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_equalizer_slider.c --- a/src/audacious/ui_skinned_equalizer_slider.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,392 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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 . - */ - -#include "ui_skin.h" -#include "ui_skinned_equalizer_slider.h" -#include "ui_equalizer.h" -#include "ui_main.h" -#include "equalizer_flow.h" -#include - -#define UI_TYPE_SKINNED_EQUALIZER_SLIDER (ui_skinned_equalizer_slider_get_type()) -#define UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UI_TYPE_SKINNED_EQUALIZER_SLIDER, UiSkinnedEqualizerSliderPrivate)) -typedef struct _UiSkinnedEqualizerSliderPrivate UiSkinnedEqualizerSliderPrivate; - -enum { - DOUBLED, - LAST_SIGNAL -}; - -struct _UiSkinnedEqualizerSliderPrivate { - SkinPixmapId skin_index; - gboolean scaled; - gint position; - gint width, height; - gboolean pressed; - gint drag_y; - gfloat value; /* store gain as is to prevent truncation --asphyx */ -}; - -static void ui_skinned_equalizer_slider_class_init (UiSkinnedEqualizerSliderClass *klass); -static void ui_skinned_equalizer_slider_init (UiSkinnedEqualizerSlider *equalizer_slider); -static void ui_skinned_equalizer_slider_destroy (GtkObject *object); -static void ui_skinned_equalizer_slider_realize (GtkWidget *widget); -static void ui_skinned_equalizer_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_skinned_equalizer_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_skinned_equalizer_slider_expose (GtkWidget *widget, GdkEventExpose *event); -static gboolean ui_skinned_equalizer_slider_button_press (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_equalizer_slider_button_release (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_equalizer_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); -static gboolean ui_skinned_equalizer_slider_scroll (GtkWidget *widget, GdkEventScroll *event); -static void ui_skinned_equalizer_slider_toggle_scaled (UiSkinnedEqualizerSlider *equalizer_slider); -void ui_skinned_equalizer_slider_set_mainwin_text (UiSkinnedEqualizerSlider * es); - -static GtkWidgetClass *parent_class = NULL; -static guint equalizer_slider_signals[LAST_SIGNAL] = { 0 }; - -GType ui_skinned_equalizer_slider_get_type() { - static GType equalizer_slider_type = 0; - if (!equalizer_slider_type) { - static const GTypeInfo equalizer_slider_info = { - sizeof (UiSkinnedEqualizerSliderClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_equalizer_slider_class_init, - NULL, - NULL, - sizeof (UiSkinnedEqualizerSlider), - 0, - (GInstanceInitFunc) ui_skinned_equalizer_slider_init, - }; - equalizer_slider_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedEqualizerSlider_", &equalizer_slider_info, 0); - } - - return equalizer_slider_type; -} - -static void ui_skinned_equalizer_slider_class_init(UiSkinnedEqualizerSliderClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_equalizer_slider_destroy; - - widget_class->realize = ui_skinned_equalizer_slider_realize; - widget_class->expose_event = ui_skinned_equalizer_slider_expose; - widget_class->size_request = ui_skinned_equalizer_slider_size_request; - widget_class->size_allocate = ui_skinned_equalizer_slider_size_allocate; - widget_class->button_press_event = ui_skinned_equalizer_slider_button_press; - widget_class->button_release_event = ui_skinned_equalizer_slider_button_release; - widget_class->motion_notify_event = ui_skinned_equalizer_slider_motion_notify; - widget_class->scroll_event = ui_skinned_equalizer_slider_scroll; - - klass->scaled = ui_skinned_equalizer_slider_toggle_scaled; - - equalizer_slider_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedEqualizerSliderClass, scaled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - g_type_class_add_private (gobject_class, sizeof (UiSkinnedEqualizerSliderPrivate)); -} - -static void ui_skinned_equalizer_slider_init(UiSkinnedEqualizerSlider *equalizer_slider) { - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(equalizer_slider); - priv->pressed = FALSE; -} - -GtkWidget* ui_skinned_equalizer_slider_new(GtkWidget *fixed, gint x, gint y) { - UiSkinnedEqualizerSlider *es = g_object_new (ui_skinned_equalizer_slider_get_type (), NULL); - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(es); - - es->x = x; - es->y = y; - priv->width = 14; - priv->height = 63; - priv->skin_index = SKIN_EQMAIN; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(es), es->x, es->y); - - return GTK_WIDGET(es); -} - -static void ui_skinned_equalizer_slider_destroy(GtkObject *object) { - UiSkinnedEqualizerSlider *equalizer_slider; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (object)); - - equalizer_slider = UI_SKINNED_EQUALIZER_SLIDER (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_equalizer_slider_realize(GtkWidget *widget) { - UiSkinnedEqualizerSlider *equalizer_slider; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - equalizer_slider = UI_SKINNED_EQUALIZER_SLIDER(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - - widget->style = gtk_style_attach(widget->style, widget->window); - gdk_window_set_user_data(widget->window, widget); -} - -static void ui_skinned_equalizer_slider_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); - - requisition->width = priv->width*(priv->scaled ? cfg.scale_factor : 1); - requisition->height = priv->height*(priv->scaled ? cfg.scale_factor : 1); -} - -static void ui_skinned_equalizer_slider_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedEqualizerSlider *equalizer_slider = UI_SKINNED_EQUALIZER_SLIDER (widget); - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(equalizer_slider); - - widget->allocation = *allocation; - widget->allocation.x *= (priv->scaled ? cfg.scale_factor : 1); - widget->allocation.y *= (priv->scaled ? cfg.scale_factor : 1); - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - - equalizer_slider->x = widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1); - equalizer_slider->y = widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1); -} - -static gboolean ui_skinned_equalizer_slider_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedEqualizerSlider *es = UI_SKINNED_EQUALIZER_SLIDER (widget); - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(es); - g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); - - GdkPixbuf *obj = NULL; - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->width, priv->height); - - gint frame; - frame = 27 - ((priv->position * 27) / 50); - if (frame < 14) - skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, (frame * 15) + 13, 164, 0, 0, priv->width, priv->height); - else - skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, ((frame - 14) * 15) + 13, 229, 0, 0, priv->width, priv->height); - - if (priv->pressed) - skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, 0, 176, 1, priv->position, 11, 11); - else - skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, 0, 164, 1, priv->position, 11, 11); - - ui_skinned_widget_draw(widget, obj, priv->width, priv->height, priv->scaled); - - g_object_unref(obj); - - return FALSE; -} - -static gboolean ui_skinned_equalizer_slider_button_press(GtkWidget *widget, GdkEventButton *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedEqualizerSlider *es = UI_SKINNED_EQUALIZER_SLIDER (widget); - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(es); - - gint y; - - if (event->type == GDK_BUTTON_PRESS) { - if (event->button == 1) { - priv->pressed = TRUE; - y = event->y/(priv->scaled ? cfg.scale_factor : 1); - - if (y >= priv->position && y < priv->position + 11) - priv->drag_y = y - priv->position; - else { - priv->position = y - 5; - priv->drag_y = 5; - if (priv->position < 0) - priv->position = 0; - if (priv->position > 50) - priv->position = 50; - if (priv->position >= 24 && priv->position <= 26) - priv->position = 25; - - priv->value = ((gfloat) (25 - priv->position) * EQUALIZER_MAX_GAIN / 25.0 ); - equalizerwin_eq_changed(); - } - - ui_skinned_equalizer_slider_set_mainwin_text(es); - gtk_widget_queue_draw(widget); - } - } - - return TRUE; -} - -static gboolean ui_skinned_equalizer_slider_button_release(GtkWidget *widget, GdkEventButton *event) { - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); - - if (event->button == 1) { - priv->pressed = FALSE; - mainwin_release_info_text(); - gtk_widget_queue_draw(widget); - } - return TRUE; -} - -static gboolean ui_skinned_equalizer_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - UiSkinnedEqualizerSlider *es = UI_SKINNED_EQUALIZER_SLIDER(widget); - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); - - if (priv->pressed) { - gint y; - - y = event->y/(priv->scaled ? cfg.scale_factor : 1); - priv->position = y - priv->drag_y; - - if (priv->position < 0) - priv->position = 0; - if (priv->position > 50) - priv->position = 50; - if (priv->position >= 24 && priv->position <= 26) - priv->position = 25; - - priv->value = ((gfloat) (25 - priv->position) * EQUALIZER_MAX_GAIN / 25.0 ); - ui_skinned_equalizer_slider_set_mainwin_text(es); - equalizerwin_eq_changed(); - gtk_widget_queue_draw(widget); - } - - return TRUE; -} - -static gboolean ui_skinned_equalizer_slider_scroll(GtkWidget *widget, GdkEventScroll *event) { - g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); - - if (event->direction == GDK_SCROLL_UP) { - priv->position -= 2; - - if (priv->position < 0) - priv->position = 0; - } - else { - priv->position += 2; - - if (priv->position > 50) - priv->position = 50; - } - - priv->value = ((gfloat) (25 - priv->position) * EQUALIZER_MAX_GAIN / 25.0 ); - equalizerwin_eq_changed(); - gtk_widget_queue_draw(widget); - return TRUE; -} - -static void ui_skinned_equalizer_slider_toggle_scaled(UiSkinnedEqualizerSlider *equalizer_slider) { - GtkWidget *widget = GTK_WIDGET (equalizer_slider); - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(equalizer_slider); - - priv->scaled = !priv->scaled; - - gtk_widget_set_size_request(widget, priv->width*(priv->scaled ? cfg.scale_factor : 1), - priv->height*(priv->scaled ? cfg.scale_factor : 1)); - - gtk_widget_queue_draw(GTK_WIDGET(equalizer_slider)); -} - -void ui_skinned_equalizer_slider_set_position(GtkWidget *widget, gfloat pos) { - g_return_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget)); - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); - - if (priv->pressed) - return; - - priv->value = (pos > EQUALIZER_MAX_GAIN) ? EQUALIZER_MAX_GAIN : ((pos < -EQUALIZER_MAX_GAIN) ? -EQUALIZER_MAX_GAIN : pos); - priv->position = 25 - (gint) ((pos * 25.0) / EQUALIZER_MAX_GAIN); - - if (priv->position < 0) - priv->position = 0; - - if (priv->position > 50) - priv->position = 50; - - if (priv->position >= 24 && priv->position <= 26) - priv->position = 25; - - gtk_widget_queue_draw(widget); -} - -gfloat ui_skinned_equalizer_slider_get_position(GtkWidget *widget) { - g_return_val_if_fail (UI_SKINNED_IS_EQUALIZER_SLIDER (widget), -1); - UiSkinnedEqualizerSliderPrivate *priv = UI_SKINNED_EQUALIZER_SLIDER_GET_PRIVATE(widget); - return priv->value; -} - -void ui_skinned_equalizer_slider_set_mainwin_text(UiSkinnedEqualizerSlider * es) { - gint band = 0; - const gchar *bandname[11] = { N_("PREAMP"), N_("60HZ"), N_("170HZ"), - N_("310HZ"), N_("600HZ"), N_("1KHZ"), - N_("3KHZ"), N_("6KHZ"), N_("12KHZ"), - N_("14KHZ"), N_("16KHZ") - }; - gchar *tmp; - - if (es->x > 21) - band = ((es->x - 78) / 18) + 1; - - tmp = - g_strdup_printf("EQ: %s: %+.1f DB", _(bandname[band]), - ui_skinned_equalizer_slider_get_position(GTK_WIDGET(es))); - mainwin_lock_info_text(tmp); - g_free(tmp); -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_equalizer_slider.h --- a/src/audacious/ui_skinned_equalizer_slider.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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 . - */ - -#ifndef AUDACIOUS_UI_SKINNED_EQUALIZER_SLIDER_H -#define AUDACIOUS_UI_SKINNED_EQUALIZER_SLIDER_H - -#include -#include "ui_skin.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SKINNED_EQUALIZER_SLIDER(obj) GTK_CHECK_CAST (obj, ui_skinned_equalizer_slider_get_type (), UiSkinnedEqualizerSlider) -#define UI_SKINNED_EQUALIZER_SLIDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_equalizer_slider_get_type (), UiSkinnedEqualizerSliderClass) -#define UI_SKINNED_IS_EQUALIZER_SLIDER(obj) GTK_CHECK_TYPE (obj, ui_skinned_equalizer_slider_get_type ()) - -typedef struct _UiSkinnedEqualizerSlider UiSkinnedEqualizerSlider; -typedef struct _UiSkinnedEqualizerSliderClass UiSkinnedEqualizerSliderClass; - -struct _UiSkinnedEqualizerSlider { - GtkWidget widget; - gint x, y; -}; - -struct _UiSkinnedEqualizerSliderClass { - GtkWidgetClass parent_class; - void (* scaled) (UiSkinnedEqualizerSlider *equalizer_slider); -}; - -GtkWidget* ui_skinned_equalizer_slider_new(GtkWidget *fixed, gint x, gint y); -GtkType ui_skinned_equalizer_slider_get_type(void); -void ui_skinned_equalizer_slider_set_position(GtkWidget *widget, gfloat pos); -gfloat ui_skinned_equalizer_slider_get_position(GtkWidget *widget); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SKINNED_EQUALIZER_SLIDER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_horizontal_slider.c --- a/src/audacious/ui_skinned_horizontal_slider.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,386 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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. - */ - -#include "ui_skinned_horizontal_slider.h" -#include "main.h" -#include - -#define UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_horizontal_slider_get_type(), UiSkinnedHorizontalSliderPrivate)) -typedef struct _UiSkinnedHorizontalSliderPrivate UiSkinnedHorizontalSliderPrivate; - -enum { - MOTION, - RELEASE, - DOUBLED, - LAST_SIGNAL -}; - -struct _UiSkinnedHorizontalSliderPrivate { - SkinPixmapId skin_index; - gboolean scaled; - gint frame, frame_offset, frame_height, min, max; - gint knob_width, knob_height; - gint position; - gint width, height; - gint (*frame_cb) (gint); -}; - -static void ui_skinned_horizontal_slider_class_init (UiSkinnedHorizontalSliderClass *klass); -static void ui_skinned_horizontal_slider_init (UiSkinnedHorizontalSlider *horizontal_slider); -static void ui_skinned_horizontal_slider_destroy (GtkObject *object); -static void ui_skinned_horizontal_slider_realize (GtkWidget *widget); -static void ui_skinned_horizontal_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_skinned_horizontal_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_skinned_horizontal_slider_expose (GtkWidget *widget, GdkEventExpose *event); -static gboolean ui_skinned_horizontal_slider_button_press (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_horizontal_slider_button_release (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_horizontal_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); -static void ui_skinned_horizontal_slider_toggle_scaled (UiSkinnedHorizontalSlider *horizontal_slider); - -static GtkWidgetClass *parent_class = NULL; -static guint horizontal_slider_signals[LAST_SIGNAL] = { 0 }; - -GType ui_skinned_horizontal_slider_get_type() { - static GType horizontal_slider_type = 0; - if (!horizontal_slider_type) { - static const GTypeInfo horizontal_slider_info = { - sizeof (UiSkinnedHorizontalSliderClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_horizontal_slider_class_init, - NULL, - NULL, - sizeof (UiSkinnedHorizontalSlider), - 0, - (GInstanceInitFunc) ui_skinned_horizontal_slider_init, - }; - horizontal_slider_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedHorizontalSlider_", &horizontal_slider_info, 0); - } - - return horizontal_slider_type; -} - -static void ui_skinned_horizontal_slider_class_init(UiSkinnedHorizontalSliderClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_horizontal_slider_destroy; - - widget_class->realize = ui_skinned_horizontal_slider_realize; - widget_class->expose_event = ui_skinned_horizontal_slider_expose; - widget_class->size_request = ui_skinned_horizontal_slider_size_request; - widget_class->size_allocate = ui_skinned_horizontal_slider_size_allocate; - widget_class->button_press_event = ui_skinned_horizontal_slider_button_press; - widget_class->button_release_event = ui_skinned_horizontal_slider_button_release; - widget_class->motion_notify_event = ui_skinned_horizontal_slider_motion_notify; - - klass->motion = NULL; - klass->release = NULL; - klass->scaled = ui_skinned_horizontal_slider_toggle_scaled; - - horizontal_slider_signals[MOTION] = - g_signal_new ("motion", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedHorizontalSliderClass, motion), NULL, NULL, - gtk_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - - horizontal_slider_signals[RELEASE] = - g_signal_new ("release", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedHorizontalSliderClass, release), NULL, NULL, - gtk_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - - horizontal_slider_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedHorizontalSliderClass, scaled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - g_type_class_add_private (gobject_class, sizeof (UiSkinnedHorizontalSliderPrivate)); -} - -static void ui_skinned_horizontal_slider_init(UiSkinnedHorizontalSlider *horizontal_slider) { - horizontal_slider->pressed = FALSE; -} - -GtkWidget* ui_skinned_horizontal_slider_new(GtkWidget *fixed, gint x, gint y, gint w, gint h, gint knx, gint kny, - gint kpx, gint kpy, gint kw, gint kh, gint fh, - gint fo, gint min, gint max, gint(*fcb) (gint), SkinPixmapId si) { - - UiSkinnedHorizontalSlider *hs = g_object_new (ui_skinned_horizontal_slider_get_type (), NULL); - UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(hs); - - hs->x = x; - hs->y = y; - priv->width = w; - priv->height = h; - hs->knob_nx = knx; - hs->knob_ny = kny; - hs->knob_px = kpx; - hs->knob_py = kpy; - priv->knob_width = kw; - priv->knob_height = kh; - priv->frame_height = fh; - priv->frame_offset = fo; - priv->min = min; - priv->position = min; - priv->max = max; - priv->frame_cb = fcb; - if (priv->frame_cb) - priv->frame = priv->frame_cb(0); - priv->skin_index = si; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(hs), hs->x, hs->y); - - return GTK_WIDGET(hs); -} - -static void ui_skinned_horizontal_slider_destroy(GtkObject *object) { - UiSkinnedHorizontalSlider *horizontal_slider; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (object)); - - horizontal_slider = UI_SKINNED_HORIZONTAL_SLIDER (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_horizontal_slider_realize(GtkWidget *widget) { - UiSkinnedHorizontalSlider *horizontal_slider; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - horizontal_slider = UI_SKINNED_HORIZONTAL_SLIDER(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - - widget->style = gtk_style_attach(widget->style, widget->window); - gdk_window_set_user_data(widget->window, widget); -} - -static void ui_skinned_horizontal_slider_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); - - requisition->width = priv->width*(priv->scaled ? cfg.scale_factor : 1); - requisition->height = priv->height*(priv->scaled ? cfg.scale_factor : 1); -} - -static void ui_skinned_horizontal_slider_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedHorizontalSlider *horizontal_slider = UI_SKINNED_HORIZONTAL_SLIDER (widget); - UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(horizontal_slider); - - widget->allocation = *allocation; - widget->allocation.x = ceil(widget->allocation.x*(priv->scaled ? cfg.scale_factor : 1)); - widget->allocation.y = ceil(widget->allocation.y*(priv->scaled ? cfg.scale_factor : 1)); - - if (priv->knob_height == priv->height) - priv->knob_height = ceil(allocation->height/(priv->scaled ? cfg.scale_factor : 1)); - priv->width = ceil(allocation->width/(priv->scaled ? cfg.scale_factor : 1)); - priv->height = ceil(allocation->height/(priv->scaled ? cfg.scale_factor : 1)); - - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - - horizontal_slider->x = ceil(widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1)); - horizontal_slider->y = ceil(widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1)); -} - -static gboolean ui_skinned_horizontal_slider_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER (widget); - UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(hs); - g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); - - GdkPixbuf *obj = NULL; - - if (priv->position > priv->max) priv->position = priv->max; - else if (priv->position < priv->min) priv->position = priv->min; - - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->width, priv->height); - - skin_draw_pixbuf(widget, aud_active_skin, obj, - priv->skin_index, priv->frame_offset, - priv->frame * priv->frame_height, - 0, 0, priv->width, priv->height); - if (hs->pressed) - skin_draw_pixbuf(widget, aud_active_skin, obj, - priv->skin_index, hs->knob_px, - hs->knob_py, priv->position, - ((priv->height - priv->knob_height) / 2), - priv->knob_width, priv->knob_height); - else - skin_draw_pixbuf(widget, aud_active_skin, obj, - priv->skin_index, hs->knob_nx, - hs->knob_ny, priv->position, - ((priv->height - priv->knob_height) / 2), - priv->knob_width, priv->knob_height); - - ui_skinned_widget_draw(widget, obj, priv->width, priv->height, priv->scaled); - - g_object_unref(obj); - - return FALSE; -} - -static gboolean ui_skinned_horizontal_slider_button_press(GtkWidget *widget, GdkEventButton *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER (widget); - UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(hs); - - if (event->type == GDK_BUTTON_PRESS) { - if (event->button == 1) { - gint x; - - x = event->x - (priv->knob_width / (priv->scaled ? 1 : cfg.scale_factor)); - hs->pressed = TRUE; - - priv->position = x/(priv->scaled ? cfg.scale_factor : 1); - if (priv->position < priv->min) - priv->position = priv->min; - if (priv->position > priv->max) - priv->position = priv->max; - if (priv->frame_cb) - priv->frame = priv->frame_cb(priv->position); - - g_signal_emit_by_name(widget, "motion", priv->position); - gtk_widget_queue_draw(widget); - } else if (event->button == 3) { - if (hs->pressed) { - hs->pressed = FALSE; - g_signal_emit_by_name(widget, "release", priv->position); - gtk_widget_queue_draw(widget); - } - event->x = event->x + hs->x; - event->y = event->y + hs->y; - return FALSE; - } - } - return TRUE; -} - -static gboolean ui_skinned_horizontal_slider_button_release(GtkWidget *widget, GdkEventButton *event) { - UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER(widget); - UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); - - if (hs->pressed) { - hs->pressed = FALSE; - g_signal_emit_by_name(widget, "release", priv->position); - gtk_widget_queue_draw(widget); - } - return TRUE; -} - -static gboolean ui_skinned_horizontal_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER(widget); - UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); - - if (hs->pressed) { - gint x; - - x = event->x - (priv->knob_width / (priv->scaled ? 1 : cfg.scale_factor)); - priv->position = x/(priv->scaled ? cfg.scale_factor : 1); - - if (priv->position < priv->min) - priv->position = priv->min; - - if (priv->position > priv->max) - priv->position = priv->max; - - if (priv->frame_cb) - priv->frame = priv->frame_cb(priv->position); - - g_signal_emit_by_name(widget, "motion", priv->position); - gtk_widget_queue_draw(widget); - } - - return TRUE; -} - -static void ui_skinned_horizontal_slider_toggle_scaled(UiSkinnedHorizontalSlider *horizontal_slider) { - GtkWidget *widget = GTK_WIDGET (horizontal_slider); - UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(horizontal_slider); - - priv->scaled = !priv->scaled; - - gtk_widget_set_size_request(widget, - priv->width*(priv->scaled ? cfg.scale_factor : 1), - priv->height*(priv->scaled ? cfg.scale_factor : 1)); - - gtk_widget_queue_draw(GTK_WIDGET(horizontal_slider)); -} - -void ui_skinned_horizontal_slider_set_position(GtkWidget *widget, gint pos) { - g_return_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget)); - UiSkinnedHorizontalSlider *hs = UI_SKINNED_HORIZONTAL_SLIDER(widget); - UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); - - if (pos == priv->position || hs->pressed) - return; - - priv->position = pos; - - if (priv->frame_cb) - priv->frame = priv->frame_cb(priv->position); - - gtk_widget_queue_draw(widget); -} - -gint ui_skinned_horizontal_slider_get_position(GtkWidget *widget) { - g_return_val_if_fail (UI_SKINNED_IS_HORIZONTAL_SLIDER (widget), -1); - UiSkinnedHorizontalSliderPrivate *priv = UI_SKINNED_HORIZONTAL_SLIDER_GET_PRIVATE(widget); - return priv->position; -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_horizontal_slider.h --- a/src/audacious/ui_skinned_horizontal_slider.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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_SKINNED_HORIZONTAL_SLIDER_H -#define AUDACIOUS_UI_SKINNED_HORIZONTAL_SLIDER_H - -#include -#include "ui_skin.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SKINNED_HORIZONTAL_SLIDER(obj) GTK_CHECK_CAST (obj, ui_skinned_horizontal_slider_get_type (), UiSkinnedHorizontalSlider) -#define UI_SKINNED_HORIZONTAL_SLIDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_horizontal_slider_get_type (), UiSkinnedHorizontalSliderClass) -#define UI_SKINNED_IS_HORIZONTAL_SLIDER(obj) GTK_CHECK_TYPE (obj, ui_skinned_horizontal_slider_get_type ()) - -typedef struct _UiSkinnedHorizontalSlider UiSkinnedHorizontalSlider; -typedef struct _UiSkinnedHorizontalSliderClass UiSkinnedHorizontalSliderClass; - -struct _UiSkinnedHorizontalSlider { - GtkWidget widget; - gboolean pressed; - gint x, y; - gint knob_nx, knob_ny, knob_px, knob_py; -}; - -struct _UiSkinnedHorizontalSliderClass { - GtkWidgetClass parent_class; - void (* motion) (UiSkinnedHorizontalSlider *horizontal_slider); - void (* release) (UiSkinnedHorizontalSlider *horizontal_slider); - void (* scaled) (UiSkinnedHorizontalSlider *horizontal_slider); - void (* redraw) (UiSkinnedHorizontalSlider *horizontal_slider); -}; -GtkWidget* ui_skinned_horizontal_slider_new(GtkWidget *fixed, gint x, gint y, gint w, gint h, gint knx, gint kny, - gint kpx, gint kpy, gint kw, gint kh, gint fh, - gint fo, gint min, gint max, gint(*fcb) (gint), SkinPixmapId si); -GtkType ui_skinned_horizontal_slider_get_type(void); -void ui_skinned_horizontal_slider_set_position(GtkWidget *widget, gint pos); -gint ui_skinned_horizontal_slider_get_position(GtkWidget *widget); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SKINNED_HORIZONTAL_SLIDER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_menurow.c --- a/src/audacious/ui_skinned_menurow.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,331 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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. - */ - -#include "ui_skinned_menurow.h" -#include "main.h" - -enum { - DOUBLED, - CHANGE, - RELEASE, - LAST_SIGNAL -}; - -static void ui_skinned_menurow_class_init (UiSkinnedMenurowClass *klass); -static void ui_skinned_menurow_init (UiSkinnedMenurow *menurow); -static void ui_skinned_menurow_destroy (GtkObject *object); -static void ui_skinned_menurow_realize (GtkWidget *widget); -static void ui_skinned_menurow_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_skinned_menurow_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_skinned_menurow_expose (GtkWidget *widget, GdkEventExpose *event); -static MenuRowItem menurow_find_selected (UiSkinnedMenurow * mr, gint x, gint y); -static gboolean ui_skinned_menurow_button_press (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_menurow_button_release (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_menurow_motion_notify (GtkWidget *widget, GdkEventMotion *event); -static void ui_skinned_menurow_toggle_scaled (UiSkinnedMenurow *menurow); - -static GtkWidgetClass *parent_class = NULL; -static guint menurow_signals[LAST_SIGNAL] = { 0 }; - -GType ui_skinned_menurow_get_type() { - static GType menurow_type = 0; - if (!menurow_type) { - static const GTypeInfo menurow_info = { - sizeof (UiSkinnedMenurowClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_menurow_class_init, - NULL, - NULL, - sizeof (UiSkinnedMenurow), - 0, - (GInstanceInitFunc) ui_skinned_menurow_init, - }; - menurow_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedMenurow_", &menurow_info, 0); - } - - return menurow_type; -} - -static void ui_skinned_menurow_class_init(UiSkinnedMenurowClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_menurow_destroy; - - widget_class->realize = ui_skinned_menurow_realize; - widget_class->expose_event = ui_skinned_menurow_expose; - widget_class->size_request = ui_skinned_menurow_size_request; - widget_class->size_allocate = ui_skinned_menurow_size_allocate; - widget_class->button_press_event = ui_skinned_menurow_button_press; - widget_class->button_release_event = ui_skinned_menurow_button_release; - widget_class->motion_notify_event = ui_skinned_menurow_motion_notify; - - klass->scaled = ui_skinned_menurow_toggle_scaled; - klass->change = NULL; - klass->release = NULL; - - menurow_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedMenurowClass, scaled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - - menurow_signals[CHANGE] = - g_signal_new ("change", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedMenurowClass, change), NULL, NULL, - gtk_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - - menurow_signals[RELEASE] = - g_signal_new ("release", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedMenurowClass, release), NULL, NULL, - g_cclosure_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER); - -} - -static void ui_skinned_menurow_init(UiSkinnedMenurow *menurow) { - menurow->scale_selected = cfg.scaled; - menurow->always_selected = cfg.always_on_top; -} - -GtkWidget* ui_skinned_menurow_new(GtkWidget *fixed, gint x, gint y, gint nx, gint ny, gint sx, gint sy, SkinPixmapId si) { - UiSkinnedMenurow *menurow = g_object_new (ui_skinned_menurow_get_type (), NULL); - - menurow->x = x; - menurow->y = y; - menurow->width = 8; - menurow->height = 43; - menurow->nx = nx; - menurow->ny = ny; - menurow->sx = sx; - menurow->sy = sy; - menurow->selected = MENUROW_NONE; - - menurow->skin_index = si; - - menurow->scaled = FALSE; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(menurow), menurow->x, menurow->y); - - return GTK_WIDGET(menurow); -} - -static void ui_skinned_menurow_destroy(GtkObject *object) { - UiSkinnedMenurow *menurow; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_MENUROW (object)); - - menurow = UI_SKINNED_MENUROW (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_menurow_realize(GtkWidget *widget) { - UiSkinnedMenurow *menurow; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_MENUROW(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - menurow = UI_SKINNED_MENUROW(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - - widget->style = gtk_style_attach(widget->style, widget->window); - - gdk_window_set_user_data(widget->window, widget); -} - -static void ui_skinned_menurow_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW(widget); - - requisition->width = menurow->width*(menurow->scaled ? cfg.scale_factor : 1); - requisition->height = menurow->height*(menurow->scaled ? cfg.scale_factor : 1); -} - -static void ui_skinned_menurow_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW (widget); - - widget->allocation = *allocation; - widget->allocation.x *= (menurow->scaled ? cfg.scale_factor : 1); - widget->allocation.y *= (menurow->scaled ? cfg.scale_factor : 1); - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - - menurow->x = widget->allocation.x/(menurow->scaled ? cfg.scale_factor : 1); - menurow->y = widget->allocation.y/(menurow->scaled ? cfg.scale_factor : 1); -} - -static gboolean ui_skinned_menurow_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_MENUROW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW (widget); - g_return_val_if_fail (menurow->width > 0 && menurow->height > 0, FALSE); - - GdkPixbuf *obj = NULL; - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, menurow->width, menurow->height); - - if (menurow->selected == MENUROW_NONE) { - if (cfg.always_show_cb || menurow->pushed) - skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, - menurow->nx, menurow->ny, 0, 0, 8, 43); - else - skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, - menurow->nx + 8, menurow->ny, 0, 0, 8, 43); - } - else { - skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, - menurow->sx + ((menurow->selected - 1) * 8), - menurow->sy, 0, 0, 8, 43); - } - if (cfg.always_show_cb || menurow->pushed) { - if (menurow->always_selected) - skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, - menurow->sx + 8, menurow->sy + 10, 0, 10, 8, 8); - if (menurow->scale_selected) - skin_draw_pixbuf(widget, aud_active_skin, obj, menurow->skin_index, - menurow->sx + 24, menurow->sy + 26, 0, 26, 8, 8); - } - - ui_skinned_widget_draw(widget, obj, menurow->width, menurow->height, menurow->scaled); - - g_object_unref(obj); - - return FALSE; -} - -static MenuRowItem menurow_find_selected(UiSkinnedMenurow * mr, gint x, gint y) { - MenuRowItem ret = MENUROW_NONE; - - x = x/(mr->scaled ? cfg.scale_factor : 1); - y = y/(mr->scaled ? cfg.scale_factor : 1); - if (x > 0 && x < 8) { - if (y >= 0 && y <= 10) - ret = MENUROW_OPTIONS; - if (y >= 10 && y <= 17) - ret = MENUROW_ALWAYS; - if (y >= 18 && y <= 25) - ret = MENUROW_FILEINFOBOX; - if (y >= 26 && y <= 33) - ret = MENUROW_SCALE; - if (y >= 34 && y <= 42) - ret = MENUROW_VISUALIZATION; - } - return ret; -} - -static gboolean ui_skinned_menurow_button_press(GtkWidget *widget, GdkEventButton *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_MENUROW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW (widget); - - if (event->type == GDK_BUTTON_PRESS) { - if (event->button == 1) { - - menurow->pushed = TRUE; - menurow->selected = menurow_find_selected(menurow, event->x, event->y); - - gtk_widget_queue_draw(widget); - g_signal_emit_by_name(widget, "change", menurow->selected); - } - } - - return TRUE; -} - -static gboolean ui_skinned_menurow_button_release(GtkWidget *widget, GdkEventButton *event) { - UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW(widget); - if (menurow->pushed) { - menurow->pushed = FALSE; - - if (menurow->selected == MENUROW_ALWAYS) - menurow->always_selected = !menurow->always_selected; - - if (menurow->selected == MENUROW_SCALE) - menurow->scale_selected = !menurow->scale_selected; - - if ((int)(menurow->selected) != -1) - g_signal_emit_by_name(widget, "release", menurow->selected, event); - - menurow->selected = MENUROW_NONE; - gtk_widget_queue_draw(widget); - } - - return TRUE; -} - -static gboolean ui_skinned_menurow_motion_notify(GtkWidget *widget, GdkEventMotion *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_MENUROW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - UiSkinnedMenurow *menurow = UI_SKINNED_MENUROW(widget); - - if (menurow->pushed) { - menurow->selected = menurow_find_selected(menurow, event->x, event->y); - - gtk_widget_queue_draw(widget); - g_signal_emit_by_name(widget, "change", menurow->selected); - } - - return TRUE; -} - -static void ui_skinned_menurow_toggle_scaled(UiSkinnedMenurow *menurow) { - GtkWidget *widget = GTK_WIDGET (menurow); - - menurow->scaled = !menurow->scaled; - gtk_widget_set_size_request(widget, menurow->width* (menurow->scaled ? cfg.scale_factor : 1), - menurow->height * (menurow->scaled ? cfg.scale_factor : 1)); - - gtk_widget_queue_draw(GTK_WIDGET(menurow)); -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_menurow.h --- a/src/audacious/ui_skinned_menurow.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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_SKINNED_MENUROW_H -#define AUDACIOUS_UI_SKINNED_MENUROW_H - -#include -#include "ui_skin.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SKINNED_MENUROW(obj) GTK_CHECK_CAST (obj, ui_skinned_menurow_get_type (), UiSkinnedMenurow) -#define UI_SKINNED_MENUROW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_menurow_get_type (), UiSkinnedMenurowClass) -#define UI_SKINNED_IS_MENUROW(obj) GTK_CHECK_TYPE (obj, ui_skinned_menurow_get_type ()) - -typedef struct _UiSkinnedMenurow UiSkinnedMenurow; -typedef struct _UiSkinnedMenurowClass UiSkinnedMenurowClass; - -typedef enum { - MENUROW_NONE, MENUROW_OPTIONS, MENUROW_ALWAYS, MENUROW_FILEINFOBOX, - MENUROW_SCALE, MENUROW_VISUALIZATION -} MenuRowItem; - -struct _UiSkinnedMenurow { - GtkWidget widget; - - gint x, y, width, height; - gboolean scaled; - gint nx, ny; - gint sx, sy; - MenuRowItem selected; - gboolean always_selected; - gboolean scale_selected; - gboolean pushed; - SkinPixmapId skin_index; -}; - -struct _UiSkinnedMenurowClass { - GtkWidgetClass parent_class; - void (* scaled) (UiSkinnedMenurow *menurow); - void (* change) (UiSkinnedMenurow *menurow); - void (* release) (UiSkinnedMenurow *menurow); -}; - -GtkWidget* ui_skinned_menurow_new (GtkWidget *fixed, gint x, gint y, gint nx, gint ny, gint sx, gint sy, SkinPixmapId si); -GtkType ui_skinned_menurow_get_type(void); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SKINNED_MENUROW_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_monostereo.c --- a/src/audacious/ui_skinned_monostereo.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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. - */ - -#include "ui_skin.h" -#include "ui_skinned_monostereo.h" -#include "main.h" - -enum { - DOUBLED, - LAST_SIGNAL -}; - -static void ui_skinned_monostereo_class_init (UiSkinnedMonoStereoClass *klass); -static void ui_skinned_monostereo_init (UiSkinnedMonoStereo *monostereo); -static void ui_skinned_monostereo_destroy (GtkObject *object); -static void ui_skinned_monostereo_realize (GtkWidget *widget); -static void ui_skinned_monostereo_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_skinned_monostereo_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_skinned_monostereo_expose (GtkWidget *widget, GdkEventExpose *event); -static void ui_skinned_monostereo_toggle_scaled (UiSkinnedMonoStereo *monostereo); - -static GtkWidgetClass *parent_class = NULL; -static guint monostereo_signals[LAST_SIGNAL] = { 0 }; - -GType ui_skinned_monostereo_get_type() { - static GType monostereo_type = 0; - if (!monostereo_type) { - static const GTypeInfo monostereo_info = { - sizeof (UiSkinnedMonoStereoClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_monostereo_class_init, - NULL, - NULL, - sizeof (UiSkinnedMonoStereo), - 0, - (GInstanceInitFunc) ui_skinned_monostereo_init, - }; - monostereo_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedMonoStereo_", &monostereo_info, 0); - } - - return monostereo_type; -} - -static void ui_skinned_monostereo_class_init(UiSkinnedMonoStereoClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_monostereo_destroy; - - widget_class->realize = ui_skinned_monostereo_realize; - widget_class->expose_event = ui_skinned_monostereo_expose; - widget_class->size_request = ui_skinned_monostereo_size_request; - widget_class->size_allocate = ui_skinned_monostereo_size_allocate; - - klass->scaled = ui_skinned_monostereo_toggle_scaled; - - monostereo_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedMonoStereoClass, scaled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); -} - -static void ui_skinned_monostereo_init(UiSkinnedMonoStereo *monostereo) { - monostereo->width = 56; - monostereo->height = 12; -} - -GtkWidget* ui_skinned_monostereo_new(GtkWidget *fixed, gint x, gint y, SkinPixmapId si) { - UiSkinnedMonoStereo *monostereo = g_object_new (ui_skinned_monostereo_get_type (), NULL); - - monostereo->x = x; - monostereo->y = y; - monostereo->skin_index = si; - monostereo->scaled = FALSE; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(monostereo), monostereo->x, monostereo->y); - - return GTK_WIDGET(monostereo); -} - -static void ui_skinned_monostereo_destroy(GtkObject *object) { - UiSkinnedMonoStereo *monostereo; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_MONOSTEREO (object)); - - monostereo = UI_SKINNED_MONOSTEREO (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_monostereo_realize(GtkWidget *widget) { - UiSkinnedMonoStereo *monostereo; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_MONOSTEREO(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - monostereo = UI_SKINNED_MONOSTEREO(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - - widget->style = gtk_style_attach(widget->style, widget->window); - - gdk_window_set_user_data(widget->window, widget); -} - -static void ui_skinned_monostereo_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO(widget); - - requisition->width = monostereo->width*(monostereo->scaled ? cfg.scale_factor : 1); - requisition->height = monostereo->height*(monostereo->scaled ? cfg.scale_factor : 1); -} - -static void ui_skinned_monostereo_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO (widget); - - widget->allocation = *allocation; - widget->allocation.x *= (monostereo->scaled ? cfg.scale_factor : 1); - widget->allocation.y *= (monostereo->scaled ? cfg.scale_factor : 1); - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - - monostereo->x = widget->allocation.x/(monostereo->scaled ? cfg.scale_factor : 1); - monostereo->y = widget->allocation.y/(monostereo->scaled ? cfg.scale_factor : 1); -} - -static gboolean ui_skinned_monostereo_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_MONOSTEREO (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO (widget); - g_return_val_if_fail (monostereo->width > 0 && monostereo->height > 0, FALSE); - - GdkPixbuf *obj = NULL; - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, monostereo->width, monostereo->height); - - switch (monostereo->num_channels) { - case 1: - skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 29, 0, 0, 0, 27, 12); - skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 0, 12, 27, 0, 29, 12); - break; - case 2: - skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 29, 12, 0, 0, 27, 12); - skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 0, 0, 27, 0, 29, 12); - break; - default: - case 0: - skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 29, 12, 0, 0, 27, 12); - skin_draw_pixbuf(widget, aud_active_skin, obj, monostereo->skin_index, 0, 12, 27, 0, 29, 12); - break; - } - - ui_skinned_widget_draw(widget, obj, monostereo->width, monostereo->height, monostereo->scaled); - - g_object_unref(obj); - - return FALSE; -} - -static void ui_skinned_monostereo_toggle_scaled(UiSkinnedMonoStereo *monostereo) { - GtkWidget *widget = GTK_WIDGET (monostereo); - - monostereo->scaled = !monostereo->scaled; - gtk_widget_set_size_request(widget, monostereo->width*(monostereo->scaled ? cfg.scale_factor : 1), monostereo->height*(monostereo->scaled ? cfg.scale_factor : 1)); - - gtk_widget_queue_draw(GTK_WIDGET(monostereo)); -} - -void ui_skinned_monostereo_set_num_channels(GtkWidget *widget, gint nch) { - g_return_if_fail (UI_SKINNED_IS_MONOSTEREO (widget)); - UiSkinnedMonoStereo *monostereo = UI_SKINNED_MONOSTEREO (widget); - - monostereo->num_channels = nch; - gtk_widget_queue_draw(widget); -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_monostereo.h --- a/src/audacious/ui_skinned_monostereo.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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_SKINNED_MONOSTEREO_H -#define AUDACIOUS_UI_SKINNED_MONOSTEREO_H - -#include -#include "ui_skin.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SKINNED_MONOSTEREO(obj) GTK_CHECK_CAST (obj, ui_skinned_monostereo_get_type (), UiSkinnedMonoStereo) -#define UI_SKINNED_MONOSTEREO_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_monostereo_get_type (), UiSkinnedMonoStereoClass) -#define UI_SKINNED_IS_MONOSTEREO(obj) GTK_CHECK_TYPE (obj, ui_skinned_monostereo_get_type ()) - -typedef struct _UiSkinnedMonoStereo UiSkinnedMonoStereo; -typedef struct _UiSkinnedMonoStereoClass UiSkinnedMonoStereoClass; - -struct _UiSkinnedMonoStereo { - GtkWidget widget; - - gint x, y, width, height; - gint num_channels; - SkinPixmapId skin_index; - gboolean scaled; -}; - -struct _UiSkinnedMonoStereoClass { - GtkWidgetClass parent_class; - void (* scaled) (UiSkinnedMonoStereo *menurow); -}; - -GtkWidget* ui_skinned_monostereo_new (GtkWidget *fixed, gint x, gint y, SkinPixmapId si); -GtkType ui_skinned_monostereo_get_type(void); -void ui_skinned_monostereo_set_num_channels(GtkWidget *widget, gint nch); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SKINNED_MONOSTEREO_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_number.c --- a/src/audacious/ui_skinned_number.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,234 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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. - */ - -#include "ui_skinned_number.h" -#include "main.h" -#include "strings.h" -#include -#include -#include -#include - -#define UI_TYPE_SKINNED_NUMBER (ui_skinned_number_get_type()) - -enum { - DOUBLED, - LAST_SIGNAL -}; - -static void ui_skinned_number_class_init (UiSkinnedNumberClass *klass); -static void ui_skinned_number_init (UiSkinnedNumber *number); -static void ui_skinned_number_destroy (GtkObject *object); -static void ui_skinned_number_realize (GtkWidget *widget); -static void ui_skinned_number_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_skinned_number_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_skinned_number_expose (GtkWidget *widget, GdkEventExpose *event); -static void ui_skinned_number_toggle_scaled (UiSkinnedNumber *number); - -static GtkWidgetClass *parent_class = NULL; -static guint number_signals[LAST_SIGNAL] = { 0 }; - -GType ui_skinned_number_get_type() { - static GType number_type = 0; - if (!number_type) { - static const GTypeInfo number_info = { - sizeof (UiSkinnedNumberClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_number_class_init, - NULL, - NULL, - sizeof (UiSkinnedNumber), - 0, - (GInstanceInitFunc) ui_skinned_number_init, - }; - number_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedNumber_", &number_info, 0); - } - - return number_type; -} - -static void ui_skinned_number_class_init(UiSkinnedNumberClass *klass) { - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_number_destroy; - - widget_class->realize = ui_skinned_number_realize; - widget_class->expose_event = ui_skinned_number_expose; - widget_class->size_request = ui_skinned_number_size_request; - widget_class->size_allocate = ui_skinned_number_size_allocate; - - klass->scaled = ui_skinned_number_toggle_scaled; - - number_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedNumberClass, scaled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); -} - -static void ui_skinned_number_init(UiSkinnedNumber *number) { - number->width = 9; - number->height = 13; -} - -GtkWidget* ui_skinned_number_new(GtkWidget *fixed, gint x, gint y, SkinPixmapId si) { - UiSkinnedNumber *number = g_object_new (ui_skinned_number_get_type (), NULL); - - number->x = x; - number->y = y; - number->num = 0; - number->skin_index = si; - - number->scaled = FALSE; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(number), number->x, number->y); - - return GTK_WIDGET(number); -} - -static void ui_skinned_number_destroy(GtkObject *object) { - UiSkinnedNumber *number; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_NUMBER (object)); - - number = UI_SKINNED_NUMBER (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_number_realize(GtkWidget *widget) { - UiSkinnedNumber *number; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_NUMBER(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - number = UI_SKINNED_NUMBER(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - - widget->style = gtk_style_attach(widget->style, widget->window); - - gdk_window_set_user_data(widget->window, widget); -} - -static void ui_skinned_number_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedNumber *number = UI_SKINNED_NUMBER(widget); - - requisition->width = number->width * ( number->scaled ? cfg.scale_factor : 1 ); - requisition->height = number->height*( number->scaled ? cfg.scale_factor : 1); -} - -static void ui_skinned_number_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); - - widget->allocation = *allocation; - widget->allocation.x *= (number->scaled ? cfg.scale_factor: 1 ); - widget->allocation.y *= (number->scaled ? cfg.scale_factor: 1 ); - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - - number->x = widget->allocation.x/(number->scaled ? cfg.scale_factor : 1); - number->y = widget->allocation.y/(number->scaled ? cfg.scale_factor : 1); -} - -static gboolean ui_skinned_number_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_NUMBER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); - g_return_val_if_fail (number->width > 0 && number->height > 0, FALSE); - - GdkPixbuf *obj; - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, number->width, number->height); - - if (number->num > 11 || number->num < 0) - number->num = 10; - - skin_draw_pixbuf(widget, aud_active_skin, obj, - number->skin_index, number->num * 9, 0, - 0, 0, number->width, number->height); - - ui_skinned_widget_draw(widget, obj, number->width, number->height, number->scaled); - - g_object_unref(obj); - - return FALSE; -} - -static void ui_skinned_number_toggle_scaled(UiSkinnedNumber *number) { - GtkWidget *widget = GTK_WIDGET (number); - number->scaled = !number->scaled; - - gtk_widget_set_size_request(widget, number->width * ( number->scaled ? cfg.scale_factor : 1), - number->height * ( number->scaled ? cfg.scale_factor : 1) ); - - gtk_widget_queue_draw(GTK_WIDGET(number)); -} - -void ui_skinned_number_set_number(GtkWidget *widget, gint num) { - g_return_if_fail(UI_SKINNED_IS_NUMBER(widget)); - UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); - - if (number->num == num) - return; - - number->num = num; - gtk_widget_queue_draw(GTK_WIDGET(number)); -} - -void ui_skinned_number_set_size(GtkWidget *widget, gint width, gint height) { - g_return_if_fail(UI_SKINNED_IS_NUMBER(widget)); - UiSkinnedNumber *number = UI_SKINNED_NUMBER (widget); - - number->width = width; - number->height = height; - - gtk_widget_set_size_request(widget, width*(number->scaled ? cfg.scale_factor : 1 ), - height*(number->scaled ? cfg.scale_factor : 1 )); -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_number.h --- a/src/audacious/ui_skinned_number.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * 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_SKINNED_NUMBER_H -#define AUDACIOUS_UI_SKINNED_NUMBER_H - -#include -#include "ui_skin.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SKINNED_NUMBER(obj) GTK_CHECK_CAST (obj, ui_skinned_number_get_type (), UiSkinnedNumber) -#define UI_SKINNED_NUMBER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_number_get_type (), UiSkinnedNumberClass) -#define UI_SKINNED_IS_NUMBER(obj) GTK_CHECK_TYPE (obj, ui_skinned_number_get_type ()) - -typedef struct _UiSkinnedNumber UiSkinnedNumber; -typedef struct _UiSkinnedNumberClass UiSkinnedNumberClass; - -struct _UiSkinnedNumber { - GtkWidget widget; - - gint x, y, width, height; - gint num; - gboolean scaled; - SkinPixmapId skin_index; -}; - -struct _UiSkinnedNumberClass { - GtkWidgetClass parent_class; - void (* scaled) (UiSkinnedNumber *textbox); -}; - -GtkWidget* ui_skinned_number_new (GtkWidget *fixed, gint x, gint y, SkinPixmapId si); -GtkType ui_skinned_number_get_type(void); -void ui_skinned_number_set_number(GtkWidget *widget, gint num); -void ui_skinned_number_set_size(GtkWidget *widget, gint width, gint height); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SKINNED_NUMBER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_playlist.c --- a/src/audacious/ui_skinned_playlist.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1105 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * Copyright (c) 2008 William Pitcock - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * - * 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. - */ - -/* - * A note about Pango and some funky spacey fonts: Weirdly baselined - * fonts, or fonts with weird ascents or descents _will_ display a - * little bit weird in the playlist widget, but the display engine - * won't make it look too bad, just a little deranged. I honestly - * don't think it's worth fixing (around...), it doesn't have to be - * perfectly fitting, just the general look has to be ok, which it - * IMHO is. - * - * A second note: The numbers aren't perfectly aligned, but in the - * end it looks better when using a single Pango layout for each - * number. - */ - -#include "ui_skinned_playlist.h" - -#include "debug.h" -#include "input.h" -#include "main.h" -#include "playback.h" -#include "playlist.h" -#include "strings.h" -#include "ui_fileinfopopup.h" -#include "ui_manager.h" -#include "ui_playlist.h" -#include "ui_skin.h" -#include "util.h" - -static PangoFontDescription *playlist_list_font = NULL; -static gint ascent, descent, width_delta_digit_one; -static gboolean has_slant; -static guint padding; - -/* FIXME: the following globals should not be needed. */ -static gint width_approx_letters; -static gint width_colon, width_colon_third; -static gint width_approx_digits, width_approx_digits_half; - -#define UI_SKINNED_PLAYLIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_playlist_get_type(), UiSkinnedPlaylistPrivate)) -typedef struct _UiSkinnedPlaylistPrivate UiSkinnedPlaylistPrivate; - -enum { - REDRAW, - LAST_SIGNAL -}; - -struct _UiSkinnedPlaylistPrivate { - SkinPixmapId skin_index; - gint width, height; - gint resize_width, resize_height; - gint drag_pos; - gboolean dragging, auto_drag_down, auto_drag_up; - gint auto_drag_up_tag, auto_drag_down_tag; -}; - -static void ui_skinned_playlist_class_init (UiSkinnedPlaylistClass *klass); -static void ui_skinned_playlist_init (UiSkinnedPlaylist *playlist); -static void ui_skinned_playlist_destroy (GtkObject *object); -static void ui_skinned_playlist_realize (GtkWidget *widget); -static void ui_skinned_playlist_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_skinned_playlist_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_skinned_playlist_expose (GtkWidget *widget, GdkEventExpose *event); -static gboolean ui_skinned_playlist_button_press (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_playlist_button_release (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_playlist_motion_notify (GtkWidget *widget, GdkEventMotion *event); -static gboolean ui_skinned_playlist_leave_notify (GtkWidget *widget, GdkEventCrossing *event); -static void ui_skinned_playlist_redraw (UiSkinnedPlaylist *playlist); -static gboolean ui_skinned_playlist_popup_show (gpointer data); -static void ui_skinned_playlist_popup_hide (GtkWidget *widget); -static void ui_skinned_playlist_popup_timer_start (GtkWidget *widget); -static void ui_skinned_playlist_popup_timer_stop (GtkWidget *widget); - -static GtkWidgetClass *parent_class = NULL; -static guint playlist_signals[LAST_SIGNAL] = { 0 }; - -GType ui_skinned_playlist_get_type() { - static GType playlist_type = 0; - if (!playlist_type) { - static const GTypeInfo playlist_info = { - sizeof (UiSkinnedPlaylistClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_playlist_class_init, - NULL, - NULL, - sizeof (UiSkinnedPlaylist), - 0, - (GInstanceInitFunc) ui_skinned_playlist_init, - }; - playlist_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedPlaylist_", &playlist_info, 0); - } - - return playlist_type; -} - -static void ui_skinned_playlist_class_init(UiSkinnedPlaylistClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_playlist_destroy; - - widget_class->realize = ui_skinned_playlist_realize; - widget_class->expose_event = ui_skinned_playlist_expose; - widget_class->size_request = ui_skinned_playlist_size_request; - widget_class->size_allocate = ui_skinned_playlist_size_allocate; - widget_class->button_press_event = ui_skinned_playlist_button_press; - widget_class->button_release_event = ui_skinned_playlist_button_release; - widget_class->motion_notify_event = ui_skinned_playlist_motion_notify; - widget_class->leave_notify_event = ui_skinned_playlist_leave_notify; - - klass->redraw = ui_skinned_playlist_redraw; - - playlist_signals[REDRAW] = - g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedPlaylistClass, redraw), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - g_type_class_add_private (gobject_class, sizeof (UiSkinnedPlaylistPrivate)); -} - -static void ui_skinned_playlist_init(UiSkinnedPlaylist *playlist) { - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(playlist); - playlist->pressed = FALSE; - priv->resize_width = 0; - priv->resize_height = 0; - playlist->prev_selected = -1; - playlist->prev_min = -1; - playlist->prev_max = -1; - - g_object_set_data(G_OBJECT(playlist), "timer_id", GINT_TO_POINTER(0)); - g_object_set_data(G_OBJECT(playlist), "timer_active", GINT_TO_POINTER(0)); - - GtkWidget *popup = fileinfopopup_create(); - g_object_set_data(G_OBJECT(playlist), "popup", popup); - g_object_set_data(G_OBJECT(playlist), "popup_active", GINT_TO_POINTER(0)); - g_object_set_data(G_OBJECT(playlist), "popup_position", GINT_TO_POINTER(-1)); -} - -GtkWidget* ui_skinned_playlist_new(GtkWidget *fixed, gint x, gint y, gint w, gint h) { - - UiSkinnedPlaylist *hs = g_object_new (ui_skinned_playlist_get_type (), NULL); - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(hs); - - hs->x = x; - hs->y = y; - priv->width = w; - priv->height = h; - priv->skin_index = SKIN_PLEDIT; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(hs), hs->x, hs->y); - gtk_widget_set_double_buffered(GTK_WIDGET(hs), TRUE); - - return GTK_WIDGET(hs); -} - -static void ui_skinned_playlist_destroy(GtkObject *object) { - UiSkinnedPlaylist *playlist; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_PLAYLIST (object)); - - playlist = UI_SKINNED_PLAYLIST (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_playlist_realize(GtkWidget *widget) { - UiSkinnedPlaylist *playlist; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_PLAYLIST(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - playlist = UI_SKINNED_PLAYLIST(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | - GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - - widget->style = gtk_style_attach(widget->style, widget->window); - gdk_window_set_user_data(widget->window, widget); -} - -static void ui_skinned_playlist_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); - - requisition->width = priv->width; - requisition->height = priv->height; -} - -static void ui_skinned_playlist_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedPlaylist *playlist = UI_SKINNED_PLAYLIST (widget); - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(playlist); - - widget->allocation = *allocation; - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - - playlist->x = widget->allocation.x; - playlist->y = widget->allocation.y; - - if (priv->height != widget->allocation.height || priv->width != widget->allocation.width) { - priv->width = priv->width + priv->resize_width; - priv->height = priv->height + priv->resize_height; - priv->resize_width = 0; - priv->resize_height = 0; - gtk_widget_queue_draw(widget); - } -} - -static gboolean ui_skinned_playlist_auto_drag_down_func(gpointer data) { - UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST(data); - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(data); - - if (priv->auto_drag_down) { - ui_skinned_playlist_move_down(pl); - pl->first++; - playlistwin_update_list(playlist_get_active()); - return TRUE; - } - return FALSE; -} - -static gboolean ui_skinned_playlist_auto_drag_up_func(gpointer data) { - UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST(data); - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(data); - - if (priv->auto_drag_up) { - ui_skinned_playlist_move_up(pl); - pl->first--; - playlistwin_update_list(playlist_get_active()); - return TRUE; - - } - return FALSE; -} - -void ui_skinned_playlist_move_up(UiSkinnedPlaylist * pl) { - GList *list; - Playlist *playlist = playlist_get_active(); - - if (!playlist) - return; - - PLAYLIST_LOCK(playlist); - if ((list = playlist->entries) == NULL) { - PLAYLIST_UNLOCK(playlist); - return; - } - if (PLAYLIST_ENTRY(list->data)->selected) { - /* We are at the top */ - PLAYLIST_UNLOCK(playlist); - return; - } - while (list) { - if (PLAYLIST_ENTRY(list->data)->selected) - glist_moveup(list); - list = g_list_next(list); - } - PLAYLIST_INCR_SERIAL(playlist); - PLAYLIST_UNLOCK(playlist); - if (pl->prev_selected != -1) - pl->prev_selected--; - if (pl->prev_min != -1) - pl->prev_min--; - if (pl->prev_max != -1) - pl->prev_max--; -} - -void ui_skinned_playlist_move_down(UiSkinnedPlaylist * pl) { - GList *list; - Playlist *playlist = playlist_get_active(); - - if (!playlist) - return; - - PLAYLIST_LOCK(playlist); - - if (!(list = g_list_last(playlist->entries))) { - PLAYLIST_UNLOCK(playlist); - return; - } - - if (PLAYLIST_ENTRY(list->data)->selected) { - /* We are at the bottom */ - PLAYLIST_UNLOCK(playlist); - return; - } - - while (list) { - if (PLAYLIST_ENTRY(list->data)->selected) - glist_movedown(list); - list = g_list_previous(list); - } - - PLAYLIST_INCR_SERIAL(playlist); - PLAYLIST_UNLOCK(playlist); - - if (pl->prev_selected != -1) - pl->prev_selected++; - if (pl->prev_min != -1) - pl->prev_min++; - if (pl->prev_max != -1) - pl->prev_max++; -} - -static void -playlist_list_draw_string(cairo_t *cr, UiSkinnedPlaylist *pl, - PangoFontDescription * font, - gint line, - gint width, - const gchar * text, - guint ppos) -{ - guint plist_length_int; - Playlist *playlist = playlist_get_active(); - PangoLayout *layout; - - REQUIRE_LOCK(playlist->mutex); - - cairo_new_path(cr); - - if (cfg.show_numbers_in_pl) { - gchar *pos_string = g_strdup_printf(cfg.show_separator_in_pl == TRUE ? "%d" : "%d.", ppos); - plist_length_int = - gint_count_digits(playlist_get_length(playlist)) + !cfg.show_separator_in_pl + 1; /* cf.show_separator_in_pl will be 0 if false */ - - padding = plist_length_int; - padding = ((padding + 1) * width_approx_digits); - - layout = gtk_widget_create_pango_layout(playlistwin, pos_string); - pango_layout_set_font_description(layout, playlist_list_font); - pango_layout_set_width(layout, plist_length_int * 100); - - pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); - - cairo_move_to(cr, (width_approx_digits * - (-1 + plist_length_int - strlen(pos_string))) + - (width_approx_digits / 4), (line - 1) * pl->fheight + - ascent + abs(descent)); - pango_cairo_show_layout(cr, layout); - - g_free(pos_string); - g_object_unref(layout); - - if (!cfg.show_separator_in_pl) - padding -= (width_approx_digits * 1.5); - } else { - padding = 3; - } - - width -= padding; - - layout = gtk_widget_create_pango_layout(playlistwin, text); - - pango_layout_set_font_description(layout, playlist_list_font); - pango_layout_set_width(layout, width * PANGO_SCALE); - pango_layout_set_single_paragraph_mode(layout, TRUE); - pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); - - cairo_move_to(cr, padding + (width_approx_letters / 4), - (line - 1) * pl->fheight + - ascent + abs(descent)); - pango_cairo_show_layout(cr, layout); - - g_object_unref(layout); -} - -static gboolean ui_skinned_playlist_expose(GtkWidget *widget, GdkEventExpose *event) { - UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST (widget); - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(pl); - g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); - - Playlist *playlist = playlist_get_active(); - PlaylistEntry *entry; - GList *list; - PangoLayout *layout; - gchar *title; - gint width, height; - gint i, max_first; - guint padding, padding_dwidth, padding_plength; - guint max_time_len = 0; - gfloat queue_tailpadding = 0; - gint tpadding; - gsize tpadding_dwidth = 0; - gint x, y; - guint tail_width; - guint tail_len; - gboolean in_selection = FALSE; - - gchar tail[100]; - gchar queuepos[255]; - gchar length[40]; - - gchar **frags; - gchar *frag0; - - gint plw_w, plw_h; - - cairo_t *cr; - gint yc; - gint pos; - gdouble rounding_offset; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_PLAYLIST (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - cr = gdk_cairo_create(widget->window); - - width = priv->width; - height = priv->height; - - plw_w = playlistwin_get_width(); - plw_h = playlistwin_get_height(); - - gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_NORMALBG)); - - cairo_rectangle(cr, 0, 0, width, height); - cairo_paint(cr); - - if (!playlist_list_font) { - g_critical("Couldn't open playlist font"); - return FALSE; - } - - pl->fheight = (ascent + abs(descent)); - pl->num_visible = height / pl->fheight; - - rounding_offset = pl->fheight / 3; - - max_first = playlist_get_length(playlist) - pl->num_visible; - max_first = MAX(max_first, 0); - - pl->first = CLAMP(pl->first, 0, max_first); - - PLAYLIST_LOCK(playlist); - list = playlist->entries; - list = g_list_nth(list, pl->first); - - /* It sucks having to run the iteration twice but this is the only - way you can reliably get the maximum width so we can get our - playlist nice and aligned... -- plasmaroo */ - - for (i = pl->first; - list && i < pl->first + pl->num_visible; - list = g_list_next(list), i++) { - entry = list->data; - - if (entry->length != -1) - { - g_snprintf(length, sizeof(length), "%d:%-2.2d", - entry->length / 60000, (entry->length / 1000) % 60); - tpadding_dwidth = MAX(tpadding_dwidth, strlen(length)); - } - } - - /* Reset */ - list = playlist->entries; - list = g_list_nth(list, pl->first); - - for (i = pl->first; - list && i < pl->first + pl->num_visible; - list = g_list_next(list), i++) { - entry = list->data; - - if (entry->selected && !in_selection) { - yc = ((i - pl->first) * pl->fheight); - - cairo_new_path(cr); - - cairo_move_to(cr, 0, yc + (rounding_offset * 2)); - cairo_curve_to(cr, 0, yc + rounding_offset, 0, yc + 0.5, 0 + rounding_offset, yc + 0.5); - - cairo_line_to(cr, 0 + width - (rounding_offset * 2), yc + 0.5); - cairo_curve_to(cr, 0 + width - rounding_offset, yc + 0.5, - 0 + width, yc + 0.5, 0 + width, yc + rounding_offset); - - in_selection = TRUE; - } - - if ((!entry->selected || - (i == pl->first + pl->num_visible - 1) || !g_list_next(list)) - && in_selection) { - - if (!entry->selected) - yc = (((i - 1) - pl->first) * pl->fheight); - else /* last visible item */ - yc = ((i - pl->first) * pl->fheight); - - cairo_line_to(cr, 0 + width, yc + pl->fheight - (rounding_offset * 2)); - cairo_curve_to (cr, 0 + width, yc + pl->fheight - rounding_offset, - 0 + width, yc + pl->fheight - 0.5, - 0 + width-rounding_offset, yc + pl->fheight - 0.5); - - cairo_line_to (cr, 0 + (rounding_offset * 2), yc + pl->fheight - 0.5); - cairo_curve_to (cr, 0 + rounding_offset, yc + pl->fheight - 0.5, - 0, yc + pl->fheight - 0.5, - 0, yc + pl->fheight - rounding_offset); - - cairo_close_path (cr); - - gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_SELECTEDBG)); - - cairo_fill(cr); - - in_selection = FALSE; - } - } - - list = playlist->entries; - list = g_list_nth(list, pl->first); - - /* now draw the text */ - for (i = pl->first; - list && i < pl->first + pl->num_visible; - list = g_list_next(list), i++) { - entry = list->data; - - /* FIXME: entry->title should NEVER be NULL, and there should - NEVER be a need to do a UTF-8 conversion. Playlist title - strings should be kept properly. */ - - if (!entry->title) { - gchar *realfn = g_filename_from_uri(entry->filename, NULL, NULL); - gchar *basename = g_path_get_basename(realfn ? realfn : entry->filename); - title = filename_to_utf8(basename); - g_free(basename); g_free(realfn); - } - else - title = str_assert_utf8(entry->title); - - title = convert_title_text(title); - - pos = playlist_get_queue_position(playlist, entry); - - tail[0] = 0; - queuepos[0] = 0; - length[0] = 0; - - if (pos != -1) - g_snprintf(queuepos, sizeof(queuepos), "%d", pos + 1); - - if (entry->length != -1) - { - g_snprintf(length, sizeof(length), "%d:%-2.2d", - entry->length / 60000, (entry->length / 1000) % 60); - } - - strncat(tail, length, sizeof(tail) - 1); - tail_len = strlen(tail); - - max_time_len = MAX(max_time_len, tail_len); - - if (pos != -1 && tpadding_dwidth <= 0) - tail_width = width - (width_approx_digits * (strlen(queuepos) + 2.25)); - else if (pos != -1) - tail_width = width - (width_approx_digits * (tpadding_dwidth + strlen(queuepos) + 4)); - else if (tpadding_dwidth > 0) - tail_width = width - (width_approx_digits * (tpadding_dwidth + 2.5)); - else - tail_width = width; - - if (i == playlist_get_position_nolock(playlist)) - gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_CURRENT)); - else - gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_NORMAL)); - - playlist_list_draw_string(cr, pl, playlist_list_font, - i - pl->first, tail_width, title, - i + 1); - - x = width - width_approx_digits * 2; - y = ((i - pl->first) - 1) * pl->fheight + ascent; - - frags = NULL; - frag0 = NULL; - - if ((strlen(tail) > 0) && (tail != NULL)) { - frags = g_strsplit(tail, ":", 0); - frag0 = g_strconcat(frags[0], ":", NULL); - - layout = gtk_widget_create_pango_layout(playlistwin, frags[1]); - pango_layout_set_font_description(layout, playlist_list_font); - pango_layout_set_width(layout, tail_len * 100); - pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); - - cairo_new_path(cr); - cairo_move_to(cr, x - (0.5 * width_approx_digits), y + abs(descent)); - pango_cairo_show_layout(cr, layout); - g_object_unref(layout); - - layout = gtk_widget_create_pango_layout(playlistwin, frag0); - pango_layout_set_font_description(layout, playlist_list_font); - pango_layout_set_width(layout, tail_len * 100); - pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT); - - cairo_move_to(cr, x - (0.75 * width_approx_digits), y + abs(descent)); - pango_cairo_show_layout(cr, layout); - g_object_unref(layout); - - g_free(frag0); - g_strfreev(frags); - } - - if (pos != -1) { - if (tpadding_dwidth > 0) - queue_tailpadding = tpadding_dwidth + 1; - else - queue_tailpadding = -0.75; - - cairo_rectangle(cr, - x - - (((queue_tailpadding + - strlen(queuepos)) * - width_approx_digits) + - (width_approx_digits / 4)), - y + abs(descent), - (strlen(queuepos)) * - width_approx_digits + - (width_approx_digits / 2), - pl->fheight - 2); - - layout = - gtk_widget_create_pango_layout(playlistwin, queuepos); - pango_layout_set_font_description(layout, playlist_list_font); - pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); - - cairo_move_to(cr, - x - - ((queue_tailpadding + - strlen(queuepos)) * width_approx_digits) + - (width_approx_digits / 4), - y + abs(descent)); - pango_cairo_show_layout(cr, layout); - - g_object_unref(layout); - } - - cairo_stroke(cr); - - g_free(title); - } - - - /* - * Drop target hovering over the playlist, so draw some hint where the - * drop will occur. - * - * This is (currently? unfixably?) broken when dragging files from Qt/KDE apps, - * probably due to DnD signaling problems (actually i have no clue). - * - */ - - if (pl->drag_motion) { - guint pos, plength, lpadding; - - if (cfg.show_numbers_in_pl) { - lpadding = gint_count_digits(playlist_get_length(playlist)) + 1; - lpadding = ((lpadding + 1) * width_approx_digits); - } - else { - lpadding = 3; - }; - - /* We already hold the mutex and have the playlist locked, so call - the non-locking function. */ - plength = playlist_get_length(playlist); - - x = pl->drag_motion_x; - y = pl->drag_motion_y; - - if ((x > pl->x) && !(x > priv->width)) { - - if ((y > pl->y) - && !(y > (priv->height + pl->y))) { - - pos = (y / pl->fheight) + - pl->first; - - if (pos > (plength)) { - pos = plength; - } - - gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_CURRENT)); - - cairo_new_path(cr); - - cairo_move_to(cr, 0, ((pos - pl->first) * pl->fheight)); - cairo_rel_line_to(cr, priv->width - 1, 0); - - cairo_set_line_width(cr, 1); - cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); - cairo_stroke(cr); - } - - } - - /* When dropping on the borders of the playlist, outside the text area, - * files get appended at the end of the list. Show that too. - */ - - if ((y < pl->y) || (y > priv->height + pl->y)) { - if ((y >= 0) || (y <= (priv->height + pl->y))) { - pos = plength; - - gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_CURRENT)); - - cairo_new_path(cr); - - cairo_move_to(cr, 0, ((pos - pl->first) * pl->fheight)); - cairo_rel_line_to(cr, priv->width - 1, 0); - - cairo_set_line_width(cr, 1); - cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); - cairo_stroke(cr); - } - } - } - - gdk_cairo_set_source_color(cr, skin_get_color(aud_active_skin, SKIN_PLEDIT_NORMAL)); - cairo_set_line_width(cr, 1); - cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); - - if (cfg.show_numbers_in_pl) - { - padding_plength = playlist_get_length(playlist); - - if (padding_plength == 0) { - padding_dwidth = 0; - } - else { - padding_dwidth = gint_count_digits(playlist_get_length(playlist)); - } - - padding = - (padding_dwidth * - width_approx_digits) + width_approx_digits; - - - /* For italic or oblique fonts we add another half of the - * approximate width */ - if (has_slant) - padding += width_approx_digits_half; - - if (cfg.show_separator_in_pl) { - cairo_new_path(cr); - - cairo_move_to(cr, padding, 0); - cairo_rel_line_to(cr, 0, priv->height - 1); - - cairo_stroke(cr); - } - } - - if (tpadding_dwidth != 0) - { - tpadding = (tpadding_dwidth * width_approx_digits) + (width_approx_digits * 1.5); - - if (has_slant) - tpadding += width_approx_digits_half; - - if (cfg.show_separator_in_pl) { - cairo_new_path(cr); - - cairo_move_to(cr, priv->width - tpadding, 0); - cairo_rel_line_to(cr, 0, priv->height - 1); - - cairo_stroke(cr); - } - } - - PLAYLIST_UNLOCK(playlist); - - cairo_destroy(cr); - - return FALSE; -} - -gint ui_skinned_playlist_get_position(GtkWidget *widget, gint x, gint y) { - gint iy, length; - gint ret; - Playlist *playlist = playlist_get_active(); - UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST (widget); - - if (!pl->fheight) - return -1; - - if ((length = playlist_get_length(playlist)) == 0) - return -1; - iy = y; - - ret = (iy / pl->fheight) + pl->first; - - if (ret > length - 1) - ret = -1; - - return ret; -} - -static gboolean ui_skinned_playlist_button_press(GtkWidget *widget, GdkEventButton *event) { - UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST (widget); - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); - - gint nr; - Playlist *playlist = playlist_get_active(); - - nr = ui_skinned_playlist_get_position(widget, event->x, event->y); - if (nr == -1) - return FALSE; - - if (event->button == 3) { - ui_manager_popup_menu_show(GTK_MENU(playlistwin_popup_menu), - event->x_root, event->y_root + 5, - event->button, event->time); - GList* selection = playlist_get_selected(playlist); - if (g_list_find(selection, GINT_TO_POINTER(nr)) == NULL) { - playlist_select_all(playlist, FALSE); - playlist_select_range(playlist, nr, nr, TRUE); - } - } else if (event->button == 1) { - if (!(event->state & GDK_CONTROL_MASK)) - playlist_select_all(playlist, FALSE); - - if ((event->state & GDK_MOD1_MASK)) - playlist_queue_position(playlist, nr); - - if (event->state & GDK_SHIFT_MASK && pl->prev_selected != -1) { - playlist_select_range(playlist, pl->prev_selected, nr, TRUE); - pl->prev_min = pl->prev_selected; - pl->prev_max = nr; - priv->drag_pos = nr - pl->first; - } - else { - if (playlist_select_invert(playlist, nr)) { - if (event->state & GDK_CONTROL_MASK) { - if (pl->prev_min == -1) { - pl->prev_min = pl->prev_selected; - pl->prev_max = pl->prev_selected; - } - if (nr < pl->prev_min) - pl->prev_min = nr; - else if (nr > pl->prev_max) - pl->prev_max = nr; - } - else - pl->prev_min = -1; - pl->prev_selected = nr; - priv->drag_pos = nr - pl->first; - } - } - if (event->type == GDK_2BUTTON_PRESS) { - /* - * Ungrab the pointer to prevent us from - * hanging on to it during the sometimes slow - * playback_initiate(). - */ - gdk_pointer_ungrab(GDK_CURRENT_TIME); - playlist_set_position(playlist, nr); - if (!playback_get_playing()) - playback_initiate(); - } - - priv->dragging = TRUE; - } - playlistwin_update_list(playlist); - ui_skinned_playlist_popup_hide(widget); - ui_skinned_playlist_popup_timer_stop(widget); - - return TRUE; -} - -static gboolean ui_skinned_playlist_button_release(GtkWidget *widget, GdkEventButton *event) { - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); - - priv->dragging = FALSE; - priv->auto_drag_down = FALSE; - priv->auto_drag_up = FALSE; - gtk_widget_queue_draw(widget); - - ui_skinned_playlist_popup_hide(widget); - ui_skinned_playlist_popup_timer_stop(widget); - return TRUE; -} - -static gboolean ui_skinned_playlist_motion_notify(GtkWidget *widget, GdkEventMotion *event) { - UiSkinnedPlaylist *pl = UI_SKINNED_PLAYLIST(widget); - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); - - gint nr, y, off, i; - if (priv->dragging) { - y = event->y; - nr = (y / pl->fheight); - if (nr < 0) { - nr = 0; - if (!priv->auto_drag_up) { - priv->auto_drag_up = TRUE; - priv->auto_drag_up_tag = - g_timeout_add(100, ui_skinned_playlist_auto_drag_up_func, pl); - } - } - else if (priv->auto_drag_up) - priv->auto_drag_up = FALSE; - - if (nr >= pl->num_visible) { - nr = pl->num_visible - 1; - if (!priv->auto_drag_down) { - priv->auto_drag_down = TRUE; - priv->auto_drag_down_tag = - g_timeout_add(100, ui_skinned_playlist_auto_drag_down_func, pl); - } - } - else if (priv->auto_drag_down) - priv->auto_drag_down = FALSE; - - off = nr - priv->drag_pos; - if (off) { - for (i = 0; i < abs(off); i++) { - if (off < 0) - ui_skinned_playlist_move_up(pl); - else - ui_skinned_playlist_move_down(pl); - - } - playlistwin_update_list(playlist_get_active()); - } - priv->drag_pos = nr; - } else if (cfg.show_filepopup_for_tuple) { - gint pos = ui_skinned_playlist_get_position(widget, event->x, event->y); - gint cur_pos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "popup_position")); - if (pos != cur_pos) { - g_object_set_data(G_OBJECT(widget), "popup_position", GINT_TO_POINTER(pos)); - ui_skinned_playlist_popup_hide(widget); - ui_skinned_playlist_popup_timer_stop(widget); - if (pos != -1) - ui_skinned_playlist_popup_timer_start(widget); - } - } - - return TRUE; -} - -static gboolean ui_skinned_playlist_leave_notify(GtkWidget *widget, GdkEventCrossing *event) { - ui_skinned_playlist_popup_hide(widget); - ui_skinned_playlist_popup_timer_stop(widget); - - return FALSE; -} - -static void ui_skinned_playlist_redraw(UiSkinnedPlaylist *playlist) { - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(playlist); - - if (priv->resize_height || priv->resize_width) - gtk_widget_set_size_request(GTK_WIDGET(playlist), priv->width+priv->resize_width, priv->height+priv->resize_height); - - gtk_widget_queue_draw(GTK_WIDGET(playlist)); -} - -void ui_skinned_playlist_set_font(const gchar * font) { - /* Welcome to bad hack central 2k3 */ - gchar *font_lower; - gint width_temp; - gint width_temp_0; - - playlist_list_font = pango_font_description_from_string(font); - - text_get_extents(font, - "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz ", - &width_approx_letters, NULL, &ascent, &descent); - - width_approx_letters = (width_approx_letters / 53); - - /* Experimental: We don't weigh the 1 into total because it's width is almost always - * very different from the rest - */ - text_get_extents(font, "023456789", &width_approx_digits, NULL, NULL, - NULL); - width_approx_digits = (width_approx_digits / 9); - - /* Precache some often used calculations */ - width_approx_digits_half = width_approx_digits / 2; - - /* FIXME: We assume that any other number is broader than the "1" */ - text_get_extents(font, "1", &width_temp, NULL, NULL, NULL); - text_get_extents(font, "2", &width_temp_0, NULL, NULL, NULL); - - if (abs(width_temp_0 - width_temp) < 2) { - width_delta_digit_one = 0; - } - else { - width_delta_digit_one = ((width_temp_0 - width_temp) / 2) + 2; - } - - text_get_extents(font, ":", &width_colon, NULL, NULL, NULL); - width_colon_third = width_colon / 4; - - font_lower = g_utf8_strdown(font, strlen(font)); - /* This doesn't take any i18n into account, but i think there is none with TTF fonts - * FIXME: This can probably be retrieved trough Pango too - */ - has_slant = g_strstr_len(font_lower, strlen(font_lower), "oblique") - || g_strstr_len(font_lower, strlen(font_lower), "italic"); - - g_free(font_lower); -} - -void ui_skinned_playlist_resize_relative(GtkWidget *widget, gint w, gint h) { - UiSkinnedPlaylistPrivate *priv = UI_SKINNED_PLAYLIST_GET_PRIVATE(widget); - priv->resize_width += w; - priv->resize_height += h; -} - -static gboolean ui_skinned_playlist_popup_show(gpointer data) { - GtkWidget *widget = data; - gint pos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "popup_position")); - - if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "timer_active")) == 1 && pos != -1) { - Tuple *tuple; - Playlist *pl_active = playlist_get_active(); - GtkWidget *popup = g_object_get_data(G_OBJECT(widget), "popup"); - - tuple = playlist_get_tuple(pl_active, pos); - if ((tuple == NULL) || (tuple_get_int(tuple, FIELD_LENGTH, NULL) < 1)) { - gchar *title = playlist_get_songtitle(pl_active, pos); - fileinfopopup_show_from_title(popup, title); - g_free(title); - } else { - fileinfopopup_show_from_tuple(popup , tuple); - } - g_object_set_data(G_OBJECT(widget), "popup_active" , GINT_TO_POINTER(1)); - } - - ui_skinned_playlist_popup_timer_stop(widget); - return FALSE; -} - -static void ui_skinned_playlist_popup_hide(GtkWidget *widget) { - if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "popup_active")) == 1) { - GtkWidget *popup = g_object_get_data(G_OBJECT(widget), "popup"); - g_object_set_data(G_OBJECT(widget), "popup_active", GINT_TO_POINTER(0)); - fileinfopopup_hide(popup, NULL); - } -} - -static void ui_skinned_playlist_popup_timer_start(GtkWidget *widget) { - gint timer_id = g_timeout_add(cfg.filepopup_delay*100, ui_skinned_playlist_popup_show, widget); - g_object_set_data(G_OBJECT(widget), "timer_id", GINT_TO_POINTER(timer_id)); - g_object_set_data(G_OBJECT(widget), "timer_active", GINT_TO_POINTER(1)); -} - -static void ui_skinned_playlist_popup_timer_stop(GtkWidget *widget) { - if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "timer_active")) == 1) - g_source_remove(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "timer_id"))); - - g_object_set_data(G_OBJECT(widget), "timer_id", GINT_TO_POINTER(0)); - g_object_set_data(G_OBJECT(widget), "timer_active", GINT_TO_POINTER(0)); -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_playlist.h --- a/src/audacious/ui_skinned_playlist.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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_SKINNED_PLAYLIST_H -#define AUDACIOUS_UI_SKINNED_PLAYLIST_H - -#include - -#include -#include - -#include "ui_skin.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SKINNED_PLAYLIST(obj) GTK_CHECK_CAST (obj, ui_skinned_playlist_get_type (), UiSkinnedPlaylist) -#define UI_SKINNED_PLAYLIST_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_playlist_get_type (), UiSkinnedPlaylistClass) -#define UI_SKINNED_IS_PLAYLIST(obj) GTK_CHECK_TYPE (obj, ui_skinned_playlist_get_type ()) - -typedef struct _UiSkinnedPlaylist UiSkinnedPlaylist; -typedef struct _UiSkinnedPlaylistClass UiSkinnedPlaylistClass; - -struct _UiSkinnedPlaylist { - GtkWidget widget; - gboolean pressed; - gint x, y; - gint first; - gint num_visible; - gint prev_selected, prev_min, prev_max; - gboolean drag_motion; - gint drag_motion_x, drag_motion_y; - gint fheight; -}; - -struct _UiSkinnedPlaylistClass { - GtkWidgetClass parent_class; - void (* redraw) (UiSkinnedPlaylist *playlist); -}; - -GtkWidget* ui_skinned_playlist_new(GtkWidget *fixed, gint x, gint y, gint w, gint h); -GtkType ui_skinned_playlist_get_type(void); -void ui_skinned_playlist_resize_relative(GtkWidget *widget, gint w, gint h); -void ui_skinned_playlist_set_font(const gchar * font); -void ui_skinned_playlist_move_up(UiSkinnedPlaylist *pl); -void ui_skinned_playlist_move_down(UiSkinnedPlaylist *pl); -gint ui_skinned_playlist_get_position(GtkWidget *widget, gint x, gint y); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SKINNED_PLAYLIST_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_playlist_slider.c --- a/src/audacious/ui_skinned_playlist_slider.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,338 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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. - */ - -#include "ui_skin.h" -#include "ui_skinned_playlist_slider.h" -#include "main.h" -#include "ui_playlist.h" - -#define UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_playlist_slider_get_type(), UiSkinnedPlaylistSliderPrivate)) -typedef struct _UiSkinnedPlaylistSliderPrivate UiSkinnedPlaylistSliderPrivate; - -enum { - REDRAW, - LAST_SIGNAL -}; - -struct _UiSkinnedPlaylistSliderPrivate { - SkinPixmapId skin_index; - gint width, height; - - gint resize_height; - gint move_x; - gint prev_y; - gint drag_y; -}; - -static void ui_skinned_playlist_slider_class_init (UiSkinnedPlaylistSliderClass *klass); -static void ui_skinned_playlist_slider_init (UiSkinnedPlaylistSlider *playlist_slider); -static void ui_skinned_playlist_slider_destroy (GtkObject *object); -static void ui_skinned_playlist_slider_realize (GtkWidget *widget); -static void ui_skinned_playlist_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_skinned_playlist_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_skinned_playlist_slider_expose (GtkWidget *widget, GdkEventExpose *event); -static void ui_skinned_playlist_slider_set_position (GtkWidget *widget, gint y); -static gboolean ui_skinned_playlist_slider_button_press (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_playlist_slider_button_release (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_playlist_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); -static void ui_skinned_playlist_slider_redraw (UiSkinnedPlaylistSlider *playlist_slider); - -static GtkWidgetClass *parent_class = NULL; -static guint playlist_slider_signals[LAST_SIGNAL] = { 0 }; - -GType ui_skinned_playlist_slider_get_type() { - static GType playlist_slider_type = 0; - if (!playlist_slider_type) { - static const GTypeInfo playlist_slider_info = { - sizeof (UiSkinnedPlaylistSliderClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_playlist_slider_class_init, - NULL, - NULL, - sizeof (UiSkinnedPlaylistSlider), - 0, - (GInstanceInitFunc) ui_skinned_playlist_slider_init, - }; - playlist_slider_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedPlaylistSlider_", &playlist_slider_info, 0); - } - - return playlist_slider_type; -} - -static void ui_skinned_playlist_slider_class_init(UiSkinnedPlaylistSliderClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_playlist_slider_destroy; - - widget_class->realize = ui_skinned_playlist_slider_realize; - widget_class->expose_event = ui_skinned_playlist_slider_expose; - widget_class->size_request = ui_skinned_playlist_slider_size_request; - widget_class->size_allocate = ui_skinned_playlist_slider_size_allocate; - widget_class->button_press_event = ui_skinned_playlist_slider_button_press; - widget_class->button_release_event = ui_skinned_playlist_slider_button_release; - widget_class->motion_notify_event = ui_skinned_playlist_slider_motion_notify; - - klass->redraw = ui_skinned_playlist_slider_redraw; - - playlist_slider_signals[REDRAW] = - g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedPlaylistSliderClass, redraw), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - g_type_class_add_private (gobject_class, sizeof (UiSkinnedPlaylistSliderPrivate)); -} - -static void ui_skinned_playlist_slider_init(UiSkinnedPlaylistSlider *playlist_slider) { - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(playlist_slider); - playlist_slider->pressed = FALSE; - priv->resize_height = 0; - priv->move_x = 0; - priv->drag_y = 0; - priv->prev_y = 0; -} - -GtkWidget* ui_skinned_playlist_slider_new(GtkWidget *fixed, gint x, gint y, gint h) { - - UiSkinnedPlaylistSlider *hs = g_object_new (ui_skinned_playlist_slider_get_type (), NULL); - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(hs); - - hs->x = x; - hs->y = y; - priv->width = 8; - priv->height = h; - priv->skin_index = SKIN_PLEDIT; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(hs), hs->x, hs->y); - - return GTK_WIDGET(hs); -} - -static void ui_skinned_playlist_slider_destroy(GtkObject *object) { - UiSkinnedPlaylistSlider *playlist_slider; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_PLAYLIST_SLIDER (object)); - - playlist_slider = UI_SKINNED_PLAYLIST_SLIDER (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_playlist_slider_realize(GtkWidget *widget) { - UiSkinnedPlaylistSlider *playlist_slider; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_PLAYLIST_SLIDER(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - playlist_slider = UI_SKINNED_PLAYLIST_SLIDER(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - - widget->style = gtk_style_attach(widget->style, widget->window); - gdk_window_set_user_data(widget->window, widget); -} - -static void ui_skinned_playlist_slider_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); - - requisition->width = priv->width; - requisition->height = priv->height; -} - -static void ui_skinned_playlist_slider_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedPlaylistSlider *playlist_slider = UI_SKINNED_PLAYLIST_SLIDER (widget); - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(playlist_slider); - - widget->allocation = *allocation; - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - - if (playlist_slider->x + priv->move_x == widget->allocation.x) - priv->move_x = 0; - playlist_slider->x = widget->allocation.x; - playlist_slider->y = widget->allocation.y; - - if (priv->height != widget->allocation.height) { - priv->height = priv->height + priv->resize_height; - priv->resize_height = 0; - gtk_widget_queue_draw(widget); - } -} - -static gboolean ui_skinned_playlist_slider_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_PLAYLIST_SLIDER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER (widget); - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(ps); - g_return_val_if_fail (priv->width > 0 && priv->height > 0, FALSE); - - GdkPixbuf *obj = NULL; - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->width, priv->height); - - gint num_visible; - num_visible = playlistwin_list_get_visible_count(); - - - Playlist *playlist = playlist_get_active(); - - gint y; - if (playlist_get_length(playlist) > num_visible) - y = (playlistwin_list_get_first() * (priv->height - 19)) / - (playlist_get_length(playlist) - num_visible); - else - y = 0; - - if (y < 0) y=0; - if (y > priv->height - 19) y = priv->height - 19; - - priv->prev_y = y; - - /* FIXME: uses aud_active_skin->pixmaps directly and may need calibration */ - /* drawing background */ - gint c; - for (c = 0; c < priv->height / 29; c++) { - gdk_pixbuf_copy_area(aud_active_skin->pixmaps[SKIN_PLEDIT].pixbuf, - 36, 42, priv->width, 29, obj, 0, c*29); - } - - /* drawing knob */ - skin_draw_pixbuf(widget, aud_active_skin, obj, priv->skin_index, ps->pressed ? 61 : 52, 53, 0, y, priv->width, 18); - - ui_skinned_widget_draw(widget, obj, priv->width, priv->height, FALSE); - - g_object_unref(obj); - - return FALSE; -} - -static void ui_skinned_playlist_slider_set_position(GtkWidget *widget, gint y) { - gint pos; - Playlist *playlist = playlist_get_active(); - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); - - y = CLAMP(y, 0, priv->height - 19); - - pos = (y * (playlist_get_length(playlist) - playlistwin_list_get_visible_count())) / (priv->height - 19); - playlistwin_set_toprow(pos); - - gtk_widget_queue_draw(widget); -} - -static gboolean ui_skinned_playlist_slider_button_press(GtkWidget *widget, GdkEventButton *event) { - UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER (widget); - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); - - if (event->button != 1 && event->button != 2) - return TRUE; - - gint y = event->y; - if (event->type == GDK_BUTTON_PRESS) { - ps->pressed = TRUE; - if ((y >= priv->prev_y && y < priv->prev_y + 18)) { - priv->drag_y = y - priv->prev_y; - } else if (event->button == 2) { - ui_skinned_playlist_slider_set_position(widget, y); - priv->drag_y = 0; - } else { - gint n = playlistwin_list_get_visible_count() / 2; - if (y < priv->prev_y) - n *= -1; - playlistwin_scroll(n); - } - gtk_widget_queue_draw(widget); - } - return TRUE; -} - -static gboolean ui_skinned_playlist_slider_button_release(GtkWidget *widget, GdkEventButton *event) { - UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER(widget); - - if (event->button == 1 || event->button == 2) { - ps->pressed = FALSE; - gtk_widget_queue_draw(widget); - } - return TRUE; -} - -static gboolean ui_skinned_playlist_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event) { - UiSkinnedPlaylistSlider *ps = UI_SKINNED_PLAYLIST_SLIDER(widget); - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); - - if (ps->pressed) { - gint y = event->y - priv->drag_y; - ui_skinned_playlist_slider_set_position(widget, y); - } - return TRUE; -} - -static void ui_skinned_playlist_slider_redraw(UiSkinnedPlaylistSlider *playlist_slider) { - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(playlist_slider); - - if (priv->resize_height) - gtk_widget_set_size_request(GTK_WIDGET(playlist_slider), priv->width, priv->height+priv->resize_height); - if (priv->move_x) - gtk_fixed_move(GTK_FIXED(gtk_widget_get_parent(GTK_WIDGET(playlist_slider))), GTK_WIDGET(playlist_slider), - playlist_slider->x+priv->move_x, playlist_slider->y); - - gtk_widget_queue_draw(GTK_WIDGET(playlist_slider)); -} - -void ui_skinned_playlist_slider_move_relative(GtkWidget *widget, gint x) { - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); - priv->move_x += x; -} - -void ui_skinned_playlist_slider_resize_relative(GtkWidget *widget, gint h) { - UiSkinnedPlaylistSliderPrivate *priv = UI_SKINNED_PLAYLIST_SLIDER_GET_PRIVATE(widget); - priv->resize_height += h; -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_playlist_slider.h --- a/src/audacious/ui_skinned_playlist_slider.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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_SKINNED_PLAYLIST_SLIDER_H -#define AUDACIOUS_UI_SKINNED_PLAYLIST_SLIDER_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SKINNED_PLAYLIST_SLIDER(obj) GTK_CHECK_CAST (obj, ui_skinned_playlist_slider_get_type (), UiSkinnedPlaylistSlider) -#define UI_SKINNED_PLAYLIST_SLIDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_playlist_slider_get_type (), UiSkinnedPlaylistSliderClass) -#define UI_SKINNED_IS_PLAYLIST_SLIDER(obj) GTK_CHECK_TYPE (obj, ui_skinned_playlist_slider_get_type ()) - -typedef struct _UiSkinnedPlaylistSlider UiSkinnedPlaylistSlider; -typedef struct _UiSkinnedPlaylistSliderClass UiSkinnedPlaylistSliderClass; - -struct _UiSkinnedPlaylistSlider { - GtkWidget widget; - gboolean pressed; - gint x, y; -}; - -struct _UiSkinnedPlaylistSliderClass { - GtkWidgetClass parent_class; - void (* redraw) (UiSkinnedPlaylistSlider *playlist_slider); -}; - -GtkWidget* ui_skinned_playlist_slider_new(GtkWidget *fixed, gint x, gint y, gint h); -GtkType ui_skinned_playlist_slider_get_type(void); -void ui_skinned_playlist_slider_move_relative(GtkWidget *widget, gint x); -void ui_skinned_playlist_slider_resize_relative(GtkWidget *widget, gint h); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SKINNED_PLAYLIST_SLIDER_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_playstatus.c --- a/src/audacious/ui_skinned_playstatus.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,246 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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. - */ - -#include "ui_skin.h" -#include "ui_skinned_playstatus.h" -#include "main.h" - -#define UI_TYPE_SKINNED_PLAYSTATUS (ui_skinned_playstatus_get_type()) - -enum { - DOUBLED, - LAST_SIGNAL -}; - -static void ui_skinned_playstatus_class_init (UiSkinnedPlaystatusClass *klass); -static void ui_skinned_playstatus_init (UiSkinnedPlaystatus *playstatus); -static void ui_skinned_playstatus_destroy (GtkObject *object); -static void ui_skinned_playstatus_realize (GtkWidget *widget); -static void ui_skinned_playstatus_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_skinned_playstatus_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_skinned_playstatus_expose (GtkWidget *widget, GdkEventExpose *event); -static void ui_skinned_playstatus_toggle_scaled (UiSkinnedPlaystatus *playstatus); - -static GtkWidgetClass *parent_class = NULL; -static guint playstatus_signals[LAST_SIGNAL] = { 0 }; - -GType ui_skinned_playstatus_get_type() { - static GType playstatus_type = 0; - if (!playstatus_type) { - static const GTypeInfo playstatus_info = { - sizeof (UiSkinnedPlaystatusClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_playstatus_class_init, - NULL, - NULL, - sizeof (UiSkinnedPlaystatus), - 0, - (GInstanceInitFunc) ui_skinned_playstatus_init, - }; - playstatus_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedPlaystatus_", &playstatus_info, 0); - } - - return playstatus_type; -} - -static void ui_skinned_playstatus_class_init(UiSkinnedPlaystatusClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_playstatus_destroy; - - widget_class->realize = ui_skinned_playstatus_realize; - widget_class->expose_event = ui_skinned_playstatus_expose; - widget_class->size_request = ui_skinned_playstatus_size_request; - widget_class->size_allocate = ui_skinned_playstatus_size_allocate; - - klass->scaled = ui_skinned_playstatus_toggle_scaled; - - playstatus_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedPlaystatusClass, scaled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); -} - -static void ui_skinned_playstatus_init(UiSkinnedPlaystatus *playstatus) { - playstatus->width = 11; - playstatus->height = 9; -} - -GtkWidget* ui_skinned_playstatus_new(GtkWidget *fixed, gint x, gint y) { - UiSkinnedPlaystatus *playstatus = g_object_new (ui_skinned_playstatus_get_type (), NULL); - - playstatus->x = x; - playstatus->y = y; - - playstatus->scaled = FALSE; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(playstatus), playstatus->x, playstatus->y); - - return GTK_WIDGET(playstatus); -} - -static void ui_skinned_playstatus_destroy(GtkObject *object) { - UiSkinnedPlaystatus *playstatus; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (object)); - - playstatus = UI_SKINNED_PLAYSTATUS (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_playstatus_realize(GtkWidget *widget) { - UiSkinnedPlaystatus *playstatus; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - playstatus = UI_SKINNED_PLAYSTATUS(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - - widget->style = gtk_style_attach(widget->style, widget->window); - - gdk_window_set_user_data(widget->window, widget); -} - -static void ui_skinned_playstatus_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS(widget); - - requisition->width = playstatus->width*(playstatus->scaled ? cfg.scale_factor : 1); - requisition->height = playstatus->height*(playstatus->scaled ? cfg.scale_factor : 1); -} - -static void ui_skinned_playstatus_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); - - widget->allocation = *allocation; - widget->allocation.x *= (playstatus->scaled ? cfg.scale_factor : 1); - widget->allocation.y *= (playstatus->scaled ? cfg.scale_factor : 1); - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - - playstatus->x = widget->allocation.x/(playstatus->scaled ? cfg.scale_factor : 1); - playstatus->y = widget->allocation.y/(playstatus->scaled ? cfg.scale_factor : 1); -} - -static gboolean ui_skinned_playstatus_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); - g_return_val_if_fail (playstatus->width > 0 && playstatus->height > 0, FALSE); - - GdkPixbuf *obj = NULL; - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, playstatus->width, playstatus->height); - - if (playstatus->status == STATUS_STOP && playstatus->buffering == TRUE) - playstatus->buffering = FALSE; - if (playstatus->status == STATUS_PLAY && playstatus->buffering == TRUE) - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 39, 0, 0, 0, 3, playstatus->height); - else if (playstatus->status == STATUS_PLAY) - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 36, 0, 0, 0, 3, playstatus->height); - else - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 27, 0, 0, 0, 2, playstatus->height); - switch (playstatus->status) { - case STATUS_STOP: - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 18, 0, 2, 0, 9, playstatus->height); - break; - case STATUS_PAUSE: - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 9, 0, 2, 0, 9, playstatus->height); - break; - case STATUS_PLAY: - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_PLAYPAUSE, 1, 0, 3, 0, 8, playstatus->height); - break; - } - - ui_skinned_widget_draw(widget, obj, playstatus->width, playstatus->height, playstatus->scaled); - - g_object_unref(obj); - - return FALSE; -} - -static void ui_skinned_playstatus_toggle_scaled(UiSkinnedPlaystatus *playstatus) { - GtkWidget *widget = GTK_WIDGET (playstatus); - - playstatus->scaled = !playstatus->scaled; - gtk_widget_set_size_request(widget, playstatus->width*(playstatus->scaled ? cfg.scale_factor : 1), playstatus->height*(playstatus->scaled ? cfg.scale_factor : 1)); - - gtk_widget_queue_draw(GTK_WIDGET(playstatus)); -} - -void ui_skinned_playstatus_set_status(GtkWidget *widget, PStatus status) { - g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget)); - UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); - - playstatus->status = status; - gtk_widget_queue_draw(widget); -} - -void ui_skinned_playstatus_set_buffering(GtkWidget *widget, gboolean status) { - g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget)); - UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); - - playstatus->buffering = status; - gtk_widget_queue_draw(widget); -} - -void ui_skinned_playstatus_set_size(GtkWidget *widget, gint width, gint height) { - g_return_if_fail (UI_SKINNED_IS_PLAYSTATUS (widget)); - UiSkinnedPlaystatus *playstatus = UI_SKINNED_PLAYSTATUS (widget); - - playstatus->width = width; - playstatus->height = height; - - gtk_widget_set_size_request(widget, width*(playstatus->scaled ? cfg.scale_factor : 1), height*(playstatus->scaled ? cfg.scale_factor : 1)); -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_playstatus.h --- a/src/audacious/ui_skinned_playstatus.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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_SKINNED_PLAYSTATUS_H -#define AUDACIOUS_UI_SKINNED_PLAYSTATUS_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SKINNED_PLAYSTATUS(obj) GTK_CHECK_CAST (obj, ui_skinned_playstatus_get_type (), UiSkinnedPlaystatus) -#define UI_SKINNED_PLAYSTATUS_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_playstatus_get_type (), UiSkinnedPlaystatusClass) -#define UI_SKINNED_IS_PLAYSTATUS(obj) GTK_CHECK_TYPE (obj, ui_skinned_playstatus_get_type ()) - -typedef struct _UiSkinnedPlaystatus UiSkinnedPlaystatus; -typedef struct _UiSkinnedPlaystatusClass UiSkinnedPlaystatusClass; - -typedef enum { - STATUS_STOP, STATUS_PAUSE, STATUS_PLAY -} PStatus; - -struct _UiSkinnedPlaystatus { - GtkWidget widget; - - gint x, y, width, height; - gboolean scaled; - PStatus status; - gboolean buffering; -}; - -struct _UiSkinnedPlaystatusClass { - GtkWidgetClass parent_class; - void (* scaled) (UiSkinnedPlaystatus *menurow); -}; - -GtkWidget* ui_skinned_playstatus_new (GtkWidget *fixed, gint x, gint y); -GtkType ui_skinned_playstatus_get_type(void); -void ui_skinned_playstatus_set_status(GtkWidget *widget, PStatus status); -void ui_skinned_playstatus_set_buffering(GtkWidget *widget, gboolean status); -void ui_skinned_playstatus_set_size(GtkWidget *widget, gint width, gint height); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SKINNED_PLAYSTATUS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_textbox.c --- a/src/audacious/ui_skinned_textbox.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,871 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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. - */ - -#include "ui_skinned_textbox.h" - -#include - -#include "main.h" -#include "util.h" -#include "strings.h" - -#define UI_SKINNED_TEXTBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ui_skinned_textbox_get_type(), UiSkinnedTextboxPrivate)) -typedef struct _UiSkinnedTextboxPrivate UiSkinnedTextboxPrivate; - -#define TEXTBOX_SCROLL_SMOOTH_TIMEOUT 30 -#define TEXTBOX_SCROLL_WAIT 80 - -enum { - CLICKED, - DOUBLE_CLICKED, - RIGHT_CLICKED, - DOUBLED, - REDRAW, - LAST_SIGNAL -}; - -struct _UiSkinnedTextboxPrivate { - SkinPixmapId skin_index; - gboolean scaled; - gboolean scroll_back; - gint nominal_y, nominal_height; - gint scroll_timeout; - gint font_ascent, font_descent; - PangoFontDescription *font; - gchar *fontname; - gchar *pixbuf_text; - gint skin_id; - gint drag_x, drag_off, offset; - gboolean is_scrollable, is_dragging; - gint pixbuf_width; - GdkPixbuf *pixbuf; - gboolean scroll_allowed, scroll_enabled; - gint scroll_dummy; - gint move_x, move_y; -}; - -static void ui_skinned_textbox_class_init (UiSkinnedTextboxClass *klass); -static void ui_skinned_textbox_init (UiSkinnedTextbox *textbox); -static void ui_skinned_textbox_destroy (GtkObject *object); -static void ui_skinned_textbox_realize (GtkWidget *widget); -static void ui_skinned_textbox_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_skinned_textbox_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_skinned_textbox_expose (GtkWidget *widget, GdkEventExpose *event); -static gboolean ui_skinned_textbox_button_press (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_textbox_button_release (GtkWidget *widget, GdkEventButton *event); -static gboolean ui_skinned_textbox_motion_notify (GtkWidget *widget, GdkEventMotion *event); -static void ui_skinned_textbox_toggle_scaled (UiSkinnedTextbox *textbox); -static void ui_skinned_textbox_redraw (UiSkinnedTextbox *textbox); -static gboolean ui_skinned_textbox_should_scroll (UiSkinnedTextbox *textbox); -static void textbox_generate_xfont_pixmap (UiSkinnedTextbox *textbox, const gchar *pixmaptext); -static gboolean textbox_scroll (gpointer data); -static void textbox_generate_pixmap (UiSkinnedTextbox *textbox); -static void textbox_handle_special_char (gchar *c, gint * x, gint * y); - -static GtkWidgetClass *parent_class = NULL; -static guint textbox_signals[LAST_SIGNAL] = { 0 }; - -GType ui_skinned_textbox_get_type() { - static GType textbox_type = 0; - if (!textbox_type) { - static const GTypeInfo textbox_info = { - sizeof (UiSkinnedTextboxClass), - NULL, - NULL, - (GClassInitFunc) ui_skinned_textbox_class_init, - NULL, - NULL, - sizeof (UiSkinnedTextbox), - 0, - (GInstanceInitFunc) ui_skinned_textbox_init, - }; - textbox_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSkinnedTextbox_", &textbox_info, 0); - } - - return textbox_type; -} - -static void ui_skinned_textbox_class_init(UiSkinnedTextboxClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_skinned_textbox_destroy; - - widget_class->realize = ui_skinned_textbox_realize; - widget_class->expose_event = ui_skinned_textbox_expose; - widget_class->size_request = ui_skinned_textbox_size_request; - widget_class->size_allocate = ui_skinned_textbox_size_allocate; - widget_class->button_press_event = ui_skinned_textbox_button_press; - widget_class->button_release_event = ui_skinned_textbox_button_release; - widget_class->motion_notify_event = ui_skinned_textbox_motion_notify; - - klass->clicked = NULL; - klass->double_clicked = NULL; - klass->right_clicked = NULL; - klass->scaled = ui_skinned_textbox_toggle_scaled; - klass->redraw = ui_skinned_textbox_redraw; - - textbox_signals[CLICKED] = - g_signal_new ("clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedTextboxClass, clicked), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - textbox_signals[DOUBLE_CLICKED] = - g_signal_new ("double-clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedTextboxClass, double_clicked), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - textbox_signals[RIGHT_CLICKED] = - g_signal_new ("right-clicked", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedTextboxClass, right_clicked), NULL, NULL, - gtk_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - - textbox_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedTextboxClass, scaled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - textbox_signals[REDRAW] = - g_signal_new ("redraw", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSkinnedTextboxClass, redraw), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - - g_type_class_add_private (gobject_class, sizeof (UiSkinnedTextboxPrivate)); -} - -static void ui_skinned_textbox_init(UiSkinnedTextbox *textbox) { - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - priv->move_x = 0; - priv->move_y = 0; -} - -GtkWidget* ui_skinned_textbox_new(GtkWidget *fixed, gint x, gint y, gint w, gboolean allow_scroll, SkinPixmapId si) { - UiSkinnedTextbox *textbox = g_object_new (ui_skinned_textbox_get_type (), NULL); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - textbox->height = aud_active_skin->properties.textbox_bitmap_font_height; - textbox->x = x; - textbox->y = y; - textbox->text = g_strdup(""); - textbox->width = w; - priv->scroll_allowed = allow_scroll; - priv->scroll_enabled = TRUE; - priv->skin_index = si; - priv->nominal_y = y; - priv->nominal_height = textbox->height; - priv->scroll_timeout = 0; - priv->scroll_dummy = 0; - - priv->scaled = FALSE; - - gtk_fixed_put(GTK_FIXED(fixed), GTK_WIDGET(textbox), textbox->x, textbox->y); - - return GTK_WIDGET(textbox); -} - -static void ui_skinned_textbox_destroy(GtkObject *object) { - UiSkinnedTextbox *textbox; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_SKINNED_IS_TEXTBOX (object)); - - textbox = UI_SKINNED_TEXTBOX (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_skinned_textbox_realize(GtkWidget *widget) { - UiSkinnedTextbox *textbox; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_SKINNED_IS_TEXTBOX(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - textbox = UI_SKINNED_TEXTBOX(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - - widget->style = gtk_style_attach(widget->style, widget->window); - - gdk_window_set_user_data(widget->window, widget); -} - -static void ui_skinned_textbox_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(widget); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - requisition->width = textbox->width*(priv->scaled ? cfg.scale_factor : 1); - requisition->height = textbox->height*(priv->scaled ? cfg.scale_factor : 1 ); -} - -static void ui_skinned_textbox_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - widget->allocation = *allocation; - widget->allocation.x *= (priv->scaled ? cfg.scale_factor : 1); - widget->allocation.y *= (priv->scaled ? cfg.scale_factor : 1); - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - - if (textbox->x + priv->move_x - widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1) <3); - priv->move_x = 0; - if (textbox->y + priv->move_y - widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1) <3); - priv->move_y = 0; - textbox->x = widget->allocation.x/(priv->scaled ? cfg.scale_factor : 1); - textbox->y = widget->allocation.y/(priv->scaled ? cfg.scale_factor : 1); - - if (textbox->width - (guint) (widget->allocation.width / (priv->scaled ? cfg.scale_factor : 1)) > 2) { - textbox->width = (guint) (widget->allocation.width / (priv->scaled ? cfg.scale_factor : 1)); - if (priv->pixbuf_text) g_free(priv->pixbuf_text); - priv->pixbuf_text = NULL; - priv->offset = 0; - gtk_widget_set_size_request(widget, textbox->width, textbox->height); - gtk_widget_queue_draw(GTK_WIDGET(textbox)); - } -} - -static gboolean ui_skinned_textbox_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_TEXTBOX (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - g_return_val_if_fail (textbox->width > 0 && textbox->height > 0, FALSE); - - GdkPixbuf *obj = NULL; - gint cw; - - if (textbox->text && (!priv->pixbuf_text || strcmp(textbox->text, priv->pixbuf_text))) - textbox_generate_pixmap(textbox); - - if (priv->pixbuf) { - if (skin_get_id() != priv->skin_id) { - priv->skin_id = skin_get_id(); - textbox_generate_pixmap(textbox); - } - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, textbox->width, textbox->height); - - if (cfg.twoway_scroll) { // twoway scroll - cw = priv->pixbuf_width - priv->offset; - if (cw > textbox->width) - cw = textbox->width; - gdk_pixbuf_copy_area(priv->pixbuf, priv->offset, 0, cw, textbox->height, obj, 0, 0); - if (cw < textbox->width) - gdk_pixbuf_copy_area(priv->pixbuf, 0, 0, textbox->width - cw, textbox->height, - obj, textbox->width - cw, textbox->height); - } else { // oneway scroll - int cw1, cw2; - - if (priv->offset >= priv->pixbuf_width) - priv->offset = 0; - - if (priv->pixbuf_width - priv->offset > textbox->width) { // case1 - cw1 = textbox->width; - gdk_pixbuf_copy_area(priv->pixbuf, priv->offset, 0, cw1, textbox->height, - obj, 0, 0); - } else { // case 2 - cw1 = priv->pixbuf_width - priv->offset; - gdk_pixbuf_copy_area(priv->pixbuf, priv->offset, 0, cw1, textbox->height, obj, 0, 0); - cw2 = textbox->width - cw1; - gdk_pixbuf_copy_area(priv->pixbuf, 0, 0, cw2, textbox->height, obj, cw1, 0); - } - } - - ui_skinned_widget_draw(widget, obj, textbox->width, textbox->height, priv->scaled); - - g_object_unref(obj); - } - - return FALSE; -} - -static gboolean ui_skinned_textbox_button_press(GtkWidget *widget, GdkEventButton *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_TEXTBOX (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - if (event->type == GDK_BUTTON_PRESS) { - textbox = UI_SKINNED_TEXTBOX(widget); - if (event->button == 3 && !g_signal_has_handler_pending(widget, textbox_signals[RIGHT_CLICKED], 0, TRUE)) - return FALSE; - else if (event->button == 1) { - if (priv->scroll_allowed) { - if ((priv->pixbuf_width > textbox->width) && priv->is_scrollable) { - priv->is_dragging = TRUE; - priv->drag_off = priv->offset; - priv->drag_x = event->x; - } - } else - g_signal_emit(widget, textbox_signals[CLICKED], 0); - - } else if (event->button == 3) { - g_signal_emit(widget, textbox_signals[RIGHT_CLICKED], 0, event); - } else - priv->is_dragging = FALSE; - } else if (event->type == GDK_2BUTTON_PRESS) { - if (event->button == 1) { - if (g_signal_has_handler_pending(widget, textbox_signals[DOUBLE_CLICKED], 0, TRUE)) - g_signal_emit(widget, textbox_signals[DOUBLE_CLICKED], 0); - else - return FALSE; - } - } - - return TRUE; -} - -static gboolean ui_skinned_textbox_button_release(GtkWidget *widget, GdkEventButton *event) { - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(widget); - - if (event->button == 1) { - priv->is_dragging = FALSE; - } - - return TRUE; -} - -static gboolean ui_skinned_textbox_motion_notify(GtkWidget *widget, GdkEventMotion *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_SKINNED_IS_TEXTBOX (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(widget); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(widget); - - if (priv->is_dragging) { - if (priv->scroll_allowed && - priv->pixbuf_width > textbox->width) { - priv->offset = priv->drag_off - (event->x - priv->drag_x); - - while (priv->offset < 0) - priv->offset = 0; - - while (priv->offset > (priv->pixbuf_width - textbox->width)) - priv->offset = (priv->pixbuf_width - textbox->width); - - gtk_widget_queue_draw(widget); - } - } - - return TRUE; -} - -static void ui_skinned_textbox_toggle_scaled(UiSkinnedTextbox *textbox) { - GtkWidget *widget = GTK_WIDGET (textbox); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - priv->scaled = !priv->scaled; - - gtk_widget_set_size_request(widget, textbox->width*(priv->scaled ? cfg.scale_factor : 1 ), - textbox->height*(priv->scaled ? cfg.scale_factor : 1 )); - - gtk_widget_queue_draw(GTK_WIDGET(textbox)); -} - -static void ui_skinned_textbox_redraw(UiSkinnedTextbox *textbox) { - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - if (priv->move_x || priv->move_y) - gtk_fixed_move(GTK_FIXED(gtk_widget_get_parent(GTK_WIDGET(textbox))), GTK_WIDGET(textbox), - textbox->x+priv->move_x, textbox->y+priv->move_y); - - gtk_widget_queue_draw(GTK_WIDGET(textbox)); -} - -static gboolean ui_skinned_textbox_should_scroll(UiSkinnedTextbox *textbox) { - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - if (!priv->scroll_allowed) - return FALSE; - - if (priv->font) { - gint width; - text_get_extents(priv->fontname, textbox->text, &width, NULL, NULL, NULL); - - if (width <= textbox->width) - return FALSE; - else - return TRUE; - } - - if (g_utf8_strlen(textbox->text, -1) * aud_active_skin->properties.textbox_bitmap_font_width > textbox->width) - return TRUE; - - return FALSE; -} - -void ui_skinned_textbox_set_xfont(GtkWidget *widget, gboolean use_xfont, const gchar * fontname) { - UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - gint ascent, descent; - - g_return_if_fail(textbox != NULL); - - if (priv->font) { - pango_font_description_free(priv->font); - priv->font = NULL; - } - - textbox->y = priv->nominal_y; - textbox->height = priv->nominal_height; - - /* Make sure the pixmap is regenerated */ - if (priv->pixbuf_text) { - g_free(priv->pixbuf_text); - priv->pixbuf_text = NULL; - } - - if (!use_xfont || strlen(fontname) == 0) - return; - - priv->font = pango_font_description_from_string(fontname); - priv->fontname = g_strdup(fontname); - - text_get_extents(fontname, - "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz ", - NULL, NULL, &ascent, &descent); - priv->font_ascent = ascent; - priv->font_descent = descent; - - - if (priv->font == NULL) - return; - - textbox->height = priv->font_ascent; - if (textbox->height > priv->nominal_height) - textbox->y -= (textbox->height - priv->nominal_height) / 2; - else - textbox->height = priv->nominal_height; -} - -void ui_skinned_textbox_set_text(GtkWidget *widget, const gchar *text) { - g_return_if_fail(text != NULL); - UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - if (!strcmp(textbox->text, text)) - return; - if (textbox->text) - g_free(textbox->text); - - textbox->text = str_assert_utf8(text); - priv->scroll_back = FALSE; - gtk_widget_queue_draw(GTK_WIDGET(textbox)); -} - -static void textbox_generate_xfont_pixmap(UiSkinnedTextbox *textbox, const gchar *pixmaptext) { - /* FIXME: should operate directly on priv->pixbuf, it shouldn't use pixmap */ - gint length, i; - GdkGC *gc, *maskgc; - GdkColor *c, pattern; - GdkBitmap *mask; - PangoLayout *layout; - gint width; - GdkPixmap *pixmap; - - g_return_if_fail(textbox != NULL); - g_return_if_fail(pixmaptext != NULL); - g_return_if_fail(textbox->height > 0); - - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - length = g_utf8_strlen(pixmaptext, -1); - - text_get_extents(priv->fontname, pixmaptext, &width, NULL, NULL, NULL); - - priv->pixbuf_width = MAX(width, textbox->width); - pixmap = gdk_pixmap_new(mainwin->window, priv->pixbuf_width, - textbox->height, - gdk_rgb_get_visual()->depth); - gc = gdk_gc_new(pixmap); - c = skin_get_color(aud_active_skin, SKIN_TEXTBG); - for (i = 0; i < textbox->height; i++) { - gdk_gc_set_foreground(gc, &c[6 * i / textbox->height]); - gdk_draw_line(pixmap, gc, 0, i, priv->pixbuf_width, i); - } - - mask = gdk_pixmap_new(mainwin->window, priv->pixbuf_width, textbox->height, 1); - maskgc = gdk_gc_new(mask); - pattern.pixel = 0; - gdk_gc_set_foreground(maskgc, &pattern); - - gdk_draw_rectangle(mask, maskgc, TRUE, 0, 0, priv->pixbuf_width, textbox->height); - pattern.pixel = 1; - gdk_gc_set_foreground(maskgc, &pattern); - - gdk_gc_set_foreground(gc, skin_get_color(aud_active_skin, SKIN_TEXTFG)); - - layout = gtk_widget_create_pango_layout(mainwin, pixmaptext); - pango_layout_set_font_description(layout, priv->font); - - gdk_draw_layout(pixmap, gc, 0, (priv->font_descent / 2), layout); - g_object_unref(layout); - - g_object_unref(maskgc); - - gdk_gc_set_clip_mask(gc, mask); - c = skin_get_color(aud_active_skin, SKIN_TEXTFG); - for (i = 0; i < textbox->height; i++) { - gdk_gc_set_foreground(gc, &c[6 * i / textbox->height]); - gdk_draw_line(pixmap, gc, 0, i, priv->pixbuf_width, i); - } - priv->pixbuf = gdk_pixbuf_get_from_drawable(NULL, pixmap, gdk_colormap_get_system(), 0, 0, 0, 0, priv->pixbuf_width, textbox->height); - g_object_unref(mask); - g_object_unref(gc); -} - -static gboolean textbox_scroll(gpointer data) { - UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(data); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - if (!priv->is_dragging) { - if (priv->scroll_dummy < TEXTBOX_SCROLL_WAIT) - priv->scroll_dummy++; - else { - if(cfg.twoway_scroll) { - if (priv->scroll_back) - priv->offset -= 1; - else - priv->offset += 1; - - if (priv->offset >= (priv->pixbuf_width - textbox->width)) { - priv->scroll_back = TRUE; - priv->scroll_dummy = 0; - priv->offset = priv->pixbuf_width - textbox->width; - } - if (priv->offset <= 0) { - priv->scroll_back = FALSE; - priv->scroll_dummy = 0; - priv->offset = 0; - } - } - else { // oneway scroll - priv->scroll_back = FALSE; - priv->offset += 1; - } - gtk_widget_queue_draw(GTK_WIDGET(textbox)); - } - } - return TRUE; -} - -static void textbox_generate_pixmap(UiSkinnedTextbox *textbox) { - gint length, i, x, y, wl; - gchar *pixmaptext; - gchar *tmp, *stxt; - - g_return_if_fail(textbox != NULL); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - if (priv->pixbuf) { - g_object_unref(priv->pixbuf); - priv->pixbuf = NULL; - } - - /* - * Don't reset the offset if only text after the last '(' has - * changed. This is a hack to avoid visual noice on vbr files - * where we guess the length. - */ - if (!(priv->pixbuf_text && strrchr(textbox->text, '(') && - !strncmp(priv->pixbuf_text, textbox->text, - strrchr(textbox->text, '(') - textbox->text))) - priv->offset = 0; - - g_free(priv->pixbuf_text); - priv->pixbuf_text = g_strdup(textbox->text); - - /* - * wl is the number of (partial) letters visible. Only makes - * sense when using skinned font. - */ - wl = textbox->width / 5; - if (wl * 5 != textbox->width) - wl++; - - length = g_utf8_strlen(textbox->text, -1); - - priv->is_scrollable = FALSE; - - priv->is_scrollable = ui_skinned_textbox_should_scroll(textbox); - - if (priv->is_scrollable) { - if(!cfg.twoway_scroll) { - pixmaptext = g_strdup_printf("%s *** ", priv->pixbuf_text); - length += 5; - } else - pixmaptext = g_strdup(priv->pixbuf_text); - } else - if (!priv->font && length <= wl) { - gint pad = wl - length; - gchar *padchars = g_strnfill(pad, ' '); - - pixmaptext = g_strconcat(priv->pixbuf_text, padchars, NULL); - g_free(padchars); - length += pad; - } else - pixmaptext = g_strdup(priv->pixbuf_text); - - if (priv->is_scrollable) { - if (priv->scroll_enabled && !priv->scroll_timeout) { - gint tag; - tag = TEXTBOX_SCROLL_SMOOTH_TIMEOUT; - priv->scroll_timeout = g_timeout_add(tag, textbox_scroll, textbox); - } - } else { - if (priv->scroll_timeout) { - g_source_remove(priv->scroll_timeout); - priv->scroll_timeout = 0; - } - priv->offset = 0; - } - - if (priv->font) { - textbox_generate_xfont_pixmap(textbox, pixmaptext); - g_free(pixmaptext); - return; - } - - priv->pixbuf_width = length * aud_active_skin->properties.textbox_bitmap_font_width; - priv->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, - priv->pixbuf_width, aud_active_skin->properties.textbox_bitmap_font_height); - - for (tmp = stxt = g_utf8_strup(pixmaptext, -1), i = 0; - tmp != NULL && i < length; i++, tmp = g_utf8_next_char(tmp)) { - gchar c = *tmp; - x = y = -1; - if (c >= 'A' && c <= 'Z') { - x = aud_active_skin->properties.textbox_bitmap_font_width * (c - 'A'); - y = 0; - } - else if (c >= '0' && c <= '9') { - x = aud_active_skin->properties.textbox_bitmap_font_width * (c - '0'); - y = aud_active_skin->properties.textbox_bitmap_font_height; - } - else - textbox_handle_special_char(tmp, &x, &y); - - skin_draw_pixbuf(GTK_WIDGET(textbox), aud_active_skin, - priv->pixbuf, priv->skin_index, - x, y, i * aud_active_skin->properties.textbox_bitmap_font_width, 0, - aud_active_skin->properties.textbox_bitmap_font_width, - aud_active_skin->properties.textbox_bitmap_font_height); - } - g_free(stxt); - g_free(pixmaptext); -} - -void ui_skinned_textbox_set_scroll(GtkWidget *widget, gboolean scroll) { - g_return_if_fail(widget != NULL); - UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(widget); - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox); - - priv->scroll_enabled = scroll; - if (priv->scroll_enabled && priv->is_scrollable && priv->scroll_allowed) { - gint tag; - tag = TEXTBOX_SCROLL_SMOOTH_TIMEOUT; - if (priv->scroll_timeout) { - g_source_remove(priv->scroll_timeout); - priv->scroll_timeout = 0; - } - priv->scroll_timeout = g_timeout_add(tag, textbox_scroll, textbox); - - } else { - - if (priv->scroll_timeout) { - g_source_remove(priv->scroll_timeout); - priv->scroll_timeout = 0; - } - - priv->offset = 0; - gtk_widget_queue_draw(GTK_WIDGET(textbox)); - } -} - -static void textbox_handle_special_char(gchar *c, gint * x, gint * y) { - gint tx, ty; - - switch (*c) { - case '"': - tx = 26; - ty = 0; - break; - case '\r': - tx = 10; - ty = 1; - break; - case ':': - case ';': - tx = 12; - ty = 1; - break; - case '(': - tx = 13; - ty = 1; - break; - case ')': - tx = 14; - ty = 1; - break; - case '-': - tx = 15; - ty = 1; - break; - case '`': - case '\'': - tx = 16; - ty = 1; - break; - case '!': - tx = 17; - ty = 1; - break; - case '_': - tx = 18; - ty = 1; - break; - case '+': - tx = 19; - ty = 1; - break; - case '\\': - tx = 20; - ty = 1; - break; - case '/': - tx = 21; - ty = 1; - break; - case '[': - tx = 22; - ty = 1; - break; - case ']': - tx = 23; - ty = 1; - break; - case '^': - tx = 24; - ty = 1; - break; - case '&': - tx = 25; - ty = 1; - break; - case '%': - tx = 26; - ty = 1; - break; - case '.': - case ',': - tx = 27; - ty = 1; - break; - case '=': - tx = 28; - ty = 1; - break; - case '$': - tx = 29; - ty = 1; - break; - case '#': - tx = 30; - ty = 1; - break; - case '?': - tx = 3; - ty = 2; - break; - case '*': - tx = 4; - ty = 2; - break; - default: - tx = 29; - ty = 0; - break; - } - - const gchar *change[] = {"Ą", "A", "Ę", "E", "Ć", "C", "Ł", "L", "Ó", "O", "Ś", "S", "Ż", "Z", "Ź", "Z", - "Ń", "N", "Ü", "U", NULL}; - int i; - for (i = 0; change[i]; i+=2) { - if (!strncmp(c, change[i], strlen(change[i]))) { - tx = (*change[i+1] - 'A'); - break; - } - } - - /* those are commonly included into skins */ - if (!strncmp(c, "Å", strlen("Å"))) { - tx = 0; - ty = 2; - } else if (!strncmp(c, "Ö", strlen("Ö"))) { - tx = 1; - ty = 2; - } else if (!strncmp(c, "Ä", strlen("Ä"))) { - tx = 2; - ty = 2; - } - - *x = tx * aud_active_skin->properties.textbox_bitmap_font_width; - *y = ty * aud_active_skin->properties.textbox_bitmap_font_height; -} - -void ui_skinned_textbox_move_relative(GtkWidget *widget, gint x, gint y) { - UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(widget); - priv->move_x += x; - priv->move_y += y; -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_textbox.h --- a/src/audacious/ui_skinned_textbox.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Tomasz Moń - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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_SKINNED_TEXTBOX_H -#define AUDACIOUS_UI_SKINNED_TEXTBOX_H - -#include -#include "ui_skin.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SKINNED_TEXTBOX(obj) GTK_CHECK_CAST (obj, ui_skinned_textbox_get_type (), UiSkinnedTextbox) -#define UI_SKINNED_TEXTBOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_textbox_get_type (), UiSkinnedTextboxClass) -#define UI_SKINNED_IS_TEXTBOX(obj) GTK_CHECK_TYPE (obj, ui_skinned_textbox_get_type ()) - -typedef struct _UiSkinnedTextbox UiSkinnedTextbox; -typedef struct _UiSkinnedTextboxClass UiSkinnedTextboxClass; - -struct _UiSkinnedTextbox { - GtkWidget widget; - - gint x, y, width, height; - gchar *text; -}; - -struct _UiSkinnedTextboxClass { - GtkWidgetClass parent_class; - void (* clicked) (UiSkinnedTextbox *textbox); - void (* double_clicked) (UiSkinnedTextbox *textbox); - void (* right_clicked) (UiSkinnedTextbox *textbox); - void (* scaled) (UiSkinnedTextbox *textbox); - void (* redraw) (UiSkinnedTextbox *textbox); -}; - -GtkWidget* ui_skinned_textbox_new (GtkWidget *fixed, gint x, gint y, gint w, gboolean allow_scroll, SkinPixmapId si); -GtkType ui_skinned_textbox_get_type(void); -void ui_skinned_textbox_set_xfont(GtkWidget *widget, gboolean use_xfont, const gchar * fontname); -void ui_skinned_textbox_set_text(GtkWidget *widget, const gchar *text); -void ui_skinned_textbox_set_scroll(GtkWidget *widget, gboolean scroll); -void ui_skinned_textbox_move_relative(GtkWidget *widget, gint x, gint y); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SKINNED_TEXTBOX_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_window.c --- a/src/audacious/ui_skinned_window.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,286 +0,0 @@ -/* - * Audacious: A cross-platform multimedia player - * Copyright (c) 2007 William Pitcock - * - * 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 "platform/smartinclude.h" -#include "ui_skin.h" - -#include -#include -#include -#include -#include -#include - -#include "main.h" -#include "ui_dock.h" -#include "ui_skinned_window.h" -#include "ui_playlist.h" - -static void ui_skinned_window_class_init(SkinnedWindowClass *klass); -static void ui_skinned_window_init(GtkWidget *widget); -static GtkWindowClass *parent = NULL; - -GType -ui_skinned_window_get_type(void) -{ - static GType window_type = 0; - - if (!window_type) - { - static const GTypeInfo window_info = - { - sizeof (SkinnedWindowClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) ui_skinned_window_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (SkinnedWindow), - 0, /* n_preallocs */ - (GInstanceInitFunc) ui_skinned_window_init - }; - - window_type = - g_type_register_static (GTK_TYPE_WINDOW, "SkinnedWindow_", - &window_info, 0); - } - - return window_type; -} - -static void -ui_skinned_window_map(GtkWidget *widget) -{ - (* GTK_WIDGET_CLASS (parent)->map) (widget); - - SkinnedWindow *window = SKINNED_WINDOW(widget); - if (window->type == WINDOW_MAIN) - gtk_widget_shape_combine_mask(widget, skin_get_mask(aud_active_skin, SKIN_MASK_MAIN + cfg.player_shaded), 0, 0); - else if (window->type == WINDOW_EQ) - gtk_widget_shape_combine_mask(widget, skin_get_mask(aud_active_skin, SKIN_MASK_EQ + cfg.equalizer_shaded), 0, 0); - - gtk_window_set_keep_above(GTK_WINDOW(widget), cfg.always_on_top); -} - -static gboolean -ui_skinned_window_motion_notify_event(GtkWidget *widget, - GdkEventMotion *event) -{ - if (dock_is_moving(GTK_WINDOW(widget))) - dock_move_motion(GTK_WINDOW(widget), event); - - return FALSE; -} - -static gboolean ui_skinned_window_focus_in(GtkWidget *widget, GdkEventFocus *focus) { - gboolean val = GTK_WIDGET_CLASS (parent)->focus_in_event (widget, focus); - gtk_widget_queue_draw(widget); - return val; -} - -static gboolean ui_skinned_window_focus_out(GtkWidget *widget, GdkEventFocus *focus) { - gboolean val = GTK_WIDGET_CLASS (parent)->focus_out_event (widget, focus); - gtk_widget_queue_draw(widget); - return val; -} - -static gboolean ui_skinned_window_button_press(GtkWidget *widget, GdkEventButton *event) { - if (event->button == 1 && event->type == GDK_BUTTON_PRESS && - (cfg.easy_move || cfg.equalizer_shaded || (event->y / cfg.scale_factor) < 14)) { - dock_move_press(get_dock_window_list(), GTK_WINDOW(widget), - event, SKINNED_WINDOW(widget)->type == WINDOW_MAIN ? TRUE : FALSE); - } - - return TRUE; -} - -static gboolean ui_skinned_window_button_release(GtkWidget *widget, GdkEventButton *event) { - if (dock_is_moving(GTK_WINDOW(widget))) - dock_move_release(GTK_WINDOW(widget)); - - return TRUE; -} - -static gboolean ui_skinned_window_expose(GtkWidget *widget, GdkEventExpose *event) { - SkinnedWindow *window = SKINNED_WINDOW(widget); - - GdkPixbuf *obj = NULL; - - gint width = 0, height = 0; - switch (window->type) { - case WINDOW_MAIN: - width = aud_active_skin->properties.mainwin_width; - height = aud_active_skin->properties.mainwin_height; - break; - case WINDOW_EQ: - width = 275 * (cfg.scaled ? cfg.scale_factor : 1); - height = 116 * (cfg.scaled ? cfg.scale_factor : 1) ; - break; - case WINDOW_PLAYLIST: - width = playlistwin_get_width(); - height = cfg.playlist_height; - break; - default: - return FALSE; - } - obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); - - gboolean focus = gtk_window_has_toplevel_focus(GTK_WINDOW(widget)); - - switch (window->type) { - case WINDOW_MAIN: - skin_draw_pixbuf(widget, aud_active_skin, obj,SKIN_MAIN, 0, 0, 0, 0, width, height); - skin_draw_mainwin_titlebar(aud_active_skin, obj, cfg.player_shaded, focus || !cfg.dim_titlebar); - break; - case WINDOW_EQ: - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQMAIN, 0, 0, 0, 0, width, height); - if (focus || !cfg.dim_titlebar) { - if (!cfg.equalizer_shaded) - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQMAIN, 0, 134, 0, 0, width, 14); - else - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQ_EX, 0, 0, 0, 0, width, 14); - } else { - if (!cfg.equalizer_shaded) - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQMAIN, 0, 149, 0, 0, width, 14); - else - skin_draw_pixbuf(widget, aud_active_skin, obj, SKIN_EQ_EX, 0, 15, 0, 0, width, 14); - } - break; - case WINDOW_PLAYLIST: - focus |= !cfg.dim_titlebar; - if (cfg.playlist_shaded) { - skin_draw_playlistwin_shaded(aud_active_skin, obj, width, focus); - } else { - skin_draw_playlistwin_frame(aud_active_skin, obj, width, cfg.playlist_height, focus); - } - break; - } - - ui_skinned_widget_draw(GTK_WIDGET(window), obj, width, height, - window->type != WINDOW_PLAYLIST && cfg.scaled); - - g_object_unref(obj); - - return FALSE; -} - -static void -ui_skinned_window_class_init(SkinnedWindowClass *klass) -{ - GtkWidgetClass *widget_class; - - widget_class = (GtkWidgetClass*) klass; - - parent = gtk_type_class(gtk_window_get_type()); - - widget_class->motion_notify_event = ui_skinned_window_motion_notify_event; - widget_class->expose_event = ui_skinned_window_expose; - widget_class->focus_in_event = ui_skinned_window_focus_in; - widget_class->focus_out_event = ui_skinned_window_focus_out; - widget_class->button_press_event = ui_skinned_window_button_press; - widget_class->button_release_event = ui_skinned_window_button_release; - widget_class->map = ui_skinned_window_map; -} - -void -ui_skinned_window_hide(SkinnedWindow *window) -{ - g_return_if_fail(SKINNED_CHECK_WINDOW(window)); - - gtk_window_get_position(GTK_WINDOW(window), &window->x, &window->y); - gtk_widget_hide(GTK_WIDGET(window)); -} - -void -ui_skinned_window_show(SkinnedWindow *window) -{ - g_return_if_fail(SKINNED_CHECK_WINDOW(window)); - - gtk_window_move(GTK_WINDOW(window), window->x, window->y); - gtk_widget_show_all(GTK_WIDGET(window)); -} - -static void -ui_skinned_window_init(GtkWidget *widget) -{ - SkinnedWindow *window; - window = SKINNED_WINDOW(widget); - window->x = -1; - window->y = -1; -} - -GtkWidget * -ui_skinned_window_new(const gchar *wmclass_name) -{ - GtkWidget *widget = g_object_new(ui_skinned_window_get_type(), NULL); - GtkWindow *window = GTK_WINDOW(widget); - - window->type = SKINNED_WINDOW_TYPE; - - if (wmclass_name) - gtk_window_set_wmclass(GTK_WINDOW(widget), wmclass_name, "Audacious"); - - gtk_widget_add_events(GTK_WIDGET(widget), - GDK_FOCUS_CHANGE_MASK | GDK_BUTTON_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_SCROLL_MASK | GDK_KEY_PRESS_MASK | - GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK); - gtk_widget_realize(GTK_WIDGET(widget)); - - set_dock_window_list(dock_window_set_decorated(get_dock_window_list(), - GTK_WINDOW(widget), - cfg.show_wm_decorations)); - gtk_widget_set_app_paintable(GTK_WIDGET(widget), TRUE); - gdk_window_set_back_pixmap(widget->window, NULL, FALSE); - gtk_widget_shape_combine_mask(widget, NULL, 0, 0); - - if (!strcmp(wmclass_name, "player")) - SKINNED_WINDOW(widget)->type = WINDOW_MAIN; - if (!strcmp(wmclass_name, "equalizer")) - SKINNED_WINDOW(widget)->type = WINDOW_EQ; - if (!strcmp(wmclass_name, "playlist")) - SKINNED_WINDOW(widget)->type = WINDOW_PLAYLIST; - - /* 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 */ - SKINNED_WINDOW(widget)->fixed = gtk_fixed_new(); - gtk_container_add(GTK_CONTAINER(widget), GTK_WIDGET(SKINNED_WINDOW(widget)->fixed)); - return widget; -} - -void ui_skinned_window_draw_all(GtkWidget *widget) { - if (SKINNED_WINDOW(widget)->type == WINDOW_MAIN) - mainwin_refresh_hints(); - - gtk_widget_queue_draw(widget); - GList *iter; - for (iter = GTK_FIXED (SKINNED_WINDOW(widget)->fixed)->children; iter; iter = g_list_next (iter)) { - GtkFixedChild *child_data = (GtkFixedChild *) iter->data; - GtkWidget *child = child_data->widget; - gtk_widget_queue_draw(child); - } -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinned_window.h --- a/src/audacious/ui_skinned_window.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Audacious: A cross-platform multimedia player - * Copyright (c) 2007 William Pitcock - * - * 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_SKINNED_WINDOW_H -#define AUDACIOUS_UI_SKINNED_WINDOW_H - -#define SKINNED_WINDOW(obj) GTK_CHECK_CAST (obj, ui_skinned_window_get_type (), SkinnedWindow) -#define SKINNED_WINDOW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_skinned_window_get_type (), SkinnedWindowClass) -#define SKINNED_CHECK_WINDOW(obj) GTK_CHECK_TYPE (obj, ui_skinned_window_get_type ()) -#define SKINNED_TYPE_WINDOW (ui_skinned_window_get_type()) - -#ifdef GDK_WINDOWING_QUARTZ -# define SKINNED_WINDOW_TYPE GTK_WINDOW_POPUP -#else -# define SKINNED_WINDOW_TYPE GTK_WINDOW_TOPLEVEL -#endif - -enum { - WINDOW_MAIN, - WINDOW_EQ, - WINDOW_PLAYLIST -}; - -typedef struct _SkinnedWindow SkinnedWindow; -typedef struct _SkinnedWindowClass SkinnedWindowClass; - -struct _SkinnedWindow -{ - GtkWindow window; - - GtkWidget *canvas; - gint x,y; - - gint type; - GtkWidget *fixed; -}; - -struct _SkinnedWindowClass -{ - GtkWindowClass parent_class; -}; - -extern GType ui_skinned_window_get_type(void); -extern GtkWidget *ui_skinned_window_new(const gchar *wmclass_name); -extern void ui_skinned_window_draw_all(GtkWidget *widget); - -#endif /* AUDACIOUS_UI_SKINNED_WINDOW_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinselector.c --- a/src/audacious/ui_skinselector.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,404 +0,0 @@ -/* 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 "ui_skinselector.h" - -#include -#include -#include - -#include "platform/smartinclude.h" - -#include -#include - -#include "main.h" -#include "ui_skin.h" -#include "util.h" - -#define EXTENSION_TARGETS 7 - -static gchar *ext_targets[EXTENSION_TARGETS] = { "bmp", "xpm", "png", "svg", - "gif", "jpg", "jpeg" }; - -#define THUMBNAIL_WIDTH 90 -#define THUMBNAIL_HEIGHT 40 - - -enum SkinViewCols { - SKIN_VIEW_COL_PREVIEW, - SKIN_VIEW_COL_FORMATTEDNAME, - SKIN_VIEW_COL_NAME, - SKIN_VIEW_N_COLS -}; - - -GList *skinlist = NULL; - - - -static gchar * -get_thumbnail_filename(const gchar * path) -{ - gchar *basename, *pngname, *thumbname; - - g_return_val_if_fail(path != NULL, NULL); - - basename = g_path_get_basename(path); - pngname = g_strconcat(basename, ".png", NULL); - - thumbname = g_build_filename(aud_paths[BMP_PATH_SKIN_THUMB_DIR], - pngname, NULL); - - g_free(basename); - g_free(pngname); - - return thumbname; -} - - -static GdkPixbuf * -skin_get_preview(const gchar * path) -{ - GdkPixbuf *preview = NULL; - gchar *dec_path, *preview_path; - gboolean is_archive = FALSE; - gint i = 0; - gchar buf[60]; /* gives us lots of room */ - - if (file_is_archive(path)) - { - if (!(dec_path = archive_decompress(path))) - return NULL; - - is_archive = TRUE; - } - else - { - dec_path = g_strdup(path); - } - - for (i = 0; i < EXTENSION_TARGETS; i++) - { - sprintf(buf, "main.%s", ext_targets[i]); - - if ((preview_path = find_path_recursively(dec_path, buf)) != NULL) - break; - } - - if (preview_path) - { - preview = gdk_pixbuf_new_from_file(preview_path, NULL); - g_free(preview_path); - } - - if (is_archive) - del_directory(dec_path); - - g_free(dec_path); - - return preview; -} - - -static GdkPixbuf * -skin_get_thumbnail(const gchar * path) -{ - GdkPixbuf *scaled = NULL; - GdkPixbuf *preview; - gchar *thumbname; - - g_return_val_if_fail(path != NULL, NULL); - - if (g_str_has_suffix(path, "thumbs")) - return NULL; - - thumbname = get_thumbnail_filename(path); - - if (g_file_test(thumbname, G_FILE_TEST_EXISTS)) { - scaled = gdk_pixbuf_new_from_file(thumbname, NULL); - g_free(thumbname); - return scaled; - } - - if (!(preview = skin_get_preview(path))) { - g_free(thumbname); - return NULL; - } - - scaled = gdk_pixbuf_scale_simple(preview, - THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, - GDK_INTERP_BILINEAR); - g_object_unref(preview); - - gdk_pixbuf_save(scaled, thumbname, "png", NULL, NULL); - g_free(thumbname); - - return scaled; -} - -static void -skinlist_add(const gchar * filename) -{ - SkinNode *node; - gchar *basename; - - g_return_if_fail(filename != NULL); - - node = g_slice_new0(SkinNode); - node->path = g_strdup(filename); - - basename = g_path_get_basename(filename); - - if (file_is_archive(filename)) { - node->name = archive_basename(basename); - node->desc = _("Archived Winamp 2.x skin"); - g_free(basename); - } - else { - node->name = basename; - node->desc = _("Unarchived Winamp 2.x skin"); - } - - skinlist = g_list_prepend(skinlist, node); -} - -static gboolean -scan_skindir_func(const gchar * path, const gchar * basename, gpointer data) -{ - if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) { - if (file_is_archive(path)) { - skinlist_add(path); - } - } - else if (g_file_test(path, G_FILE_TEST_IS_DIR)) { - skinlist_add(path); - } - - return FALSE; -} - -static void -scan_skindir(const gchar * path) -{ - GError *error = NULL; - - g_return_if_fail(path != NULL); - - if (path[0] == '.') - return; - - if (!dir_foreach(path, scan_skindir_func, NULL, &error)) { - g_warning("Failed to open directory (%s): %s", path, error->message); - g_error_free(error); - return; - } -} - -static gint -skinlist_compare_func(gconstpointer a, gconstpointer b) -{ - g_return_val_if_fail(a != NULL && SKIN_NODE(a)->name != NULL, 1); - g_return_val_if_fail(b != NULL && SKIN_NODE(b)->name != NULL, 1); - return strcasecmp(SKIN_NODE(a)->name, SKIN_NODE(b)->name); -} - -static void -skin_free_func(gpointer data) -{ - g_return_if_fail(data != NULL); - g_free(SKIN_NODE(data)->name); - g_free(SKIN_NODE(data)->path); - g_slice_free(SkinNode, data); -} - - -static void -skinlist_clear(void) -{ - if (!skinlist) - return; - - g_list_foreach(skinlist, (GFunc) skin_free_func, NULL); - g_list_free(skinlist); - skinlist = NULL; -} - -void -skinlist_update(void) -{ - gchar *skinsdir; - - skinlist_clear(); - - scan_skindir(aud_paths[BMP_PATH_USER_SKIN_DIR]); - scan_skindir(DATA_DIR G_DIR_SEPARATOR_S "Skins"); - - skinsdir = getenv("SKINSDIR"); - if (skinsdir) { - gchar **dir_list = g_strsplit(skinsdir, ":", 0); - gchar **dir; - - for (dir = dir_list; *dir; dir++) - scan_skindir(*dir); - g_strfreev(dir_list); - } - - skinlist = g_list_sort(skinlist, skinlist_compare_func); - - g_assert(skinlist != NULL); -} - -void -skin_view_update(GtkTreeView * treeview, GtkWidget * refresh_button) -{ - GtkTreeSelection *selection = NULL; - GtkListStore *store; - GtkTreeIter iter, iter_current_skin; - gboolean have_current_skin = FALSE; - GtkTreePath *path; - - GdkPixbuf *thumbnail; - gchar *formattedname; - gchar *name; - GList *entry; - - gtk_widget_set_sensitive(GTK_WIDGET(treeview), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(refresh_button), FALSE); - - store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview)); - - gtk_list_store_clear(store); - - skinlist_update(); - - for (entry = skinlist; entry; entry = g_list_next(entry)) { - thumbnail = skin_get_thumbnail(SKIN_NODE(entry->data)->path); - - formattedname = g_strdup_printf("%s\n%s", - SKIN_NODE(entry->data)->name, SKIN_NODE(entry->data)->desc); - name = SKIN_NODE(entry->data)->name; - - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - SKIN_VIEW_COL_PREVIEW, thumbnail, - SKIN_VIEW_COL_FORMATTEDNAME, formattedname, - SKIN_VIEW_COL_NAME, name, -1); - if (thumbnail) - g_object_unref(thumbnail); - g_free(formattedname); - - if (g_strstr_len(aud_active_skin->path, - strlen(aud_active_skin->path), name) ) { - iter_current_skin = iter; - have_current_skin = TRUE; - } - } - - if (have_current_skin) { - selection = gtk_tree_view_get_selection(treeview); - gtk_tree_selection_select_iter(selection, &iter_current_skin); - - path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), - &iter_current_skin); - gtk_tree_view_scroll_to_cell(treeview, path, NULL, TRUE, 0.5, 0.5); - gtk_tree_path_free(path); - } - - gtk_widget_set_sensitive(GTK_WIDGET(treeview), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(refresh_button), TRUE); -} - - -static void -skin_view_on_cursor_changed(GtkTreeView * treeview, - gpointer data) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - GList *node; - gchar *name; - gchar *comp = NULL; - - selection = gtk_tree_view_get_selection(treeview); - if (!gtk_tree_selection_get_selected(selection, &model, &iter)) - return; - - gtk_tree_model_get(model, &iter, SKIN_VIEW_COL_NAME, &name, -1); - - for (node = skinlist; node; node = g_list_next(node)) { - comp = SKIN_NODE(node->data)->path; - if (g_strrstr(comp, name)) - break; - } - - g_free(name); - - aud_active_skin_load(comp); -} - - -void -skin_view_realize(GtkTreeView * treeview) -{ - GtkListStore *store; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - GtkTreeSelection *selection; - - gtk_widget_show_all(GTK_WIDGET(treeview)); - - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); - - store = gtk_list_store_new(SKIN_VIEW_N_COLS, GDK_TYPE_PIXBUF, - G_TYPE_STRING , G_TYPE_STRING); - gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store)); - - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); - gtk_tree_view_column_set_spacing(column, 16); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), - GTK_TREE_VIEW_COLUMN(column)); - - renderer = gtk_cell_renderer_pixbuf_new(); - gtk_tree_view_column_pack_start(column, renderer, FALSE); - gtk_tree_view_column_set_attributes(column, renderer, "pixbuf", - SKIN_VIEW_COL_PREVIEW, NULL); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, TRUE); - gtk_tree_view_column_set_attributes(column, renderer, "markup", - SKIN_VIEW_COL_FORMATTEDNAME, NULL); - - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); - - g_signal_connect(treeview, "cursor-changed", - G_CALLBACK(skin_view_on_cursor_changed), NULL); -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_skinselector.h --- a/src/audacious/ui_skinselector.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* 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. - */ - -#ifndef AUDACIOUS_UI_SKINSELECTOR_H -#define AUDACIOUS_UI_SKINSELECTOR_H - -#include -#include - -#define SKIN_NODE(x) ((SkinNode *)(x)) -struct _SkinNode { - gchar *name; - gchar *desc; - gchar *path; - GTime *time; -}; - -typedef struct _SkinNode SkinNode; - -extern GList *skinlist; - -void skinlist_update(); -void skin_view_realize(GtkTreeView * treeview); -void skin_view_update(GtkTreeView * treeview, GtkWidget * refresh_button); - -#endif /* AUDACIOUS_UI_SKINSELECTOR_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_svis.c --- a/src/audacious/ui_svis.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,550 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Audacious development team. - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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. - */ - -#include "ui_skin.h" -#include "ui_svis.h" -#include "ui_vis.h" -#include "main.h" -#include "util.h" -#include "strings.h" -#include "playback.h" -#include -#include -#include -#include -#include - -#define UI_TYPE_SVIS (ui_svis_get_type()) - -static gint svis_redraw_delays[] = { 1, 2, 4, 8 }; - -/* FIXME: Are the svis_scope_colors correct? */ -static guint8 svis_scope_colors[] = { 20, 19, 18, 19, 20 }; -static guint8 svis_vu_normal_colors[] = { 17, 17, 17, 12, 12, 12, 2, 2 }; - -#define DRAW_DS_PIXEL(ptr,value) \ - *(ptr) = (value); \ - *((ptr) + 1) = (value); \ - *((ptr) + 76) = (value); \ - *((ptr) + 77) = (value); - -#define SVIS_HEIGHT 5 -#define SVIS_WIDTH 38 - -enum { - DOUBLED, - LAST_SIGNAL -}; - -static void ui_svis_class_init (UiSVisClass *klass); -static void ui_svis_init (UiSVis *svis); -static void ui_svis_destroy (GtkObject *object); -static void ui_svis_realize (GtkWidget *widget); -static void ui_svis_unrealize (GtkWidget *widget); -static void ui_svis_map (GtkWidget *widget); -static void ui_svis_unmap (GtkWidget *widget); -static void ui_svis_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_svis_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_svis_expose (GtkWidget *widget, GdkEventExpose *event); -static void ui_svis_toggle_scaled (UiSVis *svis); - -static GtkWidgetClass *parent_class = NULL; -static guint vis_signals[LAST_SIGNAL] = { 0 }; - -GType ui_svis_get_type() { - static GType vis_type = 0; - if (!vis_type) { - static const GTypeInfo vis_info = { - sizeof (UiSVisClass), - NULL, - NULL, - (GClassInitFunc) ui_svis_class_init, - NULL, - NULL, - sizeof (UiSVis), - 0, - (GInstanceInitFunc) ui_svis_init, - }; - vis_type = g_type_register_static (GTK_TYPE_WIDGET, "UiSVis_", &vis_info, 0); - } - - return vis_type; -} - -static void ui_svis_class_init(UiSVisClass *klass) { - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_svis_destroy; - - widget_class->realize = ui_svis_realize; - widget_class->unrealize = ui_svis_unrealize; - widget_class->map = ui_svis_map; - widget_class->unmap = ui_svis_unmap; - widget_class->expose_event = ui_svis_expose; - widget_class->size_request = ui_svis_size_request; - widget_class->size_allocate = ui_svis_size_allocate; - - klass->scaled = ui_svis_toggle_scaled; - - vis_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiSVisClass, scaled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); -} - -static void ui_svis_init(UiSVis *svis) { - -} - -GtkWidget* ui_svis_new(GtkWidget *fixed, gint x, gint y) { - UiSVis *svis = g_object_new (ui_svis_get_type (), NULL); - - svis->x = x; - svis->y = y; - - svis->width = SVIS_WIDTH; - svis->height = SVIS_HEIGHT; - - svis->fixed = fixed; - svis->scaled = FALSE; - - svis->visible_window = TRUE; - svis->event_window = NULL; - - gtk_fixed_put(GTK_FIXED(svis->fixed), GTK_WIDGET(svis), svis->x, svis->y); - - return GTK_WIDGET(svis); -} - -static void ui_svis_destroy(GtkObject *object) { - UiSVis *svis; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_IS_SVIS (object)); - - svis = UI_SVIS (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_svis_realize(GtkWidget *widget) { - UiSVis *svis; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_IS_SVIS(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - svis = UI_SVIS(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; - - if (svis->visible_window) - { - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - attributes.wclass = GDK_INPUT_OUTPUT; - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - GTK_WIDGET_UNSET_FLAGS(widget, GTK_NO_WINDOW); - gdk_window_set_user_data(widget->window, widget); - } - else - { - widget->window = gtk_widget_get_parent_window (widget); - g_object_ref (widget->window); - - attributes.wclass = GDK_INPUT_ONLY; - attributes_mask = GDK_WA_X | GDK_WA_Y; - svis->event_window = gdk_window_new (widget->window, &attributes, attributes_mask); - GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW); - gdk_window_set_user_data(svis->event_window, widget); - } - - widget->style = gtk_style_attach(widget->style, widget->window); -} - -static void ui_svis_unrealize(GtkWidget *widget) { - UiSVis *svis; - svis = UI_SVIS(widget); - - if ( svis->event_window != NULL ) - { - gdk_window_set_user_data( svis->event_window , NULL ); - gdk_window_destroy( svis->event_window ); - svis->event_window = NULL; - } - - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); -} - -static void ui_svis_map(GtkWidget *widget) -{ - UiSVis *svis; - svis = UI_SVIS(widget); - - if (svis->event_window != NULL) - gdk_window_show (svis->event_window); - - if (GTK_WIDGET_CLASS (parent_class)->map) - (* GTK_WIDGET_CLASS (parent_class)->map) (widget); -} - -static void ui_svis_unmap (GtkWidget *widget) -{ - UiSVis *svis; - svis = UI_SVIS(widget); - - if (svis->event_window != NULL) - gdk_window_hide (svis->event_window); - - if (GTK_WIDGET_CLASS (parent_class)->unmap) - (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget); -} - -static void ui_svis_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiSVis *svis = UI_SVIS(widget); - - requisition->width = svis->width * (svis->scaled ? cfg.scale_factor : 1); - requisition->height = svis->height*(svis->scaled ? cfg.scale_factor : 1); -} - -static void ui_svis_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiSVis *svis = UI_SVIS (widget); - - widget->allocation = *allocation; - widget->allocation.x *= (svis->scaled ? cfg.scale_factor : 1 ); - widget->allocation.y *= (svis->scaled ? cfg.scale_factor : 1); - if (GTK_WIDGET_REALIZED (widget)) - { - if (svis->event_window != NULL) - gdk_window_move_resize(svis->event_window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - else - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - } - - svis->x = widget->allocation.x/(svis->scaled ? cfg.scale_factor : 1); - svis->y = widget->allocation.y/(svis->scaled ? cfg.scale_factor : 1); -} - -static gboolean ui_svis_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_IS_SVIS (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiSVis *svis = UI_SVIS (widget); - - gint x, y, h; - guchar svis_color[24][3]; - guchar rgb_data[SVIS_WIDTH * 2 * SVIS_HEIGHT * 2], *ptr, c; - guint32 colors[24]; - GdkRgbCmap *cmap; - - if (!GTK_WIDGET_VISIBLE(widget)) - return FALSE; - - if (!svis->visible_window) - return FALSE; - - skin_get_viscolor(aud_active_skin, svis_color); - for (y = 0; y < 24; y++) { - colors[y] = - svis_color[y][0] << 16 | svis_color[y][1] << 8 | svis_color[y][2]; - } - cmap = gdk_rgb_cmap_new(colors, 24); - - if (!cfg.scaled) { - memset(rgb_data, 0, SVIS_WIDTH * SVIS_HEIGHT); - if (cfg.vis_type == VIS_ANALYZER && !playback_get_paused() && playback_get_playing()){ - for(y=0; y < SVIS_HEIGHT; y++){ - if (cfg.analyzer_type == ANALYZER_BARS){ - for(x=0;x< SVIS_WIDTH; x++){ - if(svis->data[x] > y << 1) - { - rgb_data[x*3+ (SVIS_HEIGHT - y) * SVIS_WIDTH] = 23; - rgb_data[x*3+1 + (SVIS_HEIGHT - y) * SVIS_WIDTH] = 23; - - } - } - } - else{ - for(x=0;x< SVIS_WIDTH; x++){ - if(svis->data[x] > y << 1) - { - rgb_data[x + (SVIS_HEIGHT - y) * SVIS_WIDTH] = 23; - } - } - } - } - } - else if (cfg.vis_type == VIS_VOICEPRINT){ - switch (cfg.vu_mode) { - case VU_NORMAL: - for (y = 0; y < 2; y++) { - ptr = rgb_data + ((y * 3) * 38); - h = (svis->data[y] * 7) / 37; - for (x = 0; x < h; x++, ptr += 5) { - c = svis_vu_normal_colors[x]; - *(ptr) = c; - *(ptr + 1) = c; - *(ptr + 2) = c; - *(ptr + 38) = c; - *(ptr + 39) = c; - *(ptr + 40) = c; - } - } - break; - case VU_SMOOTH: - for (y = 0; y < 2; y++) { - ptr = rgb_data + ((y * 3) * SVIS_WIDTH); - for (x = 0; x < svis->data[y]; x++, ptr++) { - c = 17 - ((x * 15) / 37); - *(ptr) = c; - *(ptr + 38) = c; - } - } - break; - } - } - else if (cfg.vis_type == VIS_SCOPE) { - for (x = 0; x < 38; x++) { - h = svis->data[x << 1] / 3; - ptr = rgb_data + ((4 - h) * 38) + x; - *ptr = svis_scope_colors[h]; - } - } - - } - else { /*svis scaling, this needs some work, since a lot of stuff is hardcoded --majeru*/ - - memset(rgb_data, 0, SVIS_WIDTH * cfg.scale_factor * SVIS_HEIGHT * cfg.scale_factor); - if (cfg.vis_type == VIS_ANALYZER && !playback_get_paused() && playback_get_playing()){ - for(y=0; y < SVIS_HEIGHT; y++){ - if (cfg.analyzer_type == ANALYZER_BARS){ - for(x=0;x< SVIS_WIDTH; x++){ - if(svis->data[x] > y << 1) - { - ptr = rgb_data + x * 6 + (SVIS_HEIGHT * 2 - y * 2) * SVIS_WIDTH *2; - DRAW_DS_PIXEL(ptr, 23); - DRAW_DS_PIXEL(ptr + 2, 23); - } - } - } - else{ - for(x=0;x< SVIS_WIDTH; x++){ - if(svis->data[x] > y << 1) - { - ptr = rgb_data + x * 2 + (SVIS_HEIGHT * 2 - y * 2) * SVIS_WIDTH * 2; - DRAW_DS_PIXEL(ptr, 23); - } - } - } - } - } - else if (cfg.vis_type == VIS_VOICEPRINT){ - switch (cfg.vu_mode) { - case VU_NORMAL: - for (y = 0; y < 2; y++) { - ptr = rgb_data + ((y * 3) * 152); - h = (svis->data[y] * 8) / 37; - for (x = 0; x < h; x++, ptr += 10) { - c = svis_vu_normal_colors[x]; - DRAW_DS_PIXEL(ptr, c); - DRAW_DS_PIXEL(ptr + 2, c); - DRAW_DS_PIXEL(ptr + 4, c); - DRAW_DS_PIXEL(ptr + 152, c); - DRAW_DS_PIXEL(ptr + 154, c); - DRAW_DS_PIXEL(ptr + 156, c); - } - } - break; - case VU_SMOOTH: - for (y = 0; y < 2; y++) { - ptr = rgb_data + ((y * 3) * 152); - for (x = 0; x < svis->data[y]; x++, ptr += 2) { - c = 17 - ((x * 15) / 37); - DRAW_DS_PIXEL(ptr, c); - DRAW_DS_PIXEL(ptr + 152, c); - } - } - break; - } - } - else if (cfg.vis_type == VIS_SCOPE) { - for (x = 0; x < 38; x++) { - h = svis->data[x << 1] / 3; - ptr = rgb_data + ((4 - h) * 152) + (x << 1); - *ptr = svis_scope_colors[h]; - *(ptr + 1) = svis_scope_colors[h]; - *(ptr + 76) = svis_scope_colors[h]; - *(ptr + 77) = svis_scope_colors[h]; - } - } - - - } - - GdkPixmap *obj = NULL; - GdkGC *gc; - obj = gdk_pixmap_new(NULL, svis->width* ( svis->scaled ? cfg.scale_factor : 1), - svis->height*(svis->scaled ? cfg.scale_factor : 1), gdk_rgb_get_visual()->depth); - gc = gdk_gc_new(obj); - - if (!svis->scaled) { - gdk_draw_indexed_image(obj, gc, 0, 0, svis->width, svis->height, - GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data, - 38, cmap); - } else { - gdk_draw_indexed_image(obj, gc, - 0 << 1, 0 << 1, - svis->width << 1, svis->height << 1, - GDK_RGB_DITHER_NONE, (guchar *) rgb_data, - 76, cmap); - } - - gdk_rgb_cmap_free(cmap); - gdk_draw_drawable (widget->window, gc, obj, 0, 0, 0, 0, - svis->width*(svis->scaled ? cfg.scale_factor : 1), - svis->height*(svis->scaled ? cfg.scale_factor : 1)); - g_object_unref(obj); - g_object_unref(gc); - - return FALSE; -} - -static void ui_svis_toggle_scaled(UiSVis *svis) { - GtkWidget *widget = GTK_WIDGET (svis); - svis->scaled = !svis->scaled; - - gtk_widget_set_size_request(widget, svis->width* cfg.scale_factor, svis->height * cfg.scale_factor); - - gtk_widget_queue_draw(widget); -} - -void ui_svis_set_visible(GtkWidget *widget, gboolean window_is_visible) -{ - UiSVis *svis; - gboolean widget_is_visible; - - g_return_if_fail(UI_IS_SVIS(widget)); - - svis = UI_SVIS (widget); - widget_is_visible = GTK_WIDGET_VISIBLE(widget); - - svis->visible_window = window_is_visible; - - if (GTK_WIDGET_REALIZED (widget)) - { - if ( widget_is_visible ) - gtk_widget_hide(widget); - - gtk_widget_unrealize(widget); - gtk_widget_realize(widget); - - if ( widget_is_visible ) - gtk_widget_show(widget); - } - - if (widget_is_visible) - gtk_widget_queue_resize(widget); -} - -void ui_svis_clear_data(GtkWidget *widget) { - g_return_if_fail(UI_IS_SVIS(widget)); - - gint i; - UiSVis *svis = UI_SVIS (widget); - - for (i = 0; i < 75; i++) { - svis->data[i] = (cfg.vis_type == VIS_SCOPE) ? 6 : 0; - } -} - -void ui_svis_timeout_func(GtkWidget *widget, guchar * data) { - g_return_if_fail(UI_IS_SVIS(widget)); - - UiSVis *svis = UI_SVIS (widget); - static GTimer *timer = NULL; - gulong micros = 9999999; - gboolean falloff = FALSE; - gint i; - - if (!timer) { - timer = g_timer_new(); - g_timer_start(timer); - } - else { - g_timer_elapsed(timer, µs); - if (micros > 14000) - g_timer_reset(timer); - - } - - if (cfg.vis_type == VIS_VOICEPRINT) { - if (micros > 14000) - falloff = TRUE; - - for (i = 0; i < 2; i++) { - if (falloff || data) { - if (data && data[i] > svis->data[i]) - svis->data[i] = data[i]; - else if (falloff) { - if (svis->data[i] >= 2) - svis->data[i] -= 2; - else - svis->data[i] = 0; - } - } - - } - } - else if (data) { - for (i = 0; i < 75; i++) - svis->data[i] = data[i]; - } - - if (micros > 14000) { - if (!svis->refresh_delay) { - gtk_widget_queue_draw(widget); - svis->refresh_delay = svis_redraw_delays[cfg.vis_refresh]; - } - svis->refresh_delay--; - } -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_svis.h --- a/src/audacious/ui_svis.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 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_SVIS_H -#define AUDACIOUS_UI_SVIS_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_SVIS(obj) GTK_CHECK_CAST (obj, ui_svis_get_type (), UiSVis) -#define UI_SVIS_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_svis_get_type (), UiSVisClass) -#define UI_IS_SVIS(obj) GTK_CHECK_TYPE (obj, ui_svis_get_type ()) - -typedef struct _UiSVis UiSVis; -typedef struct _UiSVisClass UiSVisClass; - -struct _UiSVis { - GtkWidget widget; - - gint x, y, width, height; - gint data[75]; - gint refresh_delay; - gboolean scaled; - GtkWidget *fixed; - gboolean visible_window; - GdkWindow *event_window; -}; - -struct _UiSVisClass { - GtkWidgetClass parent_class; - void (* scaled) (UiSVis *vis); -}; - -GtkWidget* ui_svis_new (GtkWidget *fixed, gint x, gint y); -GtkType ui_svis_get_type(void); -void ui_svis_clear_data(GtkWidget *widget); -void ui_svis_timeout_func(GtkWidget *widget, guchar * data); -void ui_svis_set_visible(GtkWidget *widget, gboolean window_is_visible); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_SVIS_H */ diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_urlopener.c --- a/src/audacious/ui_urlopener.c Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_urlopener.h --- a/src/audacious/ui_urlopener.h Sun Jul 06 13:55:23 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 cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_vis.c --- a/src/audacious/ui_vis.c Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,724 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 Audacious development team. - * - * Based on: - * BMP - Cross-platform multimedia player - * Copyright (C) 2003-2004 BMP development team. - * 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. - */ - -#include "ui_skin.h" -#include "ui_vis.h" -#include "main.h" -#include "util.h" -#include "playback.h" - -static const gfloat vis_afalloff_speeds[] = { 0.34, 0.5, 1.0, 1.3, 1.6 }; -static const gfloat vis_pfalloff_speeds[] = { 1.2, 1.3, 1.4, 1.5, 1.6 }; -static const gint vis_redraw_delays[] = { 1, 2, 4, 8 }; -static const guint8 vis_scope_colors[] = - { 21, 21, 20, 20, 19, 19, 18, 19, 19, 20, 20, 21, 21 }; -static guchar voiceprint_data[76*16]; - -enum { - DOUBLED, - LAST_SIGNAL -}; - -static void ui_vis_class_init (UiVisClass *klass); -static void ui_vis_init (UiVis *vis); -static void ui_vis_destroy (GtkObject *object); -static void ui_vis_realize (GtkWidget *widget); -static void ui_vis_unrealize (GtkWidget *widget); -static void ui_vis_map (GtkWidget *widget); -static void ui_vis_unmap (GtkWidget *widget); -static void ui_vis_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void ui_vis_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean ui_vis_expose (GtkWidget *widget, GdkEventExpose *event); -static void ui_vis_toggle_scaled (UiVis *vis); - -static GtkWidgetClass *parent_class = NULL; -static guint vis_signals[LAST_SIGNAL] = { 0 }; - -GType ui_vis_get_type() { - static GType vis_type = 0; - if (!vis_type) { - static const GTypeInfo vis_info = { - sizeof (UiVisClass), - NULL, - NULL, - (GClassInitFunc) ui_vis_class_init, - NULL, - NULL, - sizeof (UiVis), - 0, - (GInstanceInitFunc) ui_vis_init, - }; - vis_type = g_type_register_static (GTK_TYPE_WIDGET, "UiVis_", &vis_info, 0); - } - - return vis_type; -} - -static void ui_vis_class_init(UiVisClass *klass) { - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - parent_class = gtk_type_class (gtk_widget_get_type ()); - - object_class->destroy = ui_vis_destroy; - - widget_class->realize = ui_vis_realize; - widget_class->unrealize = ui_vis_unrealize; - widget_class->map = ui_vis_map; - widget_class->unmap = ui_vis_unmap; - widget_class->expose_event = ui_vis_expose; - widget_class->size_request = ui_vis_size_request; - widget_class->size_allocate = ui_vis_size_allocate; - - klass->doubled = ui_vis_toggle_scaled; - - vis_signals[DOUBLED] = - g_signal_new ("toggle-scaled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (UiVisClass, doubled), NULL, NULL, - gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); -} - -static void ui_vis_init(UiVis *vis) { - memset(voiceprint_data, 0, 16*76); -} - -GtkWidget* ui_vis_new(GtkWidget *fixed, gint x, gint y, gint width) { - UiVis *vis = g_object_new (ui_vis_get_type (), NULL); - - vis->x = x; - vis->y = y; - - vis->width = width; - vis->height = 16; - - vis->fixed = fixed; - vis->scaled = FALSE; - - vis->visible_window = TRUE; - vis->event_window = NULL; - - gtk_fixed_put(GTK_FIXED(vis->fixed), GTK_WIDGET(vis), vis->x, vis->y); - - return GTK_WIDGET(vis); -} - -static void ui_vis_destroy(GtkObject *object) { - UiVis *vis; - - g_return_if_fail (object != NULL); - g_return_if_fail (UI_IS_VIS (object)); - - vis = UI_VIS (object); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static void ui_vis_realize(GtkWidget *widget) { - UiVis *vis; - GdkWindowAttr attributes; - gint attributes_mask; - - g_return_if_fail (widget != NULL); - g_return_if_fail (UI_IS_VIS(widget)); - - GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); - vis = UI_VIS(widget); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; - - if (vis->visible_window) - { - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - attributes.wclass = GDK_INPUT_OUTPUT; - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask); - GTK_WIDGET_UNSET_FLAGS(widget, GTK_NO_WINDOW); - gdk_window_set_user_data(widget->window, widget); - } - else - { - widget->window = gtk_widget_get_parent_window (widget); - g_object_ref (widget->window); - - attributes.wclass = GDK_INPUT_ONLY; - attributes_mask = GDK_WA_X | GDK_WA_Y; - vis->event_window = gdk_window_new (widget->window, &attributes, attributes_mask); - GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW); - gdk_window_set_user_data(vis->event_window, widget); - } - - widget->style = gtk_style_attach(widget->style, widget->window); -} - -static void ui_vis_unrealize(GtkWidget *widget) { - UiVis *vis; - vis = UI_VIS(widget); - - if ( vis->event_window != NULL ) - { - gdk_window_set_user_data( vis->event_window , NULL ); - gdk_window_destroy( vis->event_window ); - vis->event_window = NULL; - } - - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); -} - -static void ui_vis_map(GtkWidget *widget) -{ - UiVis *vis; - vis = UI_VIS(widget); - - if (vis->event_window != NULL) - gdk_window_show (vis->event_window); - - if (GTK_WIDGET_CLASS (parent_class)->map) - (* GTK_WIDGET_CLASS (parent_class)->map) (widget); -} - -static void ui_vis_unmap (GtkWidget *widget) -{ - UiVis *vis; - vis = UI_VIS(widget); - - if (vis->event_window != NULL) - gdk_window_hide (vis->event_window); - - if (GTK_WIDGET_CLASS (parent_class)->unmap) - (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget); -} - -static void ui_vis_size_request(GtkWidget *widget, GtkRequisition *requisition) { - UiVis *vis = UI_VIS(widget); - - requisition->width = vis->width*(vis->scaled ? cfg.scale_factor : 1); - requisition->height = vis->height*(vis->scaled ? cfg.scale_factor : 1); -} - -static void ui_vis_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { - UiVis *vis = UI_VIS (widget); - - widget->allocation = *allocation; - widget->allocation.x *= (vis->scaled ? cfg.scale_factor : 1); - widget->allocation.y *= (vis->scaled ? cfg.scale_factor : 1); - if (GTK_WIDGET_REALIZED (widget)) - { - if (vis->event_window != NULL) - gdk_window_move_resize(vis->event_window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - else - gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height); - } - - vis->x = widget->allocation.x/(vis->scaled ? cfg.scale_factor : 1); - vis->y = widget->allocation.y/(vis->scaled ? cfg.scale_factor : 1); -} - -static gboolean ui_vis_expose(GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (UI_IS_VIS (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - UiVis *vis = UI_VIS (widget); - - gint x, y, n, h = 0, h2; - gfloat delta; - guchar skin_col[2][3]; - guchar vis_color[24][3]; - guchar vis_voice_color[256][3], voice_c[3]; - guchar rgb_data[76 * 16 * 3 * 2 * 2], *ptr, c; - guint32 colors[24]; - GdkColor *fgc, *bgc; - GdkRgbCmap *cmap; - - if (!GTK_WIDGET_VISIBLE(widget)) - return FALSE; - - if (!vis->visible_window) - return FALSE; - - skin_get_viscolor(aud_active_skin, vis_color); - for (y = 0; y < 24; y++) { - colors[y] = - vis_color[y][0] << 16 | vis_color[y][1] << 8 | vis_color[y][2]; - } - cmap = gdk_rgb_cmap_new(colors, 24); - - if (!vis->scaled) { - if(cfg.vis_type == VIS_VOICEPRINT /*&& cfg.voiceprint_mode != VOICEPRINT_NORMAL*/){ - memset(rgb_data, 0, 76 * 16 * 3); - } - else{ - memset(rgb_data, 0, 76 * 16); - for (y = 1; y < 16; y += 2) { - ptr = rgb_data + (y * 76); - for (x = 0; x < 76; x += 2, ptr += 2) - *ptr = 1; - } - } - } - else{ - if(cfg.vis_type == VIS_VOICEPRINT /*&& cfg.voiceprint_mode != VOICEPRINT_NORMAL*/){ - memset(rgb_data, 0, 3 * 4 * 16 * 76); - } - else{ - memset(rgb_data, 0, (guint)(76 * cfg.scale_factor) * 32); - for (y = 1; y < 16; y += 2) { - ptr = rgb_data + (y * (guint)(76 * 4 * cfg.scale_factor)); - for (x = 0; x < 76; x += 2, ptr += 4) { - *ptr = 1; - *(ptr + 1) = 1; - *(ptr + (guint)(76 * cfg.scale_factor)) = 1; - *(ptr + (guint)(76 * cfg.scale_factor)+1) = 1; - } - } - } - } - if (cfg.vis_type == VIS_ANALYZER) { - for (x = 0; x < 75; x++) { - if (cfg.analyzer_type == ANALYZER_BARS && (x % 4) == 0) - h = vis->data[x >> 2]; - else if (cfg.analyzer_type == ANALYZER_LINES) - h = vis->data[x]; - if (h && (cfg.analyzer_type == ANALYZER_LINES || - (x % 4) != 3)) { - if (!vis->scaled) { - ptr = rgb_data + ((16 - h) * 76) + x; - switch (cfg.analyzer_mode) { - case ANALYZER_NORMAL: - for (y = 0; y < h; y++, ptr += 76) - *ptr = 18 - h + y; - break; - case ANALYZER_FIRE: - for (y = 0; y < h; y++, ptr += 76) - *ptr = y + 2; - break; - case ANALYZER_VLINES: - for (y = 0; y < h; y++, ptr += 76) - *ptr = 18 - h; - break; - } - } - else{ - ptr = rgb_data + ((16 - h) * (guint)(76 * 4 * cfg.scale_factor)) + (guint)(x * cfg.scale_factor); - switch (cfg.analyzer_mode) { - case ANALYZER_NORMAL: - for (y = 0; y < h; y++, ptr += (guint)(76 * 4 * cfg.scale_factor)) { - *ptr = 18 - h + y; - *(ptr + 1) = 18 - h + y; - *(ptr + (guint)(76 * cfg.scale_factor)) = 18 - h + y; - *(ptr + (guint)(76 * cfg.scale_factor)+1) = 18 - h + y; - } - break; - case ANALYZER_FIRE: - for (y = 0; y < h; y++, ptr += (guint)(76 * 4 * cfg.scale_factor)) { - *ptr = y + 2; - *(ptr + 1) = y + 2; - *(ptr + (guint)(76 * cfg.scale_factor)) = y + 2; - *(ptr + (guint)(76 * cfg.scale_factor)+1) = y + 2; - } - break; - case ANALYZER_VLINES: - for (y = 0; y < h; y++, ptr += (guint)(76 * 4 * cfg.scale_factor)) { - *ptr = 18 - h; - *(ptr + 1) = 18 - h; - *(ptr + (guint)(76 * cfg.scale_factor)) = 18 - h; - *(ptr + (guint)(76 * cfg.scale_factor)+1) = 18 - h; - } - - break; - } - } - } - } - if (cfg.analyzer_peaks) { - for (x = 0; x < 75; x++) { - if (cfg.analyzer_type == ANALYZER_BARS && (x % 4) == 0) - h = vis->peak[x >> 2]; - else if (cfg.analyzer_type == ANALYZER_LINES) - h = vis->peak[x]; - if (h && (cfg.analyzer_type == ANALYZER_LINES || (x % 4) != 3)){ - - if (!vis->scaled) { - rgb_data[(16 - h) * 76 + x] = 23; - } - else{ - ptr = rgb_data + (16 - h) * (guint)(76 * 4 * cfg.scale_factor) + (guint)(x * cfg.scale_factor); - *ptr = 23; - *(ptr + 1) = 23; - *(ptr + (guint)(76 * cfg.scale_factor)) = 23; - *(ptr + (guint)(76 * cfg.scale_factor)+1) = 23; - } - } - } - } - } - else if (cfg.vis_type == VIS_VOICEPRINT) { - if(!playback_get_paused() && playback_get_playing()){/*Don't scroll when it's paused or stopped*/ - for (y = 0; y < 16; y ++) - for (x = 75; x > 0; x--) - voiceprint_data[x + y * 76] = voiceprint_data[x-1+y*76]; - for(y=0;y<16;y++) - voiceprint_data[y * 76] = vis->data[y]; - } - if(playback_get_playing()){ /*Only draw the data if we're playing*/ - if(cfg.voiceprint_mode == VOICEPRINT_NORMAL){ - /* Create color gradient from the skin's background- and foreground color*/ - fgc = skin_get_color(aud_active_skin, SKIN_TEXTFG); - bgc = skin_get_color(aud_active_skin, SKIN_TEXTBG); - skin_col[0][0] = fgc->red >> 8; - skin_col[0][1] = fgc->green >> 8; - skin_col[0][2] = fgc->blue >> 8; - skin_col[1][0] = bgc->red >> 8; - skin_col[1][1] = bgc->green >> 8; - skin_col[1][2] = bgc->blue >> 8; - for(n=0;n<3;n++){ - for(x=0;x<256;x++){ - if(skin_col[0][n] > skin_col[1][n]){ - delta = (gfloat)(skin_col[0][n] - skin_col[1][n]) / 256.0; - vis_voice_color[x][n] = skin_col[1][n] + (gfloat)(delta * x); - } - else if(skin_col[0][n] == skin_col[1][n]){ - vis_voice_color[x][n] = skin_col[0][n]; - } - else{ - delta = (gfloat)(skin_col[1][n] - skin_col[0][n]) / 256.0; - vis_voice_color[x][n] = skin_col[1][n] - (gfloat)(delta * x); - } - } - } - } - for (y = 0; y < 16; y ++){ - for (x = 0; x < 76; x++){ - guint8 d = voiceprint_data[x + y*76]; - - if(cfg.voiceprint_mode == VOICEPRINT_NORMAL){ - voice_c[0] = vis_voice_color[d][0]; - voice_c[1] = vis_voice_color[d][1]; - voice_c[2] = vis_voice_color[d][2]; - } - else if(cfg.voiceprint_mode == VOICEPRINT_FIRE){ - voice_c[0] = d < 64 ? (d * 2) : 255; - voice_c[1] = d < 64 ? 0 : (d < 128 ? (d-64) * 2 : 255); - voice_c[2] = d < 128 ? 0 : (d-128) * 2; - /* Test for black->blue->green->red. Isn't pretty, though... - voice_c[0] = d > 192 ? (d - 192) << 2 : 0; - voice_c[1] = d > 64 ? (d < 128 ? (d - 64) << 2 : (d < 192 ? (192 - d) << 2 : 0)) : 0; - voice_c[2] = d < 64 ? d << 2 : (d < 128 ? (128 - d) << 2 : 0); - */ - } - else if(cfg.voiceprint_mode == VOICEPRINT_ICE){ - voice_c[0] = d; - voice_c[1] = d < 128 ? d * 2 : 255; - voice_c[2] = d < 64 ? d * 4 : 255; - } - if(!vis->scaled){ - for(n=0;n<3;n++) - rgb_data[x * 3 + y * 76*3+n] = voice_c[n]; - } - else{ - ptr = rgb_data + (guint)(x * 3 * cfg.scale_factor) + (guint) (y * 76 * 3 * cfg.scale_factor); - for(n=0;n<3;n++) - { - *(ptr + n) = voice_c[n]; - *(ptr + n + 3) = voice_c[n]; - *(ptr + (guint)(n + 76 * cfg.scale_factor * 3)) = voice_c[n]; - *(ptr + (guint)(n + 3 + 76 * cfg.scale_factor * 3)) = voice_c[n]; - } - } - } - } - } - } - if (cfg.vis_type == VIS_SCOPE) { - for (x = 0; x < 75; x++) { - switch (cfg.scope_mode) { - case SCOPE_DOT: - h = vis->data[x]; - if (!vis->scaled) { - ptr = rgb_data + ((14 - h) * 76) + x; - *ptr = vis_scope_colors[h + 1]; - }else{ - ptr = rgb_data + ((14 - h) * (guint)(76 * 4 * cfg.scale_factor)) + (guint)(x * cfg.scale_factor); - *ptr = vis_scope_colors[h + 1]; - *(ptr + 1) = vis_scope_colors[h + 1]; - *(ptr + (guint)(76 * cfg.scale_factor)) = vis_scope_colors[h + 1]; - *(ptr + (guint)(76 * cfg.scale_factor)+1) = vis_scope_colors[h + 1]; - } - break; - case SCOPE_LINE: - if (x != 74) { - h = 14 - vis->data[x]; - h2 = 14 - vis->data[x + 1]; - if (h > h2) { - y = h; - h = h2; - h2 = y; - } - if (!vis->scaled) { - ptr = rgb_data + (h * 76) + x; - for (y = h; y <= h2; y++, ptr += 76) - *ptr = vis_scope_colors[y - 2]; - } - else{ - ptr = rgb_data + (h * (guint)(76 * 4 * cfg.scale_factor)) + (guint)(x * cfg.scale_factor); - for (y = h; y <= h2; y++, ptr += (guint)(76 * 4 * cfg.scale_factor)) { - *ptr = vis_scope_colors[y - 2]; - *(ptr + 1) = vis_scope_colors[y - 2]; - *(ptr + (guint)(76 * cfg.scale_factor)) = vis_scope_colors[y - 2]; - *(ptr + (guint)(76 * cfg.scale_factor)+1) = vis_scope_colors[y - 2]; - } - } - } - else { - h = 14 - vis->data[x]; - if (!vis->scaled) { - ptr = rgb_data + (h * 76) + x; - *ptr = vis_scope_colors[h + 1]; - }else{ - ptr = rgb_data + (h * (guint)(76 * 4 * cfg.scale_factor)) + (guint)(x * cfg.scale_factor); - *ptr = vis_scope_colors[h + 1]; - *(ptr + 1) = vis_scope_colors[h + 1]; - *(ptr + (guint)(76 * cfg.scale_factor)) = vis_scope_colors[h + 1]; - *(ptr + (guint)(76 * cfg.scale_factor)+1) = vis_scope_colors[h + 1]; - } - } - break; - case SCOPE_SOLID: - h = 14 - vis->data[x]; - h2 = 8; - c = vis_scope_colors[(gint) vis->data[x]]; - if (h > h2) { - y = h; - h = h2; - h2 = y; - } - if (!vis->scaled) { - ptr = rgb_data + (h * 76) + x; - for (y = h; y <= h2; y++, ptr += 76) - *ptr = c; - }else{ - ptr = rgb_data + (h * (guint)(76 * 4 * cfg.scale_factor)) + (guint)(x * cfg.scale_factor); - for (y = h; y <= h2; y++, ptr += (guint)(76 * 4 * cfg.scale_factor)) { - *ptr = c; - *(ptr + 1) = c; - *(ptr + (guint)(76 * cfg.scale_factor)) = c; - *(ptr + (guint)(76 * cfg.scale_factor)+1) = c; - } - } - break; - } - } - } - - GdkPixmap *obj = NULL; - GdkGC *gc; - obj = gdk_pixmap_new(NULL, vis->width*(vis->scaled ? cfg.scale_factor : 1), vis->height*(vis->scaled ? cfg.scale_factor : 1), gdk_rgb_get_visual()->depth); - gc = gdk_gc_new(obj); - - if (!vis->scaled) { - if (cfg.vis_type == VIS_VOICEPRINT) { - gdk_draw_rgb_image(obj, gc, 0, 0, vis->width, vis->height, - GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data, - 76 * 3); - } else { - gdk_draw_indexed_image(obj, gc, 0, 0, vis->width, vis->height, - GDK_RGB_DITHER_NORMAL, (guchar *) rgb_data, - 76 , cmap); - } - } else { - if (cfg.vis_type == VIS_VOICEPRINT) { - gdk_draw_rgb_image(obj, gc, 0 << 1, 0 << 1, - vis->width << 1, vis->height << 1, - GDK_RGB_DITHER_NONE, (guchar *) rgb_data, - 76 * 2 * 3); - } else { - gdk_draw_indexed_image(obj, gc, 0 << 1, 0 << 1, - vis->width << 1, vis->height << 1, - GDK_RGB_DITHER_NONE, (guchar *) rgb_data, - 76 * 2 , cmap); - } - } - - gdk_draw_drawable (widget->window, gc, obj, 0, 0, 0, 0, - vis->width*(vis->scaled ? cfg.scale_factor : 1), vis->height*(vis->scaled ? cfg.scale_factor : 1)); - g_object_unref(obj); - g_object_unref(gc); - gdk_rgb_cmap_free(cmap); - return FALSE; -} - -static void ui_vis_toggle_scaled(UiVis *vis) { - GtkWidget *widget = GTK_WIDGET (vis); - vis->scaled = !vis->scaled; - - gtk_widget_set_size_request(widget, vis->width*(vis->scaled ? cfg.scale_factor : 1), vis->height*(vis->scaled ? cfg.scale_factor : 1)); - - gtk_widget_queue_draw(GTK_WIDGET(vis)); -} - -void ui_vis_draw_pixel(GtkWidget *widget, guchar* texture, gint x, gint y, guint8 colour) { - UiVis *vis = UI_VIS (widget); - if (vis->scaled){ - texture[y * 76 + x] = colour; - texture[y * 76 + x + 1] = colour; - texture[y * 76 * 4 + x] = colour; - texture[y * 76 * 4 + x + 1] = colour; - } else { - texture[y * 76 + x] = colour; - } -} - -void ui_vis_set_visible(GtkWidget *widget, gboolean window_is_visible) -{ - UiVis *vis; - gboolean widget_is_visible; - - g_return_if_fail(UI_IS_VIS(widget)); - - vis = UI_VIS (widget); - widget_is_visible = GTK_WIDGET_VISIBLE(widget); - - vis->visible_window = window_is_visible; - - if (GTK_WIDGET_REALIZED (widget)) - { - if ( widget_is_visible ) - gtk_widget_hide(widget); - - gtk_widget_unrealize(widget); - gtk_widget_realize(widget); - - if ( widget_is_visible ) - gtk_widget_show(widget); - } - - if (widget_is_visible) - gtk_widget_queue_resize(widget); -} - -void ui_vis_clear_data(GtkWidget *widget) { - g_return_if_fail(UI_IS_VIS(widget)); - - gint i; - UiVis *vis = UI_VIS (widget); - - memset(voiceprint_data, 0, 16*76); - for (i = 0; i < 75; i++) { - vis->data[i] = (cfg.vis_type == VIS_SCOPE) ? 6 : 0; - vis->peak[i] = 0; - } -} - -void ui_vis_timeout_func(GtkWidget *widget, guchar * data) { - g_return_if_fail(UI_IS_VIS(widget)); - - UiVis *vis = UI_VIS (widget); - static GTimer *timer = NULL; - gulong micros = 9999999; - gboolean falloff = FALSE; - gint i; - - if (!timer) { - timer = g_timer_new(); - g_timer_start(timer); - } - else { - g_timer_elapsed(timer, µs); - if (micros > 14000) - g_timer_reset(timer); - } - if (cfg.vis_type == VIS_ANALYZER) { - if (micros > 14000) - falloff = TRUE; - if (data || falloff) { - for (i = 0; i < 75; i++) { - if (data && data[i] > vis->data[i]) { - vis->data[i] = data[i]; - if (vis->data[i] > vis->peak[i]) { - vis->peak[i] = vis->data[i]; - vis->peak_speed[i] = 0.01; - - } - else if (vis->peak[i] > 0.0) { - vis->peak[i] -= vis->peak_speed[i]; - vis->peak_speed[i] *= - vis_pfalloff_speeds[cfg.peaks_falloff]; - if (vis->peak[i] < vis->data[i]) - vis->peak[i] = vis->data[i]; - if (vis->peak[i] < 0.0) - vis->peak[i] = 0.0; - } - } - else if (falloff) { - if (vis->data[i] > 0.0) { - vis->data[i] -= - vis_afalloff_speeds[cfg.analyzer_falloff]; - if (vis->data[i] < 0.0) - vis->data[i] = 0.0; - } - if (vis->peak[i] > 0.0) { - vis->peak[i] -= vis->peak_speed[i]; - vis->peak_speed[i] *= - vis_pfalloff_speeds[cfg.peaks_falloff]; - if (vis->peak[i] < vis->data[i]) - vis->peak[i] = vis->data[i]; - if (vis->peak[i] < 0.0) - vis->peak[i] = 0.0; - } - } - } - } - } - else if (cfg.vis_type == VIS_VOICEPRINT && data){ - for(i = 0; i < 16; i++) - { - vis->data[i] = data[15 - i]; - } - } - else if (data) { - for (i = 0; i < 75; i++) - vis->data[i] = data[i]; - } - - if (micros > 14000) { - if (!vis->refresh_delay) { - gtk_widget_queue_draw(widget); - vis->refresh_delay = vis_redraw_delays[cfg.vis_refresh]; - } - vis->refresh_delay--; - } -} diff -r cfc8d1e0c78b -r 3a56d2786063 src/audacious/ui_vis.h --- a/src/audacious/ui_vis.h Sun Jul 06 13:55:23 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - * Audacious - a cross-platform multimedia player - * Copyright (c) 2007 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_VIS_H -#define AUDACIOUS_UI_VIS_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define UI_VIS(obj) GTK_CHECK_CAST (obj, ui_vis_get_type (), UiVis) -#define UI_VIS_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ui_vis_get_type (), UiVisClass) -#define UI_IS_VIS(obj) GTK_CHECK_TYPE (obj, ui_vis_get_type ()) - -typedef enum { - VIS_ANALYZER, VIS_SCOPE, VIS_VOICEPRINT, VIS_OFF -} VisType; - -typedef enum { - ANALYZER_NORMAL, ANALYZER_FIRE, ANALYZER_VLINES -} AnalyzerMode; - -typedef enum { - ANALYZER_LINES, ANALYZER_BARS -} AnalyzerType; - -typedef enum { - SCOPE_DOT, SCOPE_LINE, SCOPE_SOLID -} ScopeMode; -typedef enum { - VOICEPRINT_NORMAL, VOICEPRINT_FIRE, VOICEPRINT_ICE -} VoiceprintMode; - - -typedef enum { - VU_NORMAL, VU_SMOOTH -} VUMode; - -typedef enum { - REFRESH_FULL, REFRESH_HALF, REFRESH_QUARTER, REFRESH_EIGTH -} RefreshRate; - -typedef enum { - FALLOFF_SLOWEST, FALLOFF_SLOW, FALLOFF_MEDIUM, FALLOFF_FAST, - FALLOFF_FASTEST -} FalloffSpeed; - -typedef struct _UiVis UiVis; -typedef struct _UiVisClass UiVisClass; - -struct _UiVis { - GtkWidget widget; - - gint x, y, width, height; - gfloat data[75], peak[75], peak_speed[75]; - gint refresh_delay; - gboolean scaled; - GtkWidget *fixed; - gboolean visible_window; - GdkWindow *event_window; -}; - -struct _UiVisClass { - GtkWidgetClass parent_class; - void (* doubled) (UiVis *vis); -}; - -GtkWidget* ui_vis_new (GtkWidget *fixed, gint x, gint y, gint width); -GtkType ui_vis_get_type(void); -void ui_vis_set_vis(GtkWidget *widget, gint num); -void ui_vis_clear_data(GtkWidget *widget); -void ui_vis_timeout_func(GtkWidget *widget, guchar * data); -void ui_vis_set_visible(GtkWidget *widget, gboolean window_is_visible); - -#ifdef __cplusplus -} -#endif - -#endif /* AUDACIOUS_UI_VIS_H */