/*******************************************************************************
*                         Goggles Music Manager                                *
********************************************************************************
*           Copyright (C) 2006-2010 by Sander Jansen. All Rights Reserved      *
*                               ---                                            *
* This program is free software: you can redistribute it and/or modify         *
* it under the terms of the GNU General Public License as published by         *
* the Free Software Foundation, either version 3 of the License, 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, see http://www.gnu.org/licenses.           *
********************************************************************************/
#include "gmdefs.h"
#include <xincs.h>

#include <FXJPGImage.h>
#include <FXPNGImage.h>
#include <FXPNGIcon.h>
#include <FXArray.h>
#include <fxkeys.h>
#include <FXUTF8Codec.h>

#include <xine.h>
#include "GMPlayer.h"


#include "GMApp.h"
#include "GMAbout.h"
#include "GMWindow.h"
#include "GMTrackList.h"
#include "GMList.h"
#include "GMRemote.h"
#include "GMTag.h"
#include "GMThread.h"
#include "GMSearch.h"
#include "GMHeaderButton.h"
#include "GMSource.h"
#include "GMPlayerManager.h"
#include "GMDatabaseSource.h"
#include "GMTrackView.h"
#include "GMSourceView.h"
#include "GMAudioScrobbler.h"
#include "icons.h"
#include "GMIconTheme.h"
#include "GMImportDialog.h"
#include "GMPreferencesDialog.h"
#include "GMImageView.h"
#include "GMFilename.h"



#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>


// Define Message Map
FXDEFMAP(GMWindow) GMWindowMap[]={
  //________Message_Type_____________________ID___________________________Message_Handler___
  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_PLAYPAUSE,         GMWindow::onUpdPlayPause),
  FXMAPFUNC(SEL_UPDATE,        		  GMWindow::ID_PLAYPAUSEMENU,     GMWindow::onUpdPlayPauseMenu),

  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_PAUSE,             GMWindow::onUpdPause),
  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_STOP,              GMWindow::onUpdStop),
  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_NEXT,              GMWindow::onUpdNext),
  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_PREV,              GMWindow::onUpdPrev),
  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_REPEAT_ALL,       	GMWindow::onUpdRepeatAll),
  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_REPEAT,    				GMWindow::onUpdRepeat),
  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_REPEAT_AB,    		  GMWindow::onUpdRepeatAB),
  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_REPEAT_OFF,    		GMWindow::onUpdRepeatOff),

  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_SHUFFLE,    				GMWindow::onUpdShuffle),
  FXMAPFUNC(SEL_UPDATE,							GMWindow::ID_SLEEP,					    GMWindow::onUpdSleepTimer),
  FXMAPFUNC(SEL_UPDATE,        		 	GMWindow::ID_SHOW_TRACK,        GMWindow::onUpdShowTrack),
  FXMAPFUNC(SEL_UPDATE,					    GMWindow::ID_VOLUME_BUTTON,     GMWindow::onUpdVolumeButton),
  FXMAPFUNC(SEL_UPDATE,        		  GMWindow::ID_SHOW_MINIPLAYER,   GMWindow::onUpdShowMiniPlayer),

  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_QUIT,							GMWindow::onCmdQuit),
  FXMAPFUNC(SEL_SIGNAL,							GMWindow::ID_QUIT,							GMWindow::onCmdQuit),
  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_IMPORT_DIRS,				GMWindow::onCmdImport),
  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_IMPORT_FILES,		  GMWindow::onCmdImport),
  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_SYNC_DIRS,		      GMWindow::onCmdImport),

  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_OPEN,							GMWindow::onCmdOpen),

  FXMAPFUNC(SEL_COMMAND,         		GMWindow::ID_REPEAT_ALL,       	GMWindow::onCmdRepeatAll),
  FXMAPFUNC(SEL_COMMAND,         		GMWindow::ID_REPEAT_AB,    			GMWindow::onCmdRepeatAB),
  FXMAPFUNC(SEL_COMMAND,         		GMWindow::ID_REPEAT,    				GMWindow::onCmdRepeat),
  FXMAPFUNC(SEL_COMMAND,         		GMWindow::ID_REPEAT_OFF,    	  GMWindow::onCmdRepeatOff),

  FXMAPFUNC(SEL_COMMAND,         		GMWindow::ID_SHUFFLE,    				GMWindow::onCmdShuffle),

  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_ABOUT,             GMWindow::onCmdAbout),

  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_PLAYPAUSE,         GMWindow::onCmdPlayPause),
  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_PLAYPAUSEMENU,     GMWindow::onCmdPlayPause),

  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_PAUSE,             GMWindow::onCmdPause),
  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_STOP,              GMWindow::onCmdStop),
  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_NEXT,              GMWindow::onCmdNext),
  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_PREV,              GMWindow::onCmdPrev),

#if FOXVERSION >= FXVERSION(1,7,11)
  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_SHOW_FULLSCREEN,		GMWindow::onCmdShowFullScreen),
#endif
  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_SHOW_MINIPLAYER,   GMWindow::onCmdShowMiniPlayer),

  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_SHOW_TRACK,        GMWindow::onCmdShowTrack),

  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_PREFERENCES,       GMWindow::onCmdPreferences),

  FXMAPFUNC(SEL_COMMAND,            GMWindow::ID_RESET_COLORS,      GMWindow::onCmdResetColors),

  FXMAPFUNC(SEL_COMMAND,        		GMWindow::ID_TIMESLIDER,        GMWindow::onCmdTimeSlider),

  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_VOLUME_SLIDER,			GMWindow::onCmdVolume),
  FXMAPFUNC(SEL_CHANGED,						GMWindow::ID_VOLUME_SLIDER,			GMWindow::onCmdVolume),
  FXMAPFUNC(SEL_MOUSEWHEEL,					GMWindow::ID_VOLUME_BUTTON,     GMWindow::onCmdVolumeButton),
  FXMAPFUNC(SEL_MOUSEWHEEL,					0,															GMWindow::onCmdVolumeButton),


  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_HOMEPAGE,					GMWindow::onCmdHomePage),
  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_REPORT_ISSUE,	  	GMWindow::onCmdReportIssue),

  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_JOIN_LASTFM,	  	GMWindow::onCmdJoinLastFM),
  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_JOIN_GMM_LASTFM,	  	GMWindow::onCmdJoinGMMLastFM),

  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_SLEEP,					GMWindow::onCmdSleepTimer),

  FXMAPFUNC(SEL_COMMAND,						GMWindow::ID_CHANGE_COVERVIEW,		GMWindow::onCmdChangeCoverView),
  FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,	GMWindow::ID_COVERVIEW,					GMWindow::onCmdCoverView),

#if FOXVERSION > FXVERSION(1,7,21)
  FXMAPFUNC(SEL_UPDATE,         		GMWindow::ID_SHOW_SOURCES,       	GMWindow::onUpdShowSources),
  FXMAPFUNC(SEL_COMMAND,         		GMWindow::ID_SHOW_SOURCES,       	GMWindow::onCmdShowSources),
#endif

  FXMAPFUNCS(SEL_COMMAND,						GMWindow::ID_COVERSIZE_SMALL,GMWindow::ID_COVERSIZE_EXTRALARGE,		GMWindow::onCmdCoverSize),
  FXMAPFUNCS(SEL_UPDATE,						GMWindow::ID_COVERSIZE_SMALL,GMWindow::ID_COVERSIZE_EXTRALARGE,		GMWindow::onUpdCoverSize),


  };


// Object implementation
FXIMPLEMENT(GMWindow,FXMainWindow,GMWindowMap,ARRAYNUMBER(GMWindowMap))



#if FOXVERSION > FXVERSION(1,7,21)
#define HIDESOURCES (FX4Splitter::ExpandTopRight)
#define SHOWSOURCES (FX4Splitter::ExpandTopLeft|FX4Splitter::ExpandTopRight|FX4Splitter::ExpandBottomLeft)
#endif


//----------------------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------------------
GMWindow::GMWindow(FXApp* a,FXObject*tgt,FXSelector msg) : FXMainWindow(a,"Goggles Music Manager",NULL,NULL,DECOR_ALL,5,5,700,580) {
  flags|=FLAG_ENABLED;

  cover_small=NULL;

  icontheme = new GMIconTheme(a);
  icontheme->load();

  createFonts();

  setIcon(icontheme->icon_applogo);
  setMiniIcon(icontheme->icon_applogo_small);

#if APPLICATION_BETA > 0
  setTitle("Goggles Music Manager " APPLICATION_VERSION_STRING);
#endif

  /// Set myself as the target
  setTarget(tgt);
  setSelector(msg);

  /// Popup Volume Menu
  volumecontrol = new FXPopup(this,POPUP_VERTICAL|FRAME_RAISED|FRAME_THICK|POPUP_SHRINKWRAP);
  volumeslider = new FXSlider(volumecontrol,this,GMWindow::ID_VOLUME_SLIDER,LAYOUT_FIX_HEIGHT|LAYOUT_FIX_WIDTH|SLIDER_VERTICAL|SLIDER_TICKS_RIGHT|SLIDER_TICKS_LEFT|SLIDER_INSIDE_BAR,0,0,20,100);
  volumeslider->setTickDelta(10);
  volumeslider->setRange(0,100);
  volumeslider->setIncrement(10);

  // Make menu bar
  FXMenuBar * menubar=new FXMenuBar(this,LAYOUT_SIDE_TOP|LAYOUT_FILL_X);
  menubar->setDragCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
  statusbar = new FXStatusBar(this,LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER,0,0,0,0,3,3,2,2,3);

  new FXSeparator(this,LAYOUT_FILL_X|SEPARATOR_GROOVE|LAYOUT_SIDE_TOP);
  controlstatusseparator = new FXSeparator(this,LAYOUT_FILL_X|SEPARATOR_GROOVE|LAYOUT_SIDE_BOTTOM);
  controlstatusseparator->hide();

  controlframe    = new FXHorizontalFrame(this,LAYOUT_SIDE_TOP|LAYOUT_FILL_X,0,0,0,0,3,3,3,3);
  playpausebutton = new FXToggleButton(controlframe,tr("Play\tStart Playback\tStart Playback"),tr("Pause\tPause\tPause Playback"),icontheme->icon_play,icontheme->icon_pause,this,ID_PLAYPAUSE,BUTTON_TOOLBAR|FRAME_RAISED|ICON_ABOVE_TEXT);
  stopbutton      = new FXButton(controlframe,tr("Stop\tStop Playback\tStop Playback"),icontheme->icon_stop,this,ID_STOP,BUTTON_TOOLBAR|FRAME_RAISED|ICON_ABOVE_TEXT);
                    new FXVerticalSeparator(controlframe,LAYOUT_FILL_Y|SEPARATOR_GROOVE);
  prevbutton      = new FXButton(controlframe,tr("Previous\tPlay Previous Track\tPlay previous track."),icontheme->icon_prev,this,ID_PREV,BUTTON_TOOLBAR|FRAME_RAISED|ICON_ABOVE_TEXT);
  nextbutton      = new FXButton(controlframe,tr("Next\tPlay Next Track\tPlay next track."),icontheme->icon_next,this,ID_NEXT,BUTTON_TOOLBAR|FRAME_RAISED|ICON_ABOVE_TEXT);
                    new FXVerticalSeparator(controlframe,LAYOUT_FILL_Y|SEPARATOR_GROOVE);

  timeslider      = new FXSlider(controlframe,this,ID_TIMESLIDER,LAYOUT_FILL_X|LAYOUT_CENTER_Y);
  timeslider->setRange(0,65535);
  timeslider->setTickDelta(13107);
  timeslider->setIncrement(5000);
  timeslider->disable();
  timelabel  =new FX7Segment(controlframe,"--:--",SEVENSEGMENT_SHADOW|LAYOUT_CENTER_Y);
  timelabel->setCellWidth(10);
  timelabel->setCellHeight(15);

  new FXVerticalSeparator(controlframe,LAYOUT_FILL_Y|SEPARATOR_GROOVE);
  volumebutton = new FXMenuButton(controlframe,tr("\tAdjust Volume\tAdjust Volume"),NULL,volumecontrol,MENUBUTTON_NOARROWS|MENUBUTTON_ATTACH_LEFT|MENUBUTTON_UP|MENUBUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_CENTER_Y);
  volumebutton->setTarget(this);
  volumebutton->setSelector(ID_VOLUME_BUTTON);
  controldragcorner = new FXDragCorner(controlframe);
  controlseparator  = new FXSeparator(this,LAYOUT_FILL_X|SEPARATOR_GROOVE|LAYOUT_SIDE_TOP);

  FXVerticalFrame * mainframe = new FXVerticalFrame(this,LAYOUT_FILL_X|LAYOUT_FILL_Y);


#if FOXVERSION > FXVERSION(1,7,21)
  mainsplitter    = new FX4Splitter(mainframe,LAYOUT_FILL_X|LAYOUT_FILL_Y|FOURSPLITTER_VERTICAL|FOURSPLITTER_TRACKING);
  sourceview      = new GMSourceView(mainsplitter);
  trackview       = new GMTrackView(mainsplitter);
  coverframe      = new FXHorizontalFrame(mainsplitter,LAYOUT_BOTTOM|JUSTIFY_CENTER_X|JUSTIFY_CENTER_Y|LAYOUT_FILL_X|FRAME_SUNKEN|FRAME_THICK,0,0,0,0,5,5,5,5);
#else
  mainsplitter    = new FXSplitter(mainframe,LAYOUT_FILL_X|LAYOUT_FILL_Y|SPLITTER_HORIZONTAL|SPLITTER_TRACKING);
  sourcesplitter  = new FXSplitter(mainsplitter,LAYOUT_FILL_X|LAYOUT_FILL_Y|SPLITTER_VERTICAL|SPLITTER_TRACKING|SPLITTER_REVERSED);
  sourceview      = new GMSourceView(sourcesplitter);
  coverframe      = new FXHorizontalFrame(sourcesplitter,LAYOUT_BOTTOM|JUSTIFY_CENTER_X|JUSTIFY_CENTER_Y|LAYOUT_FILL_X|FRAME_SUNKEN|FRAME_THICK,0,0,0,0,5,5,5,5);
  trackview       = new GMTrackView(mainsplitter);
#endif
  coverframe->setBackColor(getApp()->getBackColor());
  coverframe->hide();
  coverview_x11=NULL;
  coverview_gl=NULL;
  glvisual=NULL;
  updateCoverView();

  // File Menu
  filemenu=new FXMenuPane(this);
  new FXMenuTitle(menubar,tr("&Music"),NULL,filemenu);
  new FXMenuCommand(filemenu,tr("Import Folder…\tCtrl-O\tImport Music from folder into Library"),icontheme->icon_import,this,GMWindow::ID_IMPORT_DIRS);
  new FXMenuCommand(filemenu,tr("Sync Folder…\t\tSynchronize Folder with Music in Library"),icontheme->icon_sync,this,GMWindow::ID_SYNC_DIRS);
  new FXMenuSeparator(filemenu);
  new FXMenuCommand(filemenu,tr("Play File or Stream…\t\tPlay File or Stream"),NULL,this,GMWindow::ID_OPEN);
  new FXMenuSeparator(filemenu);
  new FXMenuCommand(filemenu,tr("New Playlist…\t\tCreate a new playlist"),icontheme->icon_playlist,sourceview,GMSourceView::ID_NEW_PLAYLIST);
  new FXMenuCommand(filemenu,tr("Import Playlist…\t\tImport existing playlist"),icontheme->icon_import,GMPlayerManager::instance()->getDatabaseSource(),GMDatabaseSource::ID_IMPORT_PLAYLIST);
  new FXMenuCommand(filemenu,tr("New Radio Station…\t\tCreate a new playlist"),NULL,sourceview,GMSourceView::ID_NEW_STATION);

  new FXMenuSeparator(filemenu);
  new FXMenuCommand(filemenu,tr("&Quit\tCtrl-Q\tQuit the application."),icontheme->icon_exit,this,GMWindow::ID_QUIT);
  gm_set_window_cursor(filemenu,getApp()->getDefaultCursor(DEF_ARROW_CURSOR));

  // Help Menu
  editmenu=new FXMenuPane(this);
  new FXMenuTitle(menubar,tr("&Edit"),NULL,editmenu);
  new FXMenuCommand(editmenu,tr("&Copy\tCtrl-C\tCopy Selected Tracks"),icontheme->icon_copy,trackview,GMTrackView::ID_COPY,MENU_AUTOGRAY);
  new FXMenuCommand(editmenu,tr("&Cut\tCtrl-X\tCut Selected Tracks"),icontheme->icon_cut,trackview,GMTrackView::ID_CUT,MENU_AUTOGRAY);
  new FXMenuCommand(editmenu,tr("&Paste\tCtrl-V\tPaste Clipboard Selection"),icontheme->icon_paste,trackview,GMTrackView::ID_PASTE,MENU_AUTOGRAY);
  new FXMenuSeparator(editmenu);
  new FXMenuCommand(editmenu,tr("Find…\tCtrl-F\tShow search filter."),GMIconTheme::instance()->icon_find,trackview,GMTrackView::ID_TOGGLE_FILTER);
  new FXMenuSeparator(editmenu);
  new FXMenuCommand(editmenu,tr("Preferences…"),icontheme->icon_settings,this,GMWindow::ID_PREFERENCES);
  gm_set_window_cursor(editmenu,getApp()->getDefaultCursor(DEF_ARROW_CURSOR));

  viewmenu=new FXMenuPane(this);
  new FXMenuTitle(menubar,tr("&View"),NULL,viewmenu);
  new FXMenuCheck(viewmenu,tr("&Browse\tCtrl-B\tShow genre artist and album browser."),trackview,GMTrackView::ID_TOGGLE_BROWSER);
  new FXMenuCheck(viewmenu,tr("Show &Genres\tCtrl-G\tShow genre browser."),trackview,GMTrackView::ID_TOGGLE_GENRES);
  new FXMenuSeparator(viewmenu);
#if FOXVERSION > FXVERSION(1,7,21)
  new FXMenuCheck(viewmenu,tr("Show &Sources\tCtrl-S\tShow source browser "),this,ID_SHOW_SOURCES);
#else
  new FXMenuCheck(viewmenu,tr("Show &Sources\tCtrl-S\tShow source browser "),sourcesplitter,FXWindow::ID_TOGGLESHOWN);
#endif

  new FXMenuSeparator(viewmenu);
#if FOXVERSION >= FXVERSION(1,7,11)
  fullscreencheck = new FXMenuCheck(viewmenu,tr("Show Full Screen\tF12\tToggle fullscreen mode."),this,ID_SHOW_FULLSCREEN);
#endif
  new FXMenuCheck(viewmenu,tr("Show Mini Player\tF11\tToggle Mini Player."),this,ID_SHOW_MINIPLAYER);

  new FXMenuSeparator(viewmenu);
  new FXMenuCommand(viewmenu,tr("&Configure Columns…"),NULL,trackview,GMTrackView::ID_CONFIGURE_COLUMNS);
  new FXMenuCascade(viewmenu,tr("&Sort"),icontheme->icon_sort,trackview->getSortMenu());
  new FXMenuSeparator(viewmenu);
  new FXMenuCommand(viewmenu,tr("&Jump to Current Track\tCtrl-J\tShow current playing track."),NULL,trackview,GMTrackView::ID_SHOW_CURRENT);
  gm_set_window_cursor(viewmenu,getApp()->getDefaultCursor(DEF_ARROW_CURSOR));

  playmenu=new FXMenuPane(this);
  new FXMenuTitle(menubar,tr("&Control"),NULL,playmenu);
  new FXMenuCommand(playmenu,tr("Play\tCtrl-P\tStart playback."),icontheme->icon_play,this,ID_PLAYPAUSEMENU);
  new FXMenuCommand(playmenu,tr("Stop\tCtrl-\\\tStop playback."),icontheme->icon_stop,this,ID_STOP);
  new FXMenuCommand(playmenu,tr("Previous Track\tCtrl-[\tPlay next track."),icontheme->icon_prev,this,ID_PREV);
  new FXMenuCommand(playmenu,tr("Next Track\tCtrl-]\tPlay previous track."),icontheme->icon_next,this,ID_NEXT);
  new FXMenuSeparator(playmenu);
  new FXMenuRadio(playmenu,tr("Repeat Off\tCtrl-,\tRepeat current track."),this,ID_REPEAT_OFF);
  new FXMenuRadio(playmenu,tr("Repeat Track\tCtrl-.\tRepeat current track."),this,ID_REPEAT);
  new FXMenuRadio(playmenu,tr("Repeat All Tracks\tCtrl-/\tRepeat all tracks."),this,ID_REPEAT_ALL);
  new FXMenuCheck(playmenu,tr("Repeat A-B\tCtrl-T\tRepeat section of track."),this,ID_REPEAT_AB);
  new FXMenuCheck(playmenu,tr("Shuffle Mode\tAlt-R\tPlay tracks in random order."),this,ID_SHUFFLE);
  new FXMenuSeparator(playmenu);
  new FXMenuCommand(playmenu,tr("Equalizer\t\t"),NULL,GMPlayerManager::instance(),GMPlayerManager::ID_EQUALIZER);
  new FXMenuCheck(playmenu,tr("Sleep Timer\t\tSetup sleeptimer."),this,ID_SLEEP);
  gm_set_window_cursor(playmenu,getApp()->getDefaultCursor(DEF_ARROW_CURSOR));

  helpmenu=new FXMenuPane(this);
  new FXMenuTitle(menubar,tr("&Help"),NULL,helpmenu,LAYOUT_RIGHT);
  new FXMenuCommand(helpmenu,tr("&Homepage"),icontheme->icon_homepage,this,GMWindow::ID_HOMEPAGE);
  new FXMenuCommand(helpmenu,tr("&Report Issue…"),NULL,this,GMWindow::ID_REPORT_ISSUE);
  new FXMenuSeparator(helpmenu);
  new FXMenuCommand(helpmenu,tr("&Sign up for last.fm…"),NULL,this,GMWindow::ID_JOIN_LASTFM);
  new FXMenuCommand(helpmenu,tr("&Join GMM on last.fm…\t\tJoin the Goggles Music Manager group on last.fm…"),NULL,this,GMWindow::ID_JOIN_GMM_LASTFM);
  new FXMenuSeparator(helpmenu);
  new FXMenuCommand(helpmenu,tr("&About…"),icontheme->icon_info,this,GMWindow::ID_ABOUT);
  gm_set_window_cursor(helpmenu,getApp()->getDefaultCursor(DEF_ARROW_CURSOR));

  getAccelTable()->addAccel(parseAccel("Ctrl-W"),this,FXSEL(SEL_CLOSE,0));
  getAccelTable()->addAccel(parseAccel("/"),trackview,FXSEL(SEL_COMMAND,GMTrackView::ID_TOGGLE_FILTER));
  }


void GMWindow::init() {
  sourceview->init();
  }

//----------------------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------------------
GMWindow::~GMWindow(){
  if (coverview_gl) {
    coverview_gl->setImage(NULL);
    delete coverview_gl;
    delete glvisual;
    }
  delete icontheme;
  }


//----------------------------------------------------------------------------------
// Create Fonts
//----------------------------------------------------------------------------------
void GMWindow::createFonts(){

#if FOXVERSION < FXVERSION(1,7,17)
  FXFontDesc fontdescription;
  getApp()->getNormalFont()->getFontDesc(fontdescription);
#else
  FXFontDesc fontdescription = getApp()->getNormalFont()->getFontDesc();
#endif
  fontdescription.weight = FXFont::Bold;
  font_thick = new FXFont(getApp(),fontdescription);
  font_thick->create();
  }


//----------------------------------------------------------------------------------
// Create
//----------------------------------------------------------------------------------
void GMWindow::create(){

#if FOXVERSION > FXVERSION(1,7,21)
  mainsplitter->setHSplit(getApp()->reg().readIntEntry("window","source-list-hsplit",2500));
#else
  mainsplitter->setSplit(0,getApp()->reg().readIntEntry("window","source-list-split",200));
  sourcesplitter->setSplit(1,getApp()->reg().readIntEntry("window","cover-list-split",256+10+2));
#endif

  configureStatusbar(GMPlayerManager::instance()->getPreferences().gui_show_status_bar);

  /// Set initial Toolbar Configuration
  configureToolbar(GMPlayerManager::instance()->getPreferences().gui_toolbar_docktop,
                   GMPlayerManager::instance()->getPreferences().gui_toolbar_showlabels,
                   GMPlayerManager::instance()->getPreferences().gui_toolbar_bigicons,
                   true);

  FXMainWindow::create();

  /// Initialize the window size & position
  if (getApp()->reg().readIntEntry("window","x",-1)!=-1) {
    FXint xx=getApp()->reg().readIntEntry("window","x",getX());
    FXint yy=getApp()->reg().readIntEntry("window","y",getY());
    FXint ww=getApp()->reg().readIntEntry("window","width",500);
    FXint hh=getApp()->reg().readIntEntry("window","height",550);
    position(xx,yy,ww,hh);
    }
  else {
    place(PLACEMENT_SCREEN);
    }
  /// Set extended window manager hints on the menus for compositing window managers.
  ewmh_change_window_type(filemenu,WINDOWTYPE_DROPDOWN_MENU);
  ewmh_change_window_type(editmenu,WINDOWTYPE_DROPDOWN_MENU);
  ewmh_change_window_type(viewmenu,WINDOWTYPE_DROPDOWN_MENU);
  ewmh_change_window_type(playmenu,WINDOWTYPE_DROPDOWN_MENU);
  ewmh_change_window_type(helpmenu,WINDOWTYPE_DROPDOWN_MENU);


  gm_set_application_icon(this);
  }


#if FOXVERSION >= FXVERSION(1,7,11)
void GMWindow::setFullScreen(FXbool show){
  if (show) {
    if (isMaximized()) restore();
    getApp()->reg().writeIntEntry("window","x",getX());
    getApp()->reg().writeIntEntry("window","y",getY());
    getApp()->reg().writeIntEntry("window","width",getWidth());
    getApp()->reg().writeIntEntry("window","height",getHeight());
    fullScreen();
    statusbar->setCornerStyle(false);
    controldragcorner->hide();
    fullscreencheck->setCheck(true);
    }
  else {
    restore();
    if (!statusbar->shown() &&  GMPlayerManager::instance()->getPreferences().gui_toolbar_docktop==false)
      controldragcorner->show();
    statusbar->setCornerStyle(true);
    fullscreencheck->setCheck(false);
    }
  }
#endif


void GMWindow::hide() {
#if FOXVERSION >= FXVERSION(1,7,11)
  getApp()->reg().writeBoolEntry("window","fullscreen",isFullScreen());
#endif
  getApp()->reg().writeBoolEntry("window","maximized",isMaximized());
#if FOXVERSION >= FXVERSION(1,7,11)
  if (isFullScreen() || isMaximized() || isMinimized() )
#else
  if (isMaximized() || isMinimized() )
#endif
    restore();
  FXMainWindow::hide();
  }

void GMWindow::show(){
  FXMainWindow::show();

#if FOXVERSION >= FXVERSION(1,7,11)
    if (getApp()->reg().readBoolEntry("window","fullscreen",false)){
      getApp()->reg().writeBoolEntry("window","fullscreen",false);
      getApp()->reg().writeBoolEntry("window","maximized",false);

     if (getApp()->reg().readIntEntry("window","x",-1)!=-1) {
       FXint xx=getApp()->reg().readIntEntry("window","x",getX());
       FXint yy=getApp()->reg().readIntEntry("window","y",getY());
       FXint ww=getApp()->reg().readIntEntry("window","width",500);
       FXint hh=getApp()->reg().readIntEntry("window","height",550);
       position(xx,yy,ww,hh);
       }
     else {
       place(PLACEMENT_SCREEN);
       }
      setFullScreen(true);
      }
    else
#endif

  if (getApp()->reg().readBoolEntry("window","maximized",false)){
      getApp()->reg().writeBoolEntry("window","fullscreen",false);
      getApp()->reg().writeBoolEntry("window","maximized",false);
    maximize();
    }
  }



FXbool GMWindow::question(const FXString & title,const FXString & labeltext,const FXString & accept,const FXString & cancel){
  FXDialogBox dialog(this,title,DECOR_TITLE|DECOR_BORDER|DECOR_RESIZE,0,0,400,0,0,0,0,0,0,0);
  create_dialog_header(&dialog,title,labeltext,NULL);
  FXHorizontalFrame *closebox=new FXHorizontalFrame(&dialog,LAYOUT_BOTTOM|LAYOUT_FILL_X,0,0,0,0);
  new FXButton(closebox,accept,NULL,&dialog,FXDialogBox::ID_ACCEPT,BUTTON_INITIAL|BUTTON_DEFAULT|LAYOUT_RIGHT|FRAME_RAISED|FRAME_THICK,0,0,0,0, 20,20);
  new FXButton(closebox,cancel,NULL,&dialog,FXDialogBox::ID_CANCEL,BUTTON_DEFAULT|LAYOUT_RIGHT|FRAME_RAISED|FRAME_THICK,0,0,0,0, 20,20);
  if (dialog.execute()) {
    return TRUE;
    }
  return FALSE;
  }


void GMWindow::reset() {
  /// Reset Status Text
  statusbar->getStatusLine()->setNormalText("Ready.");

  /// Clear Cover
  loadCover(FXString::null);

#if APPLICATION_BETA > 0
  setTitle("Goggles Music Manager " APPLICATION_VERSION_STRING);
#else
  setTitle("Goggles Music Manager");
#endif
  }

void GMWindow::display(const GMTrack& info){
  FXUTF8Codec codec;
  FXString title = GMFilename::format_track(info,GMPlayerManager::instance()->getPreferences().gui_format_title,FXString::null,0,&codec);
  statusbar->getStatusLine()->setNormalText(title);

  if (GMPlayerManager::instance()->getPreferences().gui_show_playing_titlebar){

#if APPLICATION_BETA > 0
    setTitle(GMStringFormat("%s ~ Goggles Music Manager " APPLICATION_VERSION_STRING,title.text()));
#else
    setTitle(GMStringFormat("%s ~ Goggles Music Manager",title.text()));
#endif
    }
  else {
#if APPLICATION_BETA > 0
    setTitle("Goggles Music Manager " APPLICATION_VERSION_STRING);
#else
    setTitle("Goggles Music Manager");
#endif
    }
  }

void GMWindow::update_volume_display(FXint level) {
  if (level<=0)
    volumebutton->setIcon(icontheme->icon_audio_volume_muted);
  else if (level<=33)
    volumebutton->setIcon(icontheme->icon_audio_volume_low);
  else if (level<=66)
    volumebutton->setIcon(icontheme->icon_audio_volume_medium);
  else
    volumebutton->setIcon(icontheme->icon_audio_volume_high);

  volumeslider->setValue(level);
  }

void GMWindow::update_elapsed_time(FXint hours,FXint minutes,FXint seconds,FXint position,FXbool playing,FXbool seekable) {
  if (playing) {
    if (hours>0)
      timelabel->setText(GMStringFormat("%d:%.2d:%.2d",hours,minutes,seconds));
    else
      timelabel->setText(GMStringFormat("%.2d:%.2d",minutes,seconds));

    if (seekable) {
      if (!timeslider->grabbed()){
        timeslider->setValue(position);
        timeslider->enable();
        }
      }
    else {
      timeslider->disable();
      }
    }
  else {
    timelabel->setText("--:--");
    timeslider->disable();
    }
  }

long GMWindow::onCmdQuit(FXObject *,FXSelector,void*){

  sourceview->saveView();
  trackview->saveView();

  /// Save the Window State
  getApp()->reg().writeBoolEntry("window","window-show",shown());
  getApp()->reg().writeBoolEntry("window","remote-show",GMPlayerManager::instance()->getRemote()!=NULL);

#if FOXVERSION >= FXVERSION(1,7,11)
  if (!isFullScreen() && !isMaximized() && !isMinimized() &&shown()) {
#else
  if (!isMaximized() && !isMinimized() && shown()) {
#endif
    getApp()->reg().writeIntEntry("window","x",getX());
    getApp()->reg().writeIntEntry("window","y",getY());
    getApp()->reg().writeIntEntry("window","width",getWidth());
    getApp()->reg().writeIntEntry("window","height",getHeight());
    }
#if FOXVERSION >= FXVERSION(1,7,11)
  getApp()->reg().writeBoolEntry("window","fullscreen",isFullScreen());
#endif
  getApp()->reg().writeBoolEntry("window","maximized",isMaximized());


#if FOXVERSION > FXVERSION(1,7,21)
  getApp()->reg().writeIntEntry("window","source-list-hsplit",mainsplitter->getHSplit());
#else
  getApp()->reg().writeIntEntry("window","source-list-split",mainsplitter->getSplit(0));
  getApp()->reg().writeIntEntry("window","cover-list-split",sourcesplitter->getSplit(1));
#endif

  if (GMPlayerManager::instance()->getRemote())
    GMPlayerManager::instance()->getRemote()->writeRegistry();

  volumeslider->setTarget(NULL);
  volumeslider->setSelector(0);
  volumebutton->setMenu(NULL);
  delete volumecontrol;

  GMPlayerManager::instance()->exit();
  return 1;
  }



long GMWindow::onCmdAbout(FXObject *,FXSelector,void*){
  GMAboutDialog dialog(this);
  dialog.execute(PLACEMENT_SCREEN);
  return 1;
  }


#if FOXVERSION >= FXVERSION(1,7,11)
long GMWindow::onCmdShowFullScreen(FXObject*,FXSelector,void*){
  if (isFullScreen()) {
    setFullScreen(false);
    }
  else {
    setFullScreen(true);
    }
  return 1;
  }
#endif


long GMWindow::onCmdShowMiniPlayer(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->showRemote();
  hide();
  return 1;
  }

long GMWindow::onUpdShowMiniPlayer(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->getRemote())
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_CHECK),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
  return 1;
  }


long GMWindow::onCmdShowTrack(FXObject *,FXSelector,void*){
  return 1;
  }

long GMWindow::onUpdShowTrack(FXObject *sender,FXSelector,void*){
  if (!GMPlayerManager::instance()->playing())
    sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
  return 1;
  }

long GMWindow::onCmdResetColors(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->getPreferences().resetColors();
  return 1;
  }

long GMWindow::onCmdPreferences(FXObject *,FXSelector,void*){
  GMPreferencesDialog dialog(this);
  dialog.execute();
  return 1;
  }



void GMWindow::configureStatusbar(FXbool show){
  if (show) {
    statusbar->show();
    controlstatusseparator->show();
    controldragcorner->hide();
    }
  else {
    statusbar->hide();
    controlstatusseparator->hide();
    if (!GMPlayerManager::instance()->getPreferences().gui_toolbar_docktop){
      controldragcorner->show();
      controlframe->recalc();
      }
    }
  GMPlayerManager::instance()->getPreferences().gui_show_status_bar=show;
  recalc();
  controlframe->recalc();
  }


void GMWindow::layoutToolBarButtons() {
  if (GMPlayerManager::instance()->getPreferences().gui_toolbar_showlabels) {
    FXint mw = playpausebutton->getDefaultWidth();
    mw = FXMAX(mw,stopbutton->getDefaultWidth());
    mw = FXMAX(mw,prevbutton->getDefaultWidth());
    mw = FXMAX(mw,nextbutton->getDefaultWidth());

    playpausebutton->setLayoutHints(LAYOUT_FIX_WIDTH);
    playpausebutton->setWidth(mw);

    stopbutton->setLayoutHints(LAYOUT_FIX_WIDTH);
    stopbutton->setWidth(mw);

    prevbutton->setLayoutHints(LAYOUT_FIX_WIDTH);
    prevbutton->setWidth(mw);

    nextbutton->setLayoutHints(LAYOUT_FIX_WIDTH);
    nextbutton->setWidth(mw);
    }
  else {
    playpausebutton->setLayoutHints(0);
    stopbutton->setLayoutHints(0);
    prevbutton->setLayoutHints(0);
    nextbutton->setLayoutHints(0);
    }
  }


void GMWindow::configureToolbar(FXbool docktop,FXbool showlabels,FXbool bigicons,FXbool init/*=false*/){

  if ((docktop != GMPlayerManager::instance()->getPreferences().gui_toolbar_docktop) || init) {
    if (docktop) {
      controlframe->setLayoutHints(LAYOUT_FILL_X|LAYOUT_SIDE_TOP);
      controlseparator->setLayoutHints(LAYOUT_FILL_X|LAYOUT_SIDE_TOP);
      controldragcorner->hide();
      }
    else {
      controlframe->setLayoutHints(LAYOUT_FILL_X|LAYOUT_SIDE_BOTTOM);
      controlseparator->setLayoutHints(LAYOUT_FILL_X|LAYOUT_SIDE_BOTTOM);
      if (!statusbar->shown()) controldragcorner->show();
      }
    }

  if ((bigicons != GMPlayerManager::instance()->getPreferences().gui_toolbar_bigicons) || init) {

    if (bigicons) {
      playpausebutton->setIcon(icontheme->icon_play_toolbar);
      playpausebutton->setAltIcon(icontheme->icon_pause_toolbar);
      stopbutton->setIcon(icontheme->icon_stop_toolbar);
      prevbutton->setIcon(icontheme->icon_prev_toolbar);
      nextbutton->setIcon(icontheme->icon_next_toolbar);
      }
    else {
      playpausebutton->setIcon(icontheme->icon_play);
      playpausebutton->setAltIcon(icontheme->icon_pause);
      stopbutton->setIcon(icontheme->icon_stop);
      prevbutton->setIcon(icontheme->icon_prev);
      nextbutton->setIcon(icontheme->icon_next);
      }
    update_volume_display(GMPlayerManager::instance()->volume());
    }

  if (showlabels != GMPlayerManager::instance()->getPreferences().gui_toolbar_showlabels || init) {
    if (showlabels) {
      playpausebutton->setText(tr("Play"));
      playpausebutton->setAltText(tr("Pause"));
      stopbutton->setText(tr("Stop"));
      prevbutton->setText(tr("Previous"));
      nextbutton->setText(tr("Next"));
      }
    else {
      playpausebutton->setText(FXString::null);
      playpausebutton->setAltText(FXString::null);
      stopbutton->setText(FXString::null);
      prevbutton->setText(FXString::null);
      nextbutton->setText(FXString::null);
      }
    GMPlayerManager::instance()->getPreferences().gui_toolbar_showlabels=showlabels;
    layoutToolBarButtons();
    }
  GMPlayerManager::instance()->getPreferences().gui_toolbar_docktop=docktop;
  GMPlayerManager::instance()->getPreferences().gui_toolbar_bigicons=bigicons;
  }


long GMWindow::onCmdImport(FXObject *,FXSelector sel,void*){
  FXuint mode=(FXSELID(sel)==ID_IMPORT_DIRS || FXSELID(sel)==ID_SYNC_DIRS) ? IMPORT_FROMDIR : IMPORT_FROMFILE;
  if (FXSELID(sel)==ID_SYNC_DIRS) mode|=IMPORT_SYNC;

  GMImportDialog dialog(this,mode);
  if (dialog.execute()) {
    FXStringList files;
    dialog.getSelectedFiles(files);
    GMPlayerManager::instance()->stop();

    if (FXSELID(sel)==ID_SYNC_DIRS) {
      GMSyncDatabase searchdialog(this,files,GMPlayerManager::instance()->getPreferences().import,GMPlayerManager::instance()->getPreferences().sync,-1,true,font_thick);
      searchdialog.execute();
      }
    else {
      GMImportDatabase searchdialog(this,files,GMPlayerManager::instance()->getPreferences().import,-1,font_thick);
      searchdialog.execute();
      }
    if (sourceview->getSource()==GMPlayerManager::instance()->getSource(0))
      trackview->refresh();
    }
  return 1;
  }


long GMWindow::onCmdPlayPause(FXObject*,FXSelector,void*){
  if (GMPlayerManager::instance()->can_pause())
    GMPlayerManager::instance()->pause();
  else if (GMPlayerManager::instance()->can_unpause())
    GMPlayerManager::instance()->unpause();
  else
    GMPlayerManager::instance()->play();
  return 1;
  }

long GMWindow::onUpdPlayPause(FXObject*sender,FXSelector,void*){
  if ( GMPlayerManager::instance()->can_play() || GMPlayerManager::instance()->can_unpause() || GMPlayerManager::instance()->can_pause()){
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_ENABLE),NULL);
    if (GMPlayerManager::instance()->can_play() || GMPlayerManager::instance()->can_unpause())
      sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
    else
      sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_CHECK),NULL);
    }
  else {
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_DISABLE),NULL);
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
    }
  return 1;
  }

long GMWindow::onUpdPlayPauseMenu(FXObject*sender,FXSelector,void*){
  FXMenuCommand * menucommand=dynamic_cast<FXMenuCommand*>(sender);
  FXButton * button=dynamic_cast<FXButton*>(sender);

  if ( GMPlayerManager::instance()->can_play() || GMPlayerManager::instance()->can_unpause() || GMPlayerManager::instance()->can_pause()){
    if (GMPlayerManager::instance()->can_play() || GMPlayerManager::instance()->can_unpause()){
      if (button) {
        button->enable();
        button->setHelpText(tr("Start playback."));
        button->setIcon(GMIconTheme::instance()->icon_play);
        }
      else {
        menucommand->enable();
        menucommand->setText(tr("Play"));
        menucommand->setHelpText(tr("Start playback"));
        menucommand->setTipText(tr("Start playback"));
        menucommand->setIcon(GMIconTheme::instance()->icon_play);
        }
      }
    else {
      if (button) {
        button->enable();
        button->setHelpText(tr("Pause playback."));
        button->setTipText(tr("Pause playback"));
        button->setIcon(GMIconTheme::instance()->icon_pause);
        }
      else {
        menucommand->enable();
        menucommand->setText(tr("Pause"));
        menucommand->setHelpText(tr("Pause playback."));
        menucommand->setIcon(GMIconTheme::instance()->icon_pause);
        }
      }
    }
  else {
    if (button) {
      button->setText(tr("Play"));
      button->setHelpText(tr("Start playback."));
      button->setIcon(GMIconTheme::instance()->icon_play);
      button->disable();
      }
    else {
      menucommand->setText(tr("Play"));
      menucommand->setHelpText(tr("Start playback."));
      menucommand->setIcon(GMIconTheme::instance()->icon_play);
      menucommand->disable();
      }
    }
  return 1;
  }




long GMWindow::onCmdPause(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->pause();
  return 1;
  }

long GMWindow::onUpdPause(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->can_pause())
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SHOW),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_HIDE),NULL);
  return 1;
  }

long GMWindow::onCmdStop(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->stop();
  return 1;
  }

long GMWindow::onUpdStop(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->can_stop())
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_ENABLE),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_DISABLE),NULL);
  return 1;
  }

long GMWindow::onCmdNext(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->next();
  return 1;
  }

long GMWindow::onUpdNext(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->can_next())
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_ENABLE),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_DISABLE),NULL);
  return 1;
  }

long GMWindow::onCmdPrev(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->prev();
  return 1;
  }

long GMWindow::onUpdPrev(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->can_prev())
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_ENABLE),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_DISABLE),NULL);
  return 1;
  }


long GMWindow::onCmdTimeSlider(FXObject*,FXSelector,void*ptr){
  FXint pos=(FXint)(FXival)ptr;
  GMPlayerManager::instance()->seek(pos);
  return 1;
  }

long GMWindow::onCmdVolume(FXObject*,FXSelector,void*ptr){
  FXint level = (FXint)(FXival)ptr;
  GMPlayerManager::instance()->volume(level);
  update_volume_display(level);
  return 1;
  }

long GMWindow::onCmdVolumeButton(FXObject*,FXSelector sel,void*ptr){
  volumeslider->handle(this,FXSEL(FXSELTYPE(sel),0),ptr);
  return 1;
  }

long GMWindow::onUpdVolumeButton(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->getPlayer()->opened())
    sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
  return 1;
  }

long GMWindow::onCmdRepeatAB(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->getPlayer()->setRepeatAB();
  return 1;
  }

long GMWindow::onUpdRepeatAB(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->getPlayer()->playing() && GMPlayerManager::instance()->getPlayer()->seekable()) {
    const FXString state_off = tr("Repeat A-B");
    const FXString state_a = tr("Repeat A");
    const FXString state_b = tr("Repeat A-B");
    sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
    switch(GMPlayerManager::instance()->getPlayer()->getRepeatAB()){
      case REPEAT_AB_OFF: sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
                          sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&state_off);
                          break;
      case REPEAT_AB_A  : sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
                          sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&state_a);
                          break;
      case REPEAT_AB_B  : sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
                          sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&state_b);
                          break;
      }
    }
  else {
    sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
    }
  return 1;
  }



long GMWindow::onCmdRepeatOff(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->getPreferences().play_repeat=REPEAT_OFF;
  return 1;
  }

long GMWindow::onUpdRepeatOff(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->getPreferences().play_repeat==REPEAT_OFF)
    sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
  return 1;
  }

long GMWindow::onCmdRepeat(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->getPreferences().play_repeat=REPEAT_TRACK;
  return 1;
  }

long GMWindow::onUpdRepeat(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->getPreferences().play_repeat==REPEAT_TRACK)
    sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
  return 1;
  }


long GMWindow::onCmdRepeatAll(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->getPreferences().play_repeat=REPEAT_ALL;
  return 1;
  }

long GMWindow::onUpdRepeatAll(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->getPreferences().play_repeat==REPEAT_ALL)
    sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
  return 1;
  }


long GMWindow::onCmdShuffle(FXObject*,FXSelector,void*ptr){
  GMPlayerManager::instance()->getPreferences().play_shuffle = (FXbool)(FXival)(ptr);
  return 1;
  }

long GMWindow::onUpdShuffle(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->getPreferences().play_shuffle)
    sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
  return 1;
  }


long GMWindow::onCmdHomePage(FXObject*,FXSelector,void*){
  if (!gm_open_browser("http://code.google.com/p/gogglesmm")){
    FXMessageBox::error(this,MBOX_OK,tr("Unable to launch webbrowser"),"Goggles Music Manager was unable to launch a webbrowser.\nPlease visit http://code.google.com/p/gogglesmm for the official homepage.");
    }
  return 1;
  }

long GMWindow::onCmdReportIssue(FXObject*,FXSelector,void*){
  if (!gm_open_browser("http://code.google.com/p/gogglesmm/issues/list")){
    FXMessageBox::error(this,MBOX_OK,tr("Unable to launch webbrowser"),"Goggles Music Manager was unable to launch a webbrowser.\nPlease visit http://code.google.com/p/gogglesmm/issues/list to report an issue.");
    }
  return 1;
  }

long GMWindow::onCmdJoinLastFM(FXObject*,FXSelector,void*){
  if (!gm_open_browser("https://www.last.fm/join/")){
    FXMessageBox::error(this,MBOX_OK,tr("Unable to launch webbrowser"),"Goggles Music Manager was unable to launch a webbrowser.\nPlease visit https://www.last.fm/join/");
    }
  return 1;
  }

long GMWindow::onCmdJoinGMMLastFM(FXObject*,FXSelector,void*){
  if (!gm_open_browser("http://www.last.fm/group/Goggles+Music+Manager")){
    FXMessageBox::error(this,MBOX_OK,tr("Unable to launch webbrowser"),"Goggles Music Manager was unable to launch a webbrowser.\nPlease visit http://www.last.fm/group/Goggles+Music+Manager");
    }
  return 1;
  }




extern const FXchar gmfilepatterns[];

class GMOpenDialog : public FXDialogBox {
FXDECLARE(GMOpenDialog)
protected:
  FXTextField * input;
protected:
  GMOpenDialog(){}
private:
  GMOpenDialog(const GMOpenDialog&);
  GMOpenDialog &operator=(const GMOpenDialog&);
public:
  enum {
    ID_BROWSE = FXDialogBox::ID_LAST,
    ID_LAST
    };
public:
  long onCmdBrowse(FXObject*,FXSelector,void*);
  long onCmdAccept(FXObject*,FXSelector,void*);
public:
  GMOpenDialog(FXWindow*);

  FXString getFilename() const;
  };

FXDEFMAP(GMOpenDialog) GMOpenDialogMap[]={
  FXMAPFUNC(SEL_COMMAND,GMOpenDialog::ID_BROWSE,GMOpenDialog::onCmdBrowse),
  FXMAPFUNC(SEL_COMMAND,GMOpenDialog::ID_ACCEPT,GMOpenDialog::onCmdAccept)
  };

FXIMPLEMENT(GMOpenDialog,FXDialogBox,GMOpenDialogMap,ARRAYNUMBER(GMOpenDialogMap));


GMOpenDialog::GMOpenDialog(FXWindow*p) : FXDialogBox(p,fxtr("Play File or Stream"),DECOR_TITLE|DECOR_BORDER,0,0,0,0,4,4,4,4) {
  FXHorizontalFrame *closebox=new FXHorizontalFrame(this,LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|PACK_UNIFORM_WIDTH,0,0,0,0,0,0,0,0);
  new FXButton(closebox,tr("&Play"),NULL,this,FXDialogBox::ID_ACCEPT,BUTTON_INITIAL|BUTTON_DEFAULT|LAYOUT_RIGHT|FRAME_RAISED|FRAME_THICK,0,0,0,0, 15,15);
  new FXButton(closebox,tr("&Cancel"),NULL,this,FXDialogBox::ID_CANCEL,BUTTON_DEFAULT|LAYOUT_RIGHT|FRAME_RAISED|FRAME_THICK,0,0,0,0, 15,15);
  new FXSeparator(this,SEPARATOR_GROOVE|LAYOUT_FILL_X|LAYOUT_SIDE_BOTTOM);

  FXVerticalFrame * vframe = new FXVerticalFrame(this,LAYOUT_FILL_X|LAYOUT_FILL_Y);
  new FXLabel(vframe,tr("Please specify a file or url to play:"),NULL);

  FXHorizontalFrame *inputframe=new FXHorizontalFrame(vframe,LAYOUT_FILL_X,0,0,0,0,0,0,0,0);
  input = new FXTextField(inputframe,40,NULL,0,TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_CENTER_Y);
  new FXButton(inputframe,tr("…"),NULL,this,ID_BROWSE);
  input->setText(getApp()->reg().readStringEntry("GMOpenDialog","url",NULL));
  }


long GMOpenDialog::onCmdBrowse(FXObject*,FXSelector,void*){
  GMFileDialog filedialog(this,tr("Select File"));
  filedialog.setPatternList(gmfilepatterns);
  if (filedialog.execute())
    input->setText(filedialog.getFilename());
  return 1;
  }

long GMOpenDialog::onCmdAccept(FXObject*sender,FXSelector sel,void*ptr){
  getApp()->reg().writeStringEntry("GMOpenDialog","url",input->getText().text());
  return FXDialogBox::onCmdAccept(sender,sel,ptr);
  }

FXString GMOpenDialog::getFilename() const {
  return input->getText();
  }


long GMWindow::onCmdOpen(FXObject*,FXSelector,void*){
  GMOpenDialog dialog(this);
  if (dialog.execute()) {
    FXString filename = dialog.getFilename();
    GMPlayerManager::instance()->open(filename);
    }
  return 1;
  }


long GMWindow::onCmdSleepTimer(FXObject*,FXSelector,void*ptr){
  if (((FXint)(FXival)ptr)==1) {
    FXDialogBox dialog(this,tr("Sleep Timer"),DECOR_TITLE|DECOR_BORDER,0,0,0,0,0,0,0,0,0,0);
    create_dialog_header(&dialog,tr("Setup sleep timer"),tr("Stop playback within a certain time"),NULL);
    FXHorizontalFrame *closebox=new FXHorizontalFrame(&dialog,LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X,0,0,0,0);
    new FXButton(closebox,tr("&Start Timer"),NULL,&dialog,FXDialogBox::ID_ACCEPT,BUTTON_INITIAL|BUTTON_DEFAULT|LAYOUT_RIGHT|FRAME_RAISED|FRAME_THICK,0,0,0,0, 15,15);
    new FXButton(closebox,tr("&Cancel"),NULL,&dialog,FXDialogBox::ID_CANCEL,BUTTON_DEFAULT|LAYOUT_RIGHT|FRAME_RAISED|FRAME_THICK,0,0,0,0, 15,15);
    new FXSeparator(&dialog,SEPARATOR_GROOVE|LAYOUT_FILL_X|LAYOUT_SIDE_BOTTOM);

    FXHorizontalFrame * main = new FXHorizontalFrame(&dialog,LAYOUT_FILL_X,0,0,0,0,40,40,10,10);
    new FXLabel(main,tr("Sleep in"),NULL,LABEL_NORMAL|LAYOUT_CENTER_Y);
    FXSpinner* hours = new FXSpinner(main,2,NULL,0,FRAME_SUNKEN|FRAME_THICK);
    new FXLabel(main,tr("hours and"),NULL,LABEL_NORMAL|LAYOUT_CENTER_Y);
    FXSpinner* minutes = new FXSpinner(main,2,NULL,0,FRAME_SUNKEN|FRAME_THICK);
    new FXLabel(main,tr("minutes."),NULL,LABEL_NORMAL|LAYOUT_CENTER_Y);
    minutes->setRange(0,59);
    hours->setRange(0,24);

    minutes->setValue(FXCLAMP(0,getApp()->reg().readIntEntry("player","sleeptimer-minutes",0),59));
    hours->setValue(FXCLAMP(0,getApp()->reg().readIntEntry("player","sleeptimer-hours",2),24));

    if (dialog.execute()) {
      GMPlayerManager::instance()->setSleepTimer(TIME_HOUR(hours->getValue())+TIME_MIN(minutes->getValue()));
      getApp()->reg().writeIntEntry("player","sleeptimer-minutes",minutes->getValue());
      getApp()->reg().writeIntEntry("player","sleeptimer-hours",hours->getValue());
      }
    }
  else {
    GMPlayerManager::instance()->setSleepTimer(0);
    }
  return 1;
  }

long GMWindow::onUpdSleepTimer(FXObject*sender,FXSelector,void*){
  if (GMPlayerManager::instance()->hasSleepTimer())
    sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
  return 1;
  }



extern const char *albumartfiles[];



void GMWindow::loadCover(const FXString & filename) {
  FXIconSource src(getApp());
  FXImage * cover=NULL;
  FXint coverdisplaysize;
  FXString dirname=filename;

  const FXint smallcoversize=64;

  /// Whether to scale the image when loading or not
  if (coverview_gl)
    coverdisplaysize=0;
  else
    coverdisplaysize=FXCLAMP(64,GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size,500);

  /// Check if we've already loaded it.
  if (filename==coverfile) {
    return;
    }

  /// If empty skip cover searching
  if (!filename.empty()) {
    cover = GMCover::toImage(GMCover::fromTag(filename,coverdisplaysize));
    if (cover==NULL) {
      dirname = FXPath::directory(filename);
      if (!dirname.empty()) {
        if (dirname==coverfile)
          return;
        cover= GMCover::toImage(GMCover::fromPath(dirname,coverdisplaysize));
        }
      }
    }

  /// Delete current cover
  if (GMPlayerManager::instance()->getRemote())
    GMPlayerManager::instance()->getRemote()->updateCover(NULL);

  if (cover_small)  {
    delete cover_small;
    cover_small=NULL;
    }

  if (coverview_x11) {
    if (coverview_x11->getImage()){
      delete coverview_x11->getImage();
      coverview_x11->setImage(NULL);
      }
    }

  /// Set new cover to coverview
  if (coverview_gl)
    coverview_gl->setImage(cover);
  else
    coverview_x11->setImage(cover);

  if (cover) {
    coverfile = dirname;

    /// Retrieve Image Data
    FXColor * imagedata = cover->getData();

    /// Disown image data
    FXImageOwner::clear(cover);

    /// Make sure to create cover for x11
    if (coverview_x11)
      cover->create();

    /// Make small cover the owner of the data
    cover_small = new FXImage(getApp(),imagedata,IMAGE_SHMI|IMAGE_SHMP|IMAGE_KEEP|IMAGE_OWNED,cover->getWidth(),cover->getHeight());
    if (cover_small->getWidth()>smallcoversize || cover_small->getHeight()>smallcoversize) {
      if (cover_small->getWidth()>cover_small->getHeight())
        cover_small->scale(smallcoversize,(smallcoversize*cover_small->getHeight())/cover_small->getWidth(),1);
      else
        cover_small->scale((smallcoversize*cover_small->getWidth())/cover_small->getHeight(),smallcoversize,1);
      }

    /// delete the cover for gl.
    if (coverview_gl)
      delete cover;

    cover_small->create();

    if (GMPlayerManager::instance()->getRemote())
      GMPlayerManager::instance()->getRemote()->updateCover(cover_small);

    if (!coverframe->shown()) {
      coverframe->show();
      coverframe->recalc();
      }
    }
  else {
    coverfile = FXString::null;
    if (coverframe->shown()) {
      coverframe->hide();
      coverframe->recalc();
      }
    }
  }



void GMWindow::create_dialog_header(FXDialogBox * dialog,const FXString & title,const FXString & subtitle,FXIcon * icon) {
  FXHorizontalFrame * header = new FXHorizontalFrame(dialog,LAYOUT_FILL_X,0,0,0,0,0,0,0,0,0,0);
  header->setBackColor(getApp()->getBackColor());
  FXLabel * label = new FXLabel(header,FXString::null,icon,LABEL_NORMAL|LAYOUT_CENTER_Y,0,0,0,0,10,0,0,0);
  label->setBackColor(getApp()->getBackColor());
  FXVerticalFrame * frame = new FXVerticalFrame(header,LAYOUT_FILL_X,0,0,0,0,0,0,0,0,0,0);
  label = new FXLabel(frame,title,NULL,LAYOUT_FILL_X|JUSTIFY_LEFT|TEXT_AFTER_ICON,0,0,0,0,10,10,10,0);
  label->setBackColor(getApp()->getBackColor());
  label->setFont(font_thick);
  label = new FXLabel(frame,subtitle,NULL,LAYOUT_FILL_X|JUSTIFY_LEFT|TEXT_AFTER_ICON,0,0,0,0,10+30,10,0,10);
  label->setBackColor(getApp()->getBackColor());
  new FXSeparator(dialog,LAYOUT_FILL_X|SEPARATOR_GROOVE|LAYOUT_SIDE_TOP);
  }

void GMWindow::updateCoverView() {

  if (GMPlayerManager::instance()->getPreferences().gui_show_opengl_coverview && gm_has_opengl() ) {

    if (coverview_x11) {
      loadCover(FXString::null);
      delete coverview_x11;
      coverview_x11=NULL;
      }

    if (!coverview_gl) {
#if FOXVERSION < FXVERSION(1,7,15)
      glvisual = new FXGLVisual(getApp(),VISUAL_DOUBLEBUFFER);
#else
      glvisual = new FXGLVisual(getApp(),VISUAL_DOUBLE_BUFFER);
#endif
      coverview_gl = new GMImageView(coverframe,glvisual,LAYOUT_FILL_X|LAYOUT_FILL_Y);
      coverview_gl->setTarget(this);
      coverview_gl->setSelector(ID_COVERVIEW);
      coverview_gl->enable();
      if (coverframe->id()) coverview_gl->create();
      }

    }
  else {

    if (coverview_gl) {
      loadCover(FXString::null);
      delete coverview_gl;
      coverview_gl=NULL;
      delete glvisual;
      glvisual=NULL;
      }

    if (!coverview_x11) {
      coverview_x11 = new FXImageFrame(coverframe,NULL,FRAME_NONE|JUSTIFY_CENTER_X|JUSTIFY_CENTER_Y|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0,0,0,0,0);
      coverview_x11->setBackColor(getApp()->getBackColor());
      coverview_x11->setTarget(this);
      coverview_x11->setSelector(ID_COVERVIEW);
      coverview_x11->enable();
      if (coverframe->id()) coverview_x11->create();
      }

    }
  }


long GMWindow::onCmdCoverView(FXObject*,FXSelector,void*ptr){
  FXEvent * event = reinterpret_cast<FXEvent*>(ptr);
  if (!event->moved) {
    FXMenuPane pane(this);
    if (coverview_x11) {
      if (gm_has_opengl()) {
        new FXMenuCheck(&pane,"Use OpenGL viewer",this,ID_CHANGE_COVERVIEW);
        new FXMenuSeparator(&pane);
        }
      new FXMenuRadio(&pane,"Small Cover",this,ID_COVERSIZE_SMALL);
      new FXMenuRadio(&pane,"Medium Cover",this,ID_COVERSIZE_MEDIUM);
      new FXMenuRadio(&pane,"Large Cover",this,ID_COVERSIZE_LARGE);
      new FXMenuRadio(&pane,"Extra Large Cover",this,ID_COVERSIZE_EXTRALARGE);
      }
    else {
      new FXMenuCheck(&pane,"Use X11 viewer",this,ID_CHANGE_COVERVIEW);
      }
    gm_set_window_cursor(&pane,getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
    pane.create();

    ewmh_change_window_type(&pane,WINDOWTYPE_POPUP_MENU);
    pane.popup(NULL,event->root_x+3,event->root_y+3);
    getApp()->runPopup(&pane);
    return 1;
    }
  return 0;
  }

long GMWindow::onCmdChangeCoverView(FXObject*,FXSelector,void*){
  GMPlayerManager::instance()->getPreferences().gui_show_opengl_coverview=!GMPlayerManager::instance()->getPreferences().gui_show_opengl_coverview;
  updateCoverView();
  if (GMPlayerManager::instance()->playing())
    GMPlayerManager::instance()->update_cover_display();
  return 1;
  }

long GMWindow::onCmdCoverSize(FXObject*,FXSelector sel,void*){
  switch(FXSELID(sel)){
    case ID_COVERSIZE_SMALL      : GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size=128; break;
    case ID_COVERSIZE_MEDIUM     : GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size=256; break;
    case ID_COVERSIZE_LARGE      : GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size=384; break;
    case ID_COVERSIZE_EXTRALARGE : GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size=512; break;
    }
  loadCover(FXString::null);
  if (GMPlayerManager::instance()->playing())
    GMPlayerManager::instance()->update_cover_display();
  return 1;
  }

long GMWindow::onUpdCoverSize(FXObject*sender,FXSelector sel,void*){
  FXbool check=false;
  switch(FXSELID(sel)){
    case ID_COVERSIZE_SMALL      : check = (GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size<=128); break;
    case ID_COVERSIZE_MEDIUM     : check = ((GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size>128) && (GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size<384)); break;
    case ID_COVERSIZE_LARGE      : check = ((GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size>=384) && (GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size<512)); break;
    case ID_COVERSIZE_EXTRALARGE : check = (GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size>=512); break;
    }
  if (check)
    sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
  return 1;
  }

#if FOXVERSION > FXVERSION(1,7,21)
long GMWindow::onCmdShowSources(FXObject*,FXSelector,void*){
  if (mainsplitter->getExpanded()==SHOWSOURCES)
    mainsplitter->setExpanded(HIDESOURCES);
  else
    mainsplitter->setExpanded(SHOWSOURCES);
  return 1;
  }

long GMWindow::onUpdShowSources(FXObject*sender,FXSelector,void*){
  if (mainsplitter->getExpanded()==SHOWSOURCES)
    sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
  else
    sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
  return 1;
  }
#endif


