view audacious/mainwin.c @ 1938:1d9c1026d9f8 trunk

[svn] - DoubleSize support. This has bugs, the most notable one being that DoubleSize only works right if you restart the player. The second bug is rather obvious too. No osmosis skinengine. No TinyPlayer. Classic-esque skinengine only. This is because the doublesize algorithm hates you and wants you to go die in a fire.
author nenolod
date Sun, 05 Nov 2006 04:43:16 -0800
parents 35fa6f69d802
children e929aec8c8ea
line wrap: on
line source

/*  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 <glib.h>
#include <glib/gi18n.h>
#include <glib/gprintf.h>
#include <gtk/gtk.h>
#include <gtk/gtkmessagedialog.h>

/* GDK including */
#include "platform/smartinclude.h"

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <X11/Xlib.h>

#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, "<Separator>"}
#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, MAINWIN_OPT_DOUBLESIZE, MAINWIN_OPT_EASY_MOVE
};

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, *mainwin_bg_x2 = 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 int ab_position_a = -1;
static int ab_position_b = -1;

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"), "<alt>i", mainwin_general_menu_callback,
     MAINWIN_GENERAL_FILEINFO, "<ImageItem>", my_pixbuf},
    {N_("/Jump to File"), "J", mainwin_songname_menu_callback,
     MAINWIN_SONGNAME_JTF, "<StockItem>", GTK_STOCK_JUMP_TO},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Autoscroll Songname"), NULL, mainwin_songname_menu_callback,
     MAINWIN_SONGNAME_SCROLL, "<ToggleItem>", NULL},
    {N_("/Stop After Current Song"), "<control>M", mainwin_songname_menu_callback,
     MAINWIN_SONGNAME_STOPAFTERSONG, "<ToggleItem>", 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, "<Branch>", NULL},
    {N_("/Visualization Mode/Analyzer"), NULL, mainwin_vis_menu_callback,
     MAINWIN_VIS_ANALYZER, "<RadioItem>", 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, "<Branch>", NULL},
    {N_("/Analyzer Mode/Normal"), NULL, mainwin_vis_menu_callback,
     MAINWIN_VIS_ANALYZER_NORMAL, "<RadioItem>", 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, "<Separator>", NULL},
    {N_("/Analyzer Mode/Lines"), NULL, mainwin_vis_menu_callback,
     MAINWIN_VIS_ANALYZER_LINES, "<RadioItem>", NULL},
    {N_("/Analyzer Mode/Bars"), NULL, mainwin_vis_menu_callback,
     MAINWIN_VIS_ANALYZER_BARS, "/Analyzer Mode/Lines", NULL},
    {"/Analyzer Mode/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Analyzer Mode/Peaks"), NULL, mainwin_vis_menu_callback,
     MAINWIN_VIS_ANALYZER_PEAKS, "<ToggleItem>", NULL},
    {N_("/Scope Mode"), NULL, NULL, 0, "<Branch>", NULL},
    {N_("/Scope Mode/Dot Scope"), NULL, mainwin_vis_menu_callback,
     MAINWIN_VIS_SCOPE_DOT, "<RadioItem>", 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, "<Branch>", NULL},
    {N_("/WindowShade VU Mode/Normal"), NULL, mainwin_vis_menu_callback,
     MAINWIN_VIS_VU_NORMAL, "<RadioItem>", 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, "<Branch>", NULL},
    {N_("/Refresh Rate/Full (~50 fps)"), NULL, mainwin_vis_menu_callback,
     MAINWIN_VIS_REFRESH_FULL, "<RadioItem>", 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, "<Branch>", NULL},
    {N_("/Analyzer Falloff/Slowest"), NULL, mainwin_vis_menu_callback,
     MAINWIN_VIS_AFALLOFF_SLOWEST, "<RadioItem>", 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, "<Branch>", NULL},
    {N_("/Peaks Falloff/Slowest"), NULL, mainwin_vis_menu_callback,
     MAINWIN_VIS_PFALLOFF_SLOWEST, "<RadioItem>", 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"), "<alt>C", mainwin_general_menu_callback,
     MAINWIN_GENERAL_PLAYCD, "<StockItem>", GTK_STOCK_CDROM},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Repeat"), "R", mainwin_play_menu_callback,
     MAINWIN_OPT_REPEAT, "<ToggleItem>", NULL},
    {N_("/Shuffle"), "S", mainwin_play_menu_callback,
     MAINWIN_OPT_SHUFFLE, "<ToggleItem>", NULL},
    {N_("/No Playlist Advance"), "<control>N", mainwin_play_menu_callback,
     MAINWIN_OPT_NPA, "<ToggleItem>", NULL},
    {N_("/Stop After Current Song"), "<control>M", mainwin_songname_menu_callback,
     MAINWIN_SONGNAME_STOPAFTERSONG, "<ToggleItem>", NULL},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Play"), "x", mainwin_general_menu_callback,
     MAINWIN_GENERAL_PLAY, "<StockItem>", GTK_STOCK_MEDIA_PLAY},
    {N_("/Pause"), "c", mainwin_general_menu_callback,
     MAINWIN_GENERAL_PAUSE, "<StockItem>", GTK_STOCK_MEDIA_PAUSE},
    {N_("/Stop"), "v", mainwin_general_menu_callback,
     MAINWIN_GENERAL_STOP, "<StockItem>", GTK_STOCK_MEDIA_STOP},
    {N_("/Previous"), "z", mainwin_general_menu_callback,
     MAINWIN_GENERAL_PREV, "<StockItem>", GTK_STOCK_MEDIA_PREVIOUS},
    {N_("/Next"), "b", mainwin_general_menu_callback,
     MAINWIN_GENERAL_NEXT, "<StockItem>", GTK_STOCK_MEDIA_NEXT},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Jump to Playlist Start"), "<control>Z", mainwin_general_menu_callback,
     MAINWIN_GENERAL_START, "<StockItem>", GTK_STOCK_GOTO_TOP},
     {N_("/-"), NULL, NULL, 0, "<Separator>"},
     {N_("/Set A-B"), "A", mainwin_general_menu_callback,
     MAINWIN_GENERAL_SETAB, "<Item>"},
     {N_("/Clear A-B"), "<control>S", mainwin_general_menu_callback,
     MAINWIN_GENERAL_CLEARAB, "<Item>"},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Jump to File"), "J", mainwin_general_menu_callback,
     MAINWIN_GENERAL_JTF, "<StockItem>", GTK_STOCK_JUMP_TO},
    {N_("/Jump to Time"), "<control>J", mainwin_general_menu_callback,
     MAINWIN_GENERAL_JTT, "<StockItem>", GTK_STOCK_JUMP_TO},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/View Track Details"), "<alt>I", mainwin_general_menu_callback,
     MAINWIN_GENERAL_FILEINFO, "<ImageItem>", 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, "<StockItem>", GTK_STOCK_DIALOG_INFO},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Play File"), "L", mainwin_general_menu_callback,
     MAINWIN_GENERAL_PLAYFILE, "<StockItem>", GTK_STOCK_OPEN},
    {N_("/Play Location"), "<control>L", mainwin_general_menu_callback,
     MAINWIN_GENERAL_PLAYLOCATION, "<StockItem>", GTK_STOCK_NETWORK},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/V_isualization"), NULL, NULL, 0, "<Item>", NULL},
    {N_("/_Playback"), NULL, NULL, 0, "<Item>", NULL},
    {N_("/_View"), NULL, NULL, 0, "<Item>", NULL},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Preferences"), "<control>P", mainwin_general_menu_callback,
     MAINWIN_GENERAL_PREFS, "<StockItem>", GTK_STOCK_PREFERENCES},
    {N_("/_Quit"), NULL, mainwin_general_menu_callback,
     MAINWIN_GENERAL_EXIT, "<StockItem>", 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, "<StockItem>", GTK_STOCK_OPEN},
    {N_("/Internet location..."), "<control>h", mainwin_general_menu_callback,
     MAINWIN_GENERAL_PLAYLOCATION, "<StockItem>", 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"), "<alt>M", mainwin_general_menu_callback,
     MAINWIN_GENERAL_SHOWMWIN, "<ToggleItem>", NULL},
    {N_("/Show Playlist Editor"), "<alt>E", mainwin_general_menu_callback,
     MAINWIN_GENERAL_SHOWPLWIN, "<ToggleItem>", NULL},
    {N_("/Show Equalizer"), "<alt>G", mainwin_general_menu_callback,
     MAINWIN_GENERAL_SHOWEQWIN, "<ToggleItem>", NULL},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Time Elapsed"), "<control>E", mainwin_view_menu_callback,
     MAINWIN_OPT_TELAPSED, "<RadioItem>", NULL},
    {N_("/Time Remaining"), "<control>R", mainwin_view_menu_callback,
     MAINWIN_OPT_TREMAINING, "/Time Elapsed", NULL},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Always On Top"), "<control>o", mainwin_view_menu_callback,
     MAINWIN_OPT_ALWAYS, "<ToggleItem>", NULL},
    {N_("/Put on All Workspaces"), "<control>S",
     mainwin_view_menu_callback, MAINWIN_OPT_STICKY, "<ToggleItem>", NULL},
    {N_("/Autoscroll Songname"), NULL, mainwin_view_menu_callback,
     MAINWIN_SONGNAME_SCROLL, "<ToggleItem>", NULL},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/Roll up Player"), "<control>W", mainwin_view_menu_callback,
     MAINWIN_OPT_WS, "<ToggleItem>", NULL},
    {N_("/Roll up Playlist Editor"), "<control><shift>W", mainwin_view_menu_callback,
     MAINWIN_OPT_PWS, "<ToggleItem>", NULL},
    {N_("/Roll up Equalizer"), "<control><alt>W", mainwin_view_menu_callback,
     MAINWIN_OPT_EQWS, "<ToggleItem>", NULL},
    {"/-", NULL, NULL, 0, "<Separator>", NULL},
    {N_("/DoubleSize"), "<control>D", mainwin_view_menu_callback,
     MAINWIN_OPT_DOUBLESIZE, "<ToggleItem>"},
    {N_("/Easy Move"), "<control>E", mainwin_view_menu_callback,
     MAINWIN_OPT_EASY_MOVE, "<ToggleItem>"}
};

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);

void set_doublesize(gboolean doublesize);


/* 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)
{
    if (!cfg.player_visible)
        return;

    if (cfg.doublesize == FALSE)
        gtk_widget_shape_combine_mask(mainwin,
                                  skin_get_mask(bmp_active_skin,
                                                SKIN_MASK_MAIN), 0, 0);
    else
        gtk_widget_shape_combine_mask(mainwin, NULL, 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 * (cfg.doublesize + 1));

        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 {
	gint height = !bmp_active_skin->properties.mainwin_height ? MAINWIN_HEIGHT :
                     bmp_active_skin->properties.mainwin_height;

        dock_shade(dock_window_list, GTK_WINDOW(mainwin), height * (cfg.doublesize + 1));

        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, cfg.autoscroll);
        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 * (1 + cfg.doublesize),
                            y + MAINWIN_SHADED_HEIGHT * (1 + cfg.doublesize),
                            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)
{
    GdkImage *img, *img2x;
    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, bmp_active_skin->properties.mainwin_width,
                             bmp_active_skin->properties.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) {
            if (cfg.doublesize) {
                img = gdk_drawable_get_image(mainwin_bg, 0, 0, bmp_active_skin->properties.mainwin_width,
                                             cfg.player_shaded ?
                                             MAINWIN_SHADED_HEIGHT :
                                             bmp_active_skin->properties.mainwin_height);
                img2x = create_dblsize_image(img);
                gdk_draw_image(mainwin_bg_x2, mainwin_gc, img2x, 0, 0,
                               0, 0, MAINWIN_WIDTH * 2,
                               cfg.player_shaded ? MAINWIN_SHADED_HEIGHT *
                               2 : MAINWIN_HEIGHT * 2);
                gdk_image_destroy(img2x);
                gdk_image_destroy(img);
            }

            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;

                if (cfg.doublesize) {
                    img = gdk_drawable_get_image(mainwin_bg, w->x, w->y,
                                                 w->width, w->height);
                    img2x = create_dblsize_image(img);
                    gdk_draw_image(mainwin_bg_x2, mainwin_gc,
                                   img2x, 0, 0, w->x << 1, w->y << 1,
                                   w->width << 1, w->height << 1);
                    gdk_image_destroy(img2x);
                    gdk_image_destroy(img);
                    gdk_window_clear_area(mainwin->window, w->x << 1,
                                          w->y << 1, w->width << 1,
                                          w->height << 1);
                }
                else
                    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);
    }
}

static gchar *mainwin_tb_old_text = NULL;

void
mainwin_lock_info_text(const gchar * text)
{
    if (mainwin_info_text_locked != TRUE)
        mainwin_tb_old_text = g_strdup(bmp_active_skin->properties.mainwin_othertext_is_status ?
  	    mainwin_othertext->tb_text : mainwin_info->tb_text);

    mainwin_info_text_locked = TRUE;
    textbox_set_text(bmp_active_skin->properties.mainwin_othertext_is_status ?
	mainwin_othertext : mainwin_info, text);
}

void
mainwin_release_info_text(void)
{
    mainwin_info_text_locked = FALSE;

    if (mainwin_tb_old_text != NULL)
    {
        textbox_set_text(bmp_active_skin->properties.mainwin_othertext_is_status ?
  	    mainwin_othertext : mainwin_info, mainwin_tb_old_text);
        g_free(mainwin_tb_old_text);
        mainwin_tb_old_text = NULL;
    }
    else
        mainwin_set_info_text();	/* XXX: best we can do */
}


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));

	if (bmp_active_skin->properties.mainwin_othertext_visible)
	    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));
    }

    /* positioning and size attributes */
    if (bmp_active_skin->properties.mainwin_vis_x && bmp_active_skin->properties.mainwin_vis_y)
	widget_move(WIDGET(mainwin_vis), bmp_active_skin->properties.mainwin_vis_x,
		bmp_active_skin->properties.mainwin_vis_y);

    if (bmp_active_skin->properties.mainwin_vis_width)
	widget_resize(WIDGET(mainwin_info), bmp_active_skin->properties.mainwin_vis_width,
		mainwin_vis->vs_widget.height);

    if (bmp_active_skin->properties.mainwin_text_x && bmp_active_skin->properties.mainwin_text_y)
	widget_move(WIDGET(mainwin_info), bmp_active_skin->properties.mainwin_text_x,
		bmp_active_skin->properties.mainwin_text_y);

    if (bmp_active_skin->properties.mainwin_text_width)
	widget_resize(WIDGET(mainwin_info), bmp_active_skin->properties.mainwin_text_width,
		mainwin_info->tb_widget.height);

    if (bmp_active_skin->properties.mainwin_infobar_x && bmp_active_skin->properties.mainwin_infobar_y)
	widget_move(WIDGET(mainwin_othertext), bmp_active_skin->properties.mainwin_infobar_x,
		bmp_active_skin->properties.mainwin_infobar_y);

    if (bmp_active_skin->properties.mainwin_number_0_x && bmp_active_skin->properties.mainwin_number_0_y)
	widget_move(WIDGET(mainwin_minus_num), bmp_active_skin->properties.mainwin_number_0_x,
		bmp_active_skin->properties.mainwin_number_0_y);

    if (bmp_active_skin->properties.mainwin_number_1_x && bmp_active_skin->properties.mainwin_number_1_y)
	widget_move(WIDGET(mainwin_10min_num), bmp_active_skin->properties.mainwin_number_1_x,
		bmp_active_skin->properties.mainwin_number_1_y);

    if (bmp_active_skin->properties.mainwin_number_2_x && bmp_active_skin->properties.mainwin_number_2_y)
	widget_move(WIDGET(mainwin_min_num), bmp_active_skin->properties.mainwin_number_2_x,
		bmp_active_skin->properties.mainwin_number_2_y);

    if (bmp_active_skin->properties.mainwin_number_3_x && bmp_active_skin->properties.mainwin_number_3_y)
	widget_move(WIDGET(mainwin_10sec_num), bmp_active_skin->properties.mainwin_number_3_x,
		bmp_active_skin->properties.mainwin_number_3_y);

    if (bmp_active_skin->properties.mainwin_number_4_x && bmp_active_skin->properties.mainwin_number_4_y)
	widget_move(WIDGET(mainwin_sec_num), bmp_active_skin->properties.mainwin_number_4_x,
		bmp_active_skin->properties.mainwin_number_4_y);

    if (bmp_active_skin->properties.mainwin_playstatus_x && bmp_active_skin->properties.mainwin_playstatus_y)
	widget_move(WIDGET(mainwin_playstatus), bmp_active_skin->properties.mainwin_playstatus_x,
		bmp_active_skin->properties.mainwin_playstatus_y);

    if (bmp_active_skin->properties.mainwin_volume_x && bmp_active_skin->properties.mainwin_volume_y)
	widget_move(WIDGET(mainwin_volume), bmp_active_skin->properties.mainwin_volume_x,
		bmp_active_skin->properties.mainwin_volume_y);

    if (bmp_active_skin->properties.mainwin_balance_x && bmp_active_skin->properties.mainwin_balance_y)
	widget_move(WIDGET(mainwin_balance), bmp_active_skin->properties.mainwin_balance_x,
		bmp_active_skin->properties.mainwin_balance_y);

    if (bmp_active_skin->properties.mainwin_position_x && bmp_active_skin->properties.mainwin_position_y)
	widget_move(WIDGET(mainwin_position), bmp_active_skin->properties.mainwin_position_x,
		bmp_active_skin->properties.mainwin_position_y);

    if (bmp_active_skin->properties.mainwin_previous_x && bmp_active_skin->properties.mainwin_previous_y)
	widget_move(WIDGET(mainwin_rew), bmp_active_skin->properties.mainwin_previous_x,
		bmp_active_skin->properties.mainwin_previous_y);

    if (bmp_active_skin->properties.mainwin_play_x && bmp_active_skin->properties.mainwin_play_y)
	widget_move(WIDGET(mainwin_play), bmp_active_skin->properties.mainwin_play_x,
		bmp_active_skin->properties.mainwin_play_y);

    if (bmp_active_skin->properties.mainwin_pause_x && bmp_active_skin->properties.mainwin_pause_y)
	widget_move(WIDGET(mainwin_pause), bmp_active_skin->properties.mainwin_pause_x,
		bmp_active_skin->properties.mainwin_pause_y);

    if (bmp_active_skin->properties.mainwin_stop_x && bmp_active_skin->properties.mainwin_stop_y)
	widget_move(WIDGET(mainwin_stop), bmp_active_skin->properties.mainwin_stop_x,
		bmp_active_skin->properties.mainwin_stop_y);

    if (bmp_active_skin->properties.mainwin_next_x && bmp_active_skin->properties.mainwin_next_y)
	widget_move(WIDGET(mainwin_fwd), bmp_active_skin->properties.mainwin_next_x,
		bmp_active_skin->properties.mainwin_next_y);

    if (bmp_active_skin->properties.mainwin_eject_x && bmp_active_skin->properties.mainwin_eject_y)
	widget_move(WIDGET(mainwin_eject), bmp_active_skin->properties.mainwin_eject_x,
		bmp_active_skin->properties.mainwin_eject_y);

    if (bmp_active_skin->properties.mainwin_eqbutton_x && bmp_active_skin->properties.mainwin_eqbutton_y)
	widget_move(WIDGET(mainwin_eq), bmp_active_skin->properties.mainwin_eqbutton_x,
		bmp_active_skin->properties.mainwin_eqbutton_y);

    if (bmp_active_skin->properties.mainwin_plbutton_x && bmp_active_skin->properties.mainwin_plbutton_y)
	widget_move(WIDGET(mainwin_pl), bmp_active_skin->properties.mainwin_plbutton_x,
		bmp_active_skin->properties.mainwin_plbutton_y);

    if (bmp_active_skin->properties.mainwin_shuffle_x && bmp_active_skin->properties.mainwin_shuffle_y)
	widget_move(WIDGET(mainwin_shuffle), bmp_active_skin->properties.mainwin_shuffle_x,
		bmp_active_skin->properties.mainwin_shuffle_y);

    if (bmp_active_skin->properties.mainwin_repeat_x && bmp_active_skin->properties.mainwin_repeat_y)
	widget_move(WIDGET(mainwin_repeat), bmp_active_skin->properties.mainwin_repeat_x,
		bmp_active_skin->properties.mainwin_repeat_y);

    if (bmp_active_skin->properties.mainwin_about_x && bmp_active_skin->properties.mainwin_about_y)
	widget_move(WIDGET(mainwin_about), bmp_active_skin->properties.mainwin_about_x,
		bmp_active_skin->properties.mainwin_about_y);

    if (bmp_active_skin->properties.mainwin_minimize_x && bmp_active_skin->properties.mainwin_minimize_y)
	widget_move(WIDGET(mainwin_minimize), cfg.player_shaded ? 244 : bmp_active_skin->properties.mainwin_minimize_x,
		cfg.player_shaded ? 3 : bmp_active_skin->properties.mainwin_minimize_y);

    if (bmp_active_skin->properties.mainwin_shade_x && bmp_active_skin->properties.mainwin_shade_y)
	widget_move(WIDGET(mainwin_shade), cfg.player_shaded ? 254 : bmp_active_skin->properties.mainwin_shade_x,
		cfg.player_shaded ? 3 : bmp_active_skin->properties.mainwin_shade_y);

    if (bmp_active_skin->properties.mainwin_close_x && bmp_active_skin->properties.mainwin_close_y)
	widget_move(WIDGET(mainwin_close), cfg.player_shaded ? 264 : bmp_active_skin->properties.mainwin_close_x,
		cfg.player_shaded ? 3 : bmp_active_skin->properties.mainwin_close_y);

    /* visibility attributes */
    if (bmp_active_skin->properties.mainwin_menurow_visible)
        widget_show(WIDGET(mainwin_menurow));
    else
        widget_hide(WIDGET(mainwin_menurow));

    if (bmp_active_skin->properties.mainwin_text_visible)
        widget_show(WIDGET(mainwin_info));
    else
        widget_hide(WIDGET(mainwin_info));

    if (bmp_active_skin->properties.mainwin_othertext_visible)
        widget_show(WIDGET(mainwin_othertext));
    else
        widget_hide(WIDGET(mainwin_othertext));

    if (bmp_active_skin->properties.mainwin_vis_visible)
        widget_show(WIDGET(mainwin_vis));
    else
        widget_hide(WIDGET(mainwin_vis));

    /* window size, mainwinWidth && mainwinHeight properties */
    if (bmp_active_skin->properties.mainwin_height && bmp_active_skin->properties.mainwin_width)
    {
	gint width, height;

	gdk_window_get_size(mainwin->window, &width, &height);

	if (width == bmp_active_skin->properties.mainwin_width * (cfg.doublesize + 1) &&
		height == bmp_active_skin->properties.mainwin_height * (cfg.doublesize + 1))
	{
		return;
	}

        dock_window_resize(GTK_WINDOW(mainwin), cfg.player_shaded ? MAINWIN_SHADED_WIDTH : bmp_active_skin->properties.mainwin_width,
		cfg.player_shaded ? MAINWIN_SHADED_HEIGHT : bmp_active_skin->properties.mainwin_height,
		bmp_active_skin->properties.mainwin_width * (cfg.doublesize + 1),
		bmp_active_skin->properties.mainwin_height * (cfg.doublesize + 1));

	g_object_unref(mainwin_bg);
	g_object_unref(mainwin_bg_x2);
        mainwin_bg = gdk_pixmap_new(mainwin->window,
				bmp_active_skin->properties.mainwin_width,
				bmp_active_skin->properties.mainwin_height, -1);
        mainwin_bg_x2 = gdk_pixmap_new(mainwin->window,
				bmp_active_skin->properties.mainwin_width * 2,
				bmp_active_skin->properties.mainwin_height * 2, -1);
        mainwin_set_back_pixmap();
	widget_list_change_pixmap(mainwin_wlist, mainwin_bg);
	gdk_flush();
    }
}

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() && mainwin_playstatus != NULL)
        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));

        if (bmp_active_skin->properties.mainwin_othertext_visible)
            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);

    if (mainwin_playstatus != NULL)
        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 (cfg.doublesize) {
        event->x /= 2;
        event->y /= 2;
    }
    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)
{
	switch (event->direction) {
	case GDK_SCROLL_UP:
		mainwin_set_volume_diff(cfg.mouse_change);
		break;
	case GDK_SCROLL_DOWN:
		mainwin_set_volume_diff(-cfg.mouse_change);
		break;
	case GDK_SCROLL_LEFT:
		if (playlist_get_current_length() != -1)
			bmp_playback_seek(CLAMP(bmp_playback_get_time() - 1000,
			    0, playlist_get_current_length()) / 1000);
		break;
	case GDK_SCROLL_RIGHT:
		if (playlist_get_current_length() != -1)
			bmp_playback_seek(CLAMP(bmp_playback_get_time() + 1000,
			    0, playlist_get_current_length()) / 1000);
		break;
	}
}

static gboolean
mainwin_mouse_button_press(GtkWidget * widget,
                           GdkEventButton * event,
                           gpointer callback_data)
{

    gboolean grab = TRUE;

    if (cfg.doublesize) {
        /*
         * A hack to make doublesize transparent to callbacks.
         * We should make a copy of this data instead of
         * tampering with the data we get from gtk+
         */
        event->x /= 2;
        event->y /= 2;
    }

    if (event->button == 1 && event->type == GDK_BUTTON_PRESS &&
        !inside_sensitive_widgets(event->x, event->y) &&
        (cfg.easy_move || 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 (widget_contains(WIDGET(mainwin_minus_num), event->x, event->y) ||
		widget_contains(WIDGET(mainwin_10min_num), event->x, event->y) ||
		widget_contains(WIDGET(mainwin_min_num), event->x, event->y) ||
		widget_contains(WIDGET(mainwin_10sec_num), event->x, event->y) ||
		widget_contains(WIDGET(mainwin_sec_num), event->x, event->y) ||
		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)
{
    if (cfg.doublesize)
        gdk_window_set_back_pixmap(mainwin->window, mainwin_bg_x2, 0);
    else
        gdk_window_set_back_pixmap(mainwin->window, mainwin_bg, 0);
    gdk_window_clear(mainwin->window);
}

/*
 * Rewritten 09/13/06:
 *
 * Remove all of this flaky iter/sourcelist/strsplit stuff.
 * All we care about is the filepath.
 *
 * We can figure this out and easily pass it to xmms_urldecode_plain().
 *   - nenolod
 */
void
mainwin_drag_data_received(GtkWidget * widget,
                           GdkDragContext * context,
                           gint x,
                           gint y,
                           GtkSelectionData * selection_data,
                           guint info,
                           guint time,
                           gpointer user_data)
{
    g_return_if_fail(selection_data != NULL);
    g_return_if_fail(selection_data->data != NULL);

    if (str_has_prefix_nocase((gchar *) selection_data->data, "fonts:///"))
    {
        gchar *path = (gchar *) selection_data->data + 9;		/* skip fonts:/// */
	gchar *decoded = xmms_urldecode_plain(path);

        cfg.playlist_font = g_strconcat(decoded, strrchr(cfg.playlist_font, ' '), NULL);
        playlist_list_set_font(cfg.playlist_font);
        playlistwin_update_list();

        g_free(decoded);

        return;
    }

    playlist_clear();
    playlist_add_url((gchar *) selection_data->data);
    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 (ab_position_a != -1)
        bmp_playback_seek(ab_position_a / 1000);
    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,
                         !bmp_active_skin->properties.mainwin_width ? PLAYER_WIDTH :
				bmp_active_skin->properties.mainwin_width,
                         !bmp_active_skin->properties.mainwin_height ? PLAYER_HEIGHT :
				bmp_active_skin->properties.mainwin_height,
                         !bmp_active_skin->properties.mainwin_width ? PLAYER_WIDTH :
				bmp_active_skin->properties.mainwin_width,
                         !bmp_active_skin->properties.mainwin_height ? PLAYER_HEIGHT :
				bmp_active_skin->properties.mainwin_height,
                         GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
    gtk_window_resize(GTK_WINDOW(mainwin), 
                         !bmp_active_skin->properties.mainwin_width ? PLAYER_WIDTH :
				bmp_active_skin->properties.mainwin_width,
                         !bmp_active_skin->properties.mainwin_height ? PLAYER_HEIGHT :
				bmp_active_skin->properties.mainwin_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));
        check_set(mainwin_view_menu, "/Autoscroll Songname", cfg.autoscroll);
	playlistwin_set_sinfo_scroll(cfg.autoscroll); /* propagate scroll setting to playlistwin_sinfo */
        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_set_doublesize(gboolean doublesize)
{
    gint height;

    if (cfg.player_shaded)
        height = MAINWIN_SHADED_HEIGHT;
    else
        height = bmp_active_skin->properties.mainwin_height;

    mainwin_set_shape_mask();

    dock_window_resize(GTK_WINDOW(mainwin), cfg.player_shaded ? MAINWIN_SHADED_WIDTH : bmp_active_skin->properties.mainwin_width,
		cfg.player_shaded ? MAINWIN_SHADED_HEIGHT : bmp_active_skin->properties.mainwin_height,
		bmp_active_skin->properties.mainwin_width * 2, bmp_active_skin->properties.mainwin_height * 2);

    if (cfg.doublesize) {
        gdk_window_set_back_pixmap(mainwin->window, mainwin_bg_x2, 0);
    }
    else {
        gdk_window_set_back_pixmap(mainwin->window, mainwin_bg, 0);
    }

    draw_main_window(TRUE);
    vis_set_doublesize(mainwin_vis, doublesize);
}

void
set_doublesize(gboolean doublesize)
{
    cfg.doublesize = doublesize;

    mainwin_set_doublesize(doublesize);

    if (cfg.eq_doublesize_linked)
        equalizerwin_set_doublesize(doublesize);
}

                               
static void
mainwin_view_menu_callback(gpointer data,
                           guint action,
                           GtkWidget * item)
{
    GtkCheckMenuItem *check;

    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;
    case MAINWIN_OPT_DOUBLESIZE:
        mainwin_menurow->mr_doublesize_selected =
            GTK_CHECK_MENU_ITEM(gtk_item_factory_get_widget
                                (mainwin_view_menu,
                                 "/DoubleSize"))->active;
        widget_draw(WIDGET(mainwin_menurow));
        set_doublesize(mainwin_menurow->mr_doublesize_selected);
        gdk_flush();
        break;
    case MAINWIN_OPT_EASY_MOVE:
        cfg.easy_move =
            GTK_CHECK_MENU_ITEM(gtk_item_factory_get_widget
                                (mainwin_view_menu, "/Easy Move"))->active;
        break;
    case MAINWIN_SONGNAME_SCROLL:
        check = GTK_CHECK_MENU_ITEM(item);
        mainwin_set_title_scroll(gtk_check_menu_item_get_active(check));
        check_set(mainwin_songname_menu, "/Autoscroll Songname", cfg.autoscroll);
	playlistwin_set_sinfo_scroll(cfg.autoscroll); /* propagate scroll setting to playlistwin_sinfo */
        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;
    case MAINWIN_GENERAL_SETAB:
        if (playlist_get_current_length() != -1) {
            if (ab_position_a == -1) {
                ab_position_a = bmp_playback_get_time();
                ab_position_b = -1;
		mainwin_lock_info_text("LOOP-POINT A POSITION SET.");
            } else if (ab_position_b == -1) {
                int time = bmp_playback_get_time();
                if (time > ab_position_a)
                    ab_position_b = time;
		mainwin_release_info_text();
            } else {
                ab_position_a = bmp_playback_get_time();
                ab_position_b = -1;
		mainwin_lock_info_text("LOOP-POINT A POSITION RESET.");
            }
        }
        break;
    case MAINWIN_GENERAL_CLEARAB:
        if (playlist_get_current_length() != -1) {
            ab_position_a = ab_position_b = -1;
	    mainwin_release_info_text();
        }
        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:
        if (mainwin_menurow->mr_doublesize_selected)
            mainwin_lock_info_text(_("DISABLE DOUBLESIZE"));
        else
            mainwin_lock_info_text(_("ENABLE DOUBLESIZE"));
        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:
        widget =
            gtk_item_factory_get_widget(mainwin_view_menu, "/DoubleSize");
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget),
                                       mainwin_menurow->mr_doublesize_selected);
        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_("<b><big>No playable CD found.</big></b>\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_("<b><big>Couldn't open audio.</big></b>\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);
    check_set(mainwin_view_menu, "/Easy Move", cfg.easy_move);
    check_set(mainwin_view_menu, "/DoubleSize", cfg.doublesize);

    /* 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 = cfg.doublesize;
    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, cfg.doublesize);
    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 = cfg.player_shaded ? MAINWIN_SHADED_WIDTH : bmp_active_skin->properties.mainwin_width;
    height = cfg.player_shaded ? MAINWIN_SHADED_HEIGHT : bmp_active_skin->properties.mainwin_height;

    if (cfg.doublesize) {
        width *= 2;
        height *= 2;
    }

    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,
                                bmp_active_skin->properties.mainwin_width,
				bmp_active_skin->properties.mainwin_height, -1);
    mainwin_bg_x2 = gdk_pixmap_new(mainwin->window,
                                bmp_active_skin->properties.mainwin_width * 2,
				bmp_active_skin->properties.mainwin_height * 2, -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;

    if (ab_position_a != -1 && ab_position_b != -1 && time > ab_position_b)
        bmp_playback_seek(ab_position_a/1000);

    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();
	ab_position_a = ab_position_b = -1;
    }

    draw_main_window(mainwin_force_redraw);

    if (!count) {
        read_volume(VOLSET_UPDATE);
        count = 10;
    }
    else
        count--;

    mainwin_force_redraw = FALSE;
    draw_equalizer_window(FALSE);
    draw_playlist_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;
}