# HG changeset patch # User nenolod # Date 1157684247 25200 # Node ID 1a525bd78cf0f152833a76424dac15059999509a # Parent 3d3b60e664919342172d8f1fdf79ff6d6b726e2b [svn] - copy the WA2GUI code into a Plugin shell diff -r 3d3b60e66491 -r 1a525bd78cf0 ChangeLog --- a/ChangeLog Thu Sep 07 18:33:19 2006 -0700 +++ b/ChangeLog Thu Sep 07 19:57:27 2006 -0700 @@ -1,3 +1,12 @@ +2006-09-08 01:33:19 +0000 William Pitcock + revision [2215] + - use gdk_drawable_get_size() instead + + + Changes: Modified: + +1 -11 trunk/audacious/widgets/skin.c + + 2006-09-08 00:27:27 +0000 William Pitcock revision [2213] - use smartinclude here instead of conditional-based imports diff -r 3d3b60e66491 -r 1a525bd78cf0 Plugins/UserInterface/wa2gui/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/UserInterface/wa2gui/Makefile Thu Sep 07 19:57:27 2006 -0700 @@ -0,0 +1,17 @@ +include ../../../mk/rules.mk +include ../../../mk/init.mk + +OBJECTIVE_LIBS = libwa2_gui$(SHARED_SUFFIX) + +noinst_HEADERS = coreaudio.h + +LIBDIR = $(plugindir)/$(USERINTERFACE_PLUGIN_DIR) + +LIBADD = $(GTK_LIBS) +SOURCES = mainwin.c equalizer.c playlist.c filepopup.c wa2gui.c + +OBJECTS = ${SOURCES:.c=.o} + +CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) -I../../../intl -I../../.. + +include ../../../mk/objective.mk diff -r 3d3b60e66491 -r 1a525bd78cf0 Plugins/UserInterface/wa2gui/equalizer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/UserInterface/wa2gui/equalizer.c Thu Sep 07 19:57:27 2006 -0700 @@ -0,0 +1,1753 @@ +/* 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "equalizer.h" + +#include +#include +#include +#include +#include +#include + +#include "platform/smartinclude.h" +#include "widgets/widgetcore.h" +#include "dock.h" +#include "hints.h" +#include "input.h" +#include "main.h" +#include "playlist.h" +#include "ui_playlist.h" +#include "util.h" +#include "output.h" + +#include "libaudacious/rcfile.h" +#include "libaudacious/vfs.h" + +#include "images/audacious_eq.xpm" + +enum PresetViewCols { + PRESET_VIEW_COL_NAME, + PRESET_VIEW_N_COLS +}; + +enum { + EQUALIZER_PRESETS_LOAD_PRESET, + EQUALIZER_PRESETS_LOAD_AUTOPRESET, + EQUALIZER_PRESETS_LOAD_DEFAULT, + EQUALIZER_PRESETS_LOAD_ZERO, + EQUALIZER_PRESETS_LOAD_FROM_FILE, + EQUALIZER_PRESETS_LOAD_FROM_WINAMPFILE, + EQUALIZER_PRESETS_IMPORT_WINAMPFILE, + EQUALIZER_PRESETS_SAVE_PRESET, + EQUALIZER_PRESETS_SAVE_AUTOPRESET, + EQUALIZER_PRESETS_SAVE_DEFAULT, + EQUALIZER_PRESETS_SAVE_TO_FILE, + EQUALIZER_PRESETS_SAVE_TO_WINAMPFILE, + EQUALIZER_PRESETS_DELETE_PRESET, + EQUALIZER_PRESETS_DELETE_AUTOPRESET +}; + + +struct _EqualizerPreset { + gchar *name; + gfloat preamp, bands[10]; +}; + +typedef struct _EqualizerPreset EqualizerPreset; + + +GtkWidget *equalizerwin; + +static GtkWidget *equalizerwin_load_window = NULL; +static GtkWidget *equalizerwin_load_auto_window = NULL; +static GtkWidget *equalizerwin_save_window = NULL; +static GtkWidget *equalizerwin_save_entry; +static GtkWidget *equalizerwin_save_auto_window = NULL; +static GtkWidget *equalizerwin_save_auto_entry; +static GtkWidget *equalizerwin_delete_window = NULL; +static GtkWidget *equalizerwin_delete_auto_window = NULL; + +static GdkPixmap *equalizerwin_bg; +static GdkGC *equalizerwin_gc; + +static GList *equalizerwin_wlist = NULL; + +static GtkAccelGroup *equalizerwin_accel; + +static TButton *equalizerwin_on, *equalizerwin_auto; + +static PButton *equalizerwin_presets, *equalizerwin_shade; +PButton *equalizerwin_close; +static EqGraph *equalizerwin_graph; +static EqSlider *equalizerwin_preamp, *equalizerwin_bands[10]; +static HSlider *equalizerwin_volume, *equalizerwin_balance; + +static GtkItemFactory *equalizerwin_presets_menu; + +static GList *equalizer_presets = NULL, *equalizer_auto_presets = NULL; + + +static void equalizerwin_presets_menu_cb(gpointer cb_data, guint action, + GtkWidget * w); + +static GtkItemFactoryEntry equalizerwin_presets_menu_entries[] = { + {N_("/Load"), NULL, NULL, 0, "", NULL}, + {N_("/Load/Preset"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_LOAD_PRESET, "", NULL}, + {N_("/Load/Auto-load preset"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_LOAD_AUTOPRESET, "", NULL}, + {N_("/Load/Default"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_LOAD_DEFAULT, "", NULL}, + {"/Load/-", NULL, NULL, 0, "", NULL}, + {N_("/Load/Zero"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_LOAD_ZERO, "", NULL}, + {"/Load/-", NULL, NULL, 0, "", NULL}, + {N_("/Load/From file"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_LOAD_FROM_FILE, "", NULL}, + {N_("/Load/From WinAMP EQF file"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_LOAD_FROM_WINAMPFILE, "", NULL}, + {N_("/Import"), NULL, NULL, 0, "", NULL}, + {N_("/Import/WinAMP Presets"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_IMPORT_WINAMPFILE, "", NULL}, + {N_("/Save"), NULL, NULL, 0, "", NULL}, + {N_("/Save/Preset"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_SAVE_PRESET, "", NULL}, + {N_("/Save/Auto-load preset"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_SAVE_AUTOPRESET, "", NULL}, + {N_("/Save/Default"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_SAVE_DEFAULT, "", NULL}, + {"/Save/-", NULL, NULL, 0, "", NULL}, + {N_("/Save/To file"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_SAVE_TO_FILE, "", NULL}, + {N_("/Save/To WinAMP EQF file"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_SAVE_TO_WINAMPFILE, "", NULL}, + {N_("/Delete"), NULL, NULL, 0, "", NULL}, + {N_("/Delete/Preset"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_DELETE_PRESET, "", NULL}, + {N_("/Delete/Auto-load preset"), NULL, equalizerwin_presets_menu_cb, + EQUALIZER_PRESETS_DELETE_AUTOPRESET, "", NULL}, +}; + +static gint equalizerwin_presets_menu_entries_num = + G_N_ELEMENTS(equalizerwin_presets_menu_entries); + + +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); +} + + +static void +equalizerwin_set_shape_mask(void) +{ + GdkBitmap *mask; + + if (cfg.show_wm_decorations) + return; + + mask = skin_get_mask(bmp_active_skin, SKIN_MASK_EQ + cfg.equalizer_shaded); + gtk_widget_shape_combine_mask(equalizerwin, mask, 0, 0); +} + + +void +equalizerwin_set_shade_menu_cb(gboolean shaded) +{ + cfg.equalizer_shaded = shaded; + + equalizerwin_set_shape_mask(); + + if (shaded) { + dock_shade(dock_window_list, GTK_WINDOW(equalizerwin), 14); + pbutton_set_button_data(equalizerwin_shade, -1, 3, -1, 47); + pbutton_set_skin_index1(equalizerwin_shade, SKIN_EQ_EX); + pbutton_set_button_data(equalizerwin_close, 11, 38, 11, 47); + pbutton_set_skin_index(equalizerwin_close, SKIN_EQ_EX); + widget_show(WIDGET(equalizerwin_volume)); + widget_show(WIDGET(equalizerwin_balance)); + } + else { + dock_shade(dock_window_list, GTK_WINDOW(equalizerwin), 116); + pbutton_set_button_data(equalizerwin_shade, -1, 137, -1, 38); + pbutton_set_skin_index1(equalizerwin_shade, SKIN_EQMAIN); + pbutton_set_button_data(equalizerwin_close, 0, 116, 0, 125); + pbutton_set_skin_index(equalizerwin_close, SKIN_EQMAIN); + widget_hide(WIDGET(equalizerwin_volume)); + widget_hide(WIDGET(equalizerwin_balance)); + } + + draw_equalizer_window(TRUE); +} + +static void +equalizerwin_set_shade(gboolean shaded) +{ + GtkWidget *widget; + widget = gtk_item_factory_get_widget(mainwin_view_menu, + "/Roll up Equalizer"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), shaded); +} + +static void +equalizerwin_shade_toggle(void) +{ + equalizerwin_set_shade(!cfg.equalizer_shaded); +} + +static void +equalizerwin_raise(void) +{ + if (cfg.equalizer_visible) + gtk_window_present(GTK_WINDOW(equalizerwin)); +} + +void +equalizerwin_eq_changed(void) +{ + gint i; + + cfg.equalizer_preamp = eqslider_get_position(equalizerwin_preamp); + for (i = 0; i < 10; i++) + cfg.equalizer_bands[i] = eqslider_get_position(equalizerwin_bands[i]); + /* um .. i think we need both of these for xmms compatibility .. + not sure. -larne */ + input_set_eq(cfg.equalizer_active, cfg.equalizer_preamp, + cfg.equalizer_bands); + output_set_eq(cfg.equalizer_active, cfg.equalizer_preamp, + cfg.equalizer_bands); + + widget_draw(WIDGET(equalizerwin_graph)); +} + +static void +equalizerwin_on_pushed(gboolean toggled) +{ + cfg.equalizer_active = toggled; + equalizerwin_eq_changed(); +} + +static void +equalizerwin_presets_pushed(void) +{ + GdkModifierType modmask; + gint x, y; + + gdk_window_get_pointer(NULL, &x, &y, &modmask); + util_item_factory_popup(equalizerwin_presets_menu, x, y, 1, + GDK_CURRENT_TIME); +} + +static void +equalizerwin_auto_pushed(gboolean toggled) +{ + cfg.equalizer_autoload = toggled; +} + +void +draw_equalizer_window(gboolean force) +{ + gboolean redraw; + + widget_list_lock(equalizerwin_wlist); + + if (force) { + skin_draw_pixmap(bmp_active_skin, equalizerwin_bg, equalizerwin_gc, + SKIN_EQMAIN, 0, 0, 0, 0, 275, 116); + if (gtk_window_has_toplevel_focus(GTK_WINDOW(equalizerwin)) || + !cfg.dim_titlebar) { + if (!cfg.equalizer_shaded) + skin_draw_pixmap(bmp_active_skin, equalizerwin_bg, + equalizerwin_gc, SKIN_EQMAIN, 0, 134, 0, + 0, 275, 14); + else + skin_draw_pixmap(bmp_active_skin, equalizerwin_bg, + equalizerwin_gc, SKIN_EQ_EX, 0, 0, 0, 0, + 275, 14); + } + else { + if (!cfg.equalizer_shaded) + skin_draw_pixmap(bmp_active_skin, equalizerwin_bg, + equalizerwin_gc, SKIN_EQMAIN, 0, 149, 0, + 0, 275, 14); + else + skin_draw_pixmap(bmp_active_skin, equalizerwin_bg, + equalizerwin_gc, SKIN_EQ_EX, 0, 15, 0, 0, + 275, 14); + + } + } + + widget_list_draw(equalizerwin_wlist, &redraw, force); + + if (force || redraw) { + widget_list_clear_redraw(equalizerwin_wlist); + gdk_window_clear(equalizerwin->window); + gdk_flush(); + } + + widget_list_unlock(equalizerwin_wlist); +} + +static gboolean +inside_sensitive_widgets(gint x, gint y) +{ + return (widget_contains(WIDGET(equalizerwin_on), x, y) || + widget_contains(WIDGET(equalizerwin_auto), x, y) || + widget_contains(WIDGET(equalizerwin_presets), x, y) || + widget_contains(WIDGET(equalizerwin_close), x, y) || + widget_contains(WIDGET(equalizerwin_shade), x, y) || + widget_contains(WIDGET(equalizerwin_preamp), x, y) || + widget_contains(WIDGET(equalizerwin_bands[0]), x, y) || + widget_contains(WIDGET(equalizerwin_bands[1]), x, y) || + widget_contains(WIDGET(equalizerwin_bands[2]), x, y) || + widget_contains(WIDGET(equalizerwin_bands[3]), x, y) || + widget_contains(WIDGET(equalizerwin_bands[4]), x, y) || + widget_contains(WIDGET(equalizerwin_bands[5]), x, y) || + widget_contains(WIDGET(equalizerwin_bands[6]), x, y) || + widget_contains(WIDGET(equalizerwin_bands[7]), x, y) || + widget_contains(WIDGET(equalizerwin_bands[8]), x, y) || + widget_contains(WIDGET(equalizerwin_bands[9]), x, y) || + widget_contains(WIDGET(equalizerwin_volume), x, y) || + widget_contains(WIDGET(equalizerwin_balance), x, y)); +} + +gboolean +equalizerwin_press(GtkWidget * widget, GdkEventButton * event, + gpointer callback_data) +{ + gint mx, my; + gboolean grab = TRUE; + + mx = event->x; + my = event->y; + + if (event->button == 1 && event->type == GDK_BUTTON_PRESS && + ((cfg.equalizer_shaded || event->y < 14) && + !inside_sensitive_widgets(event->x, event->y))) { + if (0 && hint_move_resize_available()) { + hint_move_resize(equalizerwin, event->x_root, + event->y_root, TRUE); + grab = FALSE; + } + else { + equalizerwin_raise(); + dock_move_press(dock_window_list, GTK_WINDOW(equalizerwin), event, + FALSE); + } + } + else 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)); + } + else if (event->button == 3 && + !(widget_contains(WIDGET(equalizerwin_on), event->x, event->y) || + widget_contains(WIDGET(equalizerwin_auto), event->x, event->y))) { + /* + * Pop up the main menu a few pixels down to avoid + * anything to be selected initially. + */ + util_item_factory_popup(mainwin_general_menu, event->x_root, + event->y_root + 2, 3, event->time); + grab = FALSE; + } + else { + handle_press_cb(equalizerwin_wlist, widget, event); + draw_equalizer_window(FALSE); + } + if (grab) + gdk_pointer_grab(GDK_WINDOW(equalizerwin->window), FALSE, + GDK_BUTTON_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, + NULL, NULL, GDK_CURRENT_TIME); + + return FALSE; +} + +static void +equalizerwin_scroll(GtkWidget * widget, GdkEventScroll * event, gpointer data) +{ + handle_scroll_cb(equalizerwin_wlist, widget, event); + draw_equalizer_window(FALSE); +} + +static gboolean +equalizerwin_motion(GtkWidget * widget, + GdkEventMotion * event, gpointer callback_data) +{ + GdkEvent *gevent; + + if (dock_is_moving(GTK_WINDOW(equalizerwin))) + { + dock_move_motion(GTK_WINDOW(equalizerwin), event); + } + else + { + handle_motion_cb(equalizerwin_wlist, widget, event); + draw_equalizer_window(FALSE); + } + + gdk_flush(); + + while ((gevent = gdk_event_get()) != NULL) gdk_event_free(gevent); + + return FALSE; +} + +static gboolean +equalizerwin_release(GtkWidget * widget, + GdkEventButton * event, gpointer callback_data) +{ + gdk_pointer_ungrab(GDK_CURRENT_TIME); + gdk_flush(); + + if (dock_is_moving(GTK_WINDOW(equalizerwin))) { + dock_move_release(GTK_WINDOW(equalizerwin)); + } + else { + handle_release_cb(equalizerwin_wlist, widget, event); + draw_equalizer_window(FALSE); + } + + return FALSE; +} + +static gboolean +equalizerwin_focus_in(GtkWidget * widget, + GdkEvent * event, + gpointer data) +{ + equalizerwin_close->pb_allow_draw = TRUE; + equalizerwin_shade->pb_allow_draw = TRUE; + draw_equalizer_window(TRUE); + return TRUE; +} + +static gboolean +equalizerwin_focus_out(GtkWidget * widget, + GdkEventButton * event, + gpointer data) +{ + equalizerwin_close->pb_allow_draw = FALSE; + equalizerwin_shade->pb_allow_draw = FALSE; + draw_equalizer_window(TRUE); + return TRUE; +} + +static gboolean +equalizerwin_keypress(GtkWidget * widget, + GdkEventKey * event, + gpointer data) +{ + 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 gboolean +equalizerwin_configure(GtkWidget * window, + GdkEventConfigure * event, + gpointer data) +{ + if (!GTK_WIDGET_VISIBLE(window)) + return FALSE; + + cfg.equalizer_x = event->x; + cfg.equalizer_y = event->y; + return FALSE; +} + +static void +equalizerwin_set_back_pixmap(void) +{ + gdk_window_set_back_pixmap(equalizerwin->window, equalizerwin_bg, 0); + gdk_window_clear(equalizerwin->window); +} + +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; + + filename = g_build_filename(bmp_paths[BMP_PATH_USER_DIR], basename, NULL); + + if ((rcfile = bmp_rcfile_open(filename)) == NULL) { + g_free(filename); + return NULL; + } + + g_free(filename); + + for (;;) { + gchar section[21]; + + g_snprintf(section, sizeof(section), "Preset%d", p++); + if (bmp_rcfile_read_string(rcfile, "Presets", section, &name)) { + preset = g_new0(EqualizerPreset, 1); + preset->name = name; + bmp_rcfile_read_float(rcfile, name, "Preamp", &preset->preamp); + for (i = 0; i < 10; i++) { + gchar band[7]; + g_snprintf(band, sizeof(band), "Band%d", i); + bmp_rcfile_read_float(rcfile, name, band, &preset->bands[i]); + } + list = g_list_prepend(list, preset); + } + else + break; + } + list = g_list_reverse(list); + bmp_rcfile_free(rcfile); + return list; +} + +gint +equalizerwin_volume_frame_cb(gint pos) +{ + if (equalizerwin_volume) { + if (pos < 32) + equalizerwin_volume->hs_knob_nx = + equalizerwin_volume->hs_knob_px = 1; + else if (pos < 63) + equalizerwin_volume->hs_knob_nx = + equalizerwin_volume->hs_knob_px = 4; + else + equalizerwin_volume->hs_knob_nx = + equalizerwin_volume->hs_knob_px = 7; + } + return 1; +} + +static void +equalizerwin_volume_motion_cb(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(gint pos) +{ + mainwin_adjust_volume_release(); +} + +static gint +equalizerwin_balance_frame_cb(gint pos) +{ + if (equalizerwin_balance) { + if (pos < 13) + equalizerwin_balance->hs_knob_nx = + equalizerwin_balance->hs_knob_px = 11; + else if (pos < 26) + equalizerwin_balance->hs_knob_nx = + equalizerwin_balance->hs_knob_px = 14; + else + equalizerwin_balance->hs_knob_nx = + equalizerwin_balance->hs_knob_px = 17; + } + + return 1; +} + +static void +equalizerwin_balance_motion_cb(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(gint pos) +{ + mainwin_adjust_balance_release(); +} + +void +equalizerwin_set_balance_slider(gint percent) +{ + hslider_set_position(equalizerwin_balance, + (gint) rint((percent * 19 / 100.0) + 19)); +} + +void +equalizerwin_set_volume_slider(gint percent) +{ + hslider_set_position(equalizerwin_volume, + (gint) rint(percent * 94 / 100.0)); +} + +static void +equalizerwin_create_widgets(void) +{ + gint i; + + equalizerwin_on = + create_tbutton(&equalizerwin_wlist, equalizerwin_bg, + equalizerwin_gc, 14, 18, 25, 12, 10, 119, 128, 119, + 69, 119, 187, 119, equalizerwin_on_pushed, + SKIN_EQMAIN); + tbutton_set_toggled(equalizerwin_on, cfg.equalizer_active); + equalizerwin_auto = + create_tbutton(&equalizerwin_wlist, equalizerwin_bg, + equalizerwin_gc, 39, 18, 33, 12, 35, 119, 153, 119, + 94, 119, 212, 119, equalizerwin_auto_pushed, + SKIN_EQMAIN); + tbutton_set_toggled(equalizerwin_auto, cfg.equalizer_autoload); + equalizerwin_presets = + create_pbutton(&equalizerwin_wlist, equalizerwin_bg, + equalizerwin_gc, 217, 18, 44, 12, 224, 164, 224, + 176, equalizerwin_presets_pushed, SKIN_EQMAIN); + equalizerwin_close = + create_pbutton(&equalizerwin_wlist, equalizerwin_bg, + equalizerwin_gc, 264, 3, 9, 9, 0, 116, 0, 125, + equalizerwin_close_cb, SKIN_EQMAIN); + equalizerwin_close->pb_allow_draw = FALSE; + + equalizerwin_shade = + create_pbutton_ex(&equalizerwin_wlist, equalizerwin_bg, + equalizerwin_gc, 254, 3, 9, 9, 254, 137, 1, 38, + equalizerwin_shade_toggle, NULL, SKIN_EQMAIN, SKIN_EQ_EX); + equalizerwin_shade->pb_allow_draw = FALSE; + + equalizerwin_graph = + create_eqgraph(&equalizerwin_wlist, equalizerwin_bg, + equalizerwin_gc, 86, 17); + equalizerwin_preamp = + create_eqslider(&equalizerwin_wlist, equalizerwin_bg, + equalizerwin_gc, 21, 38); + eqslider_set_position(equalizerwin_preamp, cfg.equalizer_preamp); + for (i = 0; i < 10; i++) { + equalizerwin_bands[i] = + create_eqslider(&equalizerwin_wlist, equalizerwin_bg, + equalizerwin_gc, 78 + (i * 18), 38); + eqslider_set_position(equalizerwin_bands[i], cfg.equalizer_bands[i]); + } + + equalizerwin_volume = + create_hslider(&equalizerwin_wlist, equalizerwin_bg, + equalizerwin_gc, 61, 4, 97, 8, 1, 30, 1, 30, 3, 7, + 4, 61, 0, 94, equalizerwin_volume_frame_cb, + equalizerwin_volume_motion_cb, + equalizerwin_volume_release_cb, SKIN_EQ_EX); + equalizerwin_balance = + create_hslider(&equalizerwin_wlist, equalizerwin_bg, + equalizerwin_gc, 164, 4, 42, 8, 11, 30, 11, 30, 3, + 7, 4, 164, 0, 39, equalizerwin_balance_frame_cb, + equalizerwin_balance_motion_cb, + equalizerwin_balance_release_cb, SKIN_EQ_EX); + + if (!cfg.equalizer_shaded) { + widget_hide(WIDGET(equalizerwin_volume)); + widget_hide(WIDGET(equalizerwin_balance)); + } + else { + pbutton_set_button_data(equalizerwin_shade, -1, 3, -1, 47); + pbutton_set_skin_index1(equalizerwin_shade, SKIN_EQ_EX); + pbutton_set_button_data(equalizerwin_close, 11, 38, 11, 47); + pbutton_set_skin_index(equalizerwin_close, SKIN_EQ_EX); + } +} + + +static void +equalizerwin_create_window(void) +{ + GdkPixbuf *icon; + gint width, height; + + equalizerwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(equalizerwin), _("Audacious Equalizer")); + gtk_window_set_wmclass(GTK_WINDOW(equalizerwin), "equalizer", "Audacious"); + gtk_window_set_role(GTK_WINDOW(equalizerwin), "equalizer"); + + width = 275; + height = cfg.equalizer_shaded ? 14 : 116; + + gtk_window_set_default_size(GTK_WINDOW(equalizerwin), width, height); + gtk_window_set_resizable(GTK_WINDOW(equalizerwin), FALSE); + + dock_window_list = dock_window_set_decorated(dock_window_list, + GTK_WINDOW(equalizerwin), + cfg.show_wm_decorations); + + /* 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 **) bmp_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); + + gtk_widget_set_events(equalizerwin, + GDK_FOCUS_CHANGE_MASK | GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_VISIBILITY_NOTIFY_MASK); + gtk_widget_realize(equalizerwin); + + util_set_cursor(equalizerwin); + + 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, "button_release_event", + G_CALLBACK(equalizerwin_release), NULL); + g_signal_connect(equalizerwin, "motion_notify_event", + G_CALLBACK(equalizerwin_motion), NULL); + g_signal_connect_after(equalizerwin, "focus_in_event", + G_CALLBACK(equalizerwin_focus_in), NULL); + g_signal_connect_after(equalizerwin, "focus_out_event", + G_CALLBACK(equalizerwin_focus_out), NULL); + g_signal_connect(equalizerwin, "configure_event", + G_CALLBACK(equalizerwin_configure), NULL); + g_signal_connect(equalizerwin, "style_set", + G_CALLBACK(equalizerwin_set_back_pixmap), NULL); + g_signal_connect(equalizerwin, "key_press_event", + G_CALLBACK(equalizerwin_keypress), NULL); + g_signal_connect(equalizerwin, "scroll_event", + G_CALLBACK(equalizerwin_scroll), NULL); +} + +void +equalizerwin_create_popup_menus(void) +{ + equalizerwin_accel = gtk_accel_group_new(); + gtk_window_add_accel_group(GTK_WINDOW(equalizerwin), equalizerwin_accel); + + equalizerwin_presets_menu = create_menu(equalizerwin_presets_menu_entries, + equalizerwin_presets_menu_entries_num, + NULL); +} + +void +equalizerwin_create(void) +{ + equalizer_presets = equalizerwin_read_presets("eq.preset"); + equalizer_auto_presets = equalizerwin_read_presets("eq.auto_preset"); + + equalizerwin_create_window(); + equalizerwin_create_popup_menus(); + + equalizerwin_gc = gdk_gc_new(equalizerwin->window); + equalizerwin_bg = gdk_pixmap_new(equalizerwin->window, 275, 116, -1); + + equalizerwin_create_widgets(); + + equalizerwin_set_back_pixmap(); + gdk_window_set_back_pixmap(equalizerwin->window, equalizerwin_bg, 0); +} + + +void +equalizerwin_show(gboolean show) +{ + GtkWidget *item = gtk_item_factory_get_widget(mainwin_view_menu, + "/Show Equalizer"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), show); +} + +void +equalizerwin_real_show(void) +{ + /* + * This function should only be called from the + * main menu signal handler + */ + + gint x, y; + + gtk_window_get_position(GTK_WINDOW(equalizerwin), &x, &y); + gtk_window_move(GTK_WINDOW(equalizerwin), x, y); + gtk_widget_set_size_request(equalizerwin, 275, + (cfg.equalizer_shaded ? 14 : 116)); + gdk_flush(); + draw_equalizer_window(TRUE); + cfg.equalizer_visible = TRUE; + tbutton_set_toggled(mainwin_eq, TRUE); + + gtk_widget_show(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; + tbutton_set_toggled(mainwin_eq, FALSE); +} + +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 = bmp_rcfile_new(); + p = 0; + for (node = list; node; node = g_list_next(node)) { + preset = node->data; + tmp = g_strdup_printf("Preset%d", p++); + bmp_rcfile_write_string(rcfile, "Presets", tmp, preset->name); + g_free(tmp); + bmp_rcfile_write_float(rcfile, preset->name, "Preamp", + preset->preamp); + for (i = 0; i < 10; i++) { + tmp = g_strdup_printf("Band%d\n", i); + bmp_rcfile_write_float(rcfile, preset->name, tmp, + preset->bands[i]); + g_free(tmp); + } + } + + filename = g_build_filename(bmp_paths[BMP_PATH_USER_DIR], basename, NULL); + bmp_rcfile_write(rcfile, filename); + bmp_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) { + eqslider_set_position(equalizerwin_preamp, preset->preamp); + for (i = 0; i < 10; i++) + eqslider_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 = eqslider_get_position(equalizerwin_preamp); + for (i = 0; i < 10; i++) + preset->bands[i] = eqslider_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 GList * +import_winamp_eqf(VFSFile * file) +{ + gchar header[31]; + gchar name[257]; + gchar bands[11]; + gint i = 0; + GList *list = NULL; + EqualizerPreset *preset; + + vfs_fread(header, 1, 31, file); + if (!strncmp(header, "Winamp EQ library file v1.1", 27)) { + while (vfs_fread(name, 1, 257, file)) { + preset = equalizer_preset_new(name); + preset->preamp = 20.0 - ((bands[10] * 40.0) / 64); + + vfs_fread(bands, 1, 11, file); + + for (i = 0; i < 10; i++) + preset->bands[i] = 20.0 - ((bands[i] * 40.0) / 64); + + list = g_list_prepend(list, preset); + } + } + + list = g_list_reverse(list); + return list; +} + +static void +equalizerwin_read_winamp_eqf(VFSFile * file) +{ + gchar header[31]; + guchar bands[11]; + gint i; + + vfs_fread(header, 1, 31, file); + + if (!strncmp(header, "Winamp EQ library file v1.1", 27)) { + /* Skip name */ + if (vfs_fseek(file, 257, SEEK_CUR) == -1) + return; + + if (vfs_fread(bands, 1, 11, file) != 11) + return; + + eqslider_set_position(equalizerwin_preamp, + 20.0 - ((bands[10] * 40.0) / 63.0)); + + for (i = 0; i < 10; i++) + eqslider_set_position(equalizerwin_bands[i], + 20.0 - ((bands[i] * 40.0) / 64.0)); + } + + equalizerwin_eq_changed(); +} + +static void +equalizerwin_read_bmp_preset(RcFile * rcfile) +{ + gfloat val; + gint i; + + if (bmp_rcfile_read_float(rcfile, "Equalizer preset", "Preamp", &val)) + eqslider_set_position(equalizerwin_preamp, val); + for (i = 0; i < 10; i++) { + gchar tmp[7]; + g_snprintf(tmp, sizeof(tmp), "Band%d", i); + if (bmp_rcfile_read_float(rcfile, "Equalizer preset", tmp, &val)) + eqslider_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(GtkCList * clist, gint row, + gint column, GdkEventButton * event, gpointer data) +{ + gchar *text; + + gtk_clist_get_text(clist, row, 0, &text); + + gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_entry), text); + if (event->type == GDK_2BUTTON_PRESS) + equalizerwin_save_ok(NULL, NULL); + +} + +static void +equalizerwin_load_ok(GtkWidget * widget, gpointer data) +{ + gchar *text; + GtkCList *clist = GTK_CLIST(data); + + if (clist && clist->selection) { + gtk_clist_get_text(clist, GPOINTER_TO_INT(clist->selection->data), + 0, &text); + equalizerwin_load_preset(equalizer_presets, text); + } + gtk_widget_destroy(equalizerwin_load_window); +} + +static void +equalizerwin_load_apply(GtkWidget * widget, gpointer data) +{ + gchar *text; + GtkCList *clist = GTK_CLIST(data); + + if (clist && clist->selection) { + gtk_clist_get_text(clist, GPOINTER_TO_INT(clist->selection->data), + 0, &text); + equalizerwin_load_preset(equalizer_presets, text); + } +} + + +static void +equalizerwin_load_select(GtkCList * widget, gint row, + gint column, GdkEventButton * event, gpointer data) +{ + if (event->type == GDK_2BUTTON_PRESS) + equalizerwin_load_ok(NULL, widget); +} + +static void +equalizerwin_delete_delete(GtkWidget * widget, gpointer data) +{ + gchar *text; + GList *list, *next; + GtkCList *clist = GTK_CLIST(data); + + g_return_if_fail(clist != NULL); + + list = clist->selection; + gtk_clist_freeze(clist); + while (list) { + next = g_list_next(list); + gtk_clist_get_text(clist, GPOINTER_TO_INT(list->data), 0, &text); + equalizer_auto_presets = + equalizerwin_delete_preset(equalizer_presets, text, "eq.preset"); + gtk_clist_remove(clist, GPOINTER_TO_INT(list->data)); + list = next; + } + gtk_clist_thaw(clist); +} + +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(GtkCList * clist, gint row, + gint column, + GdkEventButton * event, gpointer data) +{ + gchar *text; + + gtk_clist_get_text(clist, row, 0, &text); + + gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_auto_entry), text); + if (event->type == GDK_2BUTTON_PRESS) + equalizerwin_save_auto_ok(NULL, NULL); + +} + +static void +equalizerwin_load_auto_ok(GtkWidget * widget, gpointer data) +{ + gchar *text; + GtkCList *clist = GTK_CLIST(data); + + if (clist && clist->selection) { + gtk_clist_get_text(clist, GPOINTER_TO_INT(clist->selection->data), + 0, &text); + equalizerwin_load_preset(equalizer_auto_presets, text); + } + gtk_widget_destroy(equalizerwin_load_auto_window); +} + +static void +equalizerwin_load_auto_select(GtkWidget * widget, gint row, + gint column, + GdkEventButton * event, gpointer data) +{ + if (event->type == GDK_2BUTTON_PRESS) + equalizerwin_load_auto_ok(NULL, widget); +} + +static void +equalizerwin_delete_auto_delete(GtkWidget * widget, gpointer data) +{ + gchar *text; + GList *list, *next; + GtkCList *clist = GTK_CLIST(data); + + g_return_if_fail(clist != NULL); + + list = clist->selection; + gtk_clist_freeze(clist); + while (list) { + next = g_list_next(list); + gtk_clist_get_text(clist, GPOINTER_TO_INT(list->data), 0, &text); + equalizer_auto_presets = + equalizerwin_delete_preset(equalizer_auto_presets, text, + "eq.auto_preset"); + gtk_clist_remove(clist, GPOINTER_TO_INT(list->data)); + list = next; + } + gtk_clist_thaw(clist); +} + + +typedef void (*ResponseHandler)(const gchar *filename); + +static void +equalizerwin_file_chooser_on_response(GtkWidget * dialog, + gint response, + gpointer data) +{ + GtkFileChooser *file_chooser = GTK_FILE_CHOOSER(dialog); + ResponseHandler handler = (ResponseHandler) data; + gchar *filename; + + gtk_widget_hide(dialog); + + switch (response) + { + case GTK_RESPONSE_ACCEPT: + filename = gtk_file_chooser_get_filename(file_chooser); + handler(filename); + g_free(filename); + break; + + case GTK_RESPONSE_REJECT: + break; + } + + gtk_widget_destroy(dialog); +} + + + +static void +load_preset_file(const gchar *filename) +{ + RcFile *rcfile; + + if ((rcfile = bmp_rcfile_open(filename)) != NULL) { + equalizerwin_read_bmp_preset(rcfile); + bmp_rcfile_free(rcfile); + } +} + +static void +load_winamp_file(const gchar * filename) +{ + VFSFile *file; + gchar *tmp; + + if (!(file = vfs_fopen(filename, "rb"))) { + tmp = g_strconcat("Failed to load WinAmp file: ",filename,"\n",NULL); + report_error(tmp); + g_free(tmp); + return; + } + + equalizerwin_read_winamp_eqf(file); + vfs_fclose(file); +} + +static void +import_winamp_file(const gchar * filename) +{ + VFSFile *file; + gchar *tmp; + + if (!(file = vfs_fopen(filename, "rb"))) { + tmp = g_strconcat("Failed to import WinAmp file: ",filename,"\n",NULL); + report_error(tmp); + g_free(tmp); + return; + } + + equalizer_presets = g_list_concat(equalizer_presets, + import_winamp_eqf(file)); + equalizerwin_write_preset_file(equalizer_presets, "eq.preset"); + + vfs_fclose(file); +} + +static void +save_preset_file(const gchar * filename) +{ + RcFile *rcfile; + gint i; + + rcfile = bmp_rcfile_new(); + bmp_rcfile_write_float(rcfile, "Equalizer preset", "Preamp", + eqslider_get_position(equalizerwin_preamp)); + + for (i = 0; i < 10; i++) { + gchar tmp[7]; + g_snprintf(tmp, sizeof(tmp), "Band%d", i); + bmp_rcfile_write_float(rcfile, "Equalizer preset", tmp, + eqslider_get_position(equalizerwin_bands[i])); + } + + bmp_rcfile_write(rcfile, filename); + bmp_rcfile_free(rcfile); +} + +static void +save_winamp_file(const gchar * filename) +{ + VFSFile *file; + + gchar name[257]; + gint i; + guchar bands[11]; + gchar *tmp; + + if (!(file = vfs_fopen(filename, "wb"))) { + tmp = g_strconcat("Failed to save WinAmp file: ",filename,"\n",NULL); + report_error(tmp); + g_free(tmp); + return; + } + + vfs_fwrite("Winamp EQ library file v1.1\x1a!--", 1, 31, file); + + memset(name, 0, 257); + strcpy(name, "Entry1"); + vfs_fwrite(name, 1, 257, file); + + for (i = 0; i < 10; i++) + bands[i] = 63 - (((eqslider_get_position(equalizerwin_bands[i]) + 20) * 63) / 40); + bands[10] = 63 - (((eqslider_get_position(equalizerwin_preamp) + 20) * 63) / 40); + vfs_fwrite(bands, 1, 11, file); + + vfs_fclose(file); +} + +static gint +equalizerwin_list_sort_func(GtkCList * clist, + gconstpointer ptr1, gconstpointer ptr2) +{ + GtkCListRow *row1 = (GtkCListRow *) ptr1; + GtkCListRow *row2 = (GtkCListRow *) ptr2; + + return strcasecmp(GTK_CELL_TEXT(row1->cell[clist->sort_column])->text, + GTK_CELL_TEXT(row2->cell[clist->sort_column])->text); +} + + +static GtkListStore * +preset_list_store_new(GList * preset) +{ + GtkListStore *store; + GtkTreeIter iter; + GList *node; + + store = gtk_list_store_new(PRESET_VIEW_N_COLS, G_TYPE_STRING); + + for (node = preset; node; node = g_list_next(node)) { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + PRESET_VIEW_COL_NAME, + &((EqualizerPreset *) node->data)->name, -1); + } + + return store; +} + + +GtkWidget * +preset_view_new(GList * preset) +{ + GtkWidget *treeview; + GtkTreeModel *model; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkListStore *store; + + store = preset_list_store_new(preset); + + model = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), + PRESET_VIEW_COL_NAME, + GTK_SORT_ASCENDING); + + treeview = gtk_tree_view_new_with_model(model); + gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview), TRUE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE); + + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Preset"), renderer, + "text", + PRESET_VIEW_COL_NAME, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); + + return treeview; +} + + +static GtkWidget * +equalizerwin_create_list_window(GList * preset_list, + const gchar * title, + GtkWidget ** window, + GtkSelectionMode sel_mode, + GtkWidget ** entry, + const gchar * btn2_stock_name, + const gchar * btn3_stock_name, + const gchar * btn1_stock_name, + GCallback btn2_func, + GCallback btn3_func, + GCallback select_row_func) +{ + GtkWidget *vbox, *scrolled_window, *bbox, *btn1, *btn2, *btn3, *clist; + gchar *preset_text[1]; + GList *node; + + *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); + + preset_text[0] = _("Presets"); + clist = gtk_clist_new_with_titles(1, preset_text); + if (select_row_func) + g_signal_connect(clist, "select_row", + G_CALLBACK(select_row_func), NULL); + gtk_clist_column_titles_passive(GTK_CLIST(clist)); + gtk_clist_set_selection_mode(GTK_CLIST(clist), sel_mode); + + for (node = preset_list; node; node = g_list_next(node)) { + gtk_clist_append(GTK_CLIST(clist), + &((EqualizerPreset *) node->data)->name); + } + gtk_clist_set_compare_func(GTK_CLIST(clist), equalizerwin_list_sort_func); + gtk_clist_sort(GTK_CLIST(clist)); + + gtk_container_add(GTK_CONTAINER(scrolled_window), clist); + gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0); + + if (entry) { + *entry = gtk_entry_new(); + g_signal_connect(*entry, "activate", btn2_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); + + btn1 = gtk_button_new_from_stock(btn1_stock_name); + g_signal_connect_swapped(btn1, "clicked", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(*window)); + gtk_box_pack_start(GTK_BOX(bbox), btn1, TRUE, TRUE, 0); + + if (btn3_stock_name) { + btn3 = gtk_button_new_from_stock(btn3_stock_name); + g_signal_connect(btn3, "clicked", G_CALLBACK(btn3_func), clist); + gtk_box_pack_start(GTK_BOX(bbox), btn3, TRUE, TRUE, 0); + } + + btn2 = gtk_button_new_from_stock(btn2_stock_name); + g_signal_connect(btn2, "clicked", G_CALLBACK(btn2_func), clist); + GTK_WIDGET_SET_FLAGS(btn2, GTK_CAN_DEFAULT); + + gtk_box_pack_start(GTK_BOX(bbox), btn2, TRUE, TRUE, 0); + + gtk_widget_grab_default(btn2); + + + gtk_widget_show_all(*window); + + return *window; +} + +void +equalizerwin_presets_menu_cb(gpointer cb_data, guint action, GtkWidget * w) +{ + GtkWidget *dialog; + + switch (action) { + case EQUALIZER_PRESETS_LOAD_PRESET: + if (!equalizerwin_load_window) + equalizerwin_create_list_window(equalizer_presets, + _("Load preset"), + &equalizerwin_load_window, + GTK_SELECTION_SINGLE, NULL, + GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CANCEL, + G_CALLBACK + (equalizerwin_load_ok), + G_CALLBACK + (equalizerwin_load_apply), + G_CALLBACK + (equalizerwin_load_select)); + else + gtk_window_present(GTK_WINDOW(equalizerwin_load_window)); + break; + case EQUALIZER_PRESETS_LOAD_AUTOPRESET: + if (!equalizerwin_load_auto_window) + equalizerwin_create_list_window(equalizer_auto_presets, + _("Load auto-preset"), + &equalizerwin_load_auto_window, + GTK_SELECTION_SINGLE, NULL, + GTK_STOCK_OK, NULL, GTK_STOCK_CANCEL, + G_CALLBACK + (equalizerwin_load_auto_ok), + NULL, + G_CALLBACK + (equalizerwin_load_auto_select)); + else + gtk_window_present(GTK_WINDOW(equalizerwin_load_auto_window)); + break; + case EQUALIZER_PRESETS_LOAD_DEFAULT: + equalizerwin_load_preset(equalizer_presets, "Default"); + break; + case EQUALIZER_PRESETS_LOAD_ZERO: + { + gint i; + + eqslider_set_position(equalizerwin_preamp, 0); + for (i = 0; i < 10; i++) + eqslider_set_position(equalizerwin_bands[i], 0); + equalizerwin_eq_changed(); + break; + } + case EQUALIZER_PRESETS_LOAD_FROM_FILE: + dialog = make_filebrowser(_("Load equalizer preset"), FALSE); + g_signal_connect(dialog , "response", + G_CALLBACK(equalizerwin_file_chooser_on_response), + load_preset_file); + break; + case EQUALIZER_PRESETS_LOAD_FROM_WINAMPFILE: + dialog = make_filebrowser(_("Load equalizer preset"), FALSE); + g_signal_connect(dialog, "response", + G_CALLBACK(equalizerwin_file_chooser_on_response), + load_winamp_file); + break; + + case EQUALIZER_PRESETS_IMPORT_WINAMPFILE: + dialog = make_filebrowser(_("Load equalizer preset"), FALSE); + g_signal_connect(dialog, "response", + G_CALLBACK(equalizerwin_file_chooser_on_response), + import_winamp_file); + break; + + case EQUALIZER_PRESETS_SAVE_PRESET: + if (!equalizerwin_save_window) + equalizerwin_create_list_window(equalizer_presets, + _("Save preset"), + &equalizerwin_save_window, + GTK_SELECTION_SINGLE, + &equalizerwin_save_entry, + GTK_STOCK_OK, NULL, GTK_STOCK_CANCEL, + G_CALLBACK + (equalizerwin_save_ok), + NULL, + G_CALLBACK + (equalizerwin_save_select)); + else + gtk_window_present(GTK_WINDOW(equalizerwin_save_window)); + break; + + case EQUALIZER_PRESETS_SAVE_AUTOPRESET: + { + gchar *name; + + if (!equalizerwin_save_auto_window) + equalizerwin_create_list_window(equalizer_auto_presets, + _("Save auto-preset"), + &equalizerwin_save_auto_window, + GTK_SELECTION_SINGLE, + &equalizerwin_save_auto_entry, + GTK_STOCK_OK, + NULL, + GTK_STOCK_CANCEL, + G_CALLBACK + (equalizerwin_save_auto_ok), + NULL, + G_CALLBACK + (equalizerwin_save_auto_select)); + else + gtk_window_present(GTK_WINDOW(equalizerwin_save_auto_window)); + + name = playlist_get_filename(playlist_get_position()); + + if (name) { + gtk_entry_set_text(GTK_ENTRY(equalizerwin_save_auto_entry), + g_basename(name)); + g_free(name); + } + break; + } + + case EQUALIZER_PRESETS_SAVE_DEFAULT: + equalizer_presets = + equalizerwin_save_preset(equalizer_presets, "Default", + "eq.preset"); + break; + + case EQUALIZER_PRESETS_SAVE_TO_FILE: + { + gchar *songname; + + dialog = make_filebrowser(_("Save equalizer preset"), TRUE); + g_signal_connect(dialog, "response", + G_CALLBACK(equalizerwin_file_chooser_on_response), + save_preset_file); + + songname = playlist_get_filename(playlist_get_position()); + 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); + } + + break; + } + + case EQUALIZER_PRESETS_SAVE_TO_WINAMPFILE: + dialog = make_filebrowser(_("Save equalizer preset"), TRUE); + g_signal_connect(dialog, "response", + G_CALLBACK(equalizerwin_file_chooser_on_response), + save_winamp_file); + break; + + case EQUALIZER_PRESETS_DELETE_PRESET: + if (!equalizerwin_delete_window) + equalizerwin_create_list_window(equalizer_presets, + _("Delete preset"), + &equalizerwin_delete_window, + GTK_SELECTION_EXTENDED, NULL, + GTK_STOCK_DELETE, + NULL, + GTK_STOCK_CLOSE, + G_CALLBACK + (equalizerwin_delete_delete), + NULL, + NULL); + else + gtk_window_present(GTK_WINDOW(equalizerwin_delete_window)); + + break; + + case EQUALIZER_PRESETS_DELETE_AUTOPRESET: + if (!equalizerwin_delete_auto_window) + equalizerwin_create_list_window(equalizer_auto_presets, + _("Delete auto-preset"), + &equalizerwin_delete_auto_window, + GTK_SELECTION_EXTENDED, NULL, + GTK_STOCK_DELETE, + NULL, + GTK_STOCK_CLOSE, + G_CALLBACK + (equalizerwin_delete_auto_delete), + NULL, + NULL); + else + gtk_window_present(GTK_WINDOW(equalizerwin_delete_auto_window)); + + break; + } +} + +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 = bmp_rcfile_open(presetfilename)) != NULL) { + g_free(presetfilename); + equalizerwin_read_bmp_preset(rcfile); + bmp_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 = bmp_rcfile_open(presetfilename)) != NULL) { + equalizerwin_read_bmp_preset(rcfile); + bmp_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) +{ + eqslider_set_position(equalizerwin_preamp, preamp); + equalizerwin_eq_changed(); +} + +void +equalizerwin_set_band(gint band, gfloat value) +{ + g_return_if_fail(band >= 0 && band < 10); + eqslider_set_position(equalizerwin_bands[band], value); +} + +gfloat +equalizerwin_get_preamp(void) +{ + return eqslider_get_position(equalizerwin_preamp); +} + +gfloat +equalizerwin_get_band(gint band) +{ + g_return_val_if_fail(band >= 0 && band < 10, 0); + return eqslider_get_position(equalizerwin_bands[band]); +} diff -r 3d3b60e66491 -r 1a525bd78cf0 Plugins/UserInterface/wa2gui/equalizer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/UserInterface/wa2gui/equalizer.h Thu Sep 07 19:57:27 2006 -0700 @@ -0,0 +1,60 @@ +/* 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef EQUALIZER_H +#define EQUALIZER_H + +#include +#include + +#include "widgets/widgetcore.h" + +#define EQUALIZER_HEIGHT (gint)(cfg.equalizer_shaded ? 14 : 116) +#define EQUALIZER_WIDTH (gint)275 + +#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_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 PButton *equalizerwin_close; +extern gboolean equalizerwin_focus; + +#endif diff -r 3d3b60e66491 -r 1a525bd78cf0 Plugins/UserInterface/wa2gui/filepopup.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/UserInterface/wa2gui/filepopup.c Thu Sep 07 19:57:27 2006 -0700 @@ -0,0 +1,512 @@ +/* + * 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 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "glade.h" + +#include "plugin.h" +#include "pluginenum.h" +#include "input.h" +#include "effect.h" +#include "general.h" +#include "output.h" +#include "visualization.h" + +#include "main.h" +#include "urldecode.h" +#include "util.h" +#include "dnd.h" +#include "libaudacious/configdb.h" +#include "libaudacious/titlestring.h" + +#include "playlist.h" + +#include "mainwin.h" +#include "ui_playlist.h" +#include "skinwin.h" +#include "build_stamp.h" +#include "ui_fileinfo.h" +#include "ui_playlist.h" + +GtkWidget *fileinfo_win; +GtkWidget *filepopup_win; +GdkPixbuf *filepopup_pixbuf; + +static void +fileinfo_entry_set_text(const char *entry, const char *text) +{ + GladeXML *xml = g_object_get_data(G_OBJECT(fileinfo_win), "glade-xml"); + GtkWidget *widget = glade_xml_get_widget(xml, entry); + + if (xml == NULL || widget == NULL) + return; + + gtk_entry_set_text(GTK_ENTRY(widget), text); +} + +static void +fileinfo_entry_set_text_free(const char *entry, char *text) +{ + GladeXML *xml = g_object_get_data(G_OBJECT(fileinfo_win), "glade-xml"); + GtkWidget *widget = glade_xml_get_widget(xml, entry); + + if (xml == NULL || widget == NULL) + return; + + gtk_entry_set_text(GTK_ENTRY(widget), text); + + g_free(text); +} + +static void +fileinfo_entry_set_image(const char *entry, const char *text) +{ + GladeXML *xml = g_object_get_data(G_OBJECT(fileinfo_win), "glade-xml"); + GtkWidget *widget = glade_xml_get_widget(xml, entry); + GdkPixbuf *pixbuf; + + if (xml == NULL || widget == NULL) + return; + + pixbuf = gdk_pixbuf_new_from_file(text, NULL); + + if (pixbuf == NULL) + return; + + if (gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf)) > 150) + { + GdkPixbuf *pixbuf2 = gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), 150, 150, 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 +filepopup_entry_set_text(const char *entry, const char *text) +{ + GladeXML *xml = g_object_get_data(G_OBJECT(filepopup_win), "glade-xml"); + GtkWidget *widget = glade_xml_get_widget(xml, entry); + + if (xml == NULL || widget == NULL) + return; + + gtk_label_set_text(GTK_LABEL(widget), text); +} + +static void +filepopup_entry_set_image(const char *entry, const char *text) +{ + GladeXML *xml = g_object_get_data(G_OBJECT(filepopup_win), "glade-xml"); + GtkWidget *widget = glade_xml_get_widget(xml, entry); + GdkPixbuf *pixbuf; + + if (xml == NULL || widget == NULL) + return; + + pixbuf = gdk_pixbuf_new_from_file(text, NULL); + + if (pixbuf == NULL) + return; + + if (gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf)) > 150) + { + GdkPixbuf *pixbuf2 = gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), 150, 150, 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 +filepopup_entry_set_text_free(const char *entry, char *text) +{ + GladeXML *xml = g_object_get_data(G_OBJECT(filepopup_win), "glade-xml"); + GtkWidget *widget = glade_xml_get_widget(xml, entry); + + if (xml == NULL || widget == NULL) + return; + + gtk_label_set_text(GTK_LABEL(widget), text); + + g_free(text); +} + +static gboolean +filepopup_pointer_check_iter(gpointer unused) +{ + gint x, y, pos; + TitleInput *tuple; + static gint prev_x = 0, prev_y = 0, ctr = 0, prev_pos = -1; + gboolean skip = FALSE; + GdkWindow *win; + + win = gdk_window_at_pointer(NULL, NULL); + gdk_window_get_pointer(GDK_WINDOW(playlistwin->window), &x, &y, NULL); + pos = playlist_list_get_playlist_position(playlistwin_list, x, y); + + if (win == NULL + || cfg.show_filepopup_for_tuple == FALSE + || playlistwin_list->pl_tooltips == FALSE + || pos != prev_pos + || win != GDK_WINDOW(playlistwin->window) + || playlistwin_is_shaded()) + { + prev_pos = pos; + ctr = 0; + if ( filepopup_win->window != NULL && + gdk_window_is_viewable(GDK_WINDOW(filepopup_win->window)) ) + filepopup_hide(NULL); + return TRUE; + } + + if (prev_x == x && prev_y == y) + ctr++; + else + { + ctr = 0; + prev_x = x; + prev_y = y; + filepopup_hide(NULL); + return TRUE; + } + + if (filepopup_win->window == NULL) + skip = TRUE; + + if (ctr >= 20 && (skip == TRUE || gdk_window_is_viewable(GDK_WINDOW(filepopup_win->window)) != TRUE)) + { + if (pos == -1) + { + filepopup_hide(NULL); + return TRUE; + } + + prev_pos = pos; + + tuple = playlist_get_tuple(pos); + filepopup_show_for_tuple(tuple); + } + + return TRUE; +} + +void fileinfo_hide(gpointer unused) +{ + 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("entry_genre", ""); + fileinfo_entry_set_text("entry_year", ""); + fileinfo_entry_set_text("entry_track", ""); + fileinfo_entry_set_text("entry_location", ""); + + fileinfo_entry_set_image("image_artwork", DATA_DIR "/images/audio.png"); +} + +void filepopup_hide(gpointer unused) +{ + gtk_widget_hide(filepopup_win); + + filepopup_entry_set_text("label_title", ""); + filepopup_entry_set_text("label_artist", ""); + filepopup_entry_set_text("label_album", ""); + filepopup_entry_set_text("label_genre", ""); + filepopup_entry_set_text("label_track", ""); + filepopup_entry_set_text("label_year", ""); + filepopup_entry_set_text("label_length", ""); + + filepopup_entry_set_image("image_artwork", DATA_DIR "/images/audio.png"); + + gtk_window_resize(GTK_WINDOW(filepopup_win), 1, 1); +} + +void +create_fileinfo_window(void) +{ + const gchar *glade_file = DATA_DIR "/glade/fileinfo.glade"; + GladeXML *xml; + GtkWidget *widget; + + xml = glade_xml_new_or_die(_("Track Information Window"), glade_file, NULL, NULL); + + glade_xml_signal_autoconnect(xml); + + fileinfo_win = glade_xml_get_widget(xml, "fileinfo_win"); + g_object_set_data(G_OBJECT(fileinfo_win), "glade-xml", xml); + gtk_window_set_transient_for(GTK_WINDOW(fileinfo_win), GTK_WINDOW(mainwin)); + + widget = glade_xml_get_widget(xml, "image_artwork"); + gtk_image_set_from_file(GTK_IMAGE(widget), DATA_DIR "/images/audio.png"); + + widget = glade_xml_get_widget(xml, "btn_close"); + g_signal_connect(G_OBJECT(widget), "clicked", (GCallback) fileinfo_hide, NULL); +} + +void +create_filepopup_window(void) +{ + const gchar *glade_file = DATA_DIR "/glade/fileinfo_popup.glade"; + GladeXML *xml; + GtkWidget *widget; + + xml = glade_xml_new_or_die(_("Track Information Popup"), glade_file, NULL, NULL); + + glade_xml_signal_autoconnect(xml); + + filepopup_win = glade_xml_get_widget(xml, "win_pl_popup"); + g_object_set_data(G_OBJECT(filepopup_win), "glade-xml", xml); + gtk_window_set_transient_for(GTK_WINDOW(filepopup_win), GTK_WINDOW(mainwin)); + + widget = glade_xml_get_widget(xml, "image_artwork"); + gtk_image_set_from_file(GTK_IMAGE(widget), DATA_DIR "/images/audio.png"); + + g_timeout_add(50, filepopup_pointer_check_iter, NULL); +} + +void +fileinfo_show_for_tuple(TitleInput *tuple) +{ + gchar *tmp = NULL; + + if (tuple == NULL) + return; + + gtk_widget_realize(fileinfo_win); + + fileinfo_entry_set_text("entry_title", tuple->track_name); + fileinfo_entry_set_text("entry_artist", tuple->performer); + fileinfo_entry_set_text("entry_album", tuple->album_name); + fileinfo_entry_set_text("entry_comment", tuple->comment); + fileinfo_entry_set_text("entry_genre", tuple->genre); + + tmp = g_strdup_printf("%s/%s", tuple->file_path, tuple->file_name); + if(tmp){ + fileinfo_entry_set_text_free("entry_location", str_to_utf8(tmp)); + g_free(tmp); + tmp = NULL; + } + + if (tuple->year != 0) + fileinfo_entry_set_text_free("entry_year", g_strdup_printf("%d", tuple->year)); + + if (tuple->track_number != 0) + fileinfo_entry_set_text_free("entry_track", g_strdup_printf("%d", tuple->track_number)); + + tmp = fileinfo_recursive_get_image(tuple->file_path, 0); + + if(tmp) + { + fileinfo_entry_set_image("image_artwork", tmp); + g_free(tmp); + } + + gtk_widget_show(fileinfo_win); +} + +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 *name) +{ + char *ext; + + ext = strrchr(name, '.'); + if (!ext) { + /* No file extension */ + return FALSE; + } + + if (g_strcasecmp(ext, ".jpg") != 0 && + g_strcasecmp(ext, ".jpeg") != 0 && + g_strcasecmp(ext, ".png") != 0) { + /* No recognized file extension */ + return FALSE; + } + + return cover_name_filter(name, cfg.cover_name_include, TRUE) && + !cover_name_filter(name, cfg.cover_name_exclude, FALSE); +} + +gchar* +fileinfo_recursive_get_image(const gchar* path, 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 = g_dir_read_name(d); + + while (f) + { + gchar *newpath = g_strdup_printf("%s/%s", path, f); + + if (is_front_cover_image(f)) + { + /* We found a suitable file in the current + * directory, use that. The string will be + * freed by the caller */ + g_dir_close(d); + return newpath; + } + else + { + f = g_dir_read_name(d); + if (cfg.recurse_for_cover) + { + /* File/directory wasn't suitable, try and recurse into it. + * This should either return a filename for a image file, + * or NULL if there was no suitable file, or 'f' wasn't a dir. + */ + gchar *tmp = fileinfo_recursive_get_image(newpath, depth+1); + + if(tmp) + { + g_free(newpath); + g_dir_close(d); + return tmp; + } + } + } + } + + g_dir_close(d); + } + + return NULL; +} + +void +filepopup_show_for_tuple(TitleInput *tuple) +{ + gchar *tmp; + gint x, y, x_off = 3, y_off = 3, h, w; + + if (tuple == NULL) + return; + + gtk_widget_realize(filepopup_win); + + filepopup_entry_set_text("label_title", tuple->track_name); + filepopup_entry_set_text("label_artist", tuple->performer); + filepopup_entry_set_text("label_album", tuple->album_name); + filepopup_entry_set_text("label_genre", tuple->genre); + + if (tuple->length != -1) + filepopup_entry_set_text_free("label_length", g_strdup_printf("%d:%02d", tuple->length / 60000, (tuple->length / 1000) % 60)); + + if (tuple->year != 0) + filepopup_entry_set_text_free("label_year", g_strdup_printf("%d", tuple->year)); + + if (tuple->track_number != 0) + filepopup_entry_set_text_free("label_track", g_strdup_printf("%d", tuple->track_number)); + + tmp = fileinfo_recursive_get_image(tuple->file_path, 0); + + if(tmp) + { + filepopup_entry_set_image("image_artwork", tmp); + g_free(tmp); + } + + gdk_window_get_pointer(NULL, &x, &y, NULL); + gtk_window_get_size(GTK_WINDOW(filepopup_win), &w, &h); + if (gdk_screen_width()-(w+3) < x) x_off = (w*-1)-3; + if (gdk_screen_height()-(h+3) < y) y_off = (h*-1)-3; + gtk_window_move(GTK_WINDOW(filepopup_win), x + x_off, y + y_off); + + gtk_widget_show(filepopup_win); +} + +void +fileinfo_show_for_path(gchar *path) +{ + TitleInput *tuple = input_get_song_tuple(path); + + if (tuple == NULL) + return input_file_info_box(path); + + fileinfo_show_for_tuple(tuple); + + bmp_title_input_free(tuple); + tuple = NULL; +} diff -r 3d3b60e66491 -r 1a525bd78cf0 Plugins/UserInterface/wa2gui/filepopup.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/UserInterface/wa2gui/filepopup.h Thu Sep 07 19:57:27 2006 -0700 @@ -0,0 +1,33 @@ +/* + * 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 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _UI_FILEINFO_H_ +#define _UI_FILEINFO_H_ + +void create_fileinfo_window(void); +void create_filepopup_window(void); +void fileinfo_show_for_tuple(TitleInput *tuple); +void filepopup_show_for_tuple(TitleInput *tuple); +gchar* fileinfo_recursive_get_image(const gchar* path, gint depth); +void fileinfo_show_for_path(gchar *path); + +void filepopup_hide(gpointer unused); + +#endif diff -r 3d3b60e66491 -r 1a525bd78cf0 Plugins/UserInterface/wa2gui/mainwin.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/UserInterface/wa2gui/mainwin.c Thu Sep 07 19:57:27 2006 -0700 @@ -0,0 +1,3570 @@ +/* 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +#include +#include +#include +#include +#include + +/* GDK including */ +#include "platform/smartinclude.h" + +#include +#include +#include + +#include + +#include "widgets/widgetcore.h" +#include "mainwin.h" +#include "pixmaps.h" + +#include "main.h" + +#include "controlsocket.h" +#include "pluginenum.h" + +#include "credits.h" +#include "dnd.h" +#include "dock.h" +#include "equalizer.h" +#include "hints.h" +#include "input.h" +#include "ui_playlist.h" +#include "prefswin.h" +#include "skinwin.h" +#include "genevent.h" +#include "playback.h" +#include "playlist.h" +#include "urldecode.h" +#include "util.h" +#include "visualization.h" +#include "libaudacious/configdb.h" + +static GTimeVal cb_time; /* click delay for tristate is defined by TRISTATE_THRESHOLD */ + +#define ITEM_SEPARATOR {"/-", NULL, NULL, 0, ""} +#define TRISTATE_THRESHOLD 200 + +/* + * If you change the menu above change these defines also + */ + +#define MAINWIN_VIS_MENU_VIS_MODE 1 +#define MAINWIN_VIS_MENU_NUM_VIS_MODE 3 +#define MAINWIN_VIS_MENU_ANALYZER_MODE 5 +#define MAINWIN_VIS_MENU_NUM_ANALYZER_MODE 3 +#define MAINWIN_VIS_MENU_ANALYZER_TYPE 9 +#define MAINWIN_VIS_MENU_NUM_ANALYZER_TYPE 2 +#define MAINWIN_VIS_MENU_ANALYZER_PEAKS 12 +#define MAINWIN_VIS_MENU_SCOPE_MODE 14 +#define MAINWIN_VIS_MENU_NUM_SCOPE_MODE 3 +#define MAINWIN_VIS_MENU_WSHADEVU_MODE 18 +#define MAINWIN_VIS_MENU_NUM_WSHADEVU_MODE 2 +#define MAINWIN_VIS_MENU_REFRESH_RATE 21 +#define MAINWIN_VIS_MENU_NUM_REFRESH_RATE 4 +#define MAINWIN_VIS_MENU_AFALLOFF 26 +#define MAINWIN_VIS_MENU_NUM_AFALLOFF 5 +#define MAINWIN_VIS_MENU_PFALLOFF 32 +#define MAINWIN_VIS_MENU_NUM_PFALLOFF 5 + +#define VOLSET_DISP_TIMES 5 + +enum { + MAINWIN_SEEK_REV = -1, + MAINWIN_SEEK_NIL, + MAINWIN_SEEK_FWD +}; + +enum { + MAINWIN_SONGNAME_FILEINFO, + MAINWIN_SONGNAME_JTF, + MAINWIN_SONGNAME_JTT, + MAINWIN_SONGNAME_SCROLL, + MAINWIN_SONGNAME_STOPAFTERSONG +}; + +enum { + MAINWIN_OPT_SKIN, MAINWIN_OPT_RELOADSKIN, + MAINWIN_OPT_REPEAT, MAINWIN_OPT_SHUFFLE, MAINWIN_OPT_NPA, + MAINWIN_OPT_TELAPSED, MAINWIN_OPT_TREMAINING, + MAINWIN_OPT_ALWAYS, + MAINWIN_OPT_STICKY, + MAINWIN_OPT_WS, + MAINWIN_OPT_PWS, + MAINWIN_OPT_EQWS +}; + +enum { + MAINWIN_VIS_ANALYZER, MAINWIN_VIS_SCOPE, MAINWIN_VIS_OFF, + MAINWIN_VIS_ANALYZER_NORMAL, MAINWIN_VIS_ANALYZER_FIRE, + MAINWIN_VIS_ANALYZER_VLINES, + MAINWIN_VIS_ANALYZER_LINES, MAINWIN_VIS_ANALYZER_BARS, + MAINWIN_VIS_ANALYZER_PEAKS, + MAINWIN_VIS_SCOPE_DOT, MAINWIN_VIS_SCOPE_LINE, MAINWIN_VIS_SCOPE_SOLID, + MAINWIN_VIS_VU_NORMAL, MAINWIN_VIS_VU_SMOOTH, + MAINWIN_VIS_REFRESH_FULL, MAINWIN_VIS_REFRESH_HALF, + MAINWIN_VIS_REFRESH_QUARTER, MAINWIN_VIS_REFRESH_EIGHTH, + MAINWIN_VIS_AFALLOFF_SLOWEST, MAINWIN_VIS_AFALLOFF_SLOW, + MAINWIN_VIS_AFALLOFF_MEDIUM, MAINWIN_VIS_AFALLOFF_FAST, + MAINWIN_VIS_AFALLOFF_FASTEST, + MAINWIN_VIS_PFALLOFF_SLOWEST, MAINWIN_VIS_PFALLOFF_SLOW, + MAINWIN_VIS_PFALLOFF_MEDIUM, MAINWIN_VIS_PFALLOFF_FAST, + MAINWIN_VIS_PFALLOFF_FASTEST, + MAINWIN_VIS_PLUGINS +}; + +enum { + MAINWIN_VIS_ACTIVE_MAINWIN, MAINWIN_VIS_ACTIVE_PLAYLISTWIN +}; + + +typedef struct _PlaybackInfo PlaybackInfo; + +struct _PlaybackInfo { + gchar *title; + gint bitrate; + gint frequency; + gint n_channels; +}; + + +GtkWidget *mainwin = NULL; +GtkWidget *err = NULL; /* an error dialog for miscellaneous error messages */ + +static GdkBitmap *nullmask; +static gint balance; + +GtkWidget *mainwin_jtf = NULL; +static GtkWidget *mainwin_jtt = NULL; + +GtkItemFactory *mainwin_songname_menu, *mainwin_vis_menu; +GtkItemFactory *mainwin_general_menu, *mainwin_play_menu, *mainwin_add_menu; +GtkItemFactory *mainwin_view_menu; + +gint seek_state = MAINWIN_SEEK_NIL; +gint seek_initial_pos = 0; + +GdkGC *mainwin_gc; +static GdkPixmap *mainwin_bg = NULL; + +GtkAccelGroup *mainwin_accel = NULL; + +static PButton *mainwin_menubtn; +static PButton *mainwin_minimize, *mainwin_shade, *mainwin_close; + +static PButton *mainwin_rew, *mainwin_fwd; +static PButton *mainwin_eject; +static PButton *mainwin_play, *mainwin_pause, *mainwin_stop; + +TButton *mainwin_shuffle, *mainwin_repeat, *mainwin_eq, *mainwin_pl; +TextBox *mainwin_info; +TextBox *mainwin_stime_min, *mainwin_stime_sec; + +static TextBox *mainwin_rate_text, *mainwin_freq_text, + *mainwin_othertext; + +PlayStatus *mainwin_playstatus; + +Number *mainwin_minus_num, *mainwin_10min_num, *mainwin_min_num; +Number *mainwin_10sec_num, *mainwin_sec_num; + +static gboolean setting_volume = FALSE; + +Vis *active_vis; +Vis *mainwin_vis; +SVis *mainwin_svis; + +HSlider *mainwin_sposition = NULL; + +static MenuRow *mainwin_menurow; +static HSlider *mainwin_volume, *mainwin_balance, *mainwin_position; +static MonoStereo *mainwin_monostereo; +static SButton *mainwin_srew, *mainwin_splay, *mainwin_spause; +static SButton *mainwin_sstop, *mainwin_sfwd, *mainwin_seject, *mainwin_about; + +static GList *mainwin_wlist = NULL; + +static gint mainwin_timeout_id; + +G_LOCK_DEFINE_STATIC(mainwin_title); + +static gboolean mainwin_force_redraw = FALSE; +static gchar *mainwin_title_text = NULL; +static gboolean mainwin_info_text_locked = FALSE; + + +static void mainwin_songname_menu_callback(gpointer user_data, + guint action, + GtkWidget * widget); + +static void mainwin_vis_menu_callback(gpointer user_data, + guint action, + GtkWidget * widget); + +static void mainwin_view_menu_callback(gpointer user_data, + guint action, + GtkWidget * widget); + +static void mainwin_play_menu_callback(gpointer user_data, + guint action, + GtkWidget * widget); + +/* Song name area menu */ + +GtkItemFactoryEntry mainwin_songname_menu_entries[] = { + {N_("/View Track Details"), "i", mainwin_general_menu_callback, + MAINWIN_GENERAL_FILEINFO, "", my_pixbuf}, + {N_("/Jump to File"), "J", mainwin_songname_menu_callback, + MAINWIN_SONGNAME_JTF, "", GTK_STOCK_JUMP_TO}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/Autoscroll Songname"), NULL, mainwin_songname_menu_callback, + MAINWIN_SONGNAME_SCROLL, "", NULL}, + {N_("/Stop After Current Song"), "M", mainwin_songname_menu_callback, + MAINWIN_SONGNAME_STOPAFTERSONG, "", NULL}, +}; + +static gint mainwin_songname_menu_entries_num = + G_N_ELEMENTS(mainwin_songname_menu_entries); + +/* Mini-visualizer area menu */ + +GtkItemFactoryEntry mainwin_vis_menu_entries[] = { + {N_("/Visualization Mode"), NULL, NULL, 0, "", NULL}, + {N_("/Visualization Mode/Analyzer"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_ANALYZER, "", NULL}, + {N_("/Visualization Mode/Scope"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_SCOPE, "/Visualization Mode/Analyzer", NULL}, + {N_("/Visualization Mode/Off"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_OFF, "/Visualization Mode/Analyzer", NULL}, + {N_("/Analyzer Mode"), NULL, NULL, 0, "", NULL}, + {N_("/Analyzer Mode/Normal"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_ANALYZER_NORMAL, "", NULL}, + {N_("/Analyzer Mode/Fire"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_ANALYZER_FIRE, "/Analyzer Mode/Normal", NULL}, + {N_("/Analyzer Mode/Vertical Lines"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_ANALYZER_VLINES, "/Analyzer Mode/Normal", NULL}, + {"/Analyzer Mode/-", NULL, NULL, 0, "", NULL}, + {N_("/Analyzer Mode/Lines"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_ANALYZER_LINES, "", NULL}, + {N_("/Analyzer Mode/Bars"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_ANALYZER_BARS, "/Analyzer Mode/Lines", NULL}, + {"/Analyzer Mode/-", NULL, NULL, 0, "", NULL}, + {N_("/Analyzer Mode/Peaks"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_ANALYZER_PEAKS, "", NULL}, + {N_("/Scope Mode"), NULL, NULL, 0, "", NULL}, + {N_("/Scope Mode/Dot Scope"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_SCOPE_DOT, "", NULL}, + {N_("/Scope Mode/Line Scope"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_SCOPE_LINE, "/Scope Mode/Dot Scope", NULL}, + {N_("/Scope Mode/Solid Scope"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_SCOPE_SOLID, "/Scope Mode/Dot Scope", NULL}, + {N_("/WindowShade VU Mode"), NULL, NULL, 0, "", NULL}, + {N_("/WindowShade VU Mode/Normal"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_VU_NORMAL, "", NULL}, + {N_("/WindowShade VU Mode/Smooth"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_VU_SMOOTH, "/WindowShade VU Mode/Normal", NULL}, + {N_("/Refresh Rate"), NULL, NULL, 0, "", NULL}, + {N_("/Refresh Rate/Full (~50 fps)"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_REFRESH_FULL, "", NULL}, + {N_("/Refresh Rate/Half (~25 fps)"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_REFRESH_HALF, "/Refresh Rate/Full (~50 fps)", NULL}, + {N_("/Refresh Rate/Quarter (~13 fps)"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_REFRESH_QUARTER, "/Refresh Rate/Full (~50 fps)", NULL}, + {N_("/Refresh Rate/Eighth (~6 fps)"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_REFRESH_EIGHTH, "/Refresh Rate/Full (~50 fps)", NULL}, + {N_("/Analyzer Falloff"), NULL, NULL, 0, "", NULL}, + {N_("/Analyzer Falloff/Slowest"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_AFALLOFF_SLOWEST, "", NULL}, + {N_("/Analyzer Falloff/Slow"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_AFALLOFF_SLOW, "/Analyzer Falloff/Slowest", NULL}, + {N_("/Analyzer Falloff/Medium"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_AFALLOFF_MEDIUM, "/Analyzer Falloff/Slowest", NULL}, + {N_("/Analyzer Falloff/Fast"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_AFALLOFF_FAST, "/Analyzer Falloff/Slowest", NULL}, + {N_("/Analyzer Falloff/Fastest"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_AFALLOFF_FASTEST, "/Analyzer Falloff/Slowest", NULL}, + {N_("/Peaks Falloff"), NULL, NULL, 0, "", NULL}, + {N_("/Peaks Falloff/Slowest"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_PFALLOFF_SLOWEST, "", NULL}, + {N_("/Peaks Falloff/Slow"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_PFALLOFF_SLOW, "/Peaks Falloff/Slowest", NULL}, + {N_("/Peaks Falloff/Medium"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_PFALLOFF_MEDIUM, "/Peaks Falloff/Slowest", NULL}, + {N_("/Peaks Falloff/Fast"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_PFALLOFF_FAST, "/Peaks Falloff/Slowest", NULL}, + {N_("/Peaks Falloff/Fastest"), NULL, mainwin_vis_menu_callback, + MAINWIN_VIS_PFALLOFF_FASTEST, "/Peaks Falloff/Slowest", NULL} +}; + +static const gint mainwin_vis_menu_entries_num = + G_N_ELEMENTS(mainwin_vis_menu_entries); + +/* Playback menu (now used only for accelerators) */ + +GtkItemFactoryEntry mainwin_playback_menu_entries[] = { + {N_("/Play CD"), "C", mainwin_general_menu_callback, + MAINWIN_GENERAL_PLAYCD, "", GTK_STOCK_CDROM}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/Repeat"), "R", mainwin_play_menu_callback, + MAINWIN_OPT_REPEAT, "", NULL}, + {N_("/Shuffle"), "S", mainwin_play_menu_callback, + MAINWIN_OPT_SHUFFLE, "", NULL}, + {N_("/No Playlist Advance"), "N", mainwin_play_menu_callback, + MAINWIN_OPT_NPA, "", NULL}, + {N_("/Stop After Current Song"), "M", mainwin_songname_menu_callback, + MAINWIN_SONGNAME_STOPAFTERSONG, "", NULL}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/Play"), "x", mainwin_general_menu_callback, + MAINWIN_GENERAL_PLAY, "", GTK_STOCK_MEDIA_PLAY}, + {N_("/Pause"), "c", mainwin_general_menu_callback, + MAINWIN_GENERAL_PAUSE, "", GTK_STOCK_MEDIA_PAUSE}, + {N_("/Stop"), "v", mainwin_general_menu_callback, + MAINWIN_GENERAL_STOP, "", GTK_STOCK_MEDIA_STOP}, + {N_("/Previous"), "z", mainwin_general_menu_callback, + MAINWIN_GENERAL_PREV, "", GTK_STOCK_MEDIA_PREVIOUS}, + {N_("/Next"), "b", mainwin_general_menu_callback, + MAINWIN_GENERAL_NEXT, "", GTK_STOCK_MEDIA_NEXT}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/Jump to Playlist Start"), "Z", mainwin_general_menu_callback, + MAINWIN_GENERAL_START, "", GTK_STOCK_GOTO_TOP}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/Jump to File"), "J", mainwin_general_menu_callback, + MAINWIN_GENERAL_JTF, "", GTK_STOCK_JUMP_TO}, + {N_("/Jump to Time"), "J", mainwin_general_menu_callback, + MAINWIN_GENERAL_JTT, "", GTK_STOCK_JUMP_TO}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/View Track Details"), "I", mainwin_general_menu_callback, + MAINWIN_GENERAL_FILEINFO, "", my_pixbuf} +}; + +static const gint mainwin_playback_menu_entries_num = + G_N_ELEMENTS(mainwin_playback_menu_entries); + +/* Main menu */ + +GtkItemFactoryEntry mainwin_general_menu_entries[] = { + {N_("/About Audacious"), NULL, mainwin_general_menu_callback, + MAINWIN_GENERAL_ABOUT, "", GTK_STOCK_DIALOG_INFO}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/Play File"), "L", mainwin_general_menu_callback, + MAINWIN_GENERAL_PLAYFILE, "", GTK_STOCK_OPEN}, + {N_("/Play Location"), "L", mainwin_general_menu_callback, + MAINWIN_GENERAL_PLAYLOCATION, "", GTK_STOCK_NETWORK}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/V_isualization"), NULL, NULL, 0, "", NULL}, + {N_("/_Playback"), NULL, NULL, 0, "", NULL}, + {N_("/_View"), NULL, NULL, 0, "", NULL}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/Preferences"), "P", mainwin_general_menu_callback, + MAINWIN_GENERAL_PREFS, "", GTK_STOCK_PREFERENCES}, + {N_("/_Quit"), NULL, mainwin_general_menu_callback, + MAINWIN_GENERAL_EXIT, "", GTK_STOCK_QUIT} +}; + +static const gint mainwin_general_menu_entries_num = + G_N_ELEMENTS(mainwin_general_menu_entries); + +/* Add submenu */ + +GtkItemFactoryEntry mainwin_add_menu_entries[] = { + {N_("/Files..."), "f", mainwin_general_menu_callback, + MAINWIN_GENERAL_PLAYFILE, "", GTK_STOCK_OPEN}, + {N_("/Internet location..."), "h", mainwin_general_menu_callback, + MAINWIN_GENERAL_PLAYLOCATION, "", GTK_STOCK_NETWORK}, +}; + +static const gint mainwin_add_menu_entries_num = + G_N_ELEMENTS(mainwin_add_menu_entries); + +/* View submenu */ + +GtkItemFactoryEntry mainwin_view_menu_entries[] = { + {N_("/Show Player"), "M", mainwin_general_menu_callback, + MAINWIN_GENERAL_SHOWMWIN, "", NULL}, + {N_("/Show Playlist Editor"), "E", mainwin_general_menu_callback, + MAINWIN_GENERAL_SHOWPLWIN, "", NULL}, + {N_("/Show Equalizer"), "G", mainwin_general_menu_callback, + MAINWIN_GENERAL_SHOWEQWIN, "", NULL}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/Time Elapsed"), "E", mainwin_view_menu_callback, + MAINWIN_OPT_TELAPSED, "", NULL}, + {N_("/Time Remaining"), "R", mainwin_view_menu_callback, + MAINWIN_OPT_TREMAINING, "/Time Elapsed", NULL}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/Always On Top"), "o", mainwin_view_menu_callback, + MAINWIN_OPT_ALWAYS, "", NULL}, + {N_("/Put on All Workspaces"), "S", + mainwin_view_menu_callback, MAINWIN_OPT_STICKY, "", NULL}, + {"/-", NULL, NULL, 0, "", NULL}, + {N_("/Roll up Player"), "W", mainwin_view_menu_callback, + MAINWIN_OPT_WS, "", NULL}, + {N_("/Roll up Playlist Editor"), "W", mainwin_view_menu_callback, + MAINWIN_OPT_PWS, "", NULL}, + {N_("/Roll up Equalizer"), "W", mainwin_view_menu_callback, + MAINWIN_OPT_EQWS, "", NULL} +}; + +static const gint mainwin_view_menu_entries_num = + G_N_ELEMENTS(mainwin_view_menu_entries); + + +static PlaybackInfo playback_info = { NULL, 0, 0, 0 }; + + +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 mainwin_refresh_hints(void); + +void mainwin_position_motion_cb(gint pos); +void mainwin_position_release_cb(gint pos); + + +/* FIXME: placed here for now */ +void +playback_get_sample_params(gint * bitrate, + gint * frequency, + gint * n_channels) +{ + if (bitrate) + *bitrate = playback_info.bitrate; + + if (frequency) + *frequency = playback_info.frequency; + + if (n_channels) + *n_channels = playback_info.n_channels; +} + +static void +playback_set_sample_params(gint bitrate, + gint frequency, + gint n_channels) +{ + if (bitrate >= 0) + playback_info.bitrate = bitrate; + + if (frequency >= 0) + playback_info.frequency = frequency; + + if (n_channels >= 0) + playback_info.n_channels = n_channels; +} + +static void +mainwin_set_title_scroll(gboolean scroll) +{ + cfg.autoscroll = scroll; + textbox_set_scroll(mainwin_info, cfg.autoscroll); +} + + +void +mainwin_set_always_on_top(gboolean always) +{ + GtkWidget *widget = gtk_item_factory_get_widget(mainwin_view_menu, + "/Always On Top"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), + mainwin_menurow->mr_always_selected); +} + +static void +mainwin_set_shape_mask(void) +{ + GdkBitmap *mask; + + if (!cfg.player_visible) + return; + + mask = skin_get_mask(bmp_active_skin, SKIN_MASK_MAIN + cfg.player_shaded); + gtk_widget_shape_combine_mask(mainwin, mask, 0, 0); +} + +static void +mainwin_set_shade(gboolean shaded) +{ + GtkWidget *widget; + widget = gtk_item_factory_get_widget(mainwin_view_menu, + "/Roll up Player"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), shaded); +} + +static void +mainwin_set_shade_menu_cb(gboolean shaded) +{ + cfg.player_shaded = shaded; + + mainwin_set_shape_mask(); + + if (shaded) { + dock_shade(dock_window_list, GTK_WINDOW(mainwin), + MAINWIN_SHADED_HEIGHT); + + widget_show(WIDGET(mainwin_svis)); + vis_clear_data(mainwin_vis); + + widget_show(WIDGET(mainwin_srew)); + widget_show(WIDGET(mainwin_splay)); + widget_show(WIDGET(mainwin_spause)); + widget_show(WIDGET(mainwin_sstop)); + widget_show(WIDGET(mainwin_sfwd)); + widget_show(WIDGET(mainwin_seject)); + + textbox_set_scroll(mainwin_info, FALSE); + if (bmp_playback_get_playing()) + { + widget_show(WIDGET(mainwin_sposition)); + widget_show(WIDGET(mainwin_stime_min)); + widget_show(WIDGET(mainwin_stime_sec)); + } + else + { + widget_hide(WIDGET(mainwin_sposition)); + widget_hide(WIDGET(mainwin_stime_min)); + widget_hide(WIDGET(mainwin_stime_sec)); + } + + mainwin_shade->pb_ny = mainwin_shade->pb_py = 27; + } + else { + dock_shade(dock_window_list, GTK_WINDOW(mainwin), MAINWIN_HEIGHT); + + widget_hide(WIDGET(mainwin_svis)); + svis_clear_data(mainwin_svis); + + widget_hide(WIDGET(mainwin_srew)); + widget_hide(WIDGET(mainwin_splay)); + widget_hide(WIDGET(mainwin_spause)); + widget_hide(WIDGET(mainwin_sstop)); + widget_hide(WIDGET(mainwin_sfwd)); + widget_hide(WIDGET(mainwin_seject)); + + widget_hide(WIDGET(mainwin_stime_min)); + widget_hide(WIDGET(mainwin_stime_sec)); + widget_hide(WIDGET(mainwin_sposition)); + + textbox_set_scroll(mainwin_info, TRUE); + mainwin_shade->pb_ny = mainwin_shade->pb_py = 18; + } + + draw_main_window(TRUE); +} + +static void +mainwin_vis_set_active_vis(gint new_vis) +{ + active_vis = mainwin_vis; +} + +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) +{ + gchar *path = + mainwin_vis_menu_entries[MAINWIN_VIS_MENU_VIS_MODE + mode].path; + GtkWidget *widget = gtk_item_factory_get_widget(mainwin_vis_menu, path); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE); +} + +static void +mainwin_vis_set_type_menu_cb(VisType mode) +{ + cfg.vis_type = mode; + + if (mode == VIS_OFF) { + if (cfg.player_shaded && cfg.player_visible) + svis_clear(mainwin_svis); + else + vis_clear(active_vis); + } + if (mode == VIS_ANALYZER || mode == VIS_SCOPE) { + vis_clear_data(active_vis); + svis_clear_data(mainwin_svis); + } +} + +static void +mainwin_menubtn_cb(void) +{ + gint x, y; + gtk_window_get_position(GTK_WINDOW(mainwin), &x, &y); + util_item_factory_popup(mainwin_general_menu, + x + 6, + y + MAINWIN_SHADED_HEIGHT, + 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) +{ + gtk_widget_hide(equalizerwin); + gtk_widget_hide(playlistwin); + gtk_widget_hide(mainwin); + gdk_flush(); + + g_source_remove(mainwin_timeout_id); + + util_set_cursor(NULL); + + bmp_config_save(); + gtk_accel_map_save(bmp_paths[BMP_PATH_ACCEL_FILE]); + + ctrlsocket_cleanup(); + + playlist_stop_get_info_thread(); + playlist_clear(); + + plugin_system_cleanup(); + + gtk_main_quit(); + + exit(EXIT_SUCCESS); +} + +static void +mainwin_destroy(GtkWidget * widget, gpointer data) +{ + mainwin_quit_cb(); +} + +static void +mainwin_draw_titlebar(gboolean focus) +{ + skin_draw_mainwin_titlebar(bmp_active_skin, mainwin_bg, mainwin_gc, + cfg.player_shaded, focus || !cfg.dim_titlebar); +} + +void +draw_main_window(gboolean force) +{ + GList *wl; + Widget *w; + gboolean redraw; + + if (!cfg.player_visible) + return; + + if (force) + mainwin_refresh_hints(); + + widget_list_lock(mainwin_wlist); + + if (force) { + if (!cfg.player_shaded) + skin_draw_pixmap(bmp_active_skin, mainwin_bg, mainwin_gc, + SKIN_MAIN, 0, 0, 0, 0, MAINWIN_WIDTH, + MAINWIN_HEIGHT); + mainwin_draw_titlebar(gtk_window_has_toplevel_focus + (GTK_WINDOW(mainwin))); + } + + widget_list_draw(mainwin_wlist, &redraw, force); + + if (redraw || force) { + if (force) { + gdk_window_clear(mainwin->window); + } + else { + for (wl = mainwin_wlist; wl; wl = g_list_next(wl)) { + w = WIDGET(wl->data); + + if (!w->redraw || !w->visible) + continue; + + gdk_window_clear_area(mainwin->window, w->x, w->y, + w->width, w->height); + w->redraw = FALSE; + } + } + + gdk_flush(); + } + + widget_list_unlock(mainwin_wlist); +} + + +void +mainwin_set_info_text(void) +{ + gchar *text; + + if (mainwin_info_text_locked) + return; + + if ((text = input_get_info_text()) != NULL) { + textbox_set_text(mainwin_info, text); + g_free(text); + } + else if ((text = playlist_get_info_text()) != NULL) { + textbox_set_text(mainwin_info, text); + g_free(text); + } +} + +void +mainwin_lock_info_text(const gchar * text) +{ + mainwin_info_text_locked = TRUE; + textbox_set_text(mainwin_info, text); +} + +void +mainwin_release_info_text(void) +{ + mainwin_info_text_locked = FALSE; + mainwin_set_info_text(); +} + + +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) +{ + G_LOCK(mainwin_title); + g_free(mainwin_title_text); + mainwin_title_text = make_mainwin_title(title); + G_UNLOCK(mainwin_title); +} + +static void +mainwin_refresh_hints(void) +{ + if (bmp_active_skin && bmp_active_skin->properties.mainwin_othertext + == TRUE) + { + widget_hide(WIDGET(mainwin_rate_text)); + widget_hide(WIDGET(mainwin_freq_text)); + widget_hide(WIDGET(mainwin_monostereo)); + widget_show(WIDGET(mainwin_othertext)); + } + else + { + widget_show(WIDGET(mainwin_rate_text)); + widget_show(WIDGET(mainwin_freq_text)); + widget_show(WIDGET(mainwin_monostereo)); + widget_hide(WIDGET(mainwin_othertext)); + } +} + +void +mainwin_set_song_info(gint bitrate, + gint frequency, + gint n_channels) +{ + gchar text[512]; + gchar *title; + + playback_set_sample_params(bitrate, frequency, n_channels); + + if (bitrate != -1) { + bitrate /= 1000; + + if (bitrate < 1000) { + /* Show bitrate in 1000s */ + g_snprintf(text, sizeof(text), "%3d", bitrate); + textbox_set_text(mainwin_rate_text, text); + } + else { + /* Show bitrate in 100,000s */ + g_snprintf(text, sizeof(text), "%2dH", bitrate / 100); + textbox_set_text(mainwin_rate_text, text); + } + } + else + textbox_set_text(mainwin_rate_text, _("VBR")); + + /* Show sampling frequency in kHz */ + g_snprintf(text, sizeof(text), "%2d", frequency / 1000); + textbox_set_text(mainwin_freq_text, text); + + monostereo_set_num_channels(mainwin_monostereo, n_channels); + + if (cfg.player_shaded) + { + widget_show(WIDGET(mainwin_stime_min)); + widget_show(WIDGET(mainwin_stime_sec)); + } + + widget_show(WIDGET(mainwin_minus_num)); + widget_show(WIDGET(mainwin_10min_num)); + widget_show(WIDGET(mainwin_min_num)); + widget_show(WIDGET(mainwin_10sec_num)); + widget_show(WIDGET(mainwin_sec_num)); + + if (!bmp_playback_get_paused()) + playstatus_set_status(mainwin_playstatus, STATUS_PLAY); + + if (playlist_get_current_length() != -1) { + if (cfg.player_shaded) + widget_show(WIDGET(mainwin_sposition)); + widget_show(WIDGET(mainwin_position)); + } + else { + widget_hide(WIDGET(mainwin_position)); + widget_hide(WIDGET(mainwin_sposition)); + mainwin_force_redraw = TRUE; + } + + if (bmp_active_skin && bmp_active_skin->properties.mainwin_othertext + == TRUE) + { + if (bitrate != -1) + g_snprintf(text, 512, "%d kbps, %0.1f kHz, %s", + bitrate, + (gfloat) frequency / 1000, + (n_channels > 1) ? _("stereo") : _("mono")); + else + g_snprintf(text, 512, "VBR, %0.1f kHz, %s", + (gfloat) frequency / 1000, + (n_channels > 1) ? _("stereo") : _("mono")); + + textbox_set_text(mainwin_othertext, text); + + widget_hide(WIDGET(mainwin_rate_text)); + widget_hide(WIDGET(mainwin_freq_text)); + widget_hide(WIDGET(mainwin_monostereo)); + widget_show(WIDGET(mainwin_othertext)); + } + else + { + widget_show(WIDGET(mainwin_rate_text)); + widget_show(WIDGET(mainwin_freq_text)); + widget_show(WIDGET(mainwin_monostereo)); + widget_hide(WIDGET(mainwin_othertext)); + } + + title = playlist_get_info_text(); + mainwin_set_song_title(title); + g_free(title); +} + +void +mainwin_clear_song_info(void) +{ + if (!mainwin) + return; + + /* clear title */ + G_LOCK(mainwin_title); + g_free(mainwin_title_text); + mainwin_title_text = NULL; + G_UNLOCK(mainwin_title); + + /* clear sampling parameters */ + playback_set_sample_params(0, 0, 0); + + mainwin_position->hs_pressed = FALSE; + mainwin_sposition->hs_pressed = FALSE; + + /* clear sampling parameter displays */ + textbox_set_text(mainwin_rate_text, " "); + textbox_set_text(mainwin_freq_text, " "); + monostereo_set_num_channels(mainwin_monostereo, 0); + + playstatus_set_status(mainwin_playstatus, STATUS_STOP); + + /* hide playback time */ + widget_hide(WIDGET(mainwin_minus_num)); + widget_hide(WIDGET(mainwin_10min_num)); + widget_hide(WIDGET(mainwin_min_num)); + widget_hide(WIDGET(mainwin_10sec_num)); + widget_hide(WIDGET(mainwin_sec_num)); + + widget_hide(WIDGET(mainwin_stime_min)); + widget_hide(WIDGET(mainwin_stime_sec)); + + widget_hide(WIDGET(mainwin_position)); + widget_hide(WIDGET(mainwin_sposition)); + + widget_hide(WIDGET(mainwin_othertext)); + + playlistwin_hide_timer(); + draw_main_window(TRUE); + + vis_clear(active_vis); +} + +void +mainwin_disable_seekbar(void) +{ + if (!mainwin) + return; + + /* + * We dont call draw_main_window() here so this will not + * remove them visually. It will only prevent us from sending + * any seek calls to the input plugin before the input plugin + * calls ->set_info(). + */ + widget_hide(WIDGET(mainwin_position)); + widget_hide(WIDGET(mainwin_sposition)); +} + +static gboolean +mainwin_mouse_button_release(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + gdk_pointer_ungrab(GDK_CURRENT_TIME); + + /* + * The gdk_flush() is just for making sure that the pointer really + * gets ungrabbed before calling any button callbacks + * + */ + + gdk_flush(); + + if (dock_is_moving(GTK_WINDOW(mainwin))) { + dock_move_release(GTK_WINDOW(mainwin)); + draw_playlist_window(TRUE); + } + + if (mainwin_menurow->mr_doublesize_selected) { + event->x /= 2; + event->y /= 2; + } + + handle_release_cb(mainwin_wlist, widget, event); + + draw_main_window(FALSE); + + return FALSE; +} + +static gboolean +mainwin_motion(GtkWidget * widget, + GdkEventMotion * event, + gpointer callback_data) +{ + int x, y; + GdkModifierType state; + + if (event->is_hint != FALSE) + { + gdk_window_get_pointer(GDK_WINDOW(mainwin->window), + &x, &y, &state); + + /* If it's a hint, we had to query X, so override the + * information we we're given... it's probably useless... --nenolod + */ + event->x = x; + event->y = y; + event->state = state; + } + else + { + x = event->x; + y = event->y; + state = event->state; + } + + if (dock_is_moving(GTK_WINDOW(mainwin))) { + dock_move_motion(GTK_WINDOW(mainwin), event); + } + else { + handle_motion_cb(mainwin_wlist, widget, event); + draw_main_window(FALSE); + } + + gdk_flush(); + + return FALSE; +} + +static gboolean +inside_sensitive_widgets(gint x, gint y) +{ + return (widget_contains(WIDGET(mainwin_menubtn), x, y) + || widget_contains(WIDGET(mainwin_minimize), x, y) + || widget_contains(WIDGET(mainwin_shade), x, y) + || widget_contains(WIDGET(mainwin_close), x, y) + || widget_contains(WIDGET(mainwin_rew), x, y) + || widget_contains(WIDGET(mainwin_play), x, y) + || widget_contains(WIDGET(mainwin_pause), x, y) + || widget_contains(WIDGET(mainwin_stop), x, y) + || widget_contains(WIDGET(mainwin_fwd), x, y) + || widget_contains(WIDGET(mainwin_eject), x, y) + || widget_contains(WIDGET(mainwin_shuffle), x, y) + || widget_contains(WIDGET(mainwin_repeat), x, y) + || widget_contains(WIDGET(mainwin_pl), x, y) + || widget_contains(WIDGET(mainwin_eq), x, y) + || widget_contains(WIDGET(mainwin_info), x, y) + || widget_contains(WIDGET(mainwin_menurow), x, y) + || widget_contains(WIDGET(mainwin_volume), x, y) + || widget_contains(WIDGET(mainwin_balance), x, y) + || (widget_contains(WIDGET(mainwin_position), x, y) && + widget_is_visible(WIDGET(mainwin_position))) + || widget_contains(WIDGET(mainwin_minus_num), x, y) + || widget_contains(WIDGET(mainwin_10min_num), x, y) + || widget_contains(WIDGET(mainwin_min_num), x, y) + || widget_contains(WIDGET(mainwin_10sec_num), x, y) + || widget_contains(WIDGET(mainwin_sec_num), x, y) + || widget_contains(WIDGET(mainwin_vis), x, y) + || widget_contains(WIDGET(mainwin_minimize), x, y) + || widget_contains(WIDGET(mainwin_shade), x, y) + || widget_contains(WIDGET(mainwin_close), x, y) + || widget_contains(WIDGET(mainwin_menubtn), x, y) + || widget_contains(WIDGET(mainwin_sposition), x, y) + || widget_contains(WIDGET(mainwin_stime_min), x, y) + || widget_contains(WIDGET(mainwin_stime_sec), x, y) + || widget_contains(WIDGET(mainwin_srew), x, y) + || widget_contains(WIDGET(mainwin_splay), x, y) + || widget_contains(WIDGET(mainwin_spause), x, y) + || widget_contains(WIDGET(mainwin_sstop), x, y) + || widget_contains(WIDGET(mainwin_sfwd), x, y) + || widget_contains(WIDGET(mainwin_seject), x, y) + || widget_contains(WIDGET(mainwin_svis), x, y) + || widget_contains(WIDGET(mainwin_about), x, y)); +} + +void +mainwin_scrolled(GtkWidget * widget, + GdkEventScroll * event, + gpointer callback_data) +{ + gint d = cfg.mouse_change; + if (event->direction == GDK_SCROLL_DOWN) + d *= -1; + mainwin_set_volume_diff(d); +} + + +static gboolean +mainwin_mouse_button_press(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + + gboolean grab = TRUE; + + if (event->button == 1 && event->type == GDK_BUTTON_PRESS && + !inside_sensitive_widgets(event->x, event->y) && event->y < 14) { + if (0 && hint_move_resize_available()) { + hint_move_resize(mainwin, event->x_root, event->y_root, TRUE); + grab = FALSE; + } + else { + gtk_window_present(GTK_WINDOW(mainwin)); + dock_move_press(dock_window_list, GTK_WINDOW(mainwin), event, + TRUE); + } + } + else if (event->button == 1 && event->type == GDK_2BUTTON_PRESS && + event->y < 14 && !inside_sensitive_widgets(event->x, event->y)) { + mainwin_set_shade(!cfg.player_shaded); + if (dock_is_moving(GTK_WINDOW(mainwin))) + dock_move_release(GTK_WINDOW(mainwin)); + } + else if (event->button == 1 && event->type == GDK_2BUTTON_PRESS && + widget_contains(WIDGET(mainwin_info), event->x, event->y)) { + playlist_fileinfo_current(); + } + else { + handle_press_cb(mainwin_wlist, widget, event); + draw_main_window(FALSE); + } + + if ((event->button == 1) && event->type != GDK_2BUTTON_PRESS && + (widget_contains(WIDGET(mainwin_vis), event->x, event->y) || + widget_contains(WIDGET(mainwin_svis), event->x, event->y))) { + + cfg.vis_type++; + + if (cfg.vis_type > VIS_OFF) + cfg.vis_type = VIS_ANALYZER; + + mainwin_vis_set_type(cfg.vis_type); + } + + if (event->button == 3) { + if (widget_contains(WIDGET(mainwin_info), event->x, event->y)) { + util_item_factory_popup(mainwin_songname_menu, + event->x_root, event->y_root, + 3, event->time); + grab = FALSE; + } + else if (widget_contains(WIDGET(mainwin_vis), event->x, event->y) || + widget_contains(WIDGET(mainwin_svis), event->x, event->y)) { + util_item_factory_popup(mainwin_vis_menu, event->x_root, + event->y_root, 3, event->time); + grab = FALSE; + } + else if ( (event->y > 70) && (event->x < 128) ) + { + + util_item_factory_popup(mainwin_play_menu, + event->x_root, + event->y_root, 3, event->time); + grab = FALSE; + } 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 + * + */ + util_item_factory_popup(mainwin_general_menu, + event->x_root, + event->y_root, 3, event->time); + grab = FALSE; + } + } + if (event->button == 1) { + if ((event->x > 35 && event->x < 100 && + event->y > 25 && event->y < 40) || + widget_contains(WIDGET(mainwin_stime_min), event->x, event->y) || + widget_contains(WIDGET(mainwin_stime_sec), event->x, event->y)) { + + if (cfg.timer_mode == TIMER_ELAPSED) + set_timer_mode(TIMER_REMAINING); + else + set_timer_mode(TIMER_ELAPSED); + } + + } + + if (grab) + gdk_pointer_grab(mainwin->window, FALSE, + GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_RELEASE_MASK, + GDK_WINDOW(GDK_NONE), NULL, GDK_CURRENT_TIME); + + return FALSE; +} + +static gboolean +mainwin_focus_in(GtkWidget * window, + GdkEventFocus * event, + gpointer data) +{ + mainwin_menubtn->pb_allow_draw = TRUE; + mainwin_minimize->pb_allow_draw = TRUE; + mainwin_shade->pb_allow_draw = TRUE; + mainwin_close->pb_allow_draw = TRUE; + draw_main_window(TRUE); + + return TRUE; +} + + +static gboolean +mainwin_focus_out(GtkWidget * widget, + GdkEventFocus * event, + gpointer callback_data) +{ + mainwin_menubtn->pb_allow_draw = FALSE; + mainwin_minimize->pb_allow_draw = FALSE; + mainwin_shade->pb_allow_draw = FALSE; + mainwin_close->pb_allow_draw = FALSE; + draw_main_window(TRUE); + + return TRUE; +} + +static gboolean +mainwin_keypress(GtkWidget * grab_widget, + GdkEventKey * event, + gpointer data) +{ + + 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() != -1) + bmp_playback_seek(CLAMP + (bmp_playback_get_time() - 1000, 0, + playlist_get_current_length()) / 1000); + break; + case GDK_Right: + case GDK_KP_Right: + case GDK_KP_9: + if (playlist_get_current_length() != -1) + bmp_playback_seek(CLAMP + (bmp_playback_get_time() + 1000, 0, + playlist_get_current_length()) / 1000); + break; + case GDK_KP_4: + playlist_prev(); + break; + case GDK_KP_6: + playlist_next(); + break; + case GDK_KP_Insert: + mainwin_jump_to_file(); + break; + case GDK_KP_5: + mainwin_play_pushed(); + break; + case GDK_Escape: + mainwin_minimize_cb(); + break; + default: + return FALSE; + } + + return TRUE; +} + +static void +mainwin_jump_to_time_cb(GtkWidget * widget, + GtkWidget * entry) +{ + guint min = 0, sec = 0, params; + gint time; + + 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() > -1 && + time <= (playlist_get_current_length() / 1000)) { + bmp_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; + guint tindex; + gchar time_str[10]; + + if (!bmp_playback_get_playing()) { + report_error("JIT can't be launched when no track is being played.\n"); + 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 = bmp_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); +} + +static void +change_song(guint pos) +{ + if (bmp_playback_get_playing()) + bmp_playback_stop(); + + playlist_set_position(pos); + bmp_playback_initiate(); +} + +static void +mainwin_jump_to_file_jump(GtkTreeView * treeview) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + gchar *pos_str; + 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_str, -1); + pos = g_ascii_strtoull(pos_str, NULL, 10) - 1; + g_free(pos_str); + + change_song(pos); + + /* FIXME: should only hide window */ + gtk_widget_destroy(mainwin_jtf); + mainwin_jtf = NULL; +} + +static void +mainwin_jump_to_file_jump_cb(GtkTreeView * treeview, + gpointer data) +{ + mainwin_jump_to_file_jump(treeview); +} + +static void +mainwin_jump_to_file_set_queue_button_label(GtkButton * button, + guint pos) +{ + if (playlist_is_position_queued(pos)) + gtk_button_set_label(button, _("Un_queue")); + else + gtk_button_set_label(button, _("_Queue")); +} + +static void +mainwin_jump_to_file_queue_cb(GtkButton * button, + gpointer data) +{ + GtkTreeView *treeview; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + gchar *pos_str; + 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_str, -1); + pos = g_ascii_strtoull(pos_str, NULL, 10) - 1; + + playlist_queue_position(pos); + + mainwin_jump_to_file_set_queue_button_label(button, pos); +} + +static void +mainwin_jump_to_file_selection_changed_cb(GtkTreeSelection *treesel, + gpointer data) +{ + GtkTreeView *treeview; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + gchar *pos_str; + 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_str, -1); + pos = g_ascii_strtoull(pos_str, NULL, 10) - 1; + g_free(pos_str); + + mainwin_jump_to_file_set_queue_button_label(GTK_BUTTON(data), pos); +} + +static gboolean +mainwin_jump_to_file_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 { + mainwin_jump_to_file_jump(GTK_TREE_VIEW(data)); + return TRUE; + } + default: + return FALSE; + } +} + +static gboolean +mainwin_jump_to_file_keypress_cb(GtkWidget * object, + GdkEventKey * event, + gpointer data) +{ + switch (event->keyval) { + case GDK_Escape: + /* FIXME: show only hide window */ + gtk_widget_destroy(mainwin_jtf); + mainwin_jtf = NULL; + return TRUE; + default: + return FALSE; + }; +} + +static gboolean +mainwin_jump_to_file_match(const gchar * song, gchar ** keys) +{ + gint i = 0; + gchar *key; + gchar *song_lc; + + song_lc = g_ascii_strdown(song, -1); + + while (keys[i]) { + key = g_ascii_strdown(keys[i], -1); + if (!g_strrstr(song_lc, key)) { + g_free(key); + g_free(song_lc); + return FALSE; + } + + g_free(key); + i++; + } + + g_free(song_lc); + + return TRUE; +} + +/* FIXME: Clear the entry when the list gets updated */ +static void +mainwin_update_jtf(GtkWidget * widget, gpointer user_data) +{ + /* FIXME: Is not in sync with playlist due to delayed extinfo + * reading */ + gint row; + GList *playlist; + gchar *desc_buf = NULL; + gchar *row_str; + GtkTreeIter iter; + GtkTreeSelection *selection; + + GtkTreeModel *store; + + if (!mainwin_jtf) + return; + + store = gtk_tree_view_get_model(GTK_TREE_VIEW(user_data)); + gtk_list_store_clear(GTK_LIST_STORE(store)); + + row = 1; + for (playlist = playlist_get(); playlist; + playlist = g_list_next(playlist)) { + PlaylistEntry *entry = PLAYLIST_ENTRY(playlist->data); + + if (entry->title) + desc_buf = g_strdup(entry->title); + else if (strchr(entry->filename, '/')) + desc_buf = str_to_utf8(strrchr(entry->filename, '/') + 1); + else + desc_buf = str_to_utf8(entry->filename); + + row_str = g_strdup_printf("%d", row++); + + gtk_list_store_append(GTK_LIST_STORE(store), &iter); + gtk_list_store_set(GTK_LIST_STORE(store), &iter, + 0, row_str, 1, desc_buf, -1); + + if(desc_buf) { + g_free(desc_buf); + desc_buf = NULL; + } + + g_free(row_str); + } + + gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(user_data)); + gtk_tree_selection_select_iter(selection, &iter); +} + +static void +mainwin_jump_to_file_edit_cb(GtkEntry * entry, gpointer user_data) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(user_data); + GtkTreeSelection *selection; + GtkTreeIter iter; + + GtkListStore *store; + + gint song_index = 0; + gchar **words; + GList *playlist; + + gboolean match = FALSE; + + /* Chop the key string into ' '-separated key words */ + words = g_strsplit(gtk_entry_get_text(entry), " ", 0); + + /* FIXME: Remove the connected signals before clearing + * (row-selected will still eventually arrive once) */ + store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview)); + gtk_list_store_clear(store); + + PLAYLIST_LOCK(); + + for (playlist = playlist_get(); playlist; + playlist = g_list_next(playlist)) { + + PlaylistEntry *entry = PLAYLIST_ENTRY(playlist->data); + const gchar *title; + gchar *filename = NULL; + + title = entry->title; + if (!title) { + filename = str_to_utf8(entry->filename); + + if (strchr(filename, '/')) + title = strrchr(filename, '/') + 1; + else + title = filename; + } + + /* Compare the key words to the string - if all the words + match, add to the ListStore */ + + /* + * 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 (words[0]) + match = mainwin_jump_to_file_match(title, words); + else + match = TRUE; + + if (match) { + gchar *song_index_str = g_strdup_printf("%d", song_index + 1); + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, song_index_str, 1, title, -1); + g_free(song_index_str); + } + + song_index++; + if (filename) { + g_free(filename); + filename = NULL; + } + } + + PLAYLIST_UNLOCK(); + + g_strfreev(words); + + 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); + } +} + +void +mainwin_jump_to_file(void) +{ + GtkWidget *scrollwin; + GtkWidget *vbox, *bbox, *sep; + GtkWidget *jump, *queue, *cancel; + GtkWidget *rescan, *edit; + GtkWidget *search_label, *hbox; + GList *playlist; + gchar *desc_buf = NULL; + gchar *row_str; + gint row; + + GtkWidget *treeview; + GtkListStore *jtf_store; + + GtkTreeIter iter; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + if (mainwin_jtf) { + gtk_window_present(GTK_WINDOW(mainwin_jtf)); + return; + } + + mainwin_jtf = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_type_hint(GTK_WINDOW(mainwin_jtf), + GDK_WINDOW_TYPE_HINT_DIALOG); + + gtk_window_set_title(GTK_WINDOW(mainwin_jtf), _("Jump to Track")); + + gtk_window_set_position(GTK_WINDOW(mainwin_jtf), GTK_WIN_POS_CENTER); + g_signal_connect(mainwin_jtf, "destroy", + G_CALLBACK(gtk_widget_destroyed), &mainwin_jtf); + + gtk_container_border_width(GTK_CONTAINER(mainwin_jtf), 10); + gtk_window_set_default_size(GTK_WINDOW(mainwin_jtf), 550, 350); + + vbox = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(mainwin_jtf), vbox); + + jtf_store = gtk_list_store_new(2, G_TYPE_STRING, 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(mainwin_jump_to_file_jump), NULL); + + hbox = gtk_hbox_new(FALSE, 3); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); + + 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(mainwin_jump_to_file_edit_cb), treeview); + + g_signal_connect(edit, "key_press_event", + G_CALLBACK(mainwin_jump_to_file_edit_keypress_cb), treeview); + + g_signal_connect(mainwin_jtf, "key_press_event", + G_CALLBACK(mainwin_jump_to_file_keypress_cb), treeview); + + gtk_box_pack_start(GTK_BOX(hbox), edit, TRUE, TRUE, 3); + + 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), 5); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + queue = gtk_button_new_with_mnemonic(_("_Queue")); + 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(mainwin_jump_to_file_queue_cb), + treeview); + g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), "changed", + G_CALLBACK(mainwin_jump_to_file_selection_changed_cb), + queue); + + rescan = gtk_button_new_from_stock(GTK_STOCK_REFRESH); + gtk_box_pack_start(GTK_BOX(bbox), rescan, FALSE, FALSE, 0); + g_signal_connect(rescan, "clicked", + G_CALLBACK(mainwin_update_jtf), treeview); + GTK_WIDGET_SET_FLAGS(rescan, GTK_CAN_DEFAULT); + gtk_widget_grab_default(rescan); + + 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(mainwin_jump_to_file_jump_cb), + treeview); + + GTK_WIDGET_SET_FLAGS(jump, GTK_CAN_DEFAULT); + gtk_widget_grab_default(jump); + + cancel = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + gtk_box_pack_start(GTK_BOX(bbox), cancel, FALSE, FALSE, 0); + g_signal_connect_swapped(cancel, "clicked", + G_CALLBACK(gtk_widget_destroy), + mainwin_jtf); + GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + + gtk_list_store_clear(jtf_store); + + row = 1; + + PLAYLIST_LOCK(); + + for (playlist = playlist_get(); playlist; + playlist = g_list_next(playlist)) { + + PlaylistEntry *entry = PLAYLIST_ENTRY(playlist->data); + + if (entry->title) + desc_buf = g_strdup(entry->title); + else if (strchr(entry->filename, '/')) + desc_buf = str_to_utf8(strrchr(entry->filename, '/') + 1); + else + desc_buf = str_to_utf8(entry->filename); + + row_str = g_strdup_printf("%d", row++); + + gtk_list_store_append(GTK_LIST_STORE(jtf_store), &iter); + gtk_list_store_set(GTK_LIST_STORE(jtf_store), &iter, + 0, row_str, 1, desc_buf, -1); + + if (desc_buf) { + g_free(desc_buf); + desc_buf = NULL; + } + g_free(row_str); + } + + PLAYLIST_UNLOCK(); + + gtk_widget_show_all(mainwin_jtf); +} + +static gboolean +mainwin_configure(GtkWidget * window, + GdkEventConfigure * event, + gpointer data) +{ + if (!GTK_WIDGET_VISIBLE(window)) + return FALSE; + + if (cfg.show_wm_decorations) + gdk_window_get_root_origin(window->window, + &cfg.player_x, &cfg.player_y); + else + gdk_window_get_deskrelative_origin(window->window, + &cfg.player_x, &cfg.player_y); + return FALSE; +} + +void +mainwin_set_back_pixmap(void) +{ + gdk_window_set_back_pixmap(mainwin->window, mainwin_bg, 0); + gdk_window_clear(mainwin->window); +} + +void +mainwin_drag_data_received(GtkWidget * widget, + GdkDragContext * context, + gint x, + gint y, + GtkSelectionData * selection_data, + guint info, + guint time, + gpointer user_data) +{ + gchar **iter, **sourcelist, *path; + gchar *decoded; + gboolean not_font = FALSE; + + if (!selection_data->data) + { + g_warning("DND data string is NULL"); + return; + } + + iter = sourcelist = g_strsplit((gchar *)(selection_data->data),"\n",-1); + + for (path = *sourcelist; *path; path = *(++sourcelist)) + { + if (path == NULL) /* damn konqueror */ + break; + + if (str_has_prefix_nocase(path, "fonts:///")) + { + path += 8; + + /* plain, since we already stripped the first URI part */ + decoded = xmms_urldecode_plain(path); + + /* Get the old font's size, and add it to the dropped + * font's name + */ + cfg.playlist_font = g_strconcat(decoded + 1, + strrchr(cfg.playlist_font, ' '), + NULL); + playlist_list_set_font(cfg.playlist_font); + playlistwin_update_list(); + + g_free(decoded); + return; + } + + if (str_has_prefix_nocase(path,"file:///")) + { + if (not_font == FALSE) + { + playlist_clear(); + not_font = TRUE; + } + playlist_add_url(path); + } + } + + g_strfreev(iter); + + if (not_font) + bmp_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(text); +} + +static void +on_add_url_ok_clicked(GtkWidget * widget, + GtkWidget * entry) +{ + const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry)); + if (text && *text) + { + playlist_clear(); + playlist_add_url(text); + bmp_playback_initiate(); + } +} + +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(GtkItemFactory * factory, + const gchar * path, + gboolean active) +{ + GtkWidget *item = gtk_item_factory_get_widget(factory, path); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), active); +} + +void +mainwin_eject_pushed(void) +{ + util_run_filebrowser(PLAY_BUTTON); +} + +void +mainwin_rev_pushed(void) +{ + g_get_current_time(&cb_time); + + seek_initial_pos = hslider_get_position(mainwin_position); + seek_state = MAINWIN_SEEK_REV; +} + +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(); + } + else + { + /* interpret as 'seek' */ + mainwin_position_release_cb( hslider_get_position(mainwin_position) ); + } + + seek_state = MAINWIN_SEEK_NIL; +} + +void +mainwin_fwd_pushed(void) +{ + g_get_current_time(&cb_time); + + seek_initial_pos = hslider_get_position(mainwin_position); + seek_state = MAINWIN_SEEK_FWD; +} + +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 previous song' */ + playlist_next(); + } + else + { + /* interpret as 'seek' */ + mainwin_position_release_cb( hslider_get_position(mainwin_position) ); + } + + seek_state = MAINWIN_SEEK_NIL; +} + +void +mainwin_play_pushed(void) +{ + if (bmp_playback_get_paused()) { + bmp_playback_pause(); + return; + } + + if (playlist_get_length()) + bmp_playback_initiate(); + else + mainwin_eject_pushed(); +} + +void +mainwin_stop_pushed(void) +{ + ip_data.stop = TRUE; + mainwin_clear_song_info(); + bmp_playback_stop(); + ip_data.stop = FALSE; +} + +void +mainwin_shuffle_pushed(gboolean toggled) +{ + check_set(mainwin_play_menu, "/Shuffle", toggled); +} + +void +mainwin_repeat_pushed(gboolean toggled) +{ + check_set(mainwin_play_menu, "/Repeat", toggled); +} + +void +mainwin_pl_pushed(gboolean toggled) +{ + if (toggled) + playlistwin_show(); + else + playlistwin_hide(); +} + +gint +mainwin_spos_frame_cb(gint pos) +{ + if (mainwin_sposition) { + if (pos < 6) + mainwin_sposition->hs_knob_nx = mainwin_sposition->hs_knob_px = + 17; + else if (pos < 9) + mainwin_sposition->hs_knob_nx = mainwin_sposition->hs_knob_px = + 20; + else + mainwin_sposition->hs_knob_nx = mainwin_sposition->hs_knob_px = + 23; + } + return 1; +} + +void +mainwin_spos_motion_cb(gint pos) +{ + gint time; + gchar *time_msg; + + pos--; + + time = ((playlist_get_current_length() / 1000) * pos) / 12; + + if (cfg.timer_mode == TIMER_REMAINING) { + time = (playlist_get_current_length() / 1000) - time; + time_msg = g_strdup_printf("-%2.2d", time / 60); + textbox_set_text(mainwin_stime_min, time_msg); + g_free(time_msg); + } + else { + time_msg = g_strdup_printf(" %2.2d", time / 60); + textbox_set_text(mainwin_stime_min, time_msg); + g_free(time_msg); + } + + time_msg = g_strdup_printf("%2.2d", time % 60); + textbox_set_text(mainwin_stime_sec, time_msg); + g_free(time_msg); +} + +void +mainwin_spos_release_cb(gint pos) +{ + bmp_playback_seek(((playlist_get_current_length() / 1000) * + (pos - 1)) / 12); +} + +void +mainwin_position_motion_cb(gint pos) +{ + gint length, time; + gchar *seek_msg; + + length = playlist_get_current_length() / 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(gint pos) +{ + gint length, time; + + length = playlist_get_current_length() / 1000; + time = (length * pos) / 219; + bmp_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; + + setting_volume = TRUE; + + 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(); + setting_volume = FALSE; + read_volume(VOLUME_ADJUSTED); +} + +void +mainwin_adjust_balance_motion(gint b) +{ + gchar *balance_msg; + gint v, pvl, pvr; + + setting_volume = TRUE; + 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(); + setting_volume = FALSE; + read_volume(VOLUME_ADJUSTED); +} + +void +mainwin_set_volume_slider(gint percent) +{ + hslider_set_position(mainwin_volume, (gint) rint((percent * 51) / 100.0)); +} + +void +mainwin_set_balance_slider(gint percent) +{ + hslider_set_position(mainwin_balance, + (gint) rint(((percent * 12) / 100.0) + 12)); +} + +void +mainwin_volume_motion_cb(gint pos) +{ + gint vol = (pos * 100) / 51; + mainwin_adjust_volume_motion(vol); + equalizerwin_set_volume_slider(vol); +} + +void +mainwin_volume_release_cb(gint pos) +{ + mainwin_adjust_volume_release(); +} + +gint +mainwin_balance_frame_cb(gint pos) +{ + return ((abs(pos - 12) * 28) / 13); +} + +void +mainwin_balance_motion_cb(gint pos) +{ + gint bal = ((pos - 12) * 100) / 12; + mainwin_adjust_balance_motion(bal); + equalizerwin_set_balance_slider(bal); +} + +void +mainwin_balance_release_cb(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); + setting_volume = FALSE; + mainwin_set_volume_slider(vol); + equalizerwin_set_volume_slider(vol); + read_volume(VOLUME_SET); +} + +void +mainwin_set_balance_diff(gint diff) +{ + gint b; + b = CLAMP(balance + diff, -100, 100); + mainwin_adjust_balance_motion(b); + setting_volume = FALSE; + mainwin_set_balance_slider(b); + equalizerwin_set_balance_slider(b); + read_volume(VOLUME_SET); +} + +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(mainwin_view_menu, "/Show Player", TRUE); + + if (cfg.player_shaded) + vis_clear_data(active_vis); + + mainwin_vis_set_active_vis(MAINWIN_VIS_ACTIVE_MAINWIN); + mainwin_set_shape_mask(); + + if (cfg.show_wm_decorations) { + if (!pposition_broken && cfg.player_x != -1 + && cfg.save_window_position) + gtk_window_move(GTK_WINDOW(mainwin), cfg.player_x, cfg.player_y); + + gtk_widget_show(mainwin); + + if (pposition_broken && cfg.player_x != -1 + && cfg.save_window_position) + gtk_window_move(GTK_WINDOW(mainwin), cfg.player_x, cfg.player_y); + + return; + } + + gtk_widget_show_all(mainwin); + + if (!nullmask) + return; + + g_object_unref(nullmask); + nullmask = NULL; + + gdk_window_set_hints(mainwin->window, 0, 0, + PLAYER_WIDTH, PLAYER_HEIGHT, + PLAYER_WIDTH, PLAYER_HEIGHT, + GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); + gtk_window_resize(GTK_WINDOW(mainwin), PLAYER_WIDTH, PLAYER_HEIGHT); + + if (cfg.player_x != -1 && cfg.player_y != -1) + gtk_window_move(GTK_WINDOW(mainwin), cfg.player_x, cfg.player_y); + + draw_main_window(TRUE); + + gtk_window_present(GTK_WINDOW(mainwin)); +} + +void +mainwin_real_hide(void) +{ + GdkGC *gc; + GdkColor pattern; + + check_set(mainwin_view_menu, "/Show Player", FALSE); + + if (cfg.player_shaded) + svis_clear_data(mainwin_svis); + + if (!cfg.show_wm_decorations) { + nullmask = gdk_pixmap_new(mainwin->window, 20, 20, 1); + gc = gdk_gc_new(nullmask); + pattern.pixel = 0; + gdk_gc_set_foreground(gc, &pattern); + gdk_draw_rectangle(nullmask, gc, TRUE, 0, 0, 20, 20); + gdk_gc_destroy(gc); + gtk_widget_shape_combine_mask(mainwin, nullmask, 0, 0); + + gdk_window_set_hints(mainwin->window, 0, 0, 0, 0, 0, 0, + GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); + gdk_window_resize(mainwin->window, 0, 0); + } + + gtk_widget_hide(mainwin); + + mainwin_vis_set_active_vis(MAINWIN_VIS_ACTIVE_PLAYLISTWIN); + cfg.player_visible = FALSE; +} + +static void +mainwin_songname_menu_callback(gpointer data, + guint action, + GtkWidget * item) +{ + GtkCheckMenuItem *check; + + switch (action) { + case MAINWIN_SONGNAME_FILEINFO: + playlist_fileinfo_current(); + break; + case MAINWIN_SONGNAME_JTF: + mainwin_jump_to_file(); + break; + case MAINWIN_SONGNAME_JTT: + mainwin_jump_to_time(); + break; + case MAINWIN_SONGNAME_SCROLL: + check = GTK_CHECK_MENU_ITEM(item); + mainwin_set_title_scroll(gtk_check_menu_item_get_active(check)); + break; + case MAINWIN_SONGNAME_STOPAFTERSONG: + check = GTK_CHECK_MENU_ITEM(item); + cfg.stopaftersong = gtk_check_menu_item_get_active(check); + check_set(mainwin_songname_menu, "/Stop After Current Song", cfg.stopaftersong); + check_set(mainwin_play_menu, "/Stop After Current Song", cfg.stopaftersong); + break; + } +} + +void +mainwin_set_stopaftersong(gboolean stop) +{ + cfg.stopaftersong = stop; + check_set(mainwin_songname_menu, "/Stop After Current Song", cfg.stopaftersong); +} + +static void +mainwin_play_menu_callback(gpointer data, + guint action, + GtkWidget * item) +{ + GtkCheckMenuItem *check; + + switch (action) { + case MAINWIN_OPT_SHUFFLE: + check = GTK_CHECK_MENU_ITEM(item); + cfg.shuffle = gtk_check_menu_item_get_active(check); + playlist_set_shuffle(cfg.shuffle); + tbutton_set_toggled(mainwin_shuffle, cfg.shuffle); + break; + case MAINWIN_OPT_REPEAT: + check = GTK_CHECK_MENU_ITEM(item); + cfg.repeat = gtk_check_menu_item_get_active(check); + tbutton_set_toggled(mainwin_repeat, cfg.repeat); + break; + case MAINWIN_OPT_NPA: + check = GTK_CHECK_MENU_ITEM(item); + cfg.no_playlist_advance = gtk_check_menu_item_get_active(check); + break; + } +} + + +static void +mainwin_view_menu_callback(gpointer data, + guint action, + GtkWidget * item) +{ + switch (action) { + case MAINWIN_OPT_TELAPSED: + set_timer_mode_menu_cb(TIMER_ELAPSED); + break; + case MAINWIN_OPT_TREMAINING: + set_timer_mode_menu_cb(TIMER_REMAINING); + break; + case MAINWIN_OPT_ALWAYS: + mainwin_menurow->mr_always_selected = GTK_CHECK_MENU_ITEM(item)->active; + cfg.always_on_top = mainwin_menurow->mr_always_selected; + widget_draw(WIDGET(mainwin_menurow)); + + if (starting_up == FALSE) + hint_set_always(cfg.always_on_top); + + break; + case MAINWIN_OPT_STICKY: + cfg.sticky = GTK_CHECK_MENU_ITEM(item)->active; + hint_set_sticky(cfg.sticky); + break; + case MAINWIN_OPT_WS: + mainwin_set_shade_menu_cb(GTK_CHECK_MENU_ITEM(item)->active); + break; + case MAINWIN_OPT_PWS: + playlistwin_set_shade(GTK_CHECK_MENU_ITEM(item)->active); + break; + case MAINWIN_OPT_EQWS: + equalizerwin_set_shade_menu_cb(GTK_CHECK_MENU_ITEM(item)->active); + break; + } +} + +void +mainwin_vis_menu_callback(gpointer data, + guint action, + GtkWidget * item) +{ + switch (action) { + case MAINWIN_VIS_ANALYZER: + case MAINWIN_VIS_SCOPE: + case MAINWIN_VIS_OFF: + mainwin_vis_set_type_menu_cb(action - MAINWIN_VIS_ANALYZER); + break; + case MAINWIN_VIS_ANALYZER_NORMAL: + case MAINWIN_VIS_ANALYZER_FIRE: + case MAINWIN_VIS_ANALYZER_VLINES: + mainwin_vis_set_analyzer_mode(action - MAINWIN_VIS_ANALYZER_NORMAL); + break; + case MAINWIN_VIS_ANALYZER_LINES: + case MAINWIN_VIS_ANALYZER_BARS: + mainwin_vis_set_analyzer_type(action - MAINWIN_VIS_ANALYZER_LINES); + break; + case MAINWIN_VIS_ANALYZER_PEAKS: + cfg.analyzer_peaks = GTK_CHECK_MENU_ITEM(item)->active; + break; + case MAINWIN_VIS_SCOPE_DOT: + case MAINWIN_VIS_SCOPE_LINE: + case MAINWIN_VIS_SCOPE_SOLID: + cfg.scope_mode = action - MAINWIN_VIS_SCOPE_DOT; + break; + case MAINWIN_VIS_VU_NORMAL: + case MAINWIN_VIS_VU_SMOOTH: + cfg.vu_mode = action - MAINWIN_VIS_VU_NORMAL; + break; + case MAINWIN_VIS_REFRESH_FULL: + case MAINWIN_VIS_REFRESH_HALF: + case MAINWIN_VIS_REFRESH_QUARTER: + case MAINWIN_VIS_REFRESH_EIGHTH: + mainwin_vis_set_refresh(action - MAINWIN_VIS_REFRESH_FULL); + break; + case MAINWIN_VIS_AFALLOFF_SLOWEST: + case MAINWIN_VIS_AFALLOFF_SLOW: + case MAINWIN_VIS_AFALLOFF_MEDIUM: + case MAINWIN_VIS_AFALLOFF_FAST: + case MAINWIN_VIS_AFALLOFF_FASTEST: + mainwin_vis_set_afalloff(action - MAINWIN_VIS_AFALLOFF_SLOWEST); + break; + case MAINWIN_VIS_PFALLOFF_SLOWEST: + case MAINWIN_VIS_PFALLOFF_SLOW: + case MAINWIN_VIS_PFALLOFF_MEDIUM: + case MAINWIN_VIS_PFALLOFF_FAST: + case MAINWIN_VIS_PFALLOFF_FASTEST: + mainwin_vis_set_pfalloff(action - MAINWIN_VIS_PFALLOFF_SLOWEST); + break; + } +} + +void +mainwin_general_menu_callback(gpointer data, + guint action, + GtkWidget * item) +{ + switch (action) { + case MAINWIN_GENERAL_PREFS: + show_prefs_window(); + break; + case MAINWIN_GENERAL_ABOUT: + show_about_window(); + break; + case MAINWIN_GENERAL_PLAYFILE: + util_run_filebrowser(NO_PLAY_BUTTON); + break; + case MAINWIN_GENERAL_PLAYCD: + play_medium(); + break; + case MAINWIN_GENERAL_ADDCD: + add_medium(); + break; + case MAINWIN_GENERAL_PLAYLOCATION: + mainwin_show_add_url_window(); + break; + case MAINWIN_GENERAL_FILEINFO: + playlist_fileinfo_current(); + 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(); + break; + case MAINWIN_GENERAL_PLAY: + mainwin_play_pushed(); + break; + case MAINWIN_GENERAL_PAUSE: + bmp_playback_pause(); + break; + case MAINWIN_GENERAL_STOP: + mainwin_stop_pushed(); + break; + case MAINWIN_GENERAL_NEXT: + playlist_next(); + break; + case MAINWIN_GENERAL_BACK5SEC: + if (bmp_playback_get_playing() + && playlist_get_current_length() != -1) + bmp_playback_seek_relative(-5); + break; + case MAINWIN_GENERAL_FWD5SEC: + if (bmp_playback_get_playing() + && playlist_get_current_length() != -1) + bmp_playback_seek_relative(5); + break; + case MAINWIN_GENERAL_START: + playlist_set_position(0); + break; + case MAINWIN_GENERAL_JTT: + mainwin_jump_to_time(); + break; + case MAINWIN_GENERAL_JTF: + mainwin_jump_to_file(); + break; + case MAINWIN_GENERAL_EXIT: + mainwin_quit_cb(); + break; + } +} + +static void +mainwin_mr_change(MenuRowItem i) +{ + switch (i) { + case MENUROW_NONE: + mainwin_set_info_text(); + break; + case MENUROW_OPTIONS: + mainwin_lock_info_text(_("OPTIONS MENU")); + break; + case MENUROW_ALWAYS: + if (mainwin_menurow->mr_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_DOUBLESIZE: + mainwin_lock_info_text(_("** DOUBLESIZE HAS BEEN REMOVED **")); + break; + case MENUROW_VISUALIZATION: + mainwin_lock_info_text(_("VISUALIZATION MENU")); + break; + } +} + +static void +mainwin_mr_release(MenuRowItem i) +{ + GdkModifierType modmask; + GtkWidget *widget; + gint x, y; + + switch (i) { + case MENUROW_OPTIONS: + gdk_window_get_pointer(NULL, &x, &y, &modmask); + util_item_factory_popup(mainwin_view_menu, x, y, 1, + GDK_CURRENT_TIME); + break; + case MENUROW_ALWAYS: + widget = + gtk_item_factory_get_widget(mainwin_view_menu, + "/Always On Top"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), + mainwin_menurow->mr_always_selected); + break; + case MENUROW_FILEINFOBOX: + playlist_fileinfo_current(); + break; + case MENUROW_DOUBLESIZE: + /* double size removed, do nothing */ + break; + case MENUROW_VISUALIZATION: + gdk_window_get_pointer(NULL, &x, &y, &modmask); + util_item_factory_popup(mainwin_vis_menu, x, y, 1, GDK_CURRENT_TIME); + break; + case MENUROW_NONE: + break; + } + mainwin_release_info_text(); +} + +static void +run_no_audiocd_dialog(void) +{ + const gchar *markup = + N_("No playable CD found.\n\n" + "No CD inserted, or inserted CD is not an audio CD.\n"); + + 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); +} + +static void +run_no_output_device_dialog(void) +{ + 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"); + + 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); +} + + +void +add_medium(void) +{ + GList *list, *node; + gchar *filename; + gchar *path; + ConfigDb *db; + + db = bmp_cfg_db_open(); + + bmp_cfg_db_get_string(db, "CDDA", "directory", &path); + bmp_cfg_db_close(db); + + if (!(list = input_scan_dir(path))) { + run_no_audiocd_dialog(); + return; + } + + for (node = list; node; node = g_list_next(node)) { + filename = g_build_filename(path, node->data, NULL); + playlist_add(filename); + g_free(filename); + g_free(node->data); + } + + g_free(path); + g_list_free(list); + +} + +void +play_medium(void) +{ + GList *list, *node; + gchar *filename; + gchar *path; + ConfigDb *db; + + db = bmp_cfg_db_open(); + bmp_cfg_db_get_string(db, "CDDA", "directory", &path); + bmp_cfg_db_close(db); + + if (!(list = input_scan_dir(path))) { + run_no_audiocd_dialog(); + return; + } + + playlist_clear(); + + for (node = list; node; node = g_list_next(node)) { + filename = g_build_filename(path, node->data, NULL); + playlist_add(filename); + g_free(filename); + g_free(node->data); + } + + g_free(path); + g_list_free(list); + + playlist_set_position(0); + bmp_playback_initiate(); +} + +void +read_volume(gint when) +{ + static gint pvl = 0, pvr = 0; + static gint times = VOLSET_DISP_TIMES; + static gboolean changing = FALSE; + + gint vl, vr, b, v; + + input_get_volume(&vl, &vr); + + switch (when) { + case VOLSET_STARTUP: + vl = CLAMP(vl, 0, 100); + vr = CLAMP(vr, 0, 100); + pvl = vl; + pvr = vr; + 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; + + balance = b; + mainwin_set_volume_slider(v); + equalizerwin_set_volume_slider(v); + mainwin_set_balance_slider(b); + equalizerwin_set_balance_slider(b); + return; + + case VOLSET_UPDATE: + if (vl == -1 || vr == -1) + return; + + if (setting_volume) { + pvl = vl; + pvr = vr; + return; + } + + if (pvr == vr && pvl == vl && changing) { + if (times < VOLSET_DISP_TIMES) + times++; + else { + mainwin_release_info_text(); + changing = FALSE; + } + } + else if (pvr != vr || pvl != vl) { + gchar *tmp; + + 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; + + if (MAX(vl, vr) != MAX(pvl, pvr)) + tmp = g_strdup_printf(_("VOLUME: %d%%"), v); + else { + if (vl > vr) { + tmp = g_strdup_printf(_("BALANCE: %d%% LEFT"), -b); + } + else if (vr == vl) + tmp = g_strdup_printf(_("BALANCE: CENTER")); + else { /* (vl < vr) */ + tmp = g_strdup_printf(_("BALANCE: %d%% RIGHT"), b); + } + } + mainwin_lock_info_text(tmp); + g_free(tmp); + + pvr = vr; + pvl = vl; + times = 0; + changing = TRUE; + mainwin_set_volume_slider(v); + equalizerwin_set_volume_slider(v); + + /* Don't change the balance slider if the volume has been + * set to zero. The balance can be anything, and our best + * guess is what is was before. */ + if (v > 0) { + balance = b; + mainwin_set_balance_slider(b); + equalizerwin_set_balance_slider(b); + } + } + break; + + case VOLUME_ADJUSTED: + pvl = vl; + pvr = vr; + break; + + case VOLUME_SET: + times = 0; + changing = TRUE; + pvl = vl; + pvr = vr; + break; + } +} + + +/* TODO: HAL! */ +gboolean +can_play_cd(void) +{ + GList *ilist; + + for (ilist = get_input_list(); ilist; ilist = g_list_next(ilist)) { + InputPlugin *ip = INPUT_PLUGIN(ilist->data); + + if (!g_ascii_strcasecmp(g_basename(ip->filename), + PLUGIN_FILENAME("cdaudio"))) { + return TRUE; + } + } + + return FALSE; +} + + +static void +set_timer_mode(TimerMode mode) +{ + if (mode == TIMER_ELAPSED) + check_set(mainwin_view_menu, "/Time Elapsed", TRUE); + else + check_set(mainwin_view_menu, "/Time Remaining", TRUE); +} + +static void +set_timer_mode_menu_cb(TimerMode mode) +{ + cfg.timer_mode = mode; +} + + +void +mainwin_setup_menus(void) +{ + set_timer_mode(cfg.timer_mode); + + /* View menu */ + + check_set(mainwin_view_menu, "/Always On Top", cfg.always_on_top); + check_set(mainwin_view_menu, "/Put on All Workspaces", cfg.sticky); + check_set(mainwin_view_menu, "/Roll up Player", cfg.player_shaded); + check_set(mainwin_view_menu, "/Roll up Playlist Editor", cfg.playlist_shaded); + check_set(mainwin_view_menu, "/Roll up Equalizer", cfg.equalizer_shaded); + + /* Songname menu */ + + check_set(mainwin_songname_menu, "/Autoscroll Songname", cfg.autoscroll); + check_set(mainwin_songname_menu, "/Stop After Current Song", cfg.stopaftersong); + + /* Playback menu */ + + check_set(mainwin_play_menu, "/Repeat", cfg.repeat); + check_set(mainwin_play_menu, "/Shuffle", cfg.shuffle); + check_set(mainwin_play_menu, "/No Playlist Advance", cfg.no_playlist_advance); + + /* Visualization menu */ + + check_set(mainwin_vis_menu, + mainwin_vis_menu_entries[MAINWIN_VIS_MENU_VIS_MODE + + cfg.vis_type].path, TRUE); + check_set(mainwin_vis_menu, + mainwin_vis_menu_entries[MAINWIN_VIS_MENU_ANALYZER_MODE + + cfg.analyzer_mode].path, TRUE); + check_set(mainwin_vis_menu, + mainwin_vis_menu_entries[MAINWIN_VIS_MENU_ANALYZER_TYPE + + cfg.analyzer_type].path, TRUE); + check_set(mainwin_vis_menu, + mainwin_vis_menu_entries[MAINWIN_VIS_MENU_ANALYZER_PEAKS]. + path, cfg.analyzer_peaks); + check_set(mainwin_vis_menu, + mainwin_vis_menu_entries[MAINWIN_VIS_MENU_SCOPE_MODE + + cfg.scope_mode].path, TRUE); + check_set(mainwin_vis_menu, + mainwin_vis_menu_entries[MAINWIN_VIS_MENU_WSHADEVU_MODE + + cfg.vu_mode].path, TRUE); + check_set(mainwin_vis_menu, + mainwin_vis_menu_entries[MAINWIN_VIS_MENU_REFRESH_RATE + + cfg.vis_refresh].path, TRUE); + check_set(mainwin_vis_menu, + mainwin_vis_menu_entries[MAINWIN_VIS_MENU_AFALLOFF + + cfg.analyzer_falloff].path, TRUE); + check_set(mainwin_vis_menu, + mainwin_vis_menu_entries[MAINWIN_VIS_MENU_PFALLOFF + + cfg.peaks_falloff].path, TRUE); +} + +static void +mainwin_create_widgets(void) +{ + mainwin_menubtn = + create_pbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 6, 3, 9, 9, + 0, 0, 0, 9, mainwin_menubtn_cb, SKIN_TITLEBAR); + mainwin_menubtn->pb_allow_draw = FALSE; + mainwin_minimize = + create_pbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 244, 3, 9, + 9, 9, 0, 9, 9, mainwin_minimize_cb, SKIN_TITLEBAR); + mainwin_minimize->pb_allow_draw = FALSE; + mainwin_shade = + create_pbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 254, 3, 9, + 9, 0, cfg.player_shaded ? 27 : 18, 9, + cfg.player_shaded ? 27 : 18, mainwin_shade_toggle, + SKIN_TITLEBAR); + mainwin_shade->pb_allow_draw = FALSE; + mainwin_close = + create_pbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 264, 3, 9, + 9, 18, 0, 18, 9, mainwin_quit_cb, SKIN_TITLEBAR); + mainwin_close->pb_allow_draw = FALSE; + + mainwin_rew = + create_pbutton_ex(&mainwin_wlist, mainwin_bg, mainwin_gc, 16, 88, 23, + 18, 0, 0, 0, 18, mainwin_rev_pushed, mainwin_rev_release, + SKIN_CBUTTONS, SKIN_CBUTTONS); + mainwin_play = + create_pbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 39, 88, 23, + 18, 23, 0, 23, 18, mainwin_play_pushed, SKIN_CBUTTONS); + mainwin_pause = + create_pbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 62, 88, 23, + 18, 46, 0, 46, 18, bmp_playback_pause, SKIN_CBUTTONS); + mainwin_stop = + create_pbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 85, 88, 23, + 18, 69, 0, 69, 18, mainwin_stop_pushed, SKIN_CBUTTONS); +#if 0 + mainwin_fwd = + create_pbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 108, 88, 22, + 18, 92, 0, 92, 18, playlist_next, SKIN_CBUTTONS); +#endif + mainwin_fwd = + create_pbutton_ex(&mainwin_wlist, mainwin_bg, mainwin_gc, 108, 88, 22, + 18, 92, 0, 92, 18, mainwin_fwd_pushed, mainwin_fwd_release, + SKIN_CBUTTONS, SKIN_CBUTTONS); + + mainwin_eject = + create_pbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 136, 89, 22, + 16, 114, 0, 114, 16, mainwin_eject_pushed, + SKIN_CBUTTONS); + + mainwin_srew = + create_sbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 169, 4, 8, + 7, playlist_prev); + mainwin_splay = + create_sbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 177, 4, 10, + 7, mainwin_play_pushed); + mainwin_spause = + create_sbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 187, 4, 10, + 7, bmp_playback_pause); + mainwin_sstop = + create_sbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 197, 4, 9, + 7, mainwin_stop_pushed); + mainwin_sfwd = + create_sbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 206, 4, 8, + 7, playlist_next); + mainwin_seject = + create_sbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 216, 4, 9, + 7, mainwin_eject_pushed); + + mainwin_shuffle = + create_tbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 164, 89, 46, + 15, 28, 0, 28, 15, 28, 30, 28, 45, + mainwin_shuffle_pushed, SKIN_SHUFREP); + + mainwin_repeat = + create_tbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 210, 89, 28, + 15, 0, 0, 0, 15, 0, 30, 0, 45, + mainwin_repeat_pushed, SKIN_SHUFREP); + + mainwin_eq = + create_tbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 219, 58, 23, + 12, 0, 61, 46, 61, 0, 73, 46, 73, equalizerwin_show, + SKIN_SHUFREP); + tbutton_set_toggled(mainwin_eq, cfg.equalizer_visible); + mainwin_pl = + create_tbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 242, 58, 23, + 12, 23, 61, 69, 61, 23, 73, 69, 73, + mainwin_pl_pushed, SKIN_SHUFREP); + tbutton_set_toggled(mainwin_pl, cfg.playlist_visible); + + mainwin_info = + create_textbox(&mainwin_wlist, mainwin_bg, mainwin_gc, 112, 27, + 153, 1, SKIN_TEXT); + textbox_set_scroll(mainwin_info, cfg.autoscroll); + textbox_set_xfont(mainwin_info, cfg.mainwin_use_xfont, cfg.mainwin_font); + + mainwin_othertext = + create_textbox(&mainwin_wlist, mainwin_bg, mainwin_gc, 112, 43, + 153, 1, SKIN_TEXT); + + mainwin_rate_text = + create_textbox(&mainwin_wlist, mainwin_bg, mainwin_gc, 111, 43, 15, + 0, SKIN_TEXT); + mainwin_freq_text = + create_textbox(&mainwin_wlist, mainwin_bg, mainwin_gc, 156, 43, 10, + 0, SKIN_TEXT); + + mainwin_menurow = + create_menurow(&mainwin_wlist, mainwin_bg, mainwin_gc, 10, 22, 304, + 0, 304, 44, mainwin_mr_change, mainwin_mr_release, + SKIN_TITLEBAR); + mainwin_menurow->mr_doublesize_selected = FALSE; + mainwin_menurow->mr_always_selected = cfg.always_on_top; + + mainwin_volume = + create_hslider(&mainwin_wlist, mainwin_bg, mainwin_gc, 107, 57, 68, + 13, 15, 422, 0, 422, 14, 11, 15, 0, 0, 51, + mainwin_volume_frame_cb, mainwin_volume_motion_cb, + mainwin_volume_release_cb, SKIN_VOLUME); + mainwin_balance = + create_hslider(&mainwin_wlist, mainwin_bg, mainwin_gc, 177, 57, 38, + 13, 15, 422, 0, 422, 14, 11, 15, 9, 0, 24, + mainwin_balance_frame_cb, mainwin_balance_motion_cb, + mainwin_balance_release_cb, SKIN_BALANCE); + + mainwin_monostereo = + create_monostereo(&mainwin_wlist, mainwin_bg, mainwin_gc, 212, 41, + SKIN_MONOSTEREO); + + mainwin_playstatus = + create_playstatus(&mainwin_wlist, mainwin_bg, mainwin_gc, 24, 28); + + mainwin_minus_num = + create_number(&mainwin_wlist, mainwin_bg, mainwin_gc, 36, 26, + SKIN_NUMBERS); + widget_hide(WIDGET(mainwin_minus_num)); + mainwin_10min_num = + create_number(&mainwin_wlist, mainwin_bg, mainwin_gc, 48, 26, + SKIN_NUMBERS); + widget_hide(WIDGET(mainwin_10min_num)); + + mainwin_min_num = + create_number(&mainwin_wlist, mainwin_bg, mainwin_gc, 60, 26, + SKIN_NUMBERS); + widget_hide(WIDGET(mainwin_min_num)); + + mainwin_10sec_num = + create_number(&mainwin_wlist, mainwin_bg, mainwin_gc, 78, 26, + SKIN_NUMBERS); + widget_hide(WIDGET(mainwin_10sec_num)); + + mainwin_sec_num = + create_number(&mainwin_wlist, mainwin_bg, mainwin_gc, 90, 26, + SKIN_NUMBERS); + widget_hide(WIDGET(mainwin_sec_num)); + + mainwin_about = + create_sbutton(&mainwin_wlist, mainwin_bg, mainwin_gc, 247, 83, 20, + 25, show_about_window); + + mainwin_vis = + create_vis(&mainwin_wlist, mainwin_bg, mainwin->window, mainwin_gc, + 24, 43, 76); + mainwin_svis = create_svis(&mainwin_wlist, mainwin_bg, mainwin_gc, 79, 5); + active_vis = mainwin_vis; + + mainwin_position = + create_hslider(&mainwin_wlist, mainwin_bg, mainwin_gc, 16, 72, 248, + 10, 248, 0, 278, 0, 29, 10, 10, 0, 0, 219, NULL, + mainwin_position_motion_cb, + mainwin_position_release_cb, SKIN_POSBAR); + widget_hide(WIDGET(mainwin_position)); + + mainwin_sposition = + create_hslider(&mainwin_wlist, mainwin_bg, mainwin_gc, 226, 4, 17, + 7, 17, 36, 17, 36, 3, 7, 36, 0, 1, 13, + mainwin_spos_frame_cb, mainwin_spos_motion_cb, + mainwin_spos_release_cb, SKIN_TITLEBAR); + widget_hide(WIDGET(mainwin_sposition)); + + mainwin_stime_min = + create_textbox(&mainwin_wlist, mainwin_bg, mainwin_gc, 130, 4, 15, + FALSE, SKIN_TEXT); + mainwin_stime_sec = + create_textbox(&mainwin_wlist, mainwin_bg, mainwin_gc, 147, 4, 10, + FALSE, SKIN_TEXT); + + if (!cfg.player_shaded) { + widget_hide(WIDGET(mainwin_svis)); + widget_hide(WIDGET(mainwin_srew)); + widget_hide(WIDGET(mainwin_splay)); + widget_hide(WIDGET(mainwin_spause)); + widget_hide(WIDGET(mainwin_sstop)); + widget_hide(WIDGET(mainwin_sfwd)); + widget_hide(WIDGET(mainwin_seject)); + widget_hide(WIDGET(mainwin_stime_min)); + widget_hide(WIDGET(mainwin_stime_sec)); + } + + err = gtk_message_dialog_new(GTK_WINDOW(mainwin), GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,"Error in Audacious."); + + + gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER); + /* Dang well better set an error message or you'll see this */ + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(err), + "Boo! Bad stuff! Booga Booga!"); + +} + +static void +mainwin_create_window(void) +{ + gint width, height; + + mainwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); + 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 = MAINWIN_WIDTH; + height = cfg.player_shaded ? MAINWIN_SHADED_HEIGHT : MAINWIN_HEIGHT; + + gtk_widget_set_size_request(mainwin, width, height); + gtk_widget_set_app_paintable(mainwin, TRUE); + + dock_window_list = dock_window_set_decorated(dock_window_list, + GTK_WINDOW(mainwin), + 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_add_events(mainwin, + 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); + gtk_widget_realize(mainwin); + + util_set_cursor(mainwin); + + 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); + g_signal_connect(mainwin, "motion_notify_event", + G_CALLBACK(mainwin_motion), NULL); + g_signal_connect_after(mainwin, "focus_in_event", + G_CALLBACK(mainwin_focus_in), NULL); + g_signal_connect_after(mainwin, "focus_out_event", + G_CALLBACK(mainwin_focus_out), NULL); + g_signal_connect(mainwin, "configure_event", + G_CALLBACK(mainwin_configure), NULL); + g_signal_connect(mainwin, "style_set", + G_CALLBACK(mainwin_set_back_pixmap), NULL); + + bmp_drag_dest_set(mainwin); + + g_signal_connect(mainwin, "key_press_event", + G_CALLBACK(mainwin_keypress), NULL); +} + +static void +mainwin_create_menus(void) +{ + mainwin_general_menu = create_menu(mainwin_general_menu_entries, + mainwin_general_menu_entries_num, + mainwin_accel); + + mainwin_play_menu = create_menu(mainwin_playback_menu_entries, + mainwin_playback_menu_entries_num, + mainwin_accel); + + mainwin_view_menu = create_menu(mainwin_view_menu_entries, + mainwin_view_menu_entries_num, + mainwin_accel); + + mainwin_songname_menu = create_menu(mainwin_songname_menu_entries, + mainwin_songname_menu_entries_num, + mainwin_accel); + + mainwin_add_menu = create_menu(mainwin_add_menu_entries, + mainwin_add_menu_entries_num, + mainwin_accel); + + mainwin_vis_menu = create_menu(mainwin_vis_menu_entries, + mainwin_vis_menu_entries_num, + mainwin_accel); + + make_submenu(mainwin_general_menu, "/View", mainwin_view_menu); + make_submenu(mainwin_general_menu, "/Playback", mainwin_play_menu); + make_submenu(mainwin_general_menu, "/Visualization", mainwin_vis_menu); + + gtk_window_add_accel_group(GTK_WINDOW(mainwin), mainwin_accel); +} + +void +mainwin_create(void) +{ + mainwin_create_window(); + + mainwin_accel = gtk_accel_group_new(); + mainwin_create_menus(); + + mainwin_gc = gdk_gc_new(mainwin->window); + mainwin_bg = gdk_pixmap_new(mainwin->window, + MAINWIN_WIDTH, MAINWIN_HEIGHT, -1); + mainwin_set_back_pixmap(); + mainwin_create_widgets(); + + vis_set_window(mainwin_vis, mainwin->window); +} + +void +mainwin_attach_idle_func(void) +{ + mainwin_timeout_id = g_timeout_add(MAINWIN_UPDATE_INTERVAL, + mainwin_idle_func, NULL); +} + +static void +idle_func_update_song_info(gint time) +{ + gint length, t; + gchar stime_prefix; + + length = playlist_get_current_length(); + if (bmp_playback_get_playing()) + playlistwin_set_time(time, length, cfg.timer_mode); + else + playlistwin_hide_timer(); + input_update_vis(time); + + if (cfg.timer_mode == TIMER_REMAINING) { + if (length != -1) { + number_set_number(mainwin_minus_num, 11); + t = length - time; + stime_prefix = '-'; + } + else { + number_set_number(mainwin_minus_num, 10); + t = time; + stime_prefix = ' '; + } + } + else { + 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; + number_set_number(mainwin_10min_num, t / 600); + number_set_number(mainwin_min_num, (t / 60) % 10); + number_set_number(mainwin_10sec_num, (t / 10) % 6); + number_set_number(mainwin_sec_num, t % 10); + + if (!mainwin_sposition->hs_pressed) { + gchar *time_str; + + time_str = g_strdup_printf("%c%2.2d", stime_prefix, t / 60); + textbox_set_text(mainwin_stime_min, time_str); + g_free(time_str); + + time_str = g_strdup_printf("%2.2d", t % 60); + textbox_set_text(mainwin_stime_sec, time_str); + g_free(time_str); + } + + time /= 1000; + length /= 1000; + if (length > 0) { + if (time > length) { + hslider_set_position(mainwin_position, 219); + hslider_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) { + hslider_set_position(mainwin_position, (time * 219) / length); + hslider_set_position(mainwin_sposition, + ((time * 12) / length) + 1); + } + } + else { + hslider_set_position(mainwin_position, 0); + hslider_set_position(mainwin_sposition, 1); + } +} + +static gboolean +mainwin_idle_func(gpointer data) +{ + static gint count = 0; + gint time = 0; + + /* run audcore events, then run our own. --nenolod */ + switch((time = audcore_generic_events())) + { + case -2: + /* no usable output device */ + GDK_THREADS_ENTER(); + run_no_output_device_dialog(); + mainwin_stop_pushed(); + GDK_THREADS_LEAVE(); + ev_waiting = FALSE; + break; + + default: + idle_func_update_song_info(time); + /* nothing at this time */ + } + + GDK_THREADS_ENTER(); + + if (bmp_playback_get_playing()) + vis_playback_start(); + else + vis_playback_stop(); + + draw_main_window(mainwin_force_redraw); + + if (!count) { + read_volume(VOLSET_UPDATE); + count = 10; + } + else + count--; + + mainwin_force_redraw = FALSE; + draw_playlist_window(FALSE); + draw_equalizer_window(FALSE); + + if (mainwin_title_text) { + G_LOCK(mainwin_title); + gtk_window_set_title(GTK_WINDOW(mainwin), mainwin_title_text); + g_free(mainwin_title_text); + mainwin_title_text = NULL; + G_UNLOCK(mainwin_title); + + mainwin_set_info_text(); + playlistwin_update_list(); + } + + /* 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; + + hslider_set_position( mainwin_position , np ); + mainwin_position_motion_cb( np ); + } + } + + GDK_THREADS_LEAVE(); + + /* + if (seek_state == MAINWIN_SEEK_REV) + bmp_playback_seek(CLAMP(bmp_playback_get_time() - 1000, 0, + playlist_get_current_length()) / 1000); + else if (seek_state == MAINWIN_SEEK_FWD) + bmp_playback_seek(CLAMP(bmp_playback_get_time() + 1000, 0, + playlist_get_current_length()) / 1000); + */ + + return TRUE; +} diff -r 3d3b60e66491 -r 1a525bd78cf0 Plugins/UserInterface/wa2gui/mainwin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/UserInterface/wa2gui/mainwin.h Thu Sep 07 19:57:27 2006 -0700 @@ -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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MAINWIN_H +#define MAINWIN_H + +#include + +#include "widgets/widgetcore.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_HEIGHT MAINWIN_TITLEBAR_HEIGHT + +#define MAINWIN_UPDATE_INTERVAL 10 + +#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_PLAYCD, + MAINWIN_GENERAL_EXIT, + + MAINWIN_GENERAL_ADDCD, + + 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 +}; + +extern GtkWidget *mainwin; +extern GtkWidget *err; +extern GdkGC *mainwin_gc; + +extern GtkAccelGroup *mainwin_accel; + +extern gboolean mainwin_moving; +extern gboolean mainwin_focus; + +extern GtkWidget *mainwin_jtf; + +extern GtkItemFactory *mainwin_general_menu; +extern GtkItemFactory *mainwin_vis_menu; +extern GtkItemFactory *mainwin_play_menu, *mainwin_view_menu; + +extern TextBox *mainwin_stime_min, *mainwin_stime_sec; +extern TextBox *mainwin_info; +extern TButton *mainwin_shuffle, *mainwin_repeat, *mainwin_eq, *mainwin_pl; + +extern Vis *active_vis; +extern Vis *mainwin_vis; +extern SVis *mainwin_svis; + +extern PlayStatus *mainwin_playstatus; + +extern Number *mainwin_minus_num, *mainwin_10min_num, *mainwin_min_num; +extern Number *mainwin_10sec_num, *mainwin_sec_num; + +extern HSlider *mainwin_sposition; + +void mainwin_create(void); +void read_volume(gint when); +void play_medium(void); +void add_medium(void); + +void draw_main_window(gboolean); + +void mainwin_quit_cb(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_set_back_pixmap(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_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_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); + +void mainwin_attach_idle_func(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); + +void mainwin_jump_to_file(void); +void mainwin_jump_to_time(void); + +void mainwin_ewmh_activate(void); + +/* FIXME: placed here for now */ +void playback_get_sample_params(gint * bitrate, + gint * frequency, + gint * numchannels); + +#endif diff -r 3d3b60e66491 -r 1a525bd78cf0 Plugins/UserInterface/wa2gui/playlist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/UserInterface/wa2gui/playlist.c Thu Sep 07 19:57:27 2006 -0700 @@ -0,0 +1,2029 @@ +/* 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "ui_playlist.h" + +#include +#include +#include +#include +#include +#include + +#include "platform/smartinclude.h" + +#include +#include + +#include "libaudacious/util.h" + +#include "dnd.h" +#include "dock.h" +#include "equalizer.h" +#include "hints.h" +#include "input.h" +#include "main.h" +#include "mainwin.h" +#include "playback.h" +#include "playlist.h" +#include "playlist_container.h" +#include "util.h" + +#include "pixmaps.h" +#include "images/audacious_playlist.xpm" + + +#define ITEM_SEPARATOR {"/-", NULL, NULL, 0, "", NULL} + + +enum { + ADD_URL, ADD_DIR, ADD_FILES, + SUB_MISC, SUB_ALL, SUB_CROP, SUB_SELECTED, + SUB_DUPLICATE_BYTITLE, SUB_DUPLICATE_BYFILENAME, SUB_DUPLICATE_BYPATH, + SEL_INV, SEL_ZERO, SEL_ALL, + MISC_SORT, MISC_FILEINFO, MISC_MISCOPTS, + PLIST_NEW, PLIST_SAVE_AS, PLIST_LOAD, + SEL_LOOKUP, CLOSE_PL_WINDOW, MOVE_UP, PLIST_SAVE, + MISC_QUEUE, PLIST_CQUEUE, PLIST_JTF, PLIST_JTT, + PLAYLISTWIN_REMOVE_DEAD_FILES, + PLAYLISTWIN_REFRESH, PLIST_DEFAULTSAVE, MISC_FILEPOPUP +}; + +enum { + PLAYLISTWIN_SORT_BYTITLE, PLAYLISTWIN_SORT_BYFILENAME, + PLAYLISTWIN_SORT_BYPATH, PLAYLISTWIN_SORT_BYDATE, + PLAYLISTWIN_SORT_BYARTIST, PLAYLISTWIN_SORT_SEL_BYARTIST, + PLAYLISTWIN_SORT_SEL_BYTITLE, PLAYLISTWIN_SORT_SEL_BYFILENAME, + PLAYLISTWIN_SORT_SEL_BYPATH, PLAYLISTWIN_SORT_SEL_BYDATE, + PLAYLISTWIN_SORT_RANDOMIZE, PLAYLISTWIN_SORT_REVERSE, + PLAYLISTWIN_SORT_BYTRACK, PLAYLISTWIN_SORT_SEL_BYTRACK, + PLAYLISTWIN_SORT_BYPLAYLIST, PLAYLISTWIN_SORT_SEL_BYPLAYLIST +}; + +GtkWidget *playlistwin; + +PlayList_List *playlistwin_list = NULL; +PButton *playlistwin_shade, *playlistwin_close; + +static gboolean playlistwin_resizing = FALSE; + +static GtkItemFactory *playlistwin_popup_menu; +static GtkItemFactory *pladd_menu, *pldel_menu; +static GtkItemFactory *plsel_menu, *plsort_menu; +static GtkItemFactory *pllist_menu; + +static GdkPixmap *playlistwin_bg; +static GdkBitmap *playlistwin_mask = NULL; +static GdkGC *playlistwin_gc; + +static GtkAccelGroup *playlistwin_accel; + +static gboolean playlistwin_hint_flag = FALSE; + +static PlaylistSlider *playlistwin_slider = NULL; +static TextBox *playlistwin_time_min, *playlistwin_time_sec; +static TextBox *playlistwin_info, *playlistwin_sinfo; +static SButton *playlistwin_srew, *playlistwin_splay; +static SButton *playlistwin_spause, *playlistwin_sstop; +static SButton *playlistwin_sfwd, *playlistwin_seject; +static SButton *playlistwin_sscroll_up, *playlistwin_sscroll_down; + +static GList *playlistwin_wlist = NULL; + +static void plsort_menu_callback(gpointer cb_data, guint action, + GtkWidget * w); +static void playlistwin_sub_menu_callback(gpointer cb_data, guint action, + GtkWidget * w); +static void playlistwin_popup_menu_callback(gpointer cb_data, guint action, + GtkWidget * w); + +static GtkItemFactoryEntry playlistwin_popup_menu_entries[] = { + {N_("/View Track Details"), NULL, + playlistwin_popup_menu_callback, + MISC_FILEINFO, "", my_pixbuf}, + + {N_("/Show Popup Info"), NULL, + playlistwin_popup_menu_callback, + MISC_FILEPOPUP, "", NULL}, + + ITEM_SEPARATOR, + + {N_("/Remove Selected"), "Delete", + playlistwin_sub_menu_callback, + SUB_SELECTED, "", GTK_STOCK_REMOVE}, + + {N_("/Remove Unselected"), NULL, + playlistwin_sub_menu_callback, + SUB_CROP, "", GTK_STOCK_REMOVE}, + + {N_("/Remove All"), NULL, + playlistwin_sub_menu_callback, + SUB_ALL, "", GTK_STOCK_CLEAR}, + + ITEM_SEPARATOR, + + {N_("/Queue Toggle"), "q", + playlistwin_popup_menu_callback, + MISC_QUEUE, "", queuetoggle_pixbuf}, +}; + +static GtkItemFactoryEntry pladd_menu_entries[] = { + {N_("/Add CD..."), "c", + mainwin_general_menu_callback, + MAINWIN_GENERAL_ADDCD, "", GTK_STOCK_CDROM}, + + {N_("/Add Internet Address..."), "h", + mainwin_general_menu_callback, + MAINWIN_GENERAL_PLAYLOCATION, "", GTK_STOCK_NETWORK}, + + {N_("/Add Files..."), "f", + mainwin_general_menu_callback, + MAINWIN_GENERAL_PLAYFILE, "", GTK_STOCK_ADD}, +}; + +static GtkItemFactoryEntry pldel_menu_entries[] = { + {N_("/Clear Queue"), "Q", + playlistwin_popup_menu_callback, + PLIST_CQUEUE, "", GTK_STOCK_CANCEL}, + + ITEM_SEPARATOR, + + {N_("/Remove Unavailable Files"), NULL, + playlistwin_sub_menu_callback, + PLAYLISTWIN_REMOVE_DEAD_FILES, "", removeunavail_pixbuf}, + + {N_("/Remove Duplicates"), NULL, NULL, 0, "", NULL}, + {N_("/Remove Duplicates/By Title"), NULL, + playlistwin_sub_menu_callback, + SUB_DUPLICATE_BYTITLE, "", removedups_pixbuf}, + {N_("/Remove Duplicates/By Filename"), NULL, + playlistwin_sub_menu_callback, + SUB_DUPLICATE_BYFILENAME, "", removedups_pixbuf}, + {N_("/Remove Duplicates/By Path + Filename"), NULL, + playlistwin_sub_menu_callback, + SUB_DUPLICATE_BYPATH, "", removedups_pixbuf}, + + ITEM_SEPARATOR, + + {N_("/Remove All"), NULL, + playlistwin_sub_menu_callback, + SUB_ALL, "", GTK_STOCK_CLEAR}, + + {N_("/Remove Unselected"), NULL, + playlistwin_sub_menu_callback, + SUB_CROP, "", GTK_STOCK_REMOVE}, + + {N_("/Remove Selected"), "Delete", + playlistwin_sub_menu_callback, + SUB_SELECTED, "", GTK_STOCK_REMOVE} +}; + +static GtkItemFactoryEntry pllist_menu_entries[] = { + {N_("/New List"), "N", + playlistwin_sub_menu_callback, + PLIST_NEW, "", GTK_STOCK_NEW}, + + ITEM_SEPARATOR, + + {N_("/Load List"), "o", + playlistwin_sub_menu_callback, + PLIST_LOAD, "", GTK_STOCK_OPEN}, + + {N_("/Save List"), "S", + playlistwin_sub_menu_callback, + PLIST_SAVE, "", GTK_STOCK_SAVE}, + + {N_("/Save Default List"), "S", + playlistwin_sub_menu_callback, + PLIST_DEFAULTSAVE, "", GTK_STOCK_SAVE}, + + ITEM_SEPARATOR, + + {N_("/Update View"), "F5", + playlistwin_sub_menu_callback, + PLAYLISTWIN_REFRESH, "", GTK_STOCK_REFRESH} +}; + +static GtkItemFactoryEntry plsel_menu_entries[] = { + {N_("/Invert Selection"), NULL, + playlistwin_sub_menu_callback, + SEL_INV, "", selectinvert_pixbuf}, + + ITEM_SEPARATOR, + + {N_("/Select None"),"A", + playlistwin_sub_menu_callback, + SEL_ZERO, "", selectnone_pixbuf}, + + {N_("/Select All"), "A", + playlistwin_sub_menu_callback, + SEL_ALL, "", selectall_pixbuf}, +}; + +static GtkItemFactoryEntry plsort_menu_entries[] = { + {N_("/Randomize List"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_RANDOMIZE, "", randomizepl_pixbuf}, + {N_("/Reverse List"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_REVERSE, "", invertpl_pixbuf}, + ITEM_SEPARATOR, + {N_("/Sort List"), NULL, NULL, 0, "", NULL}, + {N_("/Sort List/By Title"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_BYTITLE, "", sortbytitle_pixbuf}, + {N_("/Sort List/By Artist"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_BYARTIST, "", sortbytitle_pixbuf}, + {N_("/Sort List/By Filename"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_BYFILENAME, "", sortbyfilename_pixbuf}, + {N_("/Sort List/By Path + Filename"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_BYPATH, "", sortbypathfile_pixbuf}, + {N_("/Sort List/By Date"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_BYDATE, "", sortbydate_pixbuf}, + {N_("/Sort List/By Track Number"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_BYTRACK, "", sortbytitle_pixbuf}, + {N_("/Sort List/By Playlist Entry"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_BYPLAYLIST, "", sortbytitle_pixbuf}, + {N_("/Sort Selection"), NULL, NULL, 0, "", NULL}, + {N_("/Sort Selection/By Title"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_SEL_BYTITLE, "", sortbytitle_pixbuf}, + {N_("/Sort Selection/By Artist"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_SEL_BYARTIST, "", sortbytitle_pixbuf}, + {N_("/Sort Selection/By Filename"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_SEL_BYFILENAME, "", sortbyfilename_pixbuf}, + {N_("/Sort Selection/By Path + Filename"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_SEL_BYPATH, "", sortbypathfile_pixbuf}, + {N_("/Sort Selection/By Date"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_SEL_BYDATE, "", sortbydate_pixbuf}, + {N_("/Sort Selection/By Track Number"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_SEL_BYTRACK, "", sortbytitle_pixbuf}, + {N_("/Sort Selection/By Playlist Entry"), NULL, plsort_menu_callback, + PLAYLISTWIN_SORT_SEL_BYPLAYLIST, "", sortbytitle_pixbuf} +}; + + +static void playlistwin_draw_frame(void); + + +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; + gint height = cfg.playlist_height; + return 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(); +} + +void +playlistwin_get_size(gint * width, gint * height) +{ + if (width) + *width = playlistwin_get_width(); + + if (height) + *height = playlistwin_get_height(); +} + +static void +playlistwin_update_info(void) +{ + gchar *text, *sel_text, *tot_text; + gulong selection, total; + gboolean selection_more, total_more; + + playlist_get_total_time(&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); + textbox_set_text(playlistwin_info, text); + g_free(text); + g_free(tot_text); + g_free(sel_text); +} + +static void +playlistwin_update_sinfo(void) +{ + gchar *posstr, *timestr, *title, *info, *dots; + gint pos, time; + guint max_len; + + pos = playlist_get_position(); + title = playlist_get_songtitle(pos); + time = playlist_get_songtime(pos); + + if (!title) { + textbox_set_text(playlistwin_sinfo, ""); + return; + } + + if (cfg.show_numbers_in_pl) + posstr = g_strdup_printf("%d. ", pos + 1); + else + posstr = g_strdup(""); + + max_len = (playlistwin_get_width() - 35) / 5 - strlen(posstr); + + if (time != -1) { + timestr = g_strdup_printf(" %d:%-2.2d", time / 60000, + (time / 1000) % 60); + max_len -= strlen(timestr); + } + else + timestr = g_strdup(""); + + convert_title_text(title); + + if (strlen(title) > max_len) { + max_len -= 1; + dots = "\r"; + /* textbox.c interprets \r as the ellipsis character, as there + is none in ASCII. */ + } + else + dots = ""; + + info = g_strdup_printf("%s%-*.*s%s%s", posstr, max_len, max_len, + title, dots, timestr); + g_free(posstr); + g_free(title); + g_free(timestr); + + textbox_set_text(playlistwin_sinfo, info); + g_free(info); +} + +gboolean +playlistwin_item_visible(gint index) +{ + if (index >= playlistwin_list->pl_first + && index < + (playlistwin_list->pl_first + playlistwin_list->pl_num_visible)) + return TRUE; + return FALSE; +} + +gint +playlistwin_get_toprow(void) +{ + if (playlistwin_list) + return (playlistwin_list->pl_first); + return (-1); +} + +void +playlistwin_set_toprow(gint toprow) +{ + if (playlistwin_list) + playlistwin_list->pl_first = toprow; + playlistwin_update_list(); +} + +void +playlistwin_update_list(void) +{ + g_return_if_fail(playlistwin_list != NULL); + + widget_draw(WIDGET(playlistwin_list)); + widget_draw(WIDGET(playlistwin_slider)); + playlistwin_update_info(); + playlistwin_update_sinfo(); + /* mainwin_update_jtf(); */ +} + +#if 0 +static void +playlistwin_redraw_list(void) +{ + g_return_if_fail(playlistwin_list != NULL); + + draw_widget(playlistwin_list); + draw_widget(playlistwin_slider); +} +#endif + +static void +playlistwin_set_mask(void) +{ + GdkGC *gc; + GdkColor pattern; + + if (playlistwin_mask) + g_object_unref(playlistwin_mask); + + playlistwin_mask = + gdk_pixmap_new(playlistwin->window, playlistwin_get_width(), + playlistwin_get_height(), 1); + gc = gdk_gc_new(playlistwin_mask); + pattern.pixel = 1; + gdk_gc_set_foreground(gc, &pattern); + gdk_draw_rectangle(playlistwin_mask, gc, TRUE, 0, 0, + playlistwin_get_width(), playlistwin_get_height()); + gdk_gc_destroy(gc); + + gtk_widget_shape_combine_mask(playlistwin, playlistwin_mask, 0, 0); +} + +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_shade(gboolean shaded) +{ + cfg.playlist_shaded = shaded; + + if (shaded) { + widget_show(WIDGET(playlistwin_sinfo)); + playlistwin_shade->pb_nx = 128; + playlistwin_shade->pb_ny = 45; + playlistwin_shade->pb_px = 150; + playlistwin_shade->pb_py = 42; + playlistwin_close->pb_nx = 138; + playlistwin_close->pb_ny = 45; + } + else { + widget_hide(WIDGET(playlistwin_sinfo)); + playlistwin_shade->pb_nx = 157; + playlistwin_shade->pb_ny = 3; + playlistwin_shade->pb_px = 62; + playlistwin_shade->pb_py = 42; + playlistwin_close->pb_nx = 167; + playlistwin_close->pb_ny = 3; + } + + dock_shade(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()); + + playlistwin_set_mask(); + + widget_draw(WIDGET(playlistwin_list)); + widget_draw(WIDGET(playlistwin_slider)); + + draw_playlist_window(TRUE); +} + +static void +playlistwin_set_shade_menu(gboolean shaded) +{ + GtkWidget *item; + + item = gtk_item_factory_get_widget(mainwin_view_menu, + "/Roll up Playlist Editor"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), shaded); + + playlistwin_set_shade(shaded); +} + +void +playlistwin_shade_toggle(void) +{ + playlistwin_set_shade_menu(!cfg.playlist_shaded); +} + +static void +playlistwin_release(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + if (event->button == 3) + return; + + gdk_pointer_ungrab(GDK_CURRENT_TIME); + playlistwin_resizing = FALSE; + gdk_flush(); + + if (dock_is_moving(GTK_WINDOW(playlistwin))) + { + dock_move_release(GTK_WINDOW(playlistwin)); + + if (cfg.playlist_transparent) + playlistwin_update_list(); + } + else + { + handle_release_cb(playlistwin_wlist, widget, event); + draw_playlist_window(FALSE); + } +} + +void +playlistwin_scroll(gint num) +{ + playlistwin_list->pl_first += num; + playlistwin_update_list(); +} + +void +playlistwin_scroll_up_pushed(void) +{ + playlistwin_list->pl_first -= 3; + playlistwin_update_list(); +} + +void +playlistwin_scroll_down_pushed(void) +{ + playlistwin_list->pl_first += 3; + playlistwin_update_list(); +} + +static void +playlistwin_select_all(void) +{ + playlist_select_all(TRUE); + playlistwin_list->pl_prev_selected = 0; + playlistwin_list->pl_prev_min = 0; + playlistwin_list->pl_prev_max = playlist_get_length() - 1; + playlistwin_update_list(); +} + +static void +playlistwin_select_none(void) +{ + playlist_select_all(FALSE); + playlistwin_list->pl_prev_selected = -1; + playlistwin_list->pl_prev_min = -1; + playlistwin_update_list(); +} + +static void +playlistwin_inverse_selection(void) +{ + playlist_select_invert_all(); + playlistwin_list->pl_prev_selected = -1; + playlistwin_list->pl_prev_min = -1; + playlistwin_update_list(); +} + +static void +playlistwin_resize(gint width, gint height) +{ + gboolean redraw; + + g_return_if_fail(width > 0 && height > 0); + + cfg.playlist_width = width; + + if (!cfg.playlist_shaded) + cfg.playlist_height = height; + else + height = cfg.playlist_height; + + /* FIXME: why the fsck are we doing this manually? */ + /* adjust widget positions and sizes */ + + widget_resize(WIDGET(playlistwin_list), width - 31, height - 58); + + widget_move(WIDGET(playlistwin_slider), width - 15, 20); + widget_resize(WIDGET(playlistwin_slider), 8, height - 58); + + widget_resize(WIDGET(playlistwin_sinfo), width - 35, 14); + playlistwin_update_sinfo(); + + widget_move(WIDGET(playlistwin_shade), width - 21, 3); + widget_move(WIDGET(playlistwin_close), width - 11, 3); + widget_move(WIDGET(playlistwin_time_min), width - 82, height - 15); + widget_move(WIDGET(playlistwin_time_sec), width - 64, height - 15); + widget_move(WIDGET(playlistwin_info), width - 143, height - 28); + widget_move(WIDGET(playlistwin_srew), width - 144, height - 16); + widget_move(WIDGET(playlistwin_splay), width - 138, height - 16); + widget_move(WIDGET(playlistwin_spause), width - 128, height - 16); + widget_move(WIDGET(playlistwin_sstop), width - 118, height - 16); + widget_move(WIDGET(playlistwin_sfwd), width - 109, height - 16); + widget_move(WIDGET(playlistwin_seject), width - 100, height - 16); + widget_move(WIDGET(playlistwin_sscroll_up), width - 14, height - 35); + widget_move(WIDGET(playlistwin_sscroll_down), width - 14, height - 30); + + g_object_unref(playlistwin_bg); + playlistwin_bg = gdk_pixmap_new(playlistwin->window, width, height, -1); + playlistwin_set_mask(); + + widget_list_lock(playlistwin_wlist); + + widget_list_change_pixmap(playlistwin_wlist, playlistwin_bg); + playlistwin_draw_frame(); + widget_list_draw(playlistwin_wlist, &redraw, TRUE); + widget_list_clear_redraw(playlistwin_wlist); + + widget_list_unlock(playlistwin_wlist); + + gdk_window_set_back_pixmap(playlistwin->window, playlistwin_bg, 0); + gdk_window_clear(playlistwin->window); +} + + + +static void +playlistwin_motion(GtkWidget * widget, + GdkEventMotion * event, + gpointer callback_data) +{ + GdkEvent *gevent; + + if (dock_is_moving(GTK_WINDOW(playlistwin))) { + dock_move_motion(GTK_WINDOW(playlistwin), event); + } + else { + handle_motion_cb(playlistwin_wlist, widget, event); + draw_playlist_window(FALSE); + } + gdk_flush(); + + while ((gevent = gdk_event_get()) != NULL) gdk_event_free(gevent); +} + +static void +playlistwin_enter(GtkWidget * widget, + GdkEventMotion * event, + gpointer callback_data) +{ + playlistwin_list->pl_tooltips = TRUE; +} + +static void +playlistwin_leave(GtkWidget * widget, + GdkEventMotion * event, + gpointer callback_data) +{ + playlistwin_list->pl_tooltips = FALSE; +} + +static void +playlistwin_show_filebrowser(void) +{ + util_run_filebrowser(NO_PLAY_BUTTON); +} + +#if 0 +static void +playlistwin_add_dir_handler(const gchar * dir) +{ + g_free(cfg.filesel_path); + cfg.filesel_path = g_strdup(dir); + playlist_add_dir(dir); +} +#endif + +static void +playlistwin_fileinfo(void) +{ + /* Show the first selected file, or the current file if nothing is + * selected */ + GList *list = playlist_get_selected(); + if (list) { + playlist_fileinfo(GPOINTER_TO_INT(list->data)); + g_list_free(list); + } + else + playlist_fileinfo_current(); +} + +static void +menu_set_item_sensitive(GtkItemFactory * item_factory, + const gchar * path, + gboolean sensitive) +{ + GtkWidget *item = gtk_item_factory_get_widget(item_factory, path); + gtk_widget_set_sensitive(item, sensitive); +} + +/* FIXME: broken */ +static void +playlistwin_set_sensitive_sortmenu(void) +{ + gboolean set = playlist_get_num_selected() > 1; + menu_set_item_sensitive(plsort_menu, "/Sort Selection/By Title", set); + menu_set_item_sensitive(plsort_menu, "/Sort Selection/By Filename", set); + menu_set_item_sensitive(plsort_menu, "/Sort Selection/By Path + Filename", set); + menu_set_item_sensitive(plsort_menu, "/Sort Selection/By Date", set); +} + +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 != NULL); + + 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_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); + + 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_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(filename)) + show_playlist_save_error(GTK_WINDOW(playlistwin), filename); +} + +#if 0 +static void +playlistwin_save_current(void) +{ + const gchar *filename; + + if (!(filename = playlist_get_current_name())) + return; + + playlistwin_save_playlist(filename); +} +#endif + +static void +playlistwin_load_playlist(const gchar * filename) +{ + g_return_if_fail(filename != NULL); + + str_replace_in(&cfg.playlist_path, g_strdup(filename)); + + playlist_clear(); + mainwin_clear_song_info(); + mainwin_set_info_text(); + + playlist_load(filename); + playlist_set_current_name(filename); +} + +static gchar * +playlist_file_selection(const gchar * title, + gboolean save, + const gchar * default_filename) +{ + GtkWidget *dialog, *button; + gchar *filename; + + g_return_val_if_fail(title != NULL, NULL); + + dialog = gtk_file_chooser_dialog_new(title, GTK_WINDOW(mainwin), + save ? GTK_FILE_CHOOSER_ACTION_SAVE : + GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL); + if (default_filename) + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), + default_filename); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT); + gtk_button_set_use_stock(GTK_BUTTON(button), TRUE); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + save ? GTK_STOCK_SAVE : GTK_STOCK_OPEN, + GTK_RESPONSE_ACCEPT); + gtk_button_set_use_stock(GTK_BUTTON(button), TRUE); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); + + 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 Playlist"), FALSE, default_filename); + + if (filename) { + playlistwin_load_playlist(filename); + g_free(filename); + } +} + +static void +playlistwin_select_playlist_to_save(const gchar * default_filename) +{ + gchar *filename = + playlist_file_selection(_("Save Playlist"), TRUE, default_filename); + + if (filename) { + /* Default to M3U if no filename has extension */ + + /* NOTE: This doesn't work correctly for hidden files + - descender */ + if (!strchr(filename, '.')) { + gchar *tmpstr = filename; + filename = g_strconcat(filename, ".m3u", NULL); + g_free(tmpstr); + } + + playlistwin_save_playlist(filename); + g_free(filename); + } +} + +static gboolean +inside_sensitive_widgets(gint x, gint y) +{ + return (widget_contains(WIDGET(playlistwin_list), x, y) || + widget_contains(WIDGET(playlistwin_slider), x, y) || + widget_contains(WIDGET(playlistwin_close), x, y) || + widget_contains(WIDGET(playlistwin_shade), x, y) || + widget_contains(WIDGET(playlistwin_time_min), x, y) || + widget_contains(WIDGET(playlistwin_time_sec), x, y) || + widget_contains(WIDGET(playlistwin_info), x, y) || + widget_contains(WIDGET(playlistwin_srew), x, y) || + widget_contains(WIDGET(playlistwin_splay), x, y) || + widget_contains(WIDGET(playlistwin_spause), x, y) || + widget_contains(WIDGET(playlistwin_sstop), x, y) || + widget_contains(WIDGET(playlistwin_sfwd), x, y) || + widget_contains(WIDGET(playlistwin_seject), x, y) || + widget_contains(WIDGET(playlistwin_sscroll_up), x, y) || + widget_contains(WIDGET(playlistwin_sscroll_down), x, y)); +} + +#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); + +} + + + + +static gboolean +playlistwin_press(GtkWidget * widget, + GdkEventButton * event, + gpointer callback_data) +{ + gboolean grab = TRUE; + gint xpos, ypos; + GtkWidget *_menu; + 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))) { + + /* NOTE: Workaround for bug #214 */ + if (event->type != GDK_2BUTTON_PRESS && + event->type != GDK_3BUTTON_PRESS) { + /* resize area */ + playlistwin_resizing = TRUE; + gtk_window_begin_resize_drag(GTK_WINDOW(widget), + GDK_WINDOW_EDGE_SOUTH_EAST, + event->button, + event->x + xpos, event->y + ypos, + event->time); + } + grab = FALSE; + } + else if (event->button == 1 && REGION_L(12, 37, 29, 11)) { + /* ADD button menu */ + + _menu = GTK_WIDGET(pladd_menu->widget); + if (!GTK_WIDGET_REALIZED(_menu)) gtk_widget_realize(_menu); + gtk_widget_size_request(_menu, &req); + gtk_item_factory_popup_with_data(pladd_menu, + NULL, NULL, + xpos+12, + (ypos + playlistwin_get_height()) - 8 - req.height, 1, event->time); + grab = FALSE; + } + else if (event->button == 1 && REGION_L(41, 66, 29, 11)) { + /* SUB button menu */ + _menu = GTK_WIDGET(pldel_menu->widget); + if (!GTK_WIDGET_REALIZED(_menu)) gtk_widget_realize(_menu); + gtk_widget_size_request(_menu, &req); + gtk_item_factory_popup_with_data(pldel_menu, + NULL, NULL, + xpos+40, + (ypos + playlistwin_get_height()) - 8 - req.height, 1, event->time); + grab = FALSE; + } + else if (event->button == 1 && REGION_L(70, 95, 29, 11)) { + /* SEL button menu */ + _menu = GTK_WIDGET(plsel_menu->widget); + if (!GTK_WIDGET_REALIZED(_menu)) gtk_widget_realize(_menu); + gtk_widget_size_request(_menu, &req); + gtk_item_factory_popup_with_data(plsel_menu, + NULL, NULL, + xpos+68, + (ypos + playlistwin_get_height()) - 8 - req.height, 1, event->time); + + grab = FALSE; + } + else if (event->button == 1 && REGION_L(99, 124, 29, 11)) { + /* MISC button menu */ + _menu = GTK_WIDGET(plsort_menu->widget); + if (!GTK_WIDGET_REALIZED(_menu)) gtk_widget_realize(_menu); + gtk_widget_size_request(_menu, &req); + gtk_item_factory_popup_with_data(plsort_menu, + NULL, NULL, + xpos+100, + (ypos + playlistwin_get_height()) - 8 - req.height, 1, event->time); + grab = FALSE; + } + else if (event->button == 1 && REGION_R(46, 23, 29, 11)) { + /* LIST button menu */ + _menu = GTK_WIDGET(pllist_menu->widget); + if (!GTK_WIDGET_REALIZED(_menu)) gtk_widget_realize(_menu); + gtk_widget_size_request(_menu, &req); + gtk_item_factory_popup_with_data(pllist_menu, + NULL, NULL, + xpos + playlistwin_get_width() - req.width - 12, + (ypos + playlistwin_get_height()) - 8 - req.height, 1, event->time); + grab = FALSE; + } + else if (event->button == 1 && REGION_R(82, 54, 15, 9)) { + if (cfg.timer_mode == TIMER_ELAPSED) + cfg.timer_mode = TIMER_REMAINING; + else + cfg.timer_mode = TIMER_ELAPSED; + } + else if (event->button == 2 && (event->type == GDK_BUTTON_PRESS) && + widget_contains(WIDGET(playlistwin_list), event->x, event->y)) { + gtk_selection_convert(widget, GDK_SELECTION_PRIMARY, + GDK_TARGET_STRING, event->time); + } + else if (event->button == 1 && event->type == GDK_BUTTON_PRESS && + !inside_sensitive_widgets(event->x, event->y) && event->y < 14) + { + dock_move_press(dock_window_list, GTK_WINDOW(playlistwin), event, + FALSE); + gtk_window_present(GTK_WINDOW(playlistwin)); + } + else if (event->button == 1 && event->type == GDK_2BUTTON_PRESS && + !inside_sensitive_widgets(event->x, event->y) + && 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 && + !(widget_contains(WIDGET(playlistwin_list), event->x, event->y) || + (event->y >= cfg.playlist_height - 29 && + event->y < cfg.playlist_height - 11 && + ((event->x >= 12 && event->x < 37) || + (event->x >= 41 && event->x < 66) || + (event->x >= 70 && event->x < 95) || + (event->x >= 99 && event->x < 124) || + (event->x >= playlistwin_get_width() - 46 && + event->x < playlistwin_get_width() - 23))))) { + /* + * Pop up the main menu a few pixels down to avoid + * anything to be selected initially. + */ + util_item_factory_popup(mainwin_general_menu, event->x_root, + event->y_root + 2, 3, event->time); + grab = FALSE; + } + else if (event->button == 3 && + widget_contains(WIDGET(playlistwin_list), event->x, event->y)) { + /* popup menu */ + playlistwin_set_sensitive_sortmenu(); + { + GtkWidget *item = gtk_item_factory_get_widget(playlistwin_popup_menu, "/Show Popup Info"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), cfg.show_filepopup_for_tuple); + } + gtk_item_factory_popup(playlistwin_popup_menu, + event->x_root, event->y_root + 5, + 3, event->time); + grab = FALSE; + } + else { + handle_press_cb(playlistwin_wlist, widget, event); + draw_playlist_window(FALSE); + } + + if (grab) + gdk_pointer_grab(playlistwin->window, FALSE, + GDK_BUTTON_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON1_MOTION_MASK, NULL, NULL, + GDK_CURRENT_TIME); + + return FALSE; +} + +static gboolean +playlistwin_focus_in(GtkWidget * widget, GdkEvent * event, gpointer data) +{ + playlistwin_close->pb_allow_draw = TRUE; + playlistwin_shade->pb_allow_draw = TRUE; + draw_playlist_window(TRUE); + return FALSE; +} + +static gboolean +playlistwin_focus_out(GtkWidget * widget, + GdkEventButton * event, gpointer data) +{ + playlistwin_close->pb_allow_draw = FALSE; + playlistwin_shade->pb_allow_draw = FALSE; + draw_playlist_window(TRUE); + return FALSE; +} + +static gboolean +playlistwin_configure(GtkWidget * window, + GdkEventConfigure * event, gpointer data) +{ + if (!GTK_WIDGET_VISIBLE(window)) + return FALSE; + + cfg.playlist_x = event->x; + cfg.playlist_y = event->y; + + if (playlistwin_resizing) { + if (event->width != playlistwin_get_width() || + event->height != playlistwin_get_height()) + playlistwin_resize(event->width, event->height); + } + return TRUE; +} + +void +playlistwin_set_back_pixmap(void) +{ + gdk_window_set_back_pixmap(playlistwin->window, playlistwin_bg, 0); + gdk_window_clear(playlistwin->window); +} + +static gboolean +playlistwin_delete(GtkWidget * w, gpointer data) +{ + playlistwin_hide(); + return TRUE; +} + +static void +playlistwin_keypress_up_down_handler(PlayList_List * pl, + gboolean up, guint state) +{ + if ((state & GDK_MOD1_MASK) && (state & GDK_SHIFT_MASK)) + return; + if (!(state & GDK_MOD1_MASK)) + playlist_select_all(FALSE); + + if (pl->pl_prev_selected == -1 || + (!playlistwin_item_visible(pl->pl_prev_selected) && + !(state & GDK_SHIFT_MASK && pl->pl_prev_min != -1))) { + pl->pl_prev_selected = pl->pl_first; + } + else if (state & GDK_SHIFT_MASK) { + if (pl->pl_prev_min == -1) { + pl->pl_prev_max = pl->pl_prev_selected; + pl->pl_prev_min = pl->pl_prev_selected; + } + pl->pl_prev_max += (up ? -1 : 1); + pl->pl_prev_max = + CLAMP(pl->pl_prev_max, 0, playlist_get_length() - 1); + + pl->pl_first = MIN(pl->pl_first, pl->pl_prev_max); + pl->pl_first = MAX(pl->pl_first, pl->pl_prev_max - + pl->pl_num_visible + 1); + playlist_select_range(pl->pl_prev_min, pl->pl_prev_max, TRUE); + return; + } + else if (state & GDK_MOD1_MASK) { + if (up) + playlist_list_move_up(pl); + else + playlist_list_move_down(pl); + if (pl->pl_prev_min < pl->pl_first) + pl->pl_first = pl->pl_prev_min; + else if (pl->pl_prev_max >= (pl->pl_first + pl->pl_num_visible)) + pl->pl_first = pl->pl_prev_max - pl->pl_num_visible + 1; + return; + } + else if (up) + pl->pl_prev_selected--; + else + pl->pl_prev_selected++; + + pl->pl_prev_selected = + CLAMP(pl->pl_prev_selected, 0, playlist_get_length() - 1); + + if (pl->pl_prev_selected < pl->pl_first) + pl->pl_first--; + else if (pl->pl_prev_selected >= (pl->pl_first + pl->pl_num_visible)) + pl->pl_first++; + + playlist_select_range(pl->pl_prev_selected, pl->pl_prev_selected, TRUE); + pl->pl_prev_min = -1; + +} + +/* FIXME: Handle the keys through menu */ + +static gboolean +playlistwin_keypress(GtkWidget * w, GdkEventKey * event, gpointer data) +{ + guint keyval; + gboolean refresh = FALSE; + + if (cfg.playlist_shaded) + return FALSE; + + switch (keyval = event->keyval) { + case GDK_KP_Up: + case GDK_KP_Down: + case GDK_Up: + case GDK_Down: + playlistwin_keypress_up_down_handler(playlistwin_list, + keyval == GDK_Up + || keyval == GDK_KP_Up, + event->state); + refresh = TRUE; + break; + case GDK_Page_Up: + playlistwin_scroll(-playlistwin_list->pl_num_visible); + refresh = TRUE; + break; + case GDK_Page_Down: + playlistwin_scroll(playlistwin_list->pl_num_visible); + refresh = TRUE; + break; + case GDK_Home: + playlistwin_list->pl_first = 0; + refresh = TRUE; + break; + case GDK_End: + playlistwin_list->pl_first = + playlist_get_length() - playlistwin_list->pl_num_visible; + refresh = TRUE; + break; + case GDK_Return: + if (playlistwin_list->pl_prev_selected > -1 + && playlistwin_item_visible(playlistwin_list->pl_prev_selected)) { + playlist_set_position(playlistwin_list->pl_prev_selected); + if (!bmp_playback_get_playing()) + bmp_playback_initiate(); + } + break; + case GDK_3: + if (event->state & GDK_CONTROL_MASK) + playlistwin_fileinfo(); + break; + case GDK_Delete: + if (event->state & GDK_CONTROL_MASK) + playlist_delete(TRUE); + else + playlist_delete(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() != -1) + bmp_playback_seek(CLAMP + (bmp_playback_get_time() - 1000, 0, + playlist_get_current_length()) / 1000); + break; + case GDK_Right: + case GDK_KP_Right: + case GDK_KP_9: + if (playlist_get_current_length() != -1) + bmp_playback_seek(CLAMP + (bmp_playback_get_time() + 1000, 0, + playlist_get_current_length()) / 1000); + break; + + case GDK_Escape: + mainwin_minimize_cb(); + break; + default: + return FALSE; + } + + if (refresh) + playlistwin_update_list(); + + return TRUE; +} + +static void +playlistwin_draw_frame(void) +{ + gboolean focus = + gtk_window_has_toplevel_focus(GTK_WINDOW(playlistwin)) || + !cfg.dim_titlebar; + + if (cfg.playlist_shaded) { + skin_draw_playlistwin_shaded(bmp_active_skin, + playlistwin_bg, playlistwin_gc, + playlistwin_get_width(), focus); + } + else { + skin_draw_playlistwin_frame(bmp_active_skin, + playlistwin_bg, playlistwin_gc, + playlistwin_get_width(), + cfg.playlist_height, focus); + } +} + +void +draw_playlist_window(gboolean force) +{ + gboolean redraw; + GList *wl; + Widget *w; + + if (force) + playlistwin_draw_frame(); + + widget_list_lock(playlistwin_wlist); + widget_list_draw(playlistwin_wlist, &redraw, force); + + if (redraw || force) { + if (force) { + gdk_window_clear(playlistwin->window); + } + else { + for (wl = playlistwin_wlist; wl; wl = g_list_next(wl)) { + w = WIDGET(wl->data); + if (w->redraw && w->visible) { + gdk_window_clear_area(playlistwin->window, w->x, w->y, + w->width, w->height); + w->redraw = FALSE; + } + } + } + + gdk_flush(); + } + + widget_list_unlock(playlistwin_wlist); +} + + +void +playlistwin_hide_timer(void) +{ + textbox_set_text(playlistwin_time_min, " "); + 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); + textbox_set_text(playlistwin_time_min, text); + g_free(text); + + text = g_strdup_printf("%-2.2d", time % 60); + 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) +{ + playlistwin_list->pl_drag_motion = TRUE; + playlistwin_list->drag_motion_x = x; + playlistwin_list->drag_motion_y = y; + playlistwin_update_list(); + playlistwin_hint_flag = TRUE; +} + +static void +playlistwin_drag_end(GtkWidget * widget, + GdkDragContext * context, gpointer user_data) +{ + playlistwin_list->pl_drag_motion = FALSE; + playlistwin_hint_flag = FALSE; + playlistwin_update_list(); +} + +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; + + g_return_if_fail(selection_data != NULL); + + if (!selection_data->data) { + g_message("Received no DND data!"); + return; + } + + if (widget_contains(WIDGET(playlistwin_list), x, y)) { + pos = (y - WIDGET(playlistwin_list)->y) / + playlistwin_list->pl_fheight + playlistwin_list->pl_first; + + pos = MIN(pos, playlist_get_length()); + playlist_ins_url((gchar *) selection_data->data, pos); + } + else + playlist_add_url((gchar *) selection_data->data); +} + +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 = + create_textbox(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + 4, 4, playlistwin_get_width() - 35, FALSE, SKIN_TEXT); + + if (!cfg.playlist_shaded) + widget_hide(WIDGET(playlistwin_sinfo)); + + /* shade/unshade window push button */ + if (cfg.playlist_shaded) + playlistwin_shade = + create_pbutton(&playlistwin_wlist, playlistwin_bg, + playlistwin_gc, playlistwin_get_width() - 21, 3, + 9, 9, 128, 45, 150, 42, + playlistwin_shade_toggle, SKIN_PLEDIT); + else + playlistwin_shade = + create_pbutton(&playlistwin_wlist, playlistwin_bg, + playlistwin_gc, playlistwin_get_width() - 21, 3, + 9, 9, 157, 3, 62, 42, playlistwin_shade_toggle, + SKIN_PLEDIT); + + playlistwin_shade->pb_allow_draw = FALSE; + + /* close window push button */ + playlistwin_close = + create_pbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 11, 3, 9, 9, + cfg.playlist_shaded ? 138 : 167, + cfg.playlist_shaded ? 45 : 3, 52, 42, + playlistwin_hide, SKIN_PLEDIT); + playlistwin_close->pb_allow_draw = FALSE; + + /* playlist list box */ + playlistwin_list = + create_playlist_list(&playlistwin_wlist, playlistwin_bg, + playlistwin_gc, 12, 20, + playlistwin_get_width() - 31, + cfg.playlist_height - 58); + playlist_list_set_font(cfg.playlist_font); + + /* playlist list box slider */ + playlistwin_slider = + create_playlistslider(&playlistwin_wlist, playlistwin_bg, + playlistwin_gc, playlistwin_get_width() - 15, + 20, cfg.playlist_height - 58, playlistwin_list); + /* track time (minute) */ + playlistwin_time_min = + create_textbox(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 82, + cfg.playlist_height - 15, 15, FALSE, SKIN_TEXT); + + /* track time (second) */ + playlistwin_time_sec = + create_textbox(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 64, + cfg.playlist_height - 15, 10, FALSE, SKIN_TEXT); + + /* playlist information (current track length / total track length) */ + playlistwin_info = + create_textbox(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 143, + cfg.playlist_height - 28, 90, FALSE, SKIN_TEXT); + + /* mini play control buttons at right bottom corner */ + + /* rewind button */ + playlistwin_srew = + create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 144, + cfg.playlist_height - 16, 8, 7, playlist_prev); + + /* play button */ + playlistwin_splay = + create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 138, + cfg.playlist_height - 16, 10, 7, mainwin_play_pushed); + + /* pause button */ + playlistwin_spause = + create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 128, + cfg.playlist_height - 16, 10, 7, bmp_playback_pause); + + /* stop button */ + playlistwin_sstop = + create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 118, + cfg.playlist_height - 16, 9, 7, mainwin_stop_pushed); + + /* forward button */ + playlistwin_sfwd = + create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 109, + cfg.playlist_height - 16, 8, 7, playlist_next); + + /* eject button */ + playlistwin_seject = + create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 100, + cfg.playlist_height - 16, 9, 7, mainwin_eject_pushed); + + + playlistwin_sscroll_up = + create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 14, + cfg.playlist_height - 35, 8, 5, + playlistwin_scroll_up_pushed); + playlistwin_sscroll_down = + create_sbutton(&playlistwin_wlist, playlistwin_bg, playlistwin_gc, + playlistwin_get_width() - 14, + cfg.playlist_height - 30, 8, 5, + playlistwin_scroll_down_pushed); + +} + +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((gchar *) selection_data->data); +} + +static void +playlistwin_create_window(void) +{ + GdkPixbuf *icon; + + playlistwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(playlistwin), _("Audacious Playlist Editor")); + gtk_window_set_wmclass(GTK_WINDOW(playlistwin), "playlist", "Audacious"); + 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); + dock_window_list = dock_window_set_decorated(dock_window_list, + GTK_WINDOW(playlistwin), + cfg.show_wm_decorations); + + 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 **) bmp_playlist_icon); + gtk_window_set_icon(GTK_WINDOW(playlistwin), icon); + g_object_unref(icon); + + gtk_widget_set_app_paintable(playlistwin, TRUE); + + 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); + + util_set_cursor(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); + g_signal_connect(playlistwin, "enter_notify_event", + G_CALLBACK(playlistwin_enter), NULL); + g_signal_connect(playlistwin, "leave_notify_event", + G_CALLBACK(playlistwin_leave), NULL); + g_signal_connect_after(playlistwin, "focus_in_event", + G_CALLBACK(playlistwin_focus_in), NULL); + g_signal_connect_after(playlistwin, "focus_out_event", + G_CALLBACK(playlistwin_focus_out), NULL); + g_signal_connect(playlistwin, "configure_event", + G_CALLBACK(playlistwin_configure), NULL); + g_signal_connect(playlistwin, "style_set", + G_CALLBACK(playlistwin_set_back_pixmap), NULL); + + bmp_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); + + playlistwin_set_mask(); +} + +void +playlistwin_create_popup_menus(void) +{ + playlistwin_accel = gtk_accel_group_new(); + + /* playlist window popup menu */ + playlistwin_popup_menu = create_menu(playlistwin_popup_menu_entries, + G_N_ELEMENTS(playlistwin_popup_menu_entries), + playlistwin_accel); + + pladd_menu = create_menu(pladd_menu_entries, G_N_ELEMENTS(pladd_menu_entries), + playlistwin_accel); + pldel_menu = create_menu(pldel_menu_entries, G_N_ELEMENTS(pldel_menu_entries), + playlistwin_accel); + plsel_menu = create_menu(plsel_menu_entries, G_N_ELEMENTS(plsel_menu_entries), + playlistwin_accel); + plsort_menu = create_menu(plsort_menu_entries, + G_N_ELEMENTS(plsort_menu_entries), + playlistwin_accel); + pllist_menu = create_menu(pllist_menu_entries, G_N_ELEMENTS(pllist_menu_entries), + playlistwin_accel); + +#if 0 + make_submenu(playlistwin_popup_menu, "/Playlist", + playlistwin_playlist_menu); + make_submenu(playlistwin_popup_menu, "/Playback", + playlistwin_playback_menu); + make_submenu(playlistwin_popup_menu, "/Add", + pladd_menu); +#endif +} + +void +playlistwin_create(void) +{ + playlistwin_create_window(); + playlistwin_create_popup_menus(); + + /* create GC and back pixmap for custom widget to draw on */ + playlistwin_gc = gdk_gc_new(playlistwin->window); + playlistwin_bg = gdk_pixmap_new(playlistwin->window, + playlistwin_get_width(), + playlistwin_get_height_unshaded(), -1); + gdk_window_set_back_pixmap(playlistwin->window, playlistwin_bg, 0); + + playlistwin_create_widgets(); + playlistwin_update_info(); + + gtk_window_add_accel_group(GTK_WINDOW(playlistwin), playlistwin_accel); + gtk_window_add_accel_group(GTK_WINDOW(playlistwin), mainwin_accel); +} + + +void +playlistwin_show(void) +{ + GtkWidget *item; + + item = gtk_item_factory_get_widget(mainwin_view_menu, + "/Show Playlist Editor"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE); + + tbutton_set_toggled(mainwin_pl, TRUE); + cfg.playlist_visible = TRUE; + + playlistwin_set_toprow(0); + playlist_check_pos_current(); + + gtk_widget_show(playlistwin); +} + +void +playlistwin_hide(void) +{ + GtkWidget *item; + + item = gtk_item_factory_get_widget(mainwin_view_menu, + "/Show Playlist Editor"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), FALSE); + + gtk_widget_hide(playlistwin); + tbutton_set_toggled(mainwin_pl, FALSE); + cfg.playlist_visible = FALSE; + + gtk_window_present(GTK_WINDOW(mainwin)); + gtk_widget_grab_focus(mainwin); +} + + +static void +plsort_menu_callback(gpointer data, + guint action, + GtkWidget * widget) +{ + switch (action) { + case PLAYLISTWIN_SORT_BYPLAYLIST: + playlist_sort(PLAYLIST_SORT_PLAYLIST); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_BYTRACK: + playlist_sort(PLAYLIST_SORT_TRACK); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_BYTITLE: + playlist_sort(PLAYLIST_SORT_TITLE); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_BYARTIST: + playlist_sort(PLAYLIST_SORT_ARTIST); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_BYPATH: + playlist_sort(PLAYLIST_SORT_PATH); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_BYDATE: + playlist_sort(PLAYLIST_SORT_DATE); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_BYFILENAME: + playlist_sort(PLAYLIST_SORT_FILENAME); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_SEL_BYPLAYLIST: + playlist_sort_selected(PLAYLIST_SORT_PLAYLIST); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_SEL_BYTRACK: + playlist_sort_selected(PLAYLIST_SORT_TRACK); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_SEL_BYTITLE: + playlist_sort_selected(PLAYLIST_SORT_TITLE); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_SEL_BYARTIST: + playlist_sort_selected(PLAYLIST_SORT_ARTIST); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_SEL_BYFILENAME: + playlist_sort_selected(PLAYLIST_SORT_FILENAME); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_SEL_BYPATH: + playlist_sort_selected(PLAYLIST_SORT_PATH); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_SEL_BYDATE: + playlist_sort_selected(PLAYLIST_SORT_DATE); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_REVERSE: + playlist_reverse(); + playlistwin_update_list(); + break; + case PLAYLISTWIN_SORT_RANDOMIZE: + playlist_random(); + playlistwin_update_list(); + break; + } +} + +static void +playlistwin_sub_menu_callback(gpointer data, + guint action, + GtkWidget * widget) +{ + switch (action) { + case PLIST_NEW: + playlist_set_current_name(NULL); + playlist_clear(); + mainwin_clear_song_info(); + mainwin_set_info_text(); + break; + case PLIST_SAVE: + playlistwin_select_playlist_to_save(playlist_get_current_name()); + break; + case PLIST_DEFAULTSAVE: + playlist_save(bmp_paths[BMP_PATH_PLAYLIST_FILE]); + break; + case PLIST_SAVE_AS: + playlistwin_select_playlist_to_save(playlist_get_current_name()); + break; + case PLIST_LOAD: + playlistwin_select_playlist_to_load(playlist_get_current_name()); + break; + case SEL_INV: + playlistwin_inverse_selection(); + break; + case SEL_ZERO: + playlistwin_select_none(); + break; + case SEL_ALL: + playlistwin_select_all(); + break; + case SUB_ALL: + playlist_clear(); + mainwin_clear_song_info(); + mainwin_set_info_text(); + break; + case SUB_CROP: + playlist_delete(TRUE); + break; + case SUB_SELECTED: + playlist_delete(FALSE); + break; + case SUB_DUPLICATE_BYTITLE: + playlist_remove_duplicates(PLAYLIST_DUPS_TITLE); + break; + case SUB_DUPLICATE_BYFILENAME: + playlist_remove_duplicates(PLAYLIST_DUPS_FILENAME); + break; + case SUB_DUPLICATE_BYPATH: + playlist_remove_duplicates(PLAYLIST_DUPS_PATH); + break; + case PLAYLISTWIN_REMOVE_DEAD_FILES: + playlist_remove_dead_files(); + break; + case PLAYLISTWIN_REFRESH: + playlist_read_info_selection(); + playlistwin_update_list(); + break; + } +} + +static void +playlistwin_popup_menu_callback(gpointer data, + guint action, + GtkWidget * widget) +{ + extern GtkWidget *filepopupbutton; + + switch (action) { + case ADD_FILES: + playlistwin_show_filebrowser(); + break; + case CLOSE_PL_WINDOW: + playlistwin_hide(); + break; + case MISC_FILEINFO: + playlistwin_fileinfo(); + break; + case SEL_LOOKUP: + playlist_read_info_selection(); + break; + case MISC_QUEUE: + playlist_queue(); + break; + case PLIST_CQUEUE: + playlist_clear_queue(); + break; + case PLIST_JTT: + mainwin_jump_to_time(); + break; + case PLIST_JTF: + mainwin_jump_to_file(); + break; + case MISC_FILEPOPUP: + cfg.show_filepopup_for_tuple = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); + if(filepopupbutton != NULL){ + gtk_signal_emit_by_name(GTK_OBJECT(filepopupbutton), "realize"); + } + break; + + } +} diff -r 3d3b60e66491 -r 1a525bd78cf0 Plugins/UserInterface/wa2gui/ui_playlist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/UserInterface/wa2gui/ui_playlist.h Thu Sep 07 19:57:27 2006 -0700 @@ -0,0 +1,78 @@ +/* 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLAYLISTWIN_H +#define PLAYLISTWIN_H + +#include + +#include "mainwin.h" +#include "widgets/widgetcore.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); +void playlistwin_update_list(void); +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 draw_playlist_window(gboolean force); +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_set_back_pixmap(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); + +extern GtkWidget *playlistwin; +extern PlayList_List *playlistwin_list; + +extern PButton *playlistwin_shade, *playlistwin_close; + +extern gboolean playlistwin_focus; + +#endif