Merge pull request #3232 from Karlson2k/Startup_log_03
[vuplus_xbmc] / xbmc / Application.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "network/Network.h"
22 #include "threads/SystemClock.h"
23 #include "system.h"
24 #include "Application.h"
25 #include "interfaces/Builtins.h"
26 #include "utils/Variant.h"
27 #include "utils/Splash.h"
28 #include "LangInfo.h"
29 #include "utils/Screenshot.h"
30 #include "Util.h"
31 #include "URL.h"
32 #include "guilib/TextureManager.h"
33 #include "cores/IPlayer.h"
34 #include "cores/dvdplayer/DVDFileInfo.h"
35 #include "cores/AudioEngine/AEFactory.h"
36 #include "cores/AudioEngine/Utils/AEUtil.h"
37 #include "PlayListPlayer.h"
38 #include "Autorun.h"
39 #include "video/Bookmark.h"
40 #include "network/NetworkServices.h"
41 #include "guilib/GUIControlProfiler.h"
42 #include "utils/LangCodeExpander.h"
43 #include "GUIInfoManager.h"
44 #include "playlists/PlayListFactory.h"
45 #include "guilib/GUIFontManager.h"
46 #include "guilib/GUIColorManager.h"
47 #include "guilib/StereoscopicsManager.h"
48 #include "guilib/GUITextLayout.h"
49 #include "addons/Skin.h"
50 #include "interfaces/generic/ScriptInvocationManager.h"
51 #ifdef HAS_PYTHON
52 #include "interfaces/python/XBPython.h"
53 #endif
54 #include "input/ButtonTranslator.h"
55 #include "guilib/GUIAudioManager.h"
56 #include "GUIPassword.h"
57 #include "input/InertialScrollingHandler.h"
58 #include "ApplicationMessenger.h"
59 #include "SectionLoader.h"
60 #include "cores/DllLoader/DllLoaderContainer.h"
61 #include "GUIUserMessages.h"
62 #include "filesystem/DirectoryCache.h"
63 #include "filesystem/StackDirectory.h"
64 #include "filesystem/SpecialProtocol.h"
65 #include "filesystem/DllLibCurl.h"
66 #include "filesystem/MythSession.h"
67 #include "filesystem/PluginDirectory.h"
68 #ifdef HAS_FILESYSTEM_SAP
69 #include "filesystem/SAPDirectory.h"
70 #endif
71 #ifdef HAS_FILESYSTEM_HTSP
72 #include "filesystem/HTSPDirectory.h"
73 #endif
74 #include "utils/TuxBoxUtil.h"
75 #include "utils/SystemInfo.h"
76 #include "utils/TimeUtils.h"
77 #include "GUILargeTextureManager.h"
78 #include "TextureCache.h"
79 #include "playlists/SmartPlayList.h"
80 #ifdef HAS_FILESYSTEM_RAR
81 #include "filesystem/RarManager.h"
82 #endif
83 #include "playlists/PlayList.h"
84 #include "profiles/ProfilesManager.h"
85 #include "windowing/WindowingFactory.h"
86 #include "powermanagement/PowerManager.h"
87 #include "powermanagement/DPMSSupport.h"
88 #include "settings/SettingAddon.h"
89 #include "settings/Settings.h"
90 #include "settings/AdvancedSettings.h"
91 #include "settings/DisplaySettings.h"
92 #include "settings/MediaSettings.h"
93 #include "settings/MediaSourceSettings.h"
94 #include "settings/SkinSettings.h"
95 #include "guilib/LocalizeStrings.h"
96 #include "utils/CPUInfo.h"
97 #include "utils/RssManager.h"
98 #include "utils/SeekHandler.h"
99 #include "view/ViewStateSettings.h"
100
101 #include "input/KeyboardStat.h"
102 #include "input/XBMC_vkeys.h"
103 #include "input/MouseStat.h"
104
105 #ifdef HAS_SDL
106 #include <SDL/SDL.h>
107 #endif
108
109 #if defined(FILESYSTEM) && !defined(TARGET_POSIX)
110 #include "filesystem/FileDAAP.h"
111 #endif
112 #ifdef HAS_UPNP
113 #include "network/upnp/UPnP.h"
114 #include "network/upnp/UPnPSettings.h"
115 #include "filesystem/UPnPDirectory.h"
116 #endif
117 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
118 #include "filesystem/SMBDirectory.h"
119 #endif
120 #ifdef HAS_FILESYSTEM_NFS
121 #include "filesystem/NFSFile.h"
122 #endif
123 #ifdef HAS_FILESYSTEM_AFP
124 #include "filesystem/AFPFile.h"
125 #endif
126 #ifdef HAS_FILESYSTEM_SFTP
127 #include "filesystem/SFTPFile.h"
128 #endif
129 #include "PartyModeManager.h"
130 #ifdef HAS_VIDEO_PLAYBACK
131 #include "cores/VideoRenderers/RenderManager.h"
132 #endif
133 #ifdef HAS_KARAOKE
134 #include "music/karaoke/karaokelyricsmanager.h"
135 #include "music/karaoke/GUIDialogKaraokeSongSelector.h"
136 #include "music/karaoke/GUIWindowKaraokeLyrics.h"
137 #endif
138 #include "network/Zeroconf.h"
139 #include "network/ZeroconfBrowser.h"
140 #ifndef TARGET_POSIX
141 #include "threads/platform/win/Win32Exception.h"
142 #endif
143 #ifdef HAS_EVENT_SERVER
144 #include "network/EventServer.h"
145 #endif
146 #ifdef HAS_DBUS
147 #include <dbus/dbus.h>
148 #endif
149 #ifdef HAS_JSONRPC
150 #include "interfaces/json-rpc/JSONRPC.h"
151 #include "network/TCPServer.h"
152 #endif
153 #ifdef HAS_AIRPLAY
154 #include "network/AirPlayServer.h"
155 #endif
156 #ifdef HAS_AIRTUNES
157 #include "network/AirTunesServer.h"
158 #endif
159 #if defined(HAVE_LIBCRYSTALHD)
160 #include "cores/dvdplayer/DVDCodecs/Video/CrystalHD.h"
161 #endif
162 #include "interfaces/AnnouncementManager.h"
163 #include "peripherals/Peripherals.h"
164 #include "peripherals/dialogs/GUIDialogPeripheralManager.h"
165 #include "peripherals/dialogs/GUIDialogPeripheralSettings.h"
166 #include "peripherals/devices/PeripheralImon.h"
167 #include "music/infoscanner/MusicInfoScanner.h"
168
169 // Windows includes
170 #include "guilib/GUIWindowManager.h"
171 #include "windows/GUIWindowHome.h"
172 #include "settings/windows/GUIWindowSettings.h"
173 #include "windows/GUIWindowFileManager.h"
174 #include "settings/windows/GUIWindowSettingsCategory.h"
175 #include "music/windows/GUIWindowMusicPlaylist.h"
176 #include "music/windows/GUIWindowMusicSongs.h"
177 #include "music/windows/GUIWindowMusicNav.h"
178 #include "music/windows/GUIWindowMusicPlaylistEditor.h"
179 #include "video/windows/GUIWindowVideoPlaylist.h"
180 #include "music/dialogs/GUIDialogMusicInfo.h"
181 #include "video/dialogs/GUIDialogVideoInfo.h"
182 #include "video/windows/GUIWindowVideoNav.h"
183 #include "profiles/windows/GUIWindowSettingsProfile.h"
184 #ifdef HAS_GL
185 #include "rendering/gl/GUIWindowTestPatternGL.h"
186 #endif
187 #ifdef HAS_DX
188 #include "rendering/dx/GUIWindowTestPatternDX.h"
189 #endif
190 #include "settings/windows/GUIWindowSettingsScreenCalibration.h"
191 #include "programs/GUIWindowPrograms.h"
192 #include "pictures/GUIWindowPictures.h"
193 #include "windows/GUIWindowWeather.h"
194 #include "windows/GUIWindowLoginScreen.h"
195 #include "addons/GUIWindowAddonBrowser.h"
196 #include "music/windows/GUIWindowVisualisation.h"
197 #include "windows/GUIWindowDebugInfo.h"
198 #include "windows/GUIWindowPointer.h"
199 #include "windows/GUIWindowSystemInfo.h"
200 #include "windows/GUIWindowScreensaver.h"
201 #include "windows/GUIWindowScreensaverDim.h"
202 #include "pictures/GUIWindowSlideShow.h"
203 #include "windows/GUIWindowStartup.h"
204 #include "video/windows/GUIWindowFullScreen.h"
205 #include "video/dialogs/GUIDialogVideoOSD.h"
206 #include "music/dialogs/GUIDialogMusicOverlay.h"
207 #include "video/dialogs/GUIDialogVideoOverlay.h"
208 #include "video/VideoInfoScanner.h"
209 #include "video/PlayerController.h"
210
211 // Dialog includes
212 #include "music/dialogs/GUIDialogMusicOSD.h"
213 #include "music/dialogs/GUIDialogVisualisationPresetList.h"
214 #include "dialogs/GUIDialogTextViewer.h"
215 #include "network/GUIDialogNetworkSetup.h"
216 #include "dialogs/GUIDialogMediaSource.h"
217 #include "video/dialogs/GUIDialogVideoSettings.h"
218 #include "video/dialogs/GUIDialogAudioSubtitleSettings.h"
219 #include "video/dialogs/GUIDialogVideoBookmarks.h"
220 #include "profiles/dialogs/GUIDialogProfileSettings.h"
221 #include "profiles/dialogs/GUIDialogLockSettings.h"
222 #include "settings/dialogs/GUIDialogContentSettings.h"
223 #include "dialogs/GUIDialogBusy.h"
224 #include "dialogs/GUIDialogKeyboardGeneric.h"
225 #include "dialogs/GUIDialogYesNo.h"
226 #include "dialogs/GUIDialogOK.h"
227 #include "dialogs/GUIDialogProgress.h"
228 #include "dialogs/GUIDialogExtendedProgressBar.h"
229 #include "dialogs/GUIDialogSelect.h"
230 #include "dialogs/GUIDialogSeekBar.h"
231 #include "dialogs/GUIDialogKaiToast.h"
232 #include "dialogs/GUIDialogVolumeBar.h"
233 #include "dialogs/GUIDialogMuteBug.h"
234 #include "video/dialogs/GUIDialogFileStacking.h"
235 #include "dialogs/GUIDialogNumeric.h"
236 #include "dialogs/GUIDialogGamepad.h"
237 #include "dialogs/GUIDialogSubMenu.h"
238 #include "dialogs/GUIDialogFavourites.h"
239 #include "dialogs/GUIDialogButtonMenu.h"
240 #include "dialogs/GUIDialogContextMenu.h"
241 #include "dialogs/GUIDialogPlayerControls.h"
242 #include "music/dialogs/GUIDialogSongInfo.h"
243 #include "dialogs/GUIDialogSmartPlaylistEditor.h"
244 #include "dialogs/GUIDialogSmartPlaylistRule.h"
245 #include "pictures/GUIDialogPictureInfo.h"
246 #include "addons/GUIDialogAddonSettings.h"
247 #include "addons/GUIDialogAddonInfo.h"
248 #ifdef HAS_LINUX_NETWORK
249 #include "network/GUIDialogAccessPoints.h"
250 #endif
251
252 /* PVR related include Files */
253 #include "pvr/PVRManager.h"
254 #include "pvr/timers/PVRTimers.h"
255 #include "pvr/windows/GUIWindowPVR.h"
256 #include "pvr/dialogs/GUIDialogPVRChannelManager.h"
257 #include "pvr/dialogs/GUIDialogPVRChannelsOSD.h"
258 #include "pvr/dialogs/GUIDialogPVRCutterOSD.h"
259 #include "pvr/dialogs/GUIDialogPVRDirectorOSD.h"
260 #include "pvr/dialogs/GUIDialogPVRGroupManager.h"
261 #include "pvr/dialogs/GUIDialogPVRGuideInfo.h"
262 #include "pvr/dialogs/GUIDialogPVRGuideOSD.h"
263 #include "pvr/dialogs/GUIDialogPVRGuideSearch.h"
264 #include "pvr/dialogs/GUIDialogPVRRecordingInfo.h"
265 #include "pvr/dialogs/GUIDialogPVRTimerSettings.h"
266
267 #include "epg/EpgContainer.h"
268
269 #include "video/dialogs/GUIDialogFullScreenInfo.h"
270 #include "video/dialogs/GUIDialogTeletext.h"
271 #include "dialogs/GUIDialogSlider.h"
272 #include "guilib/GUIControlFactory.h"
273 #include "dialogs/GUIDialogCache.h"
274 #include "dialogs/GUIDialogPlayEject.h"
275 #include "dialogs/GUIDialogMediaFilter.h"
276 #include "utils/XMLUtils.h"
277 #include "addons/AddonInstaller.h"
278
279 #ifdef HAS_PERFORMANCE_SAMPLE
280 #include "utils/PerformanceSample.h"
281 #else
282 #define MEASURE_FUNCTION
283 #endif
284
285 #ifdef TARGET_WINDOWS
286 #include <shlobj.h>
287 #include "win32util.h"
288 #endif
289 #ifdef HAS_XRANDR
290 #include "windowing/X11/XRandR.h"
291 #endif
292
293 #ifdef TARGET_DARWIN_OSX
294 #include "osx/CocoaInterface.h"
295 #include "osx/XBMCHelper.h"
296 #endif
297 #ifdef TARGET_DARWIN
298 #include "osx/DarwinUtils.h"
299 #endif
300
301
302 #ifdef HAS_DVD_DRIVE
303 #include <cdio/logging.h>
304 #endif
305
306 #ifdef HAS_HAL
307 #include "linux/HALManager.h"
308 #endif
309
310 #include "storage/MediaManager.h"
311 #include "utils/JobManager.h"
312 #include "utils/SaveFileStateJob.h"
313 #include "utils/AlarmClock.h"
314 #include "utils/RssReader.h"
315 #include "utils/StringUtils.h"
316 #include "utils/Weather.h"
317 #include "DatabaseManager.h"
318
319 #ifdef TARGET_POSIX
320 #include "XHandle.h"
321 #endif
322
323 #ifdef HAS_LIRC
324 #include "input/linux/LIRC.h"
325 #endif
326 #ifdef HAS_IRSERVERSUITE
327   #include "input/windows/IRServerSuite.h"
328 #endif
329
330 #if defined(TARGET_WINDOWS)
331 #include "input/windows/WINJoystick.h"
332 #elif defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER)
333 #include "input/SDLJoystick.h"
334 #endif
335
336 #if defined(TARGET_ANDROID)
337 #include "android/activity/XBMCApp.h"
338 #endif
339
340 #ifdef TARGET_WINDOWS
341 #include "utils/Environment.h"
342 #endif
343
344 using namespace std;
345 using namespace ADDON;
346 using namespace XFILE;
347 #ifdef HAS_DVD_DRIVE
348 using namespace MEDIA_DETECT;
349 #endif
350 using namespace PLAYLIST;
351 using namespace VIDEO;
352 using namespace MUSIC_INFO;
353 #ifdef HAS_EVENT_SERVER
354 using namespace EVENTSERVER;
355 #endif
356 #ifdef HAS_JSONRPC
357 using namespace JSONRPC;
358 #endif
359 using namespace ANNOUNCEMENT;
360 using namespace PVR;
361 using namespace EPG;
362 using namespace PERIPHERALS;
363
364 using namespace XbmcThreads;
365
366 // uncomment this if you want to use release libs in the debug build.
367 // Atm this saves you 7 mb of memory
368 #define USE_RELEASE_LIBS
369
370 #define MAX_FFWD_SPEED 5
371
372 //extern IDirectSoundRenderer* m_pAudioDecoder;
373 CApplication::CApplication(void)
374   : m_pPlayer(new CApplicationPlayer)
375   , m_itemCurrentFile(new CFileItem)
376   , m_stackFileItemToUpdate(new CFileItem)
377   , m_progressTrackingVideoResumeBookmark(*new CBookmark)
378   , m_progressTrackingItem(new CFileItem)
379   , m_videoInfoScanner(new CVideoInfoScanner)
380   , m_musicInfoScanner(new CMusicInfoScanner)
381   , m_seekHandler(new CSeekHandler)
382   , m_playerController(new CPlayerController)
383 {
384   m_network = NULL;
385   TiXmlBase::SetCondenseWhiteSpace(false);
386   m_bInhibitIdleShutdown = false;
387   m_bScreenSave = false;
388   m_dpms = NULL;
389   m_dpmsIsActive = false;
390   m_dpmsIsManual = false;
391   m_iScreenSaveLock = 0;
392   m_bInitializing = true;
393   m_eForcedNextPlayer = EPC_NONE;
394   m_strPlayListFile = "";
395   m_nextPlaylistItem = -1;
396   m_bPlaybackStarting = false;
397   m_ePlayState = PLAY_STATE_NONE;
398   m_skinReloading = false;
399   m_loggingIn = false;
400
401 #ifdef HAS_GLX
402   XInitThreads();
403 #endif
404
405   // we start in frontend
406   m_bInBackground = false;
407
408   /* for now always keep this around */
409 #ifdef HAS_KARAOKE
410   m_pKaraokeMgr = new CKaraokeLyricsManager();
411 #endif
412   m_currentStack = new CFileItemList;
413
414   m_bPresentFrame = false;
415   m_bPlatformDirectories = true;
416
417   m_bStandalone = false;
418   m_bEnableLegacyRes = false;
419   m_bSystemScreenSaverEnable = false;
420   m_pInertialScrollingHandler = new CInertialScrollingHandler();
421 #ifdef HAS_DVD_DRIVE
422   m_Autorun = new CAutorun();
423 #endif
424
425   m_splash = NULL;
426   m_threadID = 0;
427   m_progressTrackingPlayCountUpdate = false;
428   m_currentStackPosition = 0;
429   m_lastFrameTime = 0;
430   m_lastRenderTime = 0;
431   m_bTestMode = false;
432
433   m_muted = false;
434   m_volumeLevel = 1.0f;
435 }
436
437 CApplication::~CApplication(void)
438 {
439   delete m_musicInfoScanner;
440   delete m_videoInfoScanner;
441   delete &m_progressTrackingVideoResumeBookmark;
442 #ifdef HAS_DVD_DRIVE
443   delete m_Autorun;
444 #endif
445   delete m_currentStack;
446
447 #ifdef HAS_KARAOKE
448   delete m_pKaraokeMgr;
449 #endif
450
451   delete m_dpms;
452   delete m_seekHandler;
453   delete m_playerController;
454   delete m_pInertialScrollingHandler;
455   delete m_pPlayer;
456 }
457
458 bool CApplication::OnEvent(XBMC_Event& newEvent)
459 {
460   switch(newEvent.type)
461   {
462     case XBMC_QUIT:
463       if (!g_application.m_bStop)
464         CApplicationMessenger::Get().Quit();
465       break;
466     case XBMC_KEYDOWN:
467       g_application.OnKey(g_Keyboard.ProcessKeyDown(newEvent.key.keysym));
468       break;
469     case XBMC_KEYUP:
470       g_Keyboard.ProcessKeyUp();
471       break;
472     case XBMC_MOUSEBUTTONDOWN:
473     case XBMC_MOUSEBUTTONUP:
474     case XBMC_MOUSEMOTION:
475       g_Mouse.HandleEvent(newEvent);
476       g_application.ProcessMouse();
477       break;
478     case XBMC_VIDEORESIZE:
479       if (!g_application.m_bInitializing &&
480           !g_advancedSettings.m_fullScreen)
481       {
482         g_Windowing.SetWindowResolution(newEvent.resize.w, newEvent.resize.h);
483         g_graphicsContext.SetVideoResolution(RES_WINDOW, true);
484         CSettings::Get().SetInt("window.width", newEvent.resize.w);
485         CSettings::Get().SetInt("window.height", newEvent.resize.h);
486         CSettings::Get().Save();
487       }
488       break;
489     case XBMC_VIDEOMOVE:
490 #ifdef TARGET_WINDOWS
491       if (g_advancedSettings.m_fullScreen)
492       {
493         // when fullscreen, remain fullscreen and resize to the dimensions of the new screen
494         RESOLUTION newRes = (RESOLUTION) g_Windowing.DesktopResolution(g_Windowing.GetCurrentScreen());
495         if (newRes != g_graphicsContext.GetVideoResolution())
496           CDisplaySettings::Get().SetCurrentResolution(newRes, true);
497       }
498       else
499 #endif
500       {
501         g_Windowing.OnMove(newEvent.move.x, newEvent.move.y);
502       }
503       break;
504     case XBMC_USEREVENT:
505       CApplicationMessenger::Get().UserEvent(newEvent.user.code);
506       break;
507     case XBMC_APPCOMMAND:
508       return g_application.OnAppCommand(newEvent.appcommand.action);
509     case XBMC_TOUCH:
510     {
511       int windowId = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
512
513       if (newEvent.touch.action == ACTION_TOUCH_TAP)
514       { // Send a mouse motion event with no dx,dy for getting the current guiitem selected
515         g_application.OnAction(CAction(ACTION_MOUSE_MOVE, 0, newEvent.touch.x, newEvent.touch.y, 0, 0));
516       }
517       int actionId = 0;
518       if (newEvent.touch.action == ACTION_GESTURE_BEGIN || newEvent.touch.action == ACTION_GESTURE_END)
519       {
520         actionId = newEvent.touch.action;
521         windowId = WINDOW_INVALID;
522       }
523       else if (!CButtonTranslator::GetInstance().TranslateTouchAction(newEvent.touch.action, newEvent.touch.pointers, windowId, actionId) ||
524           actionId <= 0)
525         return false;
526
527       CApplicationMessenger::Get().SendAction(CAction(actionId, 0, newEvent.touch.x, newEvent.touch.y, newEvent.touch.x2, newEvent.touch.y2), windowId, false);
528       // Post an unfocus message for touch device after the action.
529       if (newEvent.touch.action == ACTION_GESTURE_END || newEvent.touch.action == ACTION_TOUCH_TAP)
530       {
531         CGUIMessage msg(GUI_MSG_UNFOCUS_ALL, 0, 0, 0, 0);
532         CApplicationMessenger::Get().SendGUIMessage(msg);
533       }
534       break;
535     }
536   }
537   return true;
538 }
539
540 extern "C" void __stdcall init_emu_environ();
541 extern "C" void __stdcall update_emu_environ();
542
543 //
544 // Utility function used to copy files from the application bundle
545 // over to the user data directory in Application Support/XBMC.
546 //
547 static void CopyUserDataIfNeeded(const CStdString &strPath, const CStdString &file)
548 {
549   CStdString destPath = URIUtils::AddFileToFolder(strPath, file);
550   if (!CFile::Exists(destPath))
551   {
552     // need to copy it across
553     CStdString srcPath = URIUtils::AddFileToFolder("special://xbmc/userdata/", file);
554     CFile::Cache(srcPath, destPath);
555   }
556 }
557
558 void CApplication::Preflight()
559 {
560 #ifdef HAS_DBUS
561   // call 'dbus_threads_init_default' before any other dbus calls in order to
562   // avoid race conditions with other threads using dbus connections
563   dbus_threads_init_default();
564 #endif
565
566   // run any platform preflight scripts.
567 #if defined(TARGET_DARWIN_OSX)
568   CStdString install_path;
569
570   CUtil::GetHomePath(install_path);
571   setenv("XBMC_HOME", install_path.c_str(), 0);
572   install_path += "/tools/darwin/runtime/preflight";
573   system(install_path.c_str());
574 #endif
575 }
576
577 bool CApplication::Create()
578 {
579 #if defined(HAS_LINUX_NETWORK)
580   m_network = new CNetworkLinux();
581 #elif defined(HAS_WIN32_NETWORK)
582   m_network = new CNetworkWin32();
583 #else
584   m_network = new CNetwork();
585 #endif
586
587   Preflight();
588
589   for (int i = RES_HDTV_1080i; i <= RES_PAL60_16x9; i++)
590   {
591     g_graphicsContext.ResetScreenParameters((RESOLUTION)i);
592     g_graphicsContext.ResetOverscan((RESOLUTION)i, CDisplaySettings::Get().GetResolutionInfo(i).Overscan);
593   }
594
595 #ifdef TARGET_POSIX
596   tzset();   // Initialize timezone information variables
597 #endif
598
599   // Grab a handle to our thread to be used later in identifying the render thread.
600   m_threadID = CThread::GetCurrentThreadId();
601
602 #ifndef TARGET_POSIX
603   //floating point precision to 24 bits (faster performance)
604   _controlfp(_PC_24, _MCW_PC);
605
606   /* install win32 exception translator, win32 exceptions
607    * can now be caught using c++ try catch */
608   win32_exception::install_handler();
609
610 #endif
611
612   // only the InitDirectories* for the current platform should return true
613   // putting this before the first log entries saves another ifdef for g_advancedSettings.m_logFolder
614   bool inited = InitDirectoriesLinux();
615   if (!inited)
616     inited = InitDirectoriesOSX();
617   if (!inited)
618     inited = InitDirectoriesWin32();
619
620   // copy required files
621   CopyUserDataIfNeeded("special://masterprofile/", "RssFeeds.xml");
622   CopyUserDataIfNeeded("special://masterprofile/", "favourites.xml");
623   CopyUserDataIfNeeded("special://masterprofile/", "Lircmap.xml");
624
625   if (!CLog::Init(CSpecialProtocol::TranslatePath(g_advancedSettings.m_logFolder).c_str()))
626   {
627     fprintf(stderr,"Could not init logging classes. Permission errors on ~/.xbmc (%s)\n",
628       CSpecialProtocol::TranslatePath(g_advancedSettings.m_logFolder).c_str());
629     return false;
630   }
631
632   // Init our DllLoaders emu env
633   init_emu_environ();
634
635   CProfilesManager::Get().Load();
636
637   CLog::Log(LOGNOTICE, "-----------------------------------------------------------------------");
638   CLog::Log(LOGNOTICE, "Starting XBMC (%s). Platform: %s %s %d-bit", g_infoManager.GetVersion().c_str(), g_sysinfo.GetBuildTargetCpuFamily().c_str(),
639       g_sysinfo.GetBuildTargetPlatformName().c_str(), g_sysinfo.GetXbmcBitness());
640
641 /* Expand macro before stringify */
642 #define STR_MACRO(x) #x
643 #define XSTR_MACRO(x) STR_MACRO(x)
644
645   std::string compilerStr;
646 #if defined(__clang__)
647   compilerStr = "Clang " XSTR_MACRO(__clang_major__) "." XSTR_MACRO(__clang_minor__) "." XSTR_MACRO(__clang_patchlevel__);
648 #elif defined (__INTEL_COMPILER)
649   compilerStr = "Intel Compiler " XSTR_MACRO(__INTEL_COMPILER);
650 #elif defined (__GNUC__)
651 #ifdef __llvm__
652   /* Note: this will not detect GCC + DragonEgg */
653   compilerStr = "llvm-gcc "; 
654 #else // __llvm__
655   compilerStr = "GCC ";
656 #endif // !__llvm__
657   compilerStr += XSTR_MACRO(__GNUC__) "." XSTR_MACRO(__GNUC_MINOR__) "." XSTR_MACRO(__GNUC_PATCHLEVEL__);
658 #elif defined (_MSC_VER)
659   compilerStr = "MSVC " XSTR_MACRO(_MSC_FULL_VER);
660 #else
661   compilerStr = "unknown compiler";
662 #endif
663   std::string buildType;
664 #if defined(_DEBUG)
665   buildType = "Debug";
666 #elif defined(NDEBUG)
667   buildType = "Release";
668 #else
669   buildType = "Unknown";
670 #endif
671   CLog::Log(LOGNOTICE, "Using %s XBMC x%d build, compiled " __DATE__ " by %s for %s %s %d-bit %s", buildType.c_str(), g_sysinfo.GetXbmcBitness(), compilerStr.c_str(),
672       g_sysinfo.GetBuildTargetCpuFamily().c_str(), g_sysinfo.GetBuildTargetPlatformName().c_str(), g_sysinfo.GetXbmcBitness(), g_sysinfo.GetBuildTargetPlatformVersion().c_str());
673
674 #if defined(TARGET_DARWIN_OSX)
675   CLog::Log(LOGNOTICE, "Running on Darwin OSX %d-bit %s", g_sysinfo.GetKernelBitness(), g_sysinfo.GetUnameVersion().c_str());
676 #elif defined(TARGET_DARWIN_IOS)
677   CLog::Log(LOGNOTICE, "Running on Darwin iOS %d-bit %s%s", g_sysinfo.GetKernelBitness(), g_sysinfo.IsAppleTV2() ? "(AppleTV2) " : "", g_sysinfo.GetUnameVersion().c_str());
678 #elif defined(TARGET_FREEBSD)
679   CLog::Log(LOGNOTICE, "Running on FreeBSD %d-bit %s", g_sysinfo.GetKernelBitness(), g_sysinfo.GetUnameVersion().c_str());
680 #elif defined(TARGET_POSIX)
681   CLog::Log(LOGNOTICE, "Running on Linux %d-bit (%s, %s)", g_sysinfo.GetKernelBitness(), g_sysinfo.GetLinuxDistro().c_str(), g_sysinfo.GetUnameVersion().c_str());
682 #elif defined(TARGET_WINDOWS)
683   CLog::Log(LOGNOTICE, "Running on %s", g_sysinfo.GetKernelVersion().c_str());
684 #endif
685   
686   CLog::Log(LOGNOTICE, "Host CPU: %s, %d core%s available", g_cpuInfo.getCPUModel().c_str(), g_cpuInfo.getCPUCount(), (g_cpuInfo.getCPUCount()==1) ? "" : "s");
687 #if defined(TARGET_WINDOWS)
688   CLog::Log(LOGNOTICE, "%s", CWIN32Util::GetResInfoString().c_str());
689   CLog::Log(LOGNOTICE, "Running with %s rights", (CWIN32Util::IsCurrentUserLocalAdministrator() == TRUE) ? "administrator" : "restricted");
690   CLog::Log(LOGNOTICE, "Aero is %s", (g_sysinfo.IsAeroDisabled() == true) ? "disabled" : "enabled");
691 #endif
692 #if defined(__arm__)
693   if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON)
694     CLog::Log(LOGNOTICE, "ARM Features: Neon enabled");
695   else
696     CLog::Log(LOGNOTICE, "ARM Features: Neon disabled");
697 #endif
698   CSpecialProtocol::LogPaths();
699
700   CStdString executable = CUtil::ResolveExecutablePath();
701   CLog::Log(LOGNOTICE, "The executable running is: %s", executable.c_str());
702   CLog::Log(LOGNOTICE, "Local hostname: %s", m_network->GetHostName().c_str());
703   CLog::Log(LOGNOTICE, "Log File is located: %sxbmc.log", g_advancedSettings.m_logFolder.c_str());
704   CLog::Log(LOGNOTICE, "-----------------------------------------------------------------------");
705
706   CStdString strExecutablePath;
707   CUtil::GetHomePath(strExecutablePath);
708
709 #ifdef HAS_XRANDR
710   g_xrandr.LoadCustomModeLinesToAllOutputs();
711 #endif
712
713   // for python scripts that check the OS
714 #if defined(TARGET_DARWIN)
715   setenv("OS","OS X",true);
716 #elif defined(TARGET_POSIX)
717   setenv("OS","Linux",true);
718 #elif defined(TARGET_WINDOWS)
719   CEnvironment::setenv("OS", "win32");
720 #endif
721
722   g_powerManager.Initialize();
723
724   // Load the AudioEngine before settings as they need to query the engine
725   if (!CAEFactory::LoadEngine())
726   {
727     CLog::Log(LOGFATAL, "CApplication::Create: Failed to load an AudioEngine");
728     return false;
729   }
730
731   // Initialize default Settings - don't move
732   CLog::Log(LOGNOTICE, "load settings...");
733   if (!CSettings::Get().Initialize())
734     return false;
735
736   g_powerManager.SetDefaults();
737
738   // load the actual values
739   if (!CSettings::Get().Load())
740   {
741     CLog::Log(LOGFATAL, "unable to load settings");
742     return false;
743   }
744   CSettings::Get().SetLoaded();
745
746   CLog::Log(LOGINFO, "creating subdirectories");
747   CLog::Log(LOGINFO, "userdata folder: %s", CProfilesManager::Get().GetProfileUserDataFolder().c_str());
748   CLog::Log(LOGINFO, "recording folder: %s", CSettings::Get().GetString("audiocds.recordingpath").c_str());
749   CLog::Log(LOGINFO, "screenshots folder: %s", CSettings::Get().GetString("debug.screenshotpath").c_str());
750   CDirectory::Create(CProfilesManager::Get().GetUserDataFolder());
751   CDirectory::Create(CProfilesManager::Get().GetProfileUserDataFolder());
752   CProfilesManager::Get().CreateProfileFolders();
753
754   update_emu_environ();//apply the GUI settings
755
756   // initialize our charset converter
757   g_charsetConverter.reset();
758
759   // Load the langinfo to have user charset <-> utf-8 conversion
760   CStdString strLanguage = CSettings::Get().GetString("locale.language");
761   strLanguage[0] = toupper(strLanguage[0]);
762
763   CStdString strLangInfoPath;
764   strLangInfoPath.Format("special://xbmc/language/%s/langinfo.xml", strLanguage.c_str());
765
766   CLog::Log(LOGINFO, "load language info file: %s", strLangInfoPath.c_str());
767   g_langInfo.Load(strLangInfoPath);
768   g_langInfo.SetAudioLanguage(CSettings::Get().GetString("locale.audiolanguage"));
769   g_langInfo.SetSubtitleLanguage(CSettings::Get().GetString("locale.subtitlelanguage"));
770
771   CStdString strLanguagePath = "special://xbmc/language/";
772
773   CLog::Log(LOGINFO, "load %s language file, from path: %s", strLanguage.c_str(), strLanguagePath.c_str());
774   if (!g_localizeStrings.Load(strLanguagePath, strLanguage))
775   {
776     CLog::Log(LOGFATAL, "%s: Failed to load %s language file, from path: %s", __FUNCTION__, strLanguage.c_str(), strLanguagePath.c_str());
777     return false;
778   }
779
780   // start the AudioEngine
781   if (!CAEFactory::StartEngine())
782   {
783     CLog::Log(LOGFATAL, "CApplication::Create: Failed to start the AudioEngine");
784     return false;
785   }
786
787   // restore AE's previous volume state
788   SetHardwareVolume(m_volumeLevel);
789   CAEFactory::SetMute     (m_muted);
790   CAEFactory::SetSoundMode(CSettings::Get().GetInt("audiooutput.guisoundmode"));
791
792   // initialize m_replayGainSettings
793   m_replayGainSettings.iType = CSettings::Get().GetInt("musicplayer.replaygaintype");
794   m_replayGainSettings.iPreAmp = CSettings::Get().GetInt("musicplayer.replaygainpreamp");
795   m_replayGainSettings.iNoGainPreAmp = CSettings::Get().GetInt("musicplayer.replaygainnogainpreamp");
796   m_replayGainSettings.bAvoidClipping = CSettings::Get().GetBool("musicplayer.replaygainavoidclipping");
797
798   // initialize the addon database (must be before the addon manager is init'd)
799   CDatabaseManager::Get().Initialize(true);
800
801 #ifdef HAS_PYTHON
802   CScriptInvocationManager::Get().RegisterLanguageInvocationHandler(&g_pythonParser, ".py");
803 #endif // HAS_PYTHON
804
805   // start-up Addons Framework
806   // currently bails out if either cpluff Dll is unavailable or system dir can not be scanned
807   if (!CAddonMgr::Get().Init())
808   {
809     CLog::Log(LOGFATAL, "CApplication::Create: Unable to start CAddonMgr");
810     return false;
811   }
812
813   // set logging from debug add-on
814   AddonPtr addon;
815   CAddonMgr::Get().GetAddon("xbmc.debug", addon);
816   if (addon)
817     g_advancedSettings.SetExtraLogsFromAddon(addon.get());
818
819   g_peripherals.Initialise();
820
821   // Create the Mouse, Keyboard, Remote, and Joystick devices
822   // Initialize after loading settings to get joystick deadzone setting
823   g_Mouse.Initialize();
824   g_Mouse.SetEnabled(CSettings::Get().GetBool("input.enablemouse"));
825
826   g_Keyboard.Initialize();
827 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
828   g_RemoteControl.Initialize();
829 #endif
830
831 #if defined(TARGET_DARWIN_OSX)
832   // Configure and possible manually start the helper.
833   XBMCHelper::GetInstance().Configure();
834 #endif
835
836   CUtil::InitRandomSeed();
837
838   g_mediaManager.Initialize();
839
840   m_lastFrameTime = XbmcThreads::SystemClockMillis();
841   m_lastRenderTime = m_lastFrameTime;
842   return true;
843 }
844
845 bool CApplication::CreateGUI()
846 {
847   m_renderGUI = true;
848 #ifdef HAS_SDL
849   CLog::Log(LOGNOTICE, "Setup SDL");
850
851   /* Clean up on exit, exit on window close and interrupt */
852   atexit(SDL_Quit);
853
854   uint32_t sdlFlags = 0;
855
856 #if defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)
857   sdlFlags |= SDL_INIT_VIDEO;
858 #endif
859
860 #if defined(HAS_SDL_JOYSTICK) && !defined(TARGET_WINDOWS)
861   sdlFlags |= SDL_INIT_JOYSTICK;
862 #endif
863
864   //depending on how it's compiled, SDL periodically calls XResetScreenSaver when it's fullscreen
865   //this might bring the monitor out of standby, so we have to disable it explicitly
866   //by passing 0 for overwrite to setsenv, the user can still override this by setting the environment variable
867 #if defined(TARGET_POSIX) && !defined(TARGET_DARWIN)
868   setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0);
869 #endif
870
871 #endif // HAS_SDL
872
873 #ifdef TARGET_POSIX
874   // for nvidia cards - vsync currently ALWAYS enabled.
875   // the reason is that after screen has been setup changing this env var will make no difference.
876   setenv("__GL_SYNC_TO_VBLANK", "1", 0);
877   setenv("__GL_YIELD", "USLEEP", 0);
878 #endif
879
880   m_bSystemScreenSaverEnable = g_Windowing.IsSystemScreenSaverEnabled();
881   g_Windowing.EnableSystemScreenSaver(false);
882
883 #ifdef HAS_SDL
884   if (SDL_Init(sdlFlags) != 0)
885   {
886     CLog::Log(LOGFATAL, "XBAppEx: Unable to initialize SDL: %s", SDL_GetError());
887     return false;
888   }
889   #if defined(TARGET_DARWIN)
890   // SDL_Init will install a handler for segfaults, restore the default handler.
891   signal(SIGSEGV, SIG_DFL);
892   #endif
893 #endif
894
895   // Initialize core peripheral port support. Note: If these parameters
896   // are 0 and NULL, respectively, then the default number and types of
897   // controllers will be initialized.
898   if (!g_Windowing.InitWindowSystem())
899   {
900     CLog::Log(LOGFATAL, "CApplication::Create: Unable to init windowing system");
901     return false;
902   }
903
904   // Retrieve the matching resolution based on GUI settings
905   CDisplaySettings::Get().SetCurrentResolution(CDisplaySettings::Get().GetDisplayResolution());
906   CLog::Log(LOGNOTICE, "Checking resolution %i", CDisplaySettings::Get().GetCurrentResolution());
907   if (!g_graphicsContext.IsValidResolution(CDisplaySettings::Get().GetCurrentResolution()))
908   {
909     CLog::Log(LOGNOTICE, "Setting safe mode %i", RES_DESKTOP);
910     CDisplaySettings::Get().SetCurrentResolution(RES_DESKTOP, true);
911   }
912
913   // update the window resolution
914   g_Windowing.SetWindowResolution(CSettings::Get().GetInt("window.width"), CSettings::Get().GetInt("window.height"));
915
916   if (g_advancedSettings.m_startFullScreen && CDisplaySettings::Get().GetCurrentResolution() == RES_WINDOW)
917     CDisplaySettings::Get().SetCurrentResolution(RES_DESKTOP);
918
919   if (!g_graphicsContext.IsValidResolution(CDisplaySettings::Get().GetCurrentResolution()))
920   {
921     // Oh uh - doesn't look good for starting in their wanted screenmode
922     CLog::Log(LOGERROR, "The screen resolution requested is not valid, resetting to a valid mode");
923     CDisplaySettings::Get().SetCurrentResolution(RES_DESKTOP);
924   }
925   if (!InitWindow())
926   {
927     return false;
928   }
929
930   if (g_advancedSettings.m_splashImage)
931   {
932     CStdString strUserSplash = "special://home/media/Splash.png";
933     if (CFile::Exists(strUserSplash))
934     {
935       CLog::Log(LOGINFO, "load user splash image: %s", CSpecialProtocol::TranslatePath(strUserSplash).c_str());
936       m_splash = new CSplash(strUserSplash);
937     }
938     else
939     {
940       CLog::Log(LOGINFO, "load default splash image: %s", CSpecialProtocol::TranslatePath("special://xbmc/media/Splash.png").c_str());
941       m_splash = new CSplash("special://xbmc/media/Splash.png");
942     }
943     m_splash->Show();
944   }
945
946   // The key mappings may already have been loaded by a peripheral
947   CLog::Log(LOGINFO, "load keymapping");
948   if (!CButtonTranslator::GetInstance().Load())
949     return false;
950
951   RESOLUTION_INFO info = g_graphicsContext.GetResInfo();
952   CLog::Log(LOGINFO, "GUI format %ix%i, Display %s",
953             info.iWidth,
954             info.iHeight,
955             info.strMode.c_str());
956   g_windowManager.Initialize();
957
958   return true;
959 }
960
961 bool CApplication::InitWindow()
962 {
963 #ifdef TARGET_DARWIN_OSX
964   // force initial window creation to be windowed, if fullscreen, it will switch to it below
965   // fixes the white screen of death if starting fullscreen and switching to windowed.
966   bool bFullScreen = false;
967   if (!g_Windowing.CreateNewWindow("XBMC", bFullScreen, CDisplaySettings::Get().GetResolutionInfo(RES_WINDOW), OnEvent))
968   {
969     CLog::Log(LOGFATAL, "CApplication::Create: Unable to create window");
970     return false;
971   }
972 #else
973   bool bFullScreen = CDisplaySettings::Get().GetCurrentResolution() != RES_WINDOW;
974   if (!g_Windowing.CreateNewWindow("XBMC", bFullScreen, CDisplaySettings::Get().GetCurrentResolutionInfo(), OnEvent))
975   {
976     CLog::Log(LOGFATAL, "CApplication::Create: Unable to create window");
977     return false;
978   }
979 #endif
980
981   if (!g_Windowing.InitRenderSystem())
982   {
983     CLog::Log(LOGFATAL, "CApplication::Create: Unable to init rendering system");
984     return false;
985   }
986   // set GUI res and force the clear of the screen
987   g_graphicsContext.SetVideoResolution(CDisplaySettings::Get().GetCurrentResolution());
988   g_fontManager.ReloadTTFFonts();
989   return true;
990 }
991
992 bool CApplication::DestroyWindow()
993 {
994   g_fontManager.UnloadTTFFonts();
995   return g_Windowing.DestroyWindow();
996 }
997
998 bool CApplication::InitDirectoriesLinux()
999 {
1000 /*
1001    The following is the directory mapping for Platform Specific Mode:
1002
1003    special://xbmc/          => [read-only] system directory (/usr/share/xbmc)
1004    special://home/          => [read-write] user's directory that will override special://xbmc/ system-wide
1005                                installations like skins, screensavers, etc.
1006                                ($HOME/.xbmc)
1007                                NOTE: XBMC will look in both special://xbmc/addons and special://home/addons for addons.
1008    special://masterprofile/ => [read-write] userdata of master profile. It will by default be
1009                                mapped to special://home/userdata ($HOME/.xbmc/userdata)
1010    special://profile/       => [read-write] current profile's userdata directory.
1011                                Generally special://masterprofile for the master profile or
1012                                special://masterprofile/profiles/<profile_name> for other profiles.
1013
1014    NOTE: All these root directories are lowercase. Some of the sub-directories
1015          might be mixed case.
1016 */
1017
1018 #if defined(TARGET_POSIX) && !defined(TARGET_DARWIN)
1019   CStdString userName;
1020   if (getenv("USER"))
1021     userName = getenv("USER");
1022   else
1023     userName = "root";
1024
1025   CStdString userHome;
1026   if (getenv("HOME"))
1027     userHome = getenv("HOME");
1028   else
1029     userHome = "/root";
1030
1031   CStdString xbmcBinPath, xbmcPath;
1032   CUtil::GetHomePath(xbmcBinPath, "XBMC_BIN_HOME");
1033   xbmcPath = getenv("XBMC_HOME");
1034
1035   if (xbmcPath.IsEmpty())
1036   {
1037     xbmcPath = xbmcBinPath;
1038     /* Check if xbmc binaries and arch independent data files are being kept in
1039      * separate locations. */
1040     if (!CFile::Exists(URIUtils::AddFileToFolder(xbmcPath, "language")))
1041     {
1042       /* Attempt to locate arch independent data files. */
1043       CUtil::GetHomePath(xbmcPath);
1044       if (!CFile::Exists(URIUtils::AddFileToFolder(xbmcPath, "language")))
1045       {
1046         fprintf(stderr, "Unable to find path to XBMC data files!\n");
1047         exit(1);
1048       }
1049     }
1050   }
1051
1052   /* Set some environment variables */
1053   setenv("XBMC_BIN_HOME", xbmcBinPath.c_str(), 0);
1054   setenv("XBMC_HOME", xbmcPath.c_str(), 0);
1055
1056   if (m_bPlatformDirectories)
1057   {
1058     // map our special drives
1059     CSpecialProtocol::SetXBMCBinPath(xbmcBinPath);
1060     CSpecialProtocol::SetXBMCPath(xbmcPath);
1061     CSpecialProtocol::SetHomePath(userHome + "/.xbmc");
1062     CSpecialProtocol::SetMasterProfilePath(userHome + "/.xbmc/userdata");
1063
1064     CStdString strTempPath = userHome;
1065     strTempPath = URIUtils::AddFileToFolder(strTempPath, ".xbmc/temp");
1066     if (getenv("XBMC_TEMP"))
1067       strTempPath = getenv("XBMC_TEMP");
1068     CSpecialProtocol::SetTempPath(strTempPath);
1069
1070     URIUtils::AddSlashAtEnd(strTempPath);
1071     g_advancedSettings.m_logFolder = strTempPath;
1072
1073     CreateUserDirs();
1074
1075   }
1076   else
1077   {
1078     URIUtils::AddSlashAtEnd(xbmcPath);
1079     g_advancedSettings.m_logFolder = xbmcPath;
1080
1081     CSpecialProtocol::SetXBMCBinPath(xbmcBinPath);
1082     CSpecialProtocol::SetXBMCPath(xbmcPath);
1083     CSpecialProtocol::SetHomePath(URIUtils::AddFileToFolder(xbmcPath, "portable_data"));
1084     CSpecialProtocol::SetMasterProfilePath(URIUtils::AddFileToFolder(xbmcPath, "portable_data/userdata"));
1085
1086     CStdString strTempPath = xbmcPath;
1087     strTempPath = URIUtils::AddFileToFolder(strTempPath, "portable_data/temp");
1088     if (getenv("XBMC_TEMP"))
1089       strTempPath = getenv("XBMC_TEMP");
1090     CSpecialProtocol::SetTempPath(strTempPath);
1091     CreateUserDirs();
1092
1093     URIUtils::AddSlashAtEnd(strTempPath);
1094     g_advancedSettings.m_logFolder = strTempPath;
1095   }
1096
1097   return true;
1098 #else
1099   return false;
1100 #endif
1101 }
1102
1103 bool CApplication::InitDirectoriesOSX()
1104 {
1105 #if defined(TARGET_DARWIN)
1106   CStdString userName;
1107   if (getenv("USER"))
1108     userName = getenv("USER");
1109   else
1110     userName = "root";
1111
1112   CStdString userHome;
1113   if (getenv("HOME"))
1114     userHome = getenv("HOME");
1115   else
1116     userHome = "/root";
1117
1118   CStdString xbmcPath;
1119   CUtil::GetHomePath(xbmcPath);
1120   setenv("XBMC_HOME", xbmcPath.c_str(), 0);
1121
1122 #if defined(TARGET_DARWIN_IOS)
1123   CStdString fontconfigPath;
1124   fontconfigPath = xbmcPath + "/system/players/dvdplayer/etc/fonts/fonts.conf";
1125   setenv("FONTCONFIG_FILE", fontconfigPath.c_str(), 0);
1126 #endif
1127
1128   // setup path to our internal dylibs so loader can find them
1129   CStdString frameworksPath = CUtil::GetFrameworksPath();
1130   CSpecialProtocol::SetXBMCFrameworksPath(frameworksPath);
1131
1132   // OSX always runs with m_bPlatformDirectories == true
1133   if (m_bPlatformDirectories)
1134   {
1135     // map our special drives
1136     CSpecialProtocol::SetXBMCBinPath(xbmcPath);
1137     CSpecialProtocol::SetXBMCPath(xbmcPath);
1138     #if defined(TARGET_DARWIN_IOS)
1139       CSpecialProtocol::SetHomePath(userHome + "/Library/Preferences/XBMC");
1140       CSpecialProtocol::SetMasterProfilePath(userHome + "/Library/Preferences/XBMC/userdata");
1141     #else
1142       CSpecialProtocol::SetHomePath(userHome + "/Library/Application Support/XBMC");
1143       CSpecialProtocol::SetMasterProfilePath(userHome + "/Library/Application Support/XBMC/userdata");
1144     #endif
1145
1146     // location for temp files
1147     #if defined(TARGET_DARWIN_IOS)
1148       CStdString strTempPath = URIUtils::AddFileToFolder(userHome,  "Library/Preferences/XBMC/temp");
1149     #else
1150       CStdString strTempPath = URIUtils::AddFileToFolder(userHome, ".xbmc/");
1151       CDirectory::Create(strTempPath);
1152       strTempPath = URIUtils::AddFileToFolder(userHome, ".xbmc/temp");
1153     #endif
1154     CSpecialProtocol::SetTempPath(strTempPath);
1155
1156     // xbmc.log file location
1157     #if defined(TARGET_DARWIN_IOS)
1158       strTempPath = userHome + "/Library/Preferences";
1159     #else
1160       strTempPath = userHome + "/Library/Logs";
1161     #endif
1162     URIUtils::AddSlashAtEnd(strTempPath);
1163     g_advancedSettings.m_logFolder = strTempPath;
1164
1165     CreateUserDirs();
1166   }
1167   else
1168   {
1169     URIUtils::AddSlashAtEnd(xbmcPath);
1170     g_advancedSettings.m_logFolder = xbmcPath;
1171
1172     CSpecialProtocol::SetXBMCBinPath(xbmcPath);
1173     CSpecialProtocol::SetXBMCPath(xbmcPath);
1174     CSpecialProtocol::SetHomePath(URIUtils::AddFileToFolder(xbmcPath, "portable_data"));
1175     CSpecialProtocol::SetMasterProfilePath(URIUtils::AddFileToFolder(xbmcPath, "portable_data/userdata"));
1176
1177     CStdString strTempPath = URIUtils::AddFileToFolder(xbmcPath, "portable_data/temp");
1178     CSpecialProtocol::SetTempPath(strTempPath);
1179
1180     URIUtils::AddSlashAtEnd(strTempPath);
1181     g_advancedSettings.m_logFolder = strTempPath;
1182   }
1183
1184   return true;
1185 #else
1186   return false;
1187 #endif
1188 }
1189
1190 bool CApplication::InitDirectoriesWin32()
1191 {
1192 #ifdef TARGET_WINDOWS
1193   CStdString xbmcPath;
1194
1195   CUtil::GetHomePath(xbmcPath);
1196   CEnvironment::setenv("XBMC_HOME", xbmcPath);
1197   CSpecialProtocol::SetXBMCBinPath(xbmcPath);
1198   CSpecialProtocol::SetXBMCPath(xbmcPath);
1199
1200   CStdString strWin32UserFolder = CWIN32Util::GetProfilePath();
1201
1202   g_advancedSettings.m_logFolder = strWin32UserFolder;
1203   CSpecialProtocol::SetHomePath(strWin32UserFolder);
1204   CSpecialProtocol::SetMasterProfilePath(URIUtils::AddFileToFolder(strWin32UserFolder, "userdata"));
1205   CSpecialProtocol::SetTempPath(URIUtils::AddFileToFolder(strWin32UserFolder,"cache"));
1206
1207   CEnvironment::setenv("XBMC_PROFILE_USERDATA", CSpecialProtocol::TranslatePath("special://masterprofile/"));
1208
1209   CreateUserDirs();
1210
1211   // Expand the DLL search path with our directories
1212   CWIN32Util::ExtendDllPath();
1213
1214   return true;
1215 #else
1216   return false;
1217 #endif
1218 }
1219
1220 void CApplication::CreateUserDirs()
1221 {
1222   CDirectory::Create("special://home/");
1223   CDirectory::Create("special://home/addons");
1224   CDirectory::Create("special://home/addons/packages");
1225   CDirectory::Create("special://home/media");
1226   CDirectory::Create("special://home/sounds");
1227   CDirectory::Create("special://home/system");
1228   CDirectory::Create("special://masterprofile/");
1229   CDirectory::Create("special://temp/");
1230   CDirectory::Create("special://temp/temp"); // temp directory for python and dllGetTempPathA
1231 }
1232
1233 bool CApplication::Initialize()
1234 {
1235 #if defined(HAS_DVD_DRIVE) && !defined(TARGET_WINDOWS) // somehow this throws an "unresolved external symbol" on win32
1236   // turn off cdio logging
1237   cdio_loglevel_default = CDIO_LOG_ERROR;
1238 #endif
1239
1240 #ifdef TARGET_POSIX // TODO: Win32 has no special://home/ mapping by default, so we
1241               //       must create these here. Ideally this should be using special://home/ and
1242               //       be platform agnostic (i.e. unify the InitDirectories*() functions)
1243   if (!m_bPlatformDirectories)
1244 #endif
1245   {
1246     CDirectory::Create("special://xbmc/language");
1247     CDirectory::Create("special://xbmc/addons");
1248     CDirectory::Create("special://xbmc/sounds");
1249   }
1250
1251   // Load curl so curl_global_init gets called before any service threads
1252   // are started. Unloading will have no effect as curl is never fully unloaded.
1253   // To quote man curl_global_init:
1254   //  "This function is not thread safe. You must not call it when any other
1255   //  thread in the program (i.e. a thread sharing the same memory) is running.
1256   //  This doesn't just mean no other thread that is using libcurl. Because
1257   //  curl_global_init() calls functions of other libraries that are similarly
1258   //  thread unsafe, it could conflict with any other thread that
1259   //  uses these other libraries."
1260   g_curlInterface.Load();
1261   g_curlInterface.Unload();
1262
1263   // initialize (and update as needed) our databases
1264   CDatabaseManager::Get().Initialize();
1265
1266   StartServices();
1267
1268   // Init DPMS, before creating the corresponding setting control.
1269   m_dpms = new DPMSSupport();
1270   if (g_windowManager.Initialized())
1271   {
1272     CSettings::Get().GetSetting("powermanagement.displaysoff")->SetRequirementsMet(m_dpms->IsSupported());
1273
1274     g_windowManager.Add(new CGUIWindowHome);
1275     g_windowManager.Add(new CGUIWindowPrograms);
1276     g_windowManager.Add(new CGUIWindowPictures);
1277     g_windowManager.Add(new CGUIWindowFileManager);
1278     g_windowManager.Add(new CGUIWindowSettings);
1279     g_windowManager.Add(new CGUIWindowSystemInfo);
1280 #ifdef HAS_GL
1281     g_windowManager.Add(new CGUIWindowTestPatternGL);
1282 #endif
1283 #ifdef HAS_DX
1284     g_windowManager.Add(new CGUIWindowTestPatternDX);
1285 #endif
1286     g_windowManager.Add(new CGUIWindowSettingsScreenCalibration);
1287     g_windowManager.Add(new CGUIWindowSettingsCategory);
1288     g_windowManager.Add(new CGUIWindowVideoNav);
1289     g_windowManager.Add(new CGUIWindowVideoPlaylist);
1290     g_windowManager.Add(new CGUIWindowLoginScreen);
1291     g_windowManager.Add(new CGUIWindowSettingsProfile);
1292     g_windowManager.Add(new CGUIWindow(WINDOW_SKIN_SETTINGS, "SkinSettings.xml"));
1293     g_windowManager.Add(new CGUIWindowAddonBrowser);
1294     g_windowManager.Add(new CGUIWindowScreensaverDim);
1295     g_windowManager.Add(new CGUIWindowDebugInfo);
1296     g_windowManager.Add(new CGUIWindowPointer);
1297     g_windowManager.Add(new CGUIDialogYesNo);
1298     g_windowManager.Add(new CGUIDialogProgress);
1299     g_windowManager.Add(new CGUIDialogExtendedProgressBar);
1300     g_windowManager.Add(new CGUIDialogKeyboardGeneric);
1301     g_windowManager.Add(new CGUIDialogVolumeBar);
1302     g_windowManager.Add(new CGUIDialogSeekBar);
1303     g_windowManager.Add(new CGUIDialogSubMenu);
1304     g_windowManager.Add(new CGUIDialogContextMenu);
1305     g_windowManager.Add(new CGUIDialogKaiToast);
1306     g_windowManager.Add(new CGUIDialogNumeric);
1307     g_windowManager.Add(new CGUIDialogGamepad);
1308     g_windowManager.Add(new CGUIDialogButtonMenu);
1309     g_windowManager.Add(new CGUIDialogMuteBug);
1310     g_windowManager.Add(new CGUIDialogPlayerControls);
1311 #ifdef HAS_KARAOKE
1312     g_windowManager.Add(new CGUIDialogKaraokeSongSelectorSmall);
1313     g_windowManager.Add(new CGUIDialogKaraokeSongSelectorLarge);
1314 #endif
1315     g_windowManager.Add(new CGUIDialogSlider);
1316     g_windowManager.Add(new CGUIDialogMusicOSD);
1317     g_windowManager.Add(new CGUIDialogVisualisationPresetList);
1318     g_windowManager.Add(new CGUIDialogVideoSettings);
1319     g_windowManager.Add(new CGUIDialogAudioSubtitleSettings);
1320     g_windowManager.Add(new CGUIDialogVideoBookmarks);
1321     // Don't add the filebrowser dialog - it's created and added when it's needed
1322     g_windowManager.Add(new CGUIDialogNetworkSetup);
1323     g_windowManager.Add(new CGUIDialogMediaSource);
1324     g_windowManager.Add(new CGUIDialogProfileSettings);
1325     g_windowManager.Add(new CGUIDialogFavourites);
1326     g_windowManager.Add(new CGUIDialogSongInfo);
1327     g_windowManager.Add(new CGUIDialogSmartPlaylistEditor);
1328     g_windowManager.Add(new CGUIDialogSmartPlaylistRule);
1329     g_windowManager.Add(new CGUIDialogBusy);
1330     g_windowManager.Add(new CGUIDialogPictureInfo);
1331     g_windowManager.Add(new CGUIDialogAddonInfo);
1332     g_windowManager.Add(new CGUIDialogAddonSettings);
1333 #ifdef HAS_LINUX_NETWORK
1334     g_windowManager.Add(new CGUIDialogAccessPoints);
1335 #endif
1336
1337     g_windowManager.Add(new CGUIDialogLockSettings);
1338
1339     g_windowManager.Add(new CGUIDialogContentSettings);
1340
1341     g_windowManager.Add(new CGUIDialogPlayEject);
1342
1343     g_windowManager.Add(new CGUIDialogPeripheralManager);
1344     g_windowManager.Add(new CGUIDialogPeripheralSettings);
1345     
1346     g_windowManager.Add(new CGUIDialogMediaFilter);
1347
1348     g_windowManager.Add(new CGUIWindowMusicPlayList);
1349     g_windowManager.Add(new CGUIWindowMusicSongs);
1350     g_windowManager.Add(new CGUIWindowMusicNav);
1351     g_windowManager.Add(new CGUIWindowMusicPlaylistEditor);
1352
1353     /* Load PVR related Windows and Dialogs */
1354     g_windowManager.Add(new CGUIDialogTeletext);
1355     g_windowManager.Add(new CGUIWindowPVR);
1356     g_windowManager.Add(new CGUIDialogPVRGuideInfo);
1357     g_windowManager.Add(new CGUIDialogPVRRecordingInfo);
1358     g_windowManager.Add(new CGUIDialogPVRTimerSettings);
1359     g_windowManager.Add(new CGUIDialogPVRGroupManager);
1360     g_windowManager.Add(new CGUIDialogPVRChannelManager);
1361     g_windowManager.Add(new CGUIDialogPVRGuideSearch);
1362     g_windowManager.Add(new CGUIDialogPVRChannelsOSD);
1363     g_windowManager.Add(new CGUIDialogPVRGuideOSD);
1364     g_windowManager.Add(new CGUIDialogPVRDirectorOSD);
1365     g_windowManager.Add(new CGUIDialogPVRCutterOSD);
1366
1367     g_windowManager.Add(new CGUIDialogSelect);
1368     g_windowManager.Add(new CGUIDialogMusicInfo);
1369     g_windowManager.Add(new CGUIDialogOK);
1370     g_windowManager.Add(new CGUIDialogVideoInfo);
1371     g_windowManager.Add(new CGUIDialogTextViewer);
1372     g_windowManager.Add(new CGUIWindowFullScreen);
1373     g_windowManager.Add(new CGUIWindowVisualisation);
1374     g_windowManager.Add(new CGUIWindowSlideShow);
1375     g_windowManager.Add(new CGUIDialogFileStacking);
1376 #ifdef HAS_KARAOKE
1377     g_windowManager.Add(new CGUIWindowKaraokeLyrics);
1378 #endif
1379
1380     g_windowManager.Add(new CGUIDialogVideoOSD);
1381     g_windowManager.Add(new CGUIDialogMusicOverlay);
1382     g_windowManager.Add(new CGUIDialogVideoOverlay);
1383     g_windowManager.Add(new CGUIWindowScreensaver);
1384     g_windowManager.Add(new CGUIWindowWeather);
1385     g_windowManager.Add(new CGUIWindowStartup);
1386
1387     /* window id's 3000 - 3100 are reserved for python */
1388
1389     // Make sure we have at least the default skin
1390     string defaultSkin = ((const CSettingString*)CSettings::Get().GetSetting("lookandfeel.skin"))->GetDefault();
1391     if (!LoadSkin(CSettings::Get().GetString("lookandfeel.skin")) && !LoadSkin(defaultSkin))
1392     {
1393       CLog::Log(LOGERROR, "Default skin '%s' not found! Terminating..", defaultSkin.c_str());
1394       return false;
1395     }
1396
1397     if (g_advancedSettings.m_splashImage)
1398       SAFE_DELETE(m_splash);
1399
1400     if (CSettings::Get().GetBool("masterlock.startuplock") &&
1401         CProfilesManager::Get().GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE &&
1402        !CProfilesManager::Get().GetMasterProfile().getLockCode().IsEmpty())
1403     {
1404        g_passwordManager.CheckStartUpLock();
1405     }
1406
1407     // check if we should use the login screen
1408     if (CProfilesManager::Get().UsingLoginScreen())
1409       g_windowManager.ActivateWindow(WINDOW_LOGIN_SCREEN);
1410     else
1411     {
1412 #ifdef HAS_JSONRPC
1413       CJSONRPC::Initialize();
1414 #endif
1415       ADDON::CAddonMgr::Get().StartServices(false);
1416       if (g_SkinInfo->GetFirstWindow() == WINDOW_PVR)
1417       {
1418         g_windowManager.ActivateWindow(WINDOW_HOME);
1419         StartPVRManager(true);
1420       }
1421       else
1422       {
1423         StartPVRManager(false);
1424         g_windowManager.ActivateWindow(g_SkinInfo->GetFirstWindow());
1425       }
1426
1427       CStereoscopicsManager::Get().Initialize();
1428     }
1429
1430   }
1431   else //No GUI Created
1432   {
1433 #ifdef HAS_JSONRPC
1434     CJSONRPC::Initialize();
1435 #endif
1436     ADDON::CAddonMgr::Get().StartServices(false);
1437   }
1438
1439   g_sysinfo.Refresh();
1440
1441   CLog::Log(LOGINFO, "removing tempfiles");
1442   CUtil::RemoveTempFiles();
1443
1444   if (!CProfilesManager::Get().UsingLoginScreen())
1445   {
1446     UpdateLibraries();
1447     SetLoggingIn(true);
1448   }
1449
1450   m_slowTimer.StartZero();
1451
1452 #if defined(HAVE_LIBCRYSTALHD)
1453   CCrystalHD::GetInstance();
1454 #endif
1455
1456   CAddonMgr::Get().StartServices(true);
1457
1458   CLog::Log(LOGNOTICE, "initialize done");
1459
1460   m_bInitializing = false;
1461
1462   // reset our screensaver (starts timers etc.)
1463   ResetScreenSaver();
1464
1465 #ifdef HAS_SDL_JOYSTICK
1466   g_Joystick.SetEnabled(CSettings::Get().GetBool("input.enablejoystick") &&
1467                     CPeripheralImon::GetCountOfImonsConflictWithDInput() == 0 );
1468 #endif
1469
1470   return true;
1471 }
1472
1473 bool CApplication::StartServer(enum ESERVERS eServer, bool bStart, bool bWait/* = false*/)
1474 {
1475   bool ret = false;
1476   switch(eServer)
1477   {
1478     case ES_WEBSERVER:
1479       // the callback will take care of starting/stopping webserver
1480       ret = CSettings::Get().SetBool("services.webserver", bStart);
1481       break;
1482
1483     case ES_AIRPLAYSERVER:
1484       // the callback will take care of starting/stopping airplay
1485       ret = CSettings::Get().SetBool("services.airplay", bStart);
1486       break;
1487
1488     case ES_JSONRPCSERVER:
1489       // the callback will take care of starting/stopping jsonrpc server
1490       ret = CSettings::Get().SetBool("services.esenabled", bStart);
1491       break;
1492
1493     case ES_UPNPSERVER:
1494       // the callback will take care of starting/stopping upnp server
1495       ret = CSettings::Get().SetBool("services.upnpserver", bStart);
1496       break;
1497
1498     case ES_UPNPRENDERER:
1499       // the callback will take care of starting/stopping upnp renderer
1500       ret = CSettings::Get().SetBool("services.upnprenderer", bStart);
1501       break;
1502
1503     case ES_EVENTSERVER:
1504       // the callback will take care of starting/stopping event server
1505       ret = CSettings::Get().SetBool("services.esenabled", bStart);
1506       break;
1507
1508     case ES_ZEROCONF:
1509       // the callback will take care of starting/stopping zeroconf
1510       ret = CSettings::Get().SetBool("services.zeroconf", bStart);
1511       break;
1512
1513     default:
1514       ret = false;
1515       break;
1516   }
1517   CSettings::Get().Save();
1518
1519   return ret;
1520 }
1521
1522 void CApplication::StartPVRManager(bool bOpenPVRWindow /* = false */)
1523 {
1524   if (CSettings::Get().GetBool("pvrmanager.enabled"))
1525     g_PVRManager.Start(true, bOpenPVRWindow);
1526 }
1527
1528 void CApplication::StopPVRManager()
1529 {
1530   CLog::Log(LOGINFO, "stopping PVRManager");
1531   if (g_PVRManager.IsPlaying())
1532     StopPlaying();
1533   g_PVRManager.Stop();
1534   g_EpgContainer.Stop();
1535 }
1536
1537 void CApplication::StartServices()
1538 {
1539 #if !defined(TARGET_WINDOWS) && defined(HAS_DVD_DRIVE)
1540   // Start Thread for DVD Mediatype detection
1541   CLog::Log(LOGNOTICE, "start dvd mediatype detection");
1542   m_DetectDVDType.Create(false, THREAD_MINSTACKSIZE);
1543 #endif
1544
1545   CLog::Log(LOGNOTICE, "initializing playlistplayer");
1546   g_playlistPlayer.SetRepeat(PLAYLIST_MUSIC, CMediaSettings::Get().DoesMusicPlaylistRepeat() ? PLAYLIST::REPEAT_ALL : PLAYLIST::REPEAT_NONE);
1547   g_playlistPlayer.SetShuffle(PLAYLIST_MUSIC, CMediaSettings::Get().IsMusicPlaylistShuffled());
1548   g_playlistPlayer.SetRepeat(PLAYLIST_VIDEO, CMediaSettings::Get().DoesVideoPlaylistRepeat() ? PLAYLIST::REPEAT_ALL : PLAYLIST::REPEAT_NONE);
1549   g_playlistPlayer.SetShuffle(PLAYLIST_VIDEO, CMediaSettings::Get().IsVideoPlaylistShuffled());
1550   CLog::Log(LOGNOTICE, "DONE initializing playlistplayer");
1551 }
1552
1553 void CApplication::StopServices()
1554 {
1555   m_network->NetworkMessage(CNetwork::SERVICES_DOWN, 0);
1556
1557 #if !defined(TARGET_WINDOWS) && defined(HAS_DVD_DRIVE)
1558   CLog::Log(LOGNOTICE, "stop dvd detect media");
1559   m_DetectDVDType.StopThread();
1560 #endif
1561
1562   g_peripherals.Clear();
1563 }
1564
1565 void CApplication::OnSettingChanged(const CSetting *setting)
1566 {
1567   if (setting == NULL)
1568     return;
1569
1570   const std::string &settingId = setting->GetId();
1571   if (settingId == "lookandfeel.skin" ||
1572       settingId == "lookandfeel.font" ||
1573       settingId == "lookandfeel.skincolors")
1574     CApplicationMessenger::Get().ExecBuiltIn("ReloadSkin");
1575   else if (settingId == "lookandfeel.skintheme")
1576   {
1577     // also set the default color theme
1578     string colorTheme = URIUtils::ReplaceExtension(((CSettingString*)setting)->GetValue(), ".xml");
1579     if (StringUtils::EqualsNoCase(colorTheme, "Textures.xml"))
1580       colorTheme = "defaults.xml";
1581
1582     // check if we have to change the skin color
1583     // if yes, it will trigger a call to ReloadSkin() in
1584     // it's OnSettingChanged() callback
1585     // if no we have to call ReloadSkin() ourselves
1586     if (!StringUtils::EqualsNoCase(colorTheme, CSettings::Get().GetString("lookandfeel.skincolors")))
1587       CSettings::Get().SetString("lookandfeel.skincolors", colorTheme);
1588     else
1589       CApplicationMessenger::Get().ExecBuiltIn("ReloadSkin");
1590   }
1591   else if (settingId == "lookandfeel.skinzoom")
1592     g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_WINDOW_RESIZE);
1593   else if (StringUtils::StartsWithNoCase(settingId, "audiooutput."))
1594   {
1595     if (settingId == "audiooutput.guisoundmode")
1596     {
1597       CAEFactory::SetSoundMode(((CSettingInt*)setting)->GetValue());
1598     }
1599     // this tells player whether to open an audio stream passthrough or PCM
1600     // if this is changed, audio stream has to be reopened
1601     else if (settingId == "audiooutput.mode")
1602     {
1603       CApplicationMessenger::Get().MediaRestart(false);
1604       return;
1605     }
1606
1607     CAEFactory::OnSettingsChange(settingId);
1608   }
1609   else if (StringUtils::EqualsNoCase(settingId, "musicplayer.replaygaintype"))
1610     m_replayGainSettings.iType = ((CSettingInt*)setting)->GetValue();
1611   else if (StringUtils::EqualsNoCase(settingId, "musicplayer.replaygainpreamp"))
1612     m_replayGainSettings.iPreAmp = ((CSettingInt*)setting)->GetValue();
1613   else if (StringUtils::EqualsNoCase(settingId, "musicplayer.replaygainnogainpreamp"))
1614     m_replayGainSettings.iNoGainPreAmp = ((CSettingInt*)setting)->GetValue();
1615   else if (StringUtils::EqualsNoCase(settingId, "musicplayer.replaygainavoidclipping"))
1616     m_replayGainSettings.bAvoidClipping = ((CSettingBool*)setting)->GetValue();
1617 }
1618
1619 void CApplication::OnSettingAction(const CSetting *setting)
1620 {
1621   if (setting == NULL)
1622     return;
1623
1624   const std::string &settingId = setting->GetId();
1625   if (settingId == "lookandfeel.skinsettings")
1626     g_windowManager.ActivateWindow(WINDOW_SKIN_SETTINGS);
1627   else if (settingId == "screensaver.preview")
1628     ActivateScreenSaver(true);
1629   else if (settingId == "screensaver.settings")
1630   {
1631     AddonPtr addon;
1632     if (CAddonMgr::Get().GetAddon(CSettings::Get().GetString("screensaver.mode"), addon, ADDON_SCREENSAVER))
1633       CGUIDialogAddonSettings::ShowAndGetInput(addon);
1634   }
1635   else if (settingId == "videoscreen.guicalibration")
1636     g_windowManager.ActivateWindow(WINDOW_SCREEN_CALIBRATION);
1637   else if (settingId == "videoscreen.testpattern")
1638     g_windowManager.ActivateWindow(WINDOW_TEST_PATTERN);
1639 }
1640
1641 bool CApplication::OnSettingUpdate(CSetting* &setting, const char *oldSettingId, const TiXmlNode *oldSettingNode)
1642 {
1643   if (setting == NULL)
1644     return false;
1645
1646   const std::string &settingId = setting->GetId();
1647   if (settingId == "audiooutput.channels")
1648   {
1649     // check if this is an update from Eden
1650     if (oldSettingId != NULL && oldSettingNode != NULL &&
1651         StringUtils::EqualsNoCase(oldSettingId, "audiooutput.channellayout"))
1652     {
1653       bool ret = false;
1654       CSettingInt* channels = (CSettingInt*)setting;
1655       if (channels->FromString(oldSettingNode->FirstChild()->ValueStr()) && channels->GetValue() < AE_CH_LAYOUT_MAX - 1)
1656         ret = channels->SetValue(channels->GetValue() + 1);
1657
1658       // let's just reset the audiodevice settings as well
1659       std::string audiodevice = CSettings::Get().GetString("audiooutput.audiodevice");
1660       CAEFactory::VerifyOutputDevice(audiodevice, false);
1661       ret |= CSettings::Get().SetString("audiooutput.audiodevice", audiodevice.c_str());
1662
1663       return ret;
1664     }
1665   }
1666   else if (settingId == "screensaver.mode")
1667   {
1668     CSettingString *screensaverMode = (CSettingString*)setting;
1669     // we no longer ship the built-in slideshow screensaver, replace it if it's still in use
1670     if (StringUtils::EqualsNoCase(screensaverMode->GetValue(), "screensaver.xbmc.builtin.slideshow"))
1671       return screensaverMode->SetValue("screensaver.xbmc.builtin.dim");
1672   }
1673   else if (settingId == "scrapers.musicvideosdefault")
1674   {
1675     CSettingAddon *musicvideoScraper = (CSettingAddon*)setting;
1676     if (StringUtils::EqualsNoCase(musicvideoScraper->GetValue(), "metadata.musicvideos.last.fm"))
1677     {
1678       musicvideoScraper->Reset();
1679       return true;
1680     }
1681   }
1682
1683   return false;
1684 }
1685
1686 bool CApplication::OnSettingsSaving() const
1687 {
1688   // don't save settings when we're busy stopping the application
1689   // a lot of screens try to save settings on deinit and deinit is
1690   // called for every screen when the application is stopping
1691   if (m_bStop)
1692     return false;
1693
1694   return true;
1695 }
1696
1697 void CApplication::ReloadSkin()
1698 {
1699   m_skinReloading = false;
1700   CGUIMessage msg(GUI_MSG_LOAD_SKIN, -1, g_windowManager.GetActiveWindow());
1701   g_windowManager.SendMessage(msg);
1702   
1703   // Reload the skin, restoring the previously focused control.  We need this as
1704   // the window unload will reset all control states.
1705   int iCtrlID = -1;
1706   CGUIWindow* pWindow = g_windowManager.GetWindow(g_windowManager.GetActiveWindow());
1707   if (pWindow)
1708     iCtrlID = pWindow->GetFocusedControlID();
1709   
1710   g_application.LoadSkin(CSettings::Get().GetString("lookandfeel.skin"));
1711  
1712   if (iCtrlID != -1)
1713   {
1714     pWindow = g_windowManager.GetWindow(g_windowManager.GetActiveWindow());
1715     if (pWindow && pWindow->HasSaveLastControl())
1716     {
1717       CGUIMessage msg3(GUI_MSG_SETFOCUS, g_windowManager.GetActiveWindow(), iCtrlID, 0);
1718       pWindow->OnMessage(msg3);
1719     }
1720   }
1721 }
1722
1723 bool CApplication::Load(const TiXmlNode *settings)
1724 {
1725   if (settings == NULL)
1726     return false;
1727
1728   const TiXmlElement *audioElement = settings->FirstChildElement("audio");
1729   if (audioElement != NULL)
1730   {
1731     XMLUtils::GetBoolean(audioElement, "mute", m_muted);
1732     if (!XMLUtils::GetFloat(audioElement, "fvolumelevel", m_volumeLevel, VOLUME_MINIMUM, VOLUME_MAXIMUM))
1733       m_volumeLevel = VOLUME_MAXIMUM;
1734   }
1735
1736   return true;
1737 }
1738
1739 bool CApplication::Save(TiXmlNode *settings) const
1740 {
1741   if (settings == NULL)
1742     return false;
1743
1744   TiXmlElement volumeNode("audio");
1745   TiXmlNode *audioNode = settings->InsertEndChild(volumeNode);
1746   if (audioNode == NULL)
1747     return false;
1748
1749   XMLUtils::SetBoolean(audioNode, "mute", m_muted);
1750   XMLUtils::SetFloat(audioNode, "fvolumelevel", m_volumeLevel);
1751
1752   return true;
1753 }
1754
1755 bool CApplication::LoadSkin(const CStdString& skinID)
1756 {
1757   if (m_skinReloading)
1758     return false;
1759
1760   AddonPtr addon;
1761   if (CAddonMgr::Get().GetAddon(skinID, addon, ADDON_SKIN))
1762   {
1763     LoadSkin(boost::dynamic_pointer_cast<ADDON::CSkinInfo>(addon));
1764     return true;
1765   }
1766   return false;
1767 }
1768
1769 void CApplication::LoadSkin(const SkinPtr& skin)
1770 {
1771   string defaultSkin = ((const CSettingString*)CSettings::Get().GetSetting("lookandfeel.skin"))->GetDefault();
1772   if (!skin)
1773   {
1774     CLog::Log(LOGERROR, "failed to load requested skin, fallback to \"%s\" skin", defaultSkin.c_str());
1775     CSettings::Get().GetSetting("lookandfeel.skin")->Reset();
1776     return ;
1777   }
1778
1779   skin->Start();
1780   if (!skin->HasSkinFile("Home.xml"))
1781   {
1782     // failed to find home.xml
1783     // fallback to default skin
1784     if (strcmpi(skin->ID().c_str(), defaultSkin.c_str()) != 0)
1785     {
1786       CLog::Log(LOGERROR, "home.xml doesn't exist in skin: %s, fallback to \"%s\" skin", skin->ID().c_str(), defaultSkin.c_str());
1787       CSettings::Get().GetSetting("lookandfeel.skin")->Reset();
1788       CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(24102), g_localizeStrings.Get(24103));
1789       return ;
1790     }
1791   }
1792
1793   bool bPreviousPlayingState=false;
1794   bool bPreviousRenderingState=false;
1795   if (g_application.m_pPlayer->IsPlayingVideo())
1796   {
1797     bPreviousPlayingState = !g_application.m_pPlayer->IsPausedPlayback();
1798     if (bPreviousPlayingState)
1799       g_application.m_pPlayer->Pause();
1800 #ifdef HAS_VIDEO_PLAYBACK
1801     if (g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
1802     {
1803       g_windowManager.ActivateWindow(WINDOW_HOME);
1804       bPreviousRenderingState = true;
1805     }
1806 #endif
1807   }
1808   // close the music and video overlays (they're re-opened automatically later)
1809   CSingleLock lock(g_graphicsContext);
1810
1811   // save the current window details
1812   int currentWindow = g_windowManager.GetActiveWindow();
1813   vector<int> currentModelessWindows;
1814   g_windowManager.GetActiveModelessWindows(currentModelessWindows);
1815
1816   UnloadSkin();
1817
1818   CLog::Log(LOGINFO, "  load skin from: %s (version: %s)", skin->Path().c_str(), skin->Version().c_str());
1819   g_SkinInfo = skin;
1820   g_SkinInfo->Start();
1821
1822   CLog::Log(LOGINFO, "  load fonts for skin...");
1823   g_graphicsContext.SetMediaDir(skin->Path());
1824   g_directoryCache.ClearSubPaths(skin->Path());
1825   if (g_langInfo.ForceUnicodeFont() && !g_fontManager.IsFontSetUnicode(CSettings::Get().GetString("lookandfeel.font")))
1826   {
1827     CLog::Log(LOGINFO, "    language needs a ttf font, loading first ttf font available");
1828     CStdString strFontSet;
1829     if (g_fontManager.GetFirstFontSetUnicode(strFontSet))
1830     {
1831       CLog::Log(LOGINFO, "    new font is '%s'", strFontSet.c_str());
1832       CSettings::Get().SetString("lookandfeel.font", strFontSet);
1833       CSettings::Get().Save();
1834     }
1835     else
1836       CLog::Log(LOGERROR, "    no ttf font found, but needed for the language %s.", CSettings::Get().GetString("locale.language").c_str());
1837   }
1838   g_colorManager.Load(CSettings::Get().GetString("lookandfeel.skincolors"));
1839
1840   g_fontManager.LoadFonts(CSettings::Get().GetString("lookandfeel.font"));
1841
1842   // load in the skin strings
1843   CStdString langPath = URIUtils::AddFileToFolder(skin->Path(), "language");
1844   URIUtils::AddSlashAtEnd(langPath);
1845
1846   g_localizeStrings.LoadSkinStrings(langPath, CSettings::Get().GetString("locale.language"));
1847
1848   g_SkinInfo->LoadIncludes();
1849
1850   int64_t start;
1851   start = CurrentHostCounter();
1852
1853   CLog::Log(LOGINFO, "  load new skin...");
1854
1855   // Load the user windows
1856   LoadUserWindows();
1857
1858   int64_t end, freq;
1859   end = CurrentHostCounter();
1860   freq = CurrentHostFrequency();
1861   CLog::Log(LOGDEBUG,"Load Skin XML: %.2fms", 1000.f * (end - start) / freq);
1862
1863   CLog::Log(LOGINFO, "  initialize new skin...");
1864   g_windowManager.AddMsgTarget(this);
1865   g_windowManager.AddMsgTarget(&g_playlistPlayer);
1866   g_windowManager.AddMsgTarget(&g_infoManager);
1867   g_windowManager.AddMsgTarget(&g_fontManager);
1868   g_windowManager.AddMsgTarget(&CStereoscopicsManager::Get());
1869   g_windowManager.SetCallback(*this);
1870   g_windowManager.Initialize();
1871   CTextureCache::Get().Initialize();
1872   g_audioManager.Enable(true);
1873   g_audioManager.Load();
1874
1875   if (g_SkinInfo->HasSkinFile("DialogFullScreenInfo.xml"))
1876     g_windowManager.Add(new CGUIDialogFullScreenInfo);
1877
1878   { // we can't register visible condition in dialog's ctor because infomanager is cleared when unloading skin
1879     CGUIDialog *overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_OVERLAY);
1880     if (overlay) overlay->SetVisibleCondition("skin.hasvideooverlay");
1881     overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_OVERLAY);
1882     if (overlay) overlay->SetVisibleCondition("skin.hasmusicoverlay");
1883   }
1884
1885   CLog::Log(LOGINFO, "  skin loaded...");
1886
1887   // leave the graphics lock
1888   lock.Leave();
1889
1890   // restore windows
1891   if (currentWindow != WINDOW_INVALID)
1892   {
1893     g_windowManager.ActivateWindow(currentWindow);
1894     for (unsigned int i = 0; i < currentModelessWindows.size(); i++)
1895     {
1896       CGUIDialog *dialog = (CGUIDialog *)g_windowManager.GetWindow(currentModelessWindows[i]);
1897       if (dialog) dialog->Show();
1898     }
1899   }
1900
1901   if (g_application.m_pPlayer->IsPlayingVideo())
1902   {
1903     if (bPreviousPlayingState)
1904       g_application.m_pPlayer->Pause();
1905     if (bPreviousRenderingState)
1906       g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
1907   }
1908 }
1909
1910 void CApplication::UnloadSkin(bool forReload /* = false */)
1911 {
1912   m_skinReloading = forReload;
1913
1914   CLog::Log(LOGINFO, "Unloading old skin %s...", forReload ? "for reload " : "");
1915
1916   g_audioManager.Enable(false);
1917
1918   g_windowManager.DeInitialize();
1919   CTextureCache::Get().Deinitialize();
1920
1921   // remove the skin-dependent window
1922   g_windowManager.Delete(WINDOW_DIALOG_FULLSCREEN_INFO);
1923
1924   g_TextureManager.Cleanup();
1925   g_largeTextureManager.CleanupUnusedImages(true);
1926
1927   g_fontManager.Clear();
1928
1929   g_colorManager.Clear();
1930
1931   g_charsetConverter.reset();
1932
1933   g_infoManager.Clear();
1934
1935 //  The g_SkinInfo boost shared_ptr ought to be reset here
1936 // but there are too many places it's used without checking for NULL
1937 // and as a result a race condition on exit can cause a crash.
1938 }
1939
1940 bool CApplication::LoadUserWindows()
1941 {
1942   // Start from wherever home.xml is
1943   std::vector<CStdString> vecSkinPath;
1944   g_SkinInfo->GetSkinPaths(vecSkinPath);
1945   for (unsigned int i = 0;i < vecSkinPath.size();++i)
1946   {
1947     CLog::Log(LOGINFO, "Loading user windows, path %s", vecSkinPath[i].c_str());
1948     CFileItemList items;
1949     if (CDirectory::GetDirectory(vecSkinPath[i], items, ".xml", DIR_FLAG_NO_FILE_DIRS))
1950     {
1951       for (int i = 0; i < items.Size(); ++i)
1952       {
1953         if (items[i]->m_bIsFolder)
1954           continue;
1955         CStdString skinFile = URIUtils::GetFileName(items[i]->GetPath());
1956         if (skinFile.Left(6).CompareNoCase("custom") == 0)
1957         {
1958           CXBMCTinyXML xmlDoc;
1959           if (!xmlDoc.LoadFile(items[i]->GetPath()))
1960           {
1961             CLog::Log(LOGERROR, "unable to load: %s, Line %d\n%s", items[i]->GetPath().c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
1962             continue;
1963           }
1964
1965           // Root element should be <window>
1966           TiXmlElement* pRootElement = xmlDoc.RootElement();
1967           CStdString strValue = pRootElement->Value();
1968           if (!strValue.Equals("window"))
1969           {
1970             CLog::Log(LOGERROR, "file: %s doesnt contain <window>", skinFile.c_str());
1971             continue;
1972           }
1973
1974           // Read the <type> element to get the window type to create
1975           // If no type is specified, create a CGUIWindow as default
1976           CGUIWindow* pWindow = NULL;
1977           CStdString strType;
1978           if (pRootElement->Attribute("type"))
1979             strType = pRootElement->Attribute("type");
1980           else
1981           {
1982             const TiXmlNode *pType = pRootElement->FirstChild("type");
1983             if (pType && pType->FirstChild())
1984               strType = pType->FirstChild()->Value();
1985           }
1986           int id = WINDOW_INVALID;
1987           if (!pRootElement->Attribute("id", &id))
1988           {
1989             const TiXmlNode *pType = pRootElement->FirstChild("id");
1990             if (pType && pType->FirstChild())
1991               id = atol(pType->FirstChild()->Value());
1992           }
1993           CStdString visibleCondition;
1994           CGUIControlFactory::GetConditionalVisibility(pRootElement, visibleCondition);
1995
1996           if (strType.Equals("dialog"))
1997             pWindow = new CGUIDialog(id + WINDOW_HOME, skinFile);
1998           else if (strType.Equals("submenu"))
1999             pWindow = new CGUIDialogSubMenu(id + WINDOW_HOME, skinFile);
2000           else if (strType.Equals("buttonmenu"))
2001             pWindow = new CGUIDialogButtonMenu(id + WINDOW_HOME, skinFile);
2002           else
2003             pWindow = new CGUIWindow(id + WINDOW_HOME, skinFile);
2004
2005           // Check to make sure the pointer isn't still null
2006           if (pWindow == NULL)
2007           {
2008             CLog::Log(LOGERROR, "Out of memory / Failed to create new object in LoadUserWindows");
2009             return false;
2010           }
2011           if (id == WINDOW_INVALID || g_windowManager.GetWindow(WINDOW_HOME + id))
2012           {
2013             delete pWindow;
2014             continue;
2015           }
2016           pWindow->SetVisibleCondition(visibleCondition);
2017           pWindow->SetLoadType(CGUIWindow::KEEP_IN_MEMORY);
2018           g_windowManager.AddCustomWindow(pWindow);
2019         }
2020       }
2021     }
2022   }
2023   return true;
2024 }
2025
2026 bool CApplication::RenderNoPresent()
2027 {
2028   MEASURE_FUNCTION;
2029
2030 // DXMERGE: This may have been important?
2031 //  g_graphicsContext.AcquireCurrentContext();
2032
2033   g_graphicsContext.Lock();
2034
2035   // dont show GUI when playing full screen video
2036   if (g_graphicsContext.IsFullScreenVideo())
2037   {
2038     g_renderManager.Render(true, 0, 255);
2039
2040     // close window overlays
2041     CGUIDialog *overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_OVERLAY);
2042     if (overlay) overlay->Close(true);
2043     overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_OVERLAY);
2044     if (overlay) overlay->Close(true);
2045
2046   }
2047
2048   bool hasRendered = g_windowManager.Render();
2049
2050   g_graphicsContext.Unlock();
2051
2052   return hasRendered;
2053 }
2054
2055 float CApplication::GetDimScreenSaverLevel() const
2056 {
2057   if (!m_bScreenSave || !m_screenSaver ||
2058       (m_screenSaver->ID() != "screensaver.xbmc.builtin.dim" &&
2059        m_screenSaver->ID() != "screensaver.xbmc.builtin.black" &&
2060        !m_screenSaver->ID().empty()))
2061     return 0;
2062
2063   if (!m_screenSaver->GetSetting("level").IsEmpty())
2064     return 100.0f - (float)atof(m_screenSaver->GetSetting("level"));
2065   return 100.0f;
2066 }
2067
2068 void CApplication::Render()
2069 {
2070   // do not render if we are stopped or in background
2071   if (m_bStop || m_bInBackground)
2072     return;
2073
2074   MEASURE_FUNCTION;
2075
2076   int vsync_mode = CSettings::Get().GetInt("videoscreen.vsync");
2077
2078   bool hasRendered = false;
2079   bool limitFrames = false;
2080   unsigned int singleFrameTime = 10; // default limit 100 fps
2081
2082   {
2083     // Less fps in DPMS
2084     bool lowfps = m_dpmsIsActive || g_Windowing.EnableFrameLimiter();
2085     // Whether externalplayer is playing and we're unfocused
2086     bool extPlayerActive = m_pPlayer->GetCurrentPlayer() == EPC_EXTPLAYER && m_pPlayer->IsPlaying() && !m_AppFocused;
2087
2088     m_bPresentFrame = false;
2089     if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback() && g_renderManager.RendererHandlesPresent())
2090     {
2091       m_bPresentFrame = g_renderManager.FrameWait(100);
2092       hasRendered = true;
2093     }
2094     else
2095     {
2096       // engage the frame limiter as needed
2097       limitFrames = lowfps || extPlayerActive;
2098       // DXMERGE - we checked for g_videoConfig.GetVSyncMode() before this
2099       //           perhaps allowing it to be set differently than the UI option??
2100       if (vsync_mode == VSYNC_DISABLED || vsync_mode == VSYNC_VIDEO)
2101         limitFrames = true; // not using vsync.
2102       else if ((g_infoManager.GetFPS() > g_graphicsContext.GetFPS() + 10) && g_infoManager.GetFPS() > 1000 / singleFrameTime)
2103         limitFrames = true; // using vsync, but it isn't working.
2104
2105       if (limitFrames)
2106       {
2107         if (extPlayerActive)
2108         {
2109           ResetScreenSaver();  // Prevent screensaver dimming the screen
2110           singleFrameTime = 1000;  // 1 fps, high wakeup latency but v.low CPU usage
2111         }
2112         else if (lowfps)
2113           singleFrameTime = 200;  // 5 fps, <=200 ms latency to wake up
2114       }
2115
2116     }
2117   }
2118
2119   CSingleLock lock(g_graphicsContext);
2120   g_infoManager.UpdateFPS();
2121
2122   if (g_graphicsContext.IsFullScreenVideo() && m_pPlayer->IsPlaying() && vsync_mode == VSYNC_VIDEO)
2123     g_Windowing.SetVSync(true);
2124   else if (vsync_mode == VSYNC_ALWAYS)
2125     g_Windowing.SetVSync(true);
2126   else if (vsync_mode != VSYNC_DRIVER)
2127     g_Windowing.SetVSync(false);
2128
2129   if (m_bPresentFrame && m_pPlayer->IsPlaying() && !m_pPlayer->IsPaused())
2130     ResetScreenSaver();
2131
2132   if(!g_Windowing.BeginRender())
2133     return;
2134
2135   g_renderManager.FrameMove();
2136
2137   CDirtyRegionList dirtyRegions = g_windowManager.GetDirty();
2138   if(g_graphicsContext.GetStereoMode())
2139   {
2140     g_graphicsContext.SetStereoView(RENDER_STEREO_VIEW_LEFT);
2141     if(RenderNoPresent())
2142       hasRendered = true;
2143
2144     if(g_graphicsContext.GetStereoMode() != RENDER_STEREO_MODE_MONO)
2145     {
2146       g_graphicsContext.SetStereoView(RENDER_STEREO_VIEW_RIGHT);
2147       if(RenderNoPresent())
2148         hasRendered = true;
2149     }
2150     g_graphicsContext.SetStereoView(RENDER_STEREO_VIEW_OFF);
2151   }
2152   else
2153   {
2154     if(RenderNoPresent())
2155       hasRendered = true;
2156   }
2157
2158   g_renderManager.FrameFinish();
2159
2160   g_Windowing.EndRender();
2161
2162   // execute post rendering actions (finalize window closing)
2163   g_windowManager.AfterRender();
2164
2165   // reset our info cache - we do this at the end of Render so that it is
2166   // fresh for the next process(), or after a windowclose animation (where process()
2167   // isn't called)
2168   g_infoManager.ResetCache();
2169   lock.Leave();
2170
2171   unsigned int now = XbmcThreads::SystemClockMillis();
2172   if (hasRendered)
2173     m_lastRenderTime = now;
2174
2175   //when nothing has been rendered for m_guiDirtyRegionNoFlipTimeout milliseconds,
2176   //we don't call g_graphicsContext.Flip() anymore, this saves gpu and cpu usage
2177   bool flip;
2178   if (g_advancedSettings.m_guiDirtyRegionNoFlipTimeout >= 0)
2179     flip = hasRendered || (now - m_lastRenderTime) < (unsigned int)g_advancedSettings.m_guiDirtyRegionNoFlipTimeout;
2180   else
2181     flip = true;
2182
2183   //fps limiter, make sure each frame lasts at least singleFrameTime milliseconds
2184   if (limitFrames || !flip)
2185   {
2186     if (!limitFrames)
2187       singleFrameTime = 40; //if not flipping, loop at 25 fps
2188
2189     unsigned int frameTime = now - m_lastFrameTime;
2190     if (frameTime < singleFrameTime)
2191       Sleep(singleFrameTime - frameTime);
2192   }
2193   m_lastFrameTime = XbmcThreads::SystemClockMillis();
2194
2195   if (flip)
2196     g_graphicsContext.Flip(dirtyRegions);
2197   CTimeUtils::UpdateFrameTime(flip);
2198
2199   g_renderManager.UpdateResolution();
2200   g_renderManager.ManageCaptures();
2201 }
2202
2203 void CApplication::SetStandAlone(bool value)
2204 {
2205   g_advancedSettings.m_handleMounting = m_bStandalone = value;
2206 }
2207
2208 // OnKey() translates the key into a CAction which is sent on to our Window Manager.
2209 // The window manager will return true if the event is processed, false otherwise.
2210 // If not already processed, this routine handles global keypresses.  It returns
2211 // true if the key has been processed, false otherwise.
2212
2213 bool CApplication::OnKey(const CKey& key)
2214 {
2215
2216   // Turn the mouse off, as we've just got a keypress from controller or remote
2217   g_Mouse.SetActive(false);
2218
2219   // get the current active window
2220   int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
2221
2222   // this will be checked for certain keycodes that need
2223   // special handling if the screensaver is active
2224   CAction action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2225
2226   // a key has been pressed.
2227   // reset Idle Timer
2228   m_idleTimer.StartZero();
2229   bool processKey = AlwaysProcess(action);
2230
2231   if (StringUtils::StartsWithNoCase(action.GetName(),"CECToggleState") || StringUtils::StartsWithNoCase(action.GetName(),"CECStandby"))
2232   {
2233     bool ret = true;
2234
2235     CLog::Log(LOGDEBUG, "%s: action %s [%d], toggling state of playing device", __FUNCTION__, action.GetName().c_str(), action.GetID());
2236     // do not wake up the screensaver right after switching off the playing device
2237     if (StringUtils::StartsWithNoCase(action.GetName(),"CECToggleState"))
2238       ret = CApplicationMessenger::Get().CECToggleState();
2239     else
2240       ret = CApplicationMessenger::Get().CECStandby();
2241     if (!ret) /* display is switched off */
2242       return true;
2243   }
2244
2245   ResetScreenSaver();
2246
2247   // allow some keys to be processed while the screensaver is active
2248   if (WakeUpScreenSaverAndDPMS(processKey) && !processKey)
2249   {
2250     CLog::Log(LOGDEBUG, "%s: %s pressed, screen saver/dpms woken up", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str());
2251     return true;
2252   }
2253
2254   // change this if we have a dialog up
2255   if (g_windowManager.HasModalDialog())
2256   {
2257     iWin = g_windowManager.GetTopMostModalDialogID() & WINDOW_ID_MASK;
2258   }
2259   if (iWin == WINDOW_DIALOG_FULLSCREEN_INFO)
2260   { // fullscreen info dialog - special case
2261     action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2262
2263     if (!key.IsAnalogButton())
2264       CLog::Log(LOGDEBUG, "%s: %s pressed, trying fullscreen info action %s", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str(), action.GetName().c_str());
2265
2266     if (OnAction(action))
2267       return true;
2268
2269     // fallthrough to the main window
2270     iWin = WINDOW_FULLSCREEN_VIDEO;
2271   }
2272   if (iWin == WINDOW_FULLSCREEN_VIDEO)
2273   {
2274     // current active window is full screen video.
2275     if (g_application.m_pPlayer->IsInMenu())
2276     {
2277       // if player is in some sort of menu, (ie DVDMENU) map buttons differently
2278       action = CButtonTranslator::GetInstance().GetAction(WINDOW_VIDEO_MENU, key);
2279     }
2280     else if (g_PVRManager.IsStarted() && g_application.CurrentFileItem().HasPVRChannelInfoTag())
2281     {
2282       // check for PVR specific keymaps in FULLSCREEN_VIDEO window
2283       action = CButtonTranslator::GetInstance().GetAction(WINDOW_FULLSCREEN_LIVETV, key, false);
2284
2285       // if no PVR specific action/mapping is found, fall back to default
2286       if (action.GetID() == 0)
2287         action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2288     }
2289     else
2290     {
2291       // in any other case use the fullscreen window section of keymap.xml to map key->action
2292       action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2293     }
2294   }
2295   else
2296   {
2297     // current active window isnt the fullscreen window
2298     // just use corresponding section from keymap.xml
2299     // to map key->action
2300
2301     // first determine if we should use keyboard input directly
2302     bool useKeyboard = key.FromKeyboard() && (iWin == WINDOW_DIALOG_KEYBOARD || iWin == WINDOW_DIALOG_NUMERIC);
2303     CGUIWindow *window = g_windowManager.GetWindow(iWin);
2304     if (window)
2305     {
2306       CGUIControl *control = window->GetFocusedControl();
2307       if (control)
2308       {
2309         // If this is an edit control set usekeyboard to true. This causes the
2310         // keypress to be processed directly not through the key mappings.
2311         if (control->GetControlType() == CGUIControl::GUICONTROL_EDIT)
2312           useKeyboard = true;
2313
2314         // If the key pressed is shift-A to shift-Z set usekeyboard to true.
2315         // This causes the keypress to be used for list navigation.
2316         if (control->IsContainer() && key.GetModifiers() == CKey::MODIFIER_SHIFT && key.GetVKey() >= XBMCVK_A && key.GetVKey() <= XBMCVK_Z)
2317           useKeyboard = true;
2318       }
2319     }
2320     if (useKeyboard)
2321     {
2322       action = CAction(0); // reset our action
2323       if (CSettings::Get().GetBool("input.remoteaskeyboard"))
2324       {
2325         // users remote is executing keyboard commands, so use the virtualkeyboard section of keymap.xml
2326         // and send those rather than actual keyboard presses.  Only for navigation-type commands though
2327         action = CButtonTranslator::GetInstance().GetAction(WINDOW_DIALOG_KEYBOARD, key);
2328         if (!(action.GetID() == ACTION_MOVE_LEFT ||
2329               action.GetID() == ACTION_MOVE_RIGHT ||
2330               action.GetID() == ACTION_MOVE_UP ||
2331               action.GetID() == ACTION_MOVE_DOWN ||
2332               action.GetID() == ACTION_SELECT_ITEM ||
2333               action.GetID() == ACTION_ENTER ||
2334               action.GetID() == ACTION_PREVIOUS_MENU ||
2335               action.GetID() == ACTION_NAV_BACK))
2336         {
2337           // the action isn't plain navigation - check for a keyboard-specific keymap
2338           action = CButtonTranslator::GetInstance().GetAction(WINDOW_DIALOG_KEYBOARD, key, false);
2339           if (!(action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9) ||
2340                 action.GetID() == ACTION_BACKSPACE ||
2341                 action.GetID() == ACTION_SHIFT ||
2342                 action.GetID() == ACTION_SYMBOLS ||
2343                 action.GetID() == ACTION_CURSOR_LEFT ||
2344                 action.GetID() == ACTION_CURSOR_RIGHT)
2345             action = CAction(0); // don't bother with this action
2346         }
2347       }
2348       if (!action.GetID())
2349       {
2350         // keyboard entry - pass the keys through directly
2351         if (key.GetFromService())
2352           action = CAction(key.GetButtonCode() != KEY_INVALID ? key.GetButtonCode() : 0, key.GetUnicode());
2353         else
2354         {
2355           // Check for paste keypress
2356 #ifdef TARGET_WINDOWS
2357           // In Windows paste is ctrl-V
2358           if (key.GetVKey() == XBMCVK_V && key.GetModifiers() == CKey::MODIFIER_CTRL)
2359 #elif defined(TARGET_LINUX)
2360           // In Linux paste is ctrl-V
2361           if (key.GetVKey() == XBMCVK_V && key.GetModifiers() == CKey::MODIFIER_CTRL)
2362 #elif defined(TARGET_DARWIN_OSX)
2363           // In OSX paste is cmd-V
2364           if (key.GetVKey() == XBMCVK_V && key.GetModifiers() == CKey::MODIFIER_META)
2365 #else
2366           // Placeholder for other operating systems
2367           if (false)
2368 #endif
2369             action = CAction(ACTION_PASTE);
2370           // If the unicode is non-zero the keypress is a non-printing character
2371           else if (key.GetUnicode())
2372             action = CAction(key.GetAscii() | KEY_ASCII, key.GetUnicode());
2373           // The keypress is a non-printing character
2374           else
2375             action = CAction(key.GetVKey() | KEY_VKEY);
2376         }
2377       }
2378
2379       CLog::Log(LOGDEBUG, "%s: %s pressed, trying keyboard action %x", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str(), action.GetID());
2380
2381       if (OnAction(action))
2382         return true;
2383       // failed to handle the keyboard action, drop down through to standard action
2384     }
2385     if (key.GetFromService())
2386     {
2387       if (key.GetButtonCode() != KEY_INVALID)
2388         action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2389     }
2390     else
2391       action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2392   }
2393   if (!key.IsAnalogButton())
2394     CLog::Log(LOGDEBUG, "%s: %s pressed, action is %s", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str(), action.GetName().c_str());
2395
2396   return ExecuteInputAction(action);
2397 }
2398
2399 // OnAppCommand is called in response to a XBMC_APPCOMMAND event.
2400 // This needs to return true if it processed the appcommand or false if it didn't
2401 bool CApplication::OnAppCommand(const CAction &action)
2402 {
2403   // Reset the screen saver
2404   ResetScreenSaver();
2405
2406   // If we were currently in the screen saver wake up and don't process the appcommand
2407   if (WakeUpScreenSaverAndDPMS())
2408     return true;
2409
2410   // The action ID is the APPCOMMAND code. We need to retrieve the action
2411   // associated with this appcommand from the mapping table.
2412   uint32_t appcmd = action.GetID();
2413   CKey key(appcmd | KEY_APPCOMMAND, (unsigned int) 0);
2414   int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
2415   CAction appcmdaction = CButtonTranslator::GetInstance().GetAction(iWin, key);
2416
2417   // If we couldn't find an action return false to indicate we have not
2418   // handled this appcommand
2419   if (!appcmdaction.GetID())
2420   {
2421     CLog::Log(LOGDEBUG, "%s: unknown appcommand %d", __FUNCTION__, appcmd);
2422     return false;
2423   }
2424
2425   // Process the appcommand
2426   CLog::Log(LOGDEBUG, "%s: appcommand %d, trying action %s", __FUNCTION__, appcmd, appcmdaction.GetName().c_str());
2427   OnAction(appcmdaction);
2428
2429   // Always return true regardless of whether the action succeeded or not.
2430   // This stops Windows handling the appcommand itself.
2431   return true;
2432 }
2433
2434 bool CApplication::OnAction(const CAction &action)
2435 {
2436   // special case for switching between GUI & fullscreen mode.
2437   if (action.GetID() == ACTION_SHOW_GUI)
2438   { // Switch to fullscreen mode if we can
2439     if (SwitchToFullScreen())
2440     {
2441       m_navigationTimer.StartZero();
2442       return true;
2443     }
2444   }
2445
2446   if (action.GetID() == ACTION_TOGGLE_FULLSCREEN)
2447   {
2448     g_graphicsContext.ToggleFullScreenRoot();
2449     return true;
2450   }
2451
2452   if (action.IsMouse())
2453     g_Mouse.SetActive(true);
2454
2455   
2456   if (action.GetID() == ACTION_CREATE_EPISODE_BOOKMARK)   
2457   {
2458     CGUIDialogVideoBookmarks::OnAddEpisodeBookmark();
2459   }
2460   if (action.GetID() == ACTION_CREATE_BOOKMARK)
2461   {
2462     CGUIDialogVideoBookmarks::OnAddBookmark();
2463   }
2464   
2465   // The action PLAYPAUSE behaves as ACTION_PAUSE if we are currently
2466   // playing or ACTION_PLAYER_PLAY if we are not playing.
2467   if (action.GetID() == ACTION_PLAYER_PLAYPAUSE)
2468   {
2469     if (m_pPlayer->IsPlaying())
2470       return OnAction(CAction(ACTION_PAUSE));
2471     else
2472       return OnAction(CAction(ACTION_PLAYER_PLAY));
2473   }
2474
2475   //if the action would start or stop inertial scrolling
2476   //by gesture - bypass the normal OnAction handler of current window
2477   if( !m_pInertialScrollingHandler->CheckForInertialScrolling(&action) )
2478   {
2479     // in normal case
2480     // just pass the action to the current window and let it handle it
2481     if (g_windowManager.OnAction(action))
2482     {
2483       m_navigationTimer.StartZero();
2484       return true;
2485     }
2486   }
2487
2488   // handle extra global presses
2489
2490   // screenshot : take a screenshot :)
2491   if (action.GetID() == ACTION_TAKE_SCREENSHOT)
2492   {
2493     CScreenShot::TakeScreenshot();
2494     return true;
2495   }
2496   // built in functions : execute the built-in
2497   if (action.GetID() == ACTION_BUILT_IN_FUNCTION)
2498   {
2499     CBuiltins::Execute(action.GetName());
2500     m_navigationTimer.StartZero();
2501     return true;
2502   }
2503
2504   // reload keymaps
2505   if (action.GetID() == ACTION_RELOAD_KEYMAPS)
2506   {
2507     CButtonTranslator::GetInstance().Clear();
2508     CButtonTranslator::GetInstance().Load();
2509   }
2510
2511   // show info : Shows the current video or song information
2512   if (action.GetID() == ACTION_SHOW_INFO)
2513   {
2514     g_infoManager.ToggleShowInfo();
2515     return true;
2516   }
2517
2518   // codec info : Shows the current song, video or picture codec information
2519   if (action.GetID() == ACTION_SHOW_CODEC)
2520   {
2521     g_infoManager.ToggleShowCodec();
2522     return true;
2523   }
2524
2525   if ((action.GetID() == ACTION_INCREASE_RATING || action.GetID() == ACTION_DECREASE_RATING) && m_pPlayer->IsPlayingAudio())
2526   {
2527     const CMusicInfoTag *tag = g_infoManager.GetCurrentSongTag();
2528     if (tag)
2529     {
2530       *m_itemCurrentFile->GetMusicInfoTag() = *tag;
2531       char rating = tag->GetRating();
2532       bool needsUpdate(false);
2533       if (rating > '0' && action.GetID() == ACTION_DECREASE_RATING)
2534       {
2535         m_itemCurrentFile->GetMusicInfoTag()->SetRating(rating - 1);
2536         needsUpdate = true;
2537       }
2538       else if (rating < '5' && action.GetID() == ACTION_INCREASE_RATING)
2539       {
2540         m_itemCurrentFile->GetMusicInfoTag()->SetRating(rating + 1);
2541         needsUpdate = true;
2542       }
2543       if (needsUpdate)
2544       {
2545         CMusicDatabase db;
2546         if (db.Open())      // OpenForWrite() ?
2547         {
2548           db.SetSongRating(m_itemCurrentFile->GetPath(), m_itemCurrentFile->GetMusicInfoTag()->GetRating());
2549           db.Close();
2550         }
2551         // send a message to all windows to tell them to update the fileitem (eg playlistplayer, media windows)
2552         CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_ITEM, 0, m_itemCurrentFile);
2553         g_windowManager.SendMessage(msg);
2554       }
2555     }
2556     return true;
2557   }
2558
2559   // Now check with the playlist player if action can be handled.
2560   // In case of the action PREV_ITEM, we only allow the playlist player to take it if we're less than 3 seconds into playback.
2561   if (!(action.GetID() == ACTION_PREV_ITEM && m_pPlayer->CanSeek() && GetTime() > 3) )
2562   {
2563     if (g_playlistPlayer.OnAction(action))
2564       return true;
2565   }
2566
2567   // Now check with the player if action can be handled.
2568   if (g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO ||
2569       (g_windowManager.GetActiveWindow() == WINDOW_DIALOG_VIDEO_OSD && (action.GetID() == ACTION_NEXT_ITEM || action.GetID() == ACTION_PREV_ITEM || action.GetID() == ACTION_CHANNEL_UP || action.GetID() == ACTION_CHANNEL_DOWN)))
2570   {
2571     if (m_pPlayer->OnAction(action))
2572       return true;
2573   }
2574
2575   // stop : stops playing current audio song
2576   if (action.GetID() == ACTION_STOP)
2577   {
2578     StopPlaying();
2579     return true;
2580   }
2581
2582   // In case the playlist player nor the player didn't handle PREV_ITEM, because we are past the 3 secs limit.
2583   // If so, we just jump to the start of the track.
2584   if (action.GetID() == ACTION_PREV_ITEM && m_pPlayer->CanSeek())
2585   {
2586     SeekTime(0);
2587     m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
2588     return true;
2589   }
2590
2591   // forward action to g_PVRManager and break if it was able to handle it
2592   if (g_PVRManager.OnAction(action))
2593     return true;
2594
2595   // forward action to graphic context and see if it can handle it
2596   if (CStereoscopicsManager::Get().OnAction(action))
2597     return true;
2598
2599   if (m_pPlayer->IsPlaying())
2600   {
2601     // forward channel switches to the player - he knows what to do
2602     if (action.GetID() == ACTION_CHANNEL_UP || action.GetID() == ACTION_CHANNEL_DOWN)
2603     {
2604       m_pPlayer->OnAction(action);
2605       return true;
2606     }
2607
2608     // pause : pauses current audio song
2609     if (action.GetID() == ACTION_PAUSE && m_pPlayer->GetPlaySpeed() == 1)
2610     {
2611       m_pPlayer->Pause();
2612 #ifdef HAS_KARAOKE
2613       m_pKaraokeMgr->SetPaused( m_pPlayer->IsPaused() );
2614 #endif
2615       if (!m_pPlayer->IsPaused())
2616       { // unpaused - set the playspeed back to normal
2617         m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
2618       }
2619       g_audioManager.Enable(m_pPlayer->IsPaused());
2620       return true;
2621     }
2622     if (!m_pPlayer->IsPaused())
2623     {
2624       // if we do a FF/RW in my music then map PLAY action togo back to normal speed
2625       // if we are playing at normal speed, then allow play to pause
2626       if (action.GetID() == ACTION_PLAYER_PLAY || action.GetID() == ACTION_PAUSE)
2627       {
2628         if (m_pPlayer->GetPlaySpeed() != 1)
2629         {
2630           m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
2631         }
2632         else
2633         {
2634           m_pPlayer->Pause();
2635         }
2636         return true;
2637       }
2638       if (action.GetID() == ACTION_PLAYER_FORWARD || action.GetID() == ACTION_PLAYER_REWIND)
2639       {
2640         int iPlaySpeed = m_pPlayer->GetPlaySpeed();
2641         if (action.GetID() == ACTION_PLAYER_REWIND && iPlaySpeed == 1) // Enables Rewinding
2642           iPlaySpeed *= -2;
2643         else if (action.GetID() == ACTION_PLAYER_REWIND && iPlaySpeed > 1) //goes down a notch if you're FFing
2644           iPlaySpeed /= 2;
2645         else if (action.GetID() == ACTION_PLAYER_FORWARD && iPlaySpeed < 1) //goes up a notch if you're RWing
2646           iPlaySpeed /= 2;
2647         else
2648           iPlaySpeed *= 2;
2649
2650         if (action.GetID() == ACTION_PLAYER_FORWARD && iPlaySpeed == -1) //sets iSpeed back to 1 if -1 (didn't plan for a -1)
2651           iPlaySpeed = 1;
2652         if (iPlaySpeed > 32 || iPlaySpeed < -32)
2653           iPlaySpeed = 1;
2654
2655         m_pPlayer->SetPlaySpeed(iPlaySpeed, g_application.m_muted);
2656         return true;
2657       }
2658       else if ((action.GetAmount() || m_pPlayer->GetPlaySpeed() != 1) && (action.GetID() == ACTION_ANALOG_REWIND || action.GetID() == ACTION_ANALOG_FORWARD))
2659       {
2660         // calculate the speed based on the amount the button is held down
2661         int iPower = (int)(action.GetAmount() * MAX_FFWD_SPEED + 0.5f);
2662         // returns 0 -> MAX_FFWD_SPEED
2663         int iSpeed = 1 << iPower;
2664         if (iSpeed != 1 && action.GetID() == ACTION_ANALOG_REWIND)
2665           iSpeed = -iSpeed;
2666         g_application.m_pPlayer->SetPlaySpeed(iSpeed, g_application.m_muted);
2667         if (iSpeed == 1)
2668           CLog::Log(LOGDEBUG,"Resetting playspeed");
2669         return true;
2670       }
2671     }
2672     // allow play to unpause
2673     else
2674     {
2675       if (action.GetID() == ACTION_PLAYER_PLAY)
2676       {
2677         // unpause, and set the playspeed back to normal
2678         m_pPlayer->Pause();
2679         g_audioManager.Enable(m_pPlayer->IsPaused());
2680
2681         g_application.m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
2682         return true;
2683       }
2684     }
2685
2686     if (m_playerController->OnAction(action))
2687       return true;
2688   }
2689
2690
2691   if (action.GetID() == ACTION_SWITCH_PLAYER)
2692   {
2693     if(m_pPlayer->IsPlaying())
2694     {
2695       VECPLAYERCORES cores;
2696       CFileItem item(*m_itemCurrentFile.get());
2697       CPlayerCoreFactory::Get().GetPlayers(item, cores);
2698       PLAYERCOREID core = CPlayerCoreFactory::Get().SelectPlayerDialog(cores);
2699       if(core != EPC_NONE)
2700       {
2701         g_application.m_eForcedNextPlayer = core;
2702         item.m_lStartOffset = (int)(GetTime() * 75);
2703         PlayFile(item, true);
2704       }
2705     }
2706     else
2707     {
2708       VECPLAYERCORES cores;
2709       CPlayerCoreFactory::Get().GetRemotePlayers(cores);
2710       PLAYERCOREID core = CPlayerCoreFactory::Get().SelectPlayerDialog(cores);
2711       if(core != EPC_NONE)
2712       {
2713         CFileItem item;
2714         g_application.m_eForcedNextPlayer = core;
2715         PlayFile(item, false);
2716       }
2717     }
2718   }
2719
2720   if (g_peripherals.OnAction(action))
2721     return true;
2722
2723   if (action.GetID() == ACTION_MUTE)
2724   {
2725     ToggleMute();
2726     return true;
2727   }
2728
2729   if (action.GetID() == ACTION_TOGGLE_DIGITAL_ANALOG)
2730   {
2731     // TODO
2732     // revisit after new audio settings page have been implemented
2733     // makes no sense toggling a mode when you have three different settings
2734     int mode = CSettings::Get().GetInt("audiooutput.mode");
2735     if (++mode == 3)
2736       mode = 0;
2737     CSettings::Get().SetInt("audiooutput.mode", mode);
2738
2739     if (g_windowManager.GetActiveWindow() == WINDOW_SETTINGS_SYSTEM)
2740     {
2741       CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0,0,WINDOW_INVALID,g_windowManager.GetActiveWindow());
2742       g_windowManager.SendMessage(msg);
2743     }
2744     return true;
2745   }
2746
2747   // Check for global volume control
2748   if (action.GetAmount() && (action.GetID() == ACTION_VOLUME_UP || action.GetID() == ACTION_VOLUME_DOWN))
2749   {
2750     if (!m_pPlayer->IsPassthrough())
2751     {
2752       if (m_muted)
2753         UnMute();
2754       float volume = m_volumeLevel;
2755 // Android has steps based on the max available volume level
2756 #if defined(TARGET_ANDROID)
2757       float step = (VOLUME_MAXIMUM - VOLUME_MINIMUM) / CXBMCApp::GetMaxSystemVolume();
2758 #else
2759       float step   = (VOLUME_MAXIMUM - VOLUME_MINIMUM) / VOLUME_CONTROL_STEPS;
2760
2761       if (action.GetRepeat())
2762         step *= action.GetRepeat() * 50; // 50 fps
2763 #endif
2764       if (action.GetID() == ACTION_VOLUME_UP)
2765         volume += (float)fabs(action.GetAmount()) * action.GetAmount() * step;
2766       else
2767         volume -= (float)fabs(action.GetAmount()) * action.GetAmount() * step;
2768       SetVolume(volume, false);
2769     }
2770     // show visual feedback of volume change...
2771     ShowVolumeBar(&action);
2772     return true;
2773   }
2774   // Check for global seek control
2775   if (m_pPlayer->IsPlaying() && action.GetAmount() && (action.GetID() == ACTION_ANALOG_SEEK_FORWARD || action.GetID() == ACTION_ANALOG_SEEK_BACK))
2776   {
2777     if (!m_pPlayer->CanSeek()) return false;
2778     m_seekHandler->Seek(action.GetID() == ACTION_ANALOG_SEEK_FORWARD, action.GetAmount(), action.GetRepeat());
2779     return true;
2780   }
2781   if (action.GetID() == ACTION_GUIPROFILE_BEGIN)
2782   {
2783     CGUIControlProfiler::Instance().SetOutputFile(CSpecialProtocol::TranslatePath("special://home/guiprofiler.xml"));
2784     CGUIControlProfiler::Instance().Start();
2785     return true;
2786   }
2787   if (action.GetID() == ACTION_SHOW_PLAYLIST)
2788   {
2789     int iPlaylist = g_playlistPlayer.GetCurrentPlaylist();
2790     if (iPlaylist == PLAYLIST_VIDEO && g_windowManager.GetActiveWindow() != WINDOW_VIDEO_PLAYLIST)
2791       g_windowManager.ActivateWindow(WINDOW_VIDEO_PLAYLIST);
2792     else if (iPlaylist == PLAYLIST_MUSIC && g_windowManager.GetActiveWindow() != WINDOW_MUSIC_PLAYLIST)
2793       g_windowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST);
2794     return true;
2795   }
2796   return false;
2797 }
2798
2799 void CApplication::FrameMove(bool processEvents, bool processGUI)
2800 {
2801   MEASURE_FUNCTION;
2802
2803   if (processEvents)
2804   {
2805     // currently we calculate the repeat time (ie time from last similar keypress) just global as fps
2806     float frameTime = m_frameTime.GetElapsedSeconds();
2807     m_frameTime.StartZero();
2808     // never set a frametime less than 2 fps to avoid problems when debuggin and on breaks
2809     if( frameTime > 0.5 ) frameTime = 0.5;
2810
2811     if (processGUI && m_renderGUI)
2812     {
2813       g_graphicsContext.Lock();
2814       // check if there are notifications to display
2815       CGUIDialogKaiToast *toast = (CGUIDialogKaiToast *)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST);
2816       if (toast && toast->DoWork())
2817       {
2818         if (!toast->IsDialogRunning())
2819         {
2820           toast->Show();
2821         }
2822       }
2823       g_graphicsContext.Unlock();
2824     }
2825     CWinEvents::MessagePump();
2826
2827 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
2828     // Read the input from a remote
2829     g_RemoteControl.Update();
2830 #endif
2831
2832     // process input actions
2833     ProcessRemote(frameTime);
2834     ProcessGamepad(frameTime);
2835     ProcessEventServer(frameTime);
2836     ProcessPeripherals(frameTime);
2837     if (processGUI && m_renderGUI)
2838     {
2839       m_pInertialScrollingHandler->ProcessInertialScroll(frameTime);
2840       m_seekHandler->Process();
2841     }
2842   }
2843   if (processGUI && m_renderGUI)
2844   {
2845     if (!m_bStop)
2846       g_windowManager.Process(CTimeUtils::GetFrameTime());
2847     g_windowManager.FrameMove();
2848   }
2849 }
2850
2851 bool CApplication::ProcessGamepad(float frameTime)
2852 {
2853 #ifdef HAS_SDL_JOYSTICK
2854   if (!m_AppFocused)
2855     return false;
2856
2857   int iWin = GetActiveWindowID();
2858   int bid = 0;
2859   g_Joystick.Update();
2860   if (g_Joystick.GetButton(bid))
2861   {
2862     // reset Idle Timer
2863     m_idleTimer.StartZero();
2864
2865     ResetScreenSaver();
2866     if (WakeUpScreenSaverAndDPMS())
2867     {
2868       g_Joystick.Reset(true);
2869       return true;
2870     }
2871
2872     int actionID;
2873     CStdString actionName;
2874     bool fullrange;
2875     if (CButtonTranslator::GetInstance().TranslateJoystickString(iWin, g_Joystick.GetJoystick().c_str(), bid, JACTIVE_BUTTON, actionID, actionName, fullrange))
2876     {
2877       CAction action(actionID, 1.0f, 0.0f, actionName);
2878       g_Joystick.Reset();
2879       g_Mouse.SetActive(false);
2880       return ExecuteInputAction(action);
2881     }
2882     else
2883     {
2884       g_Joystick.Reset();
2885     }
2886   }
2887   if (g_Joystick.GetAxis(bid))
2888   {
2889     if (g_Joystick.GetAmount() < 0)
2890     {
2891       bid = -bid;
2892     }
2893
2894     int actionID;
2895     CStdString actionName;
2896     bool fullrange;
2897     if (CButtonTranslator::GetInstance().TranslateJoystickString(iWin, g_Joystick.GetJoystick().c_str(), bid, JACTIVE_AXIS, actionID, actionName, fullrange))
2898     {
2899       ResetScreenSaver();
2900       if (WakeUpScreenSaverAndDPMS())
2901       {
2902         return true;
2903       }
2904
2905       CAction action(actionID, fullrange ? (g_Joystick.GetAmount() + 1.0f)/2.0f : fabs(g_Joystick.GetAmount()), 0.0f, actionName);
2906       g_Joystick.Reset();
2907       g_Mouse.SetActive(false);
2908       return ExecuteInputAction(action);
2909     }
2910     else
2911     {
2912       g_Joystick.ResetAxis(abs(bid));
2913     }
2914   }
2915   int position = 0;
2916   if (g_Joystick.GetHat(bid, position))
2917   {
2918     // reset Idle Timer
2919     m_idleTimer.StartZero();
2920
2921     ResetScreenSaver();
2922     if (WakeUpScreenSaverAndDPMS())
2923     {
2924       g_Joystick.Reset();
2925       return true;
2926     }
2927
2928     int actionID;
2929     CStdString actionName;
2930     bool fullrange;
2931
2932     bid = position<<16|bid;
2933
2934     if (bid && CButtonTranslator::GetInstance().TranslateJoystickString(iWin, g_Joystick.GetJoystick().c_str(), bid, JACTIVE_HAT, actionID, actionName, fullrange))
2935     {
2936       CAction action(actionID, 1.0f, 0.0f, actionName);
2937       g_Joystick.Reset();
2938       g_Mouse.SetActive(false);
2939       return ExecuteInputAction(action);
2940     }
2941   }
2942 #endif
2943   return false;
2944 }
2945
2946 bool CApplication::ProcessRemote(float frameTime)
2947 {
2948 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
2949   if (g_RemoteControl.GetButton())
2950   {
2951     CKey key(g_RemoteControl.GetButton(), g_RemoteControl.GetHoldTime());
2952     g_RemoteControl.Reset();
2953     return OnKey(key);
2954   }
2955 #endif
2956   return false;
2957 }
2958
2959 bool CApplication::ProcessPeripherals(float frameTime)
2960 {
2961   CKey key;
2962   if (g_peripherals.GetNextKeypress(frameTime, key))
2963     return OnKey(key);
2964   return false;
2965 }
2966
2967 bool CApplication::ProcessMouse()
2968 {
2969   MEASURE_FUNCTION;
2970
2971   if (!g_Mouse.IsActive() || !m_AppFocused)
2972     return false;
2973
2974   // Get the mouse command ID
2975   uint32_t mousecommand = g_Mouse.GetAction();
2976   if (mousecommand == ACTION_NOOP)
2977     return true;
2978
2979   // Reset the screensaver and idle timers
2980   m_idleTimer.StartZero();
2981   ResetScreenSaver();
2982   if (WakeUpScreenSaverAndDPMS())
2983     return true;
2984
2985   // Retrieve the corresponding action
2986   int iWin = GetActiveWindowID();
2987   CKey key(mousecommand | KEY_MOUSE, (unsigned int) 0);
2988   CAction mouseaction = CButtonTranslator::GetInstance().GetAction(iWin, key);
2989
2990   // Deactivate mouse if non-mouse action
2991   if (!mouseaction.IsMouse())
2992     g_Mouse.SetActive(false);
2993
2994   // Consume ACTION_NOOP.
2995   // Some views or dialogs gets closed after any ACTION and
2996   // a sensitive mouse might cause problems.
2997   if (mouseaction.GetID() == ACTION_NOOP)
2998     return false;
2999
3000   // If we couldn't find an action return false to indicate we have not
3001   // handled this mouse action
3002   if (!mouseaction.GetID())
3003   {
3004     CLog::Log(LOGDEBUG, "%s: unknown mouse command %d", __FUNCTION__, mousecommand);
3005     return false;
3006   }
3007
3008   // Log mouse actions except for move and noop
3009   if (mouseaction.GetID() != ACTION_MOUSE_MOVE && mouseaction.GetID() != ACTION_NOOP)
3010     CLog::Log(LOGDEBUG, "%s: trying mouse action %s", __FUNCTION__, mouseaction.GetName().c_str());
3011
3012   // The action might not be a mouse action. For example wheel moves might
3013   // be mapped to volume up/down in mouse.xml. In this case we do not want
3014   // the mouse position saved in the action.
3015   if (!mouseaction.IsMouse())
3016     return OnAction(mouseaction);
3017
3018   // This is a mouse action so we need to record the mouse position
3019   return OnAction(CAction(mouseaction.GetID(),
3020                           g_Mouse.GetHold(MOUSE_LEFT_BUTTON),
3021                           (float)g_Mouse.GetX(),
3022                           (float)g_Mouse.GetY(),
3023                           (float)g_Mouse.GetDX(),
3024                           (float)g_Mouse.GetDY(),
3025                           mouseaction.GetName()));
3026 }
3027
3028 bool CApplication::ProcessEventServer(float frameTime)
3029 {
3030 #ifdef HAS_EVENT_SERVER
3031   CEventServer* es = CEventServer::GetInstance();
3032   if (!es || !es->Running() || es->GetNumberOfClients()==0)
3033     return false;
3034
3035   // process any queued up actions
3036   if (es->ExecuteNextAction())
3037   {
3038     // reset idle timers
3039     m_idleTimer.StartZero();
3040     ResetScreenSaver();
3041     WakeUpScreenSaverAndDPMS();
3042   }
3043
3044   // now handle any buttons or axis
3045   std::string joystickName;
3046   bool isAxis = false;
3047   float fAmount = 0.0;
3048
3049   // es->ExecuteNextAction() invalidates the ref to the CEventServer instance
3050   // when the action exits XBMC
3051   es = CEventServer::GetInstance();
3052   if (!es || !es->Running() || es->GetNumberOfClients()==0)
3053     return false;
3054   unsigned int wKeyID = es->GetButtonCode(joystickName, isAxis, fAmount);
3055
3056   if (wKeyID)
3057   {
3058     if (joystickName.length() > 0)
3059     {
3060       if (isAxis == true)
3061       {
3062         if (fabs(fAmount) >= 0.08)
3063           m_lastAxisMap[joystickName][wKeyID] = fAmount;
3064         else
3065           m_lastAxisMap[joystickName].erase(wKeyID);
3066       }
3067
3068       return ProcessJoystickEvent(joystickName, wKeyID, isAxis, fAmount);
3069     }
3070     else
3071     {
3072       CKey key;
3073       if (wKeyID & ES_FLAG_UNICODE)
3074       {
3075         key = CKey((uint8_t)0, wKeyID & ~ES_FLAG_UNICODE, 0, 0, 0);
3076         return OnKey(key);
3077       }
3078
3079       if(wKeyID == KEY_BUTTON_LEFT_ANALOG_TRIGGER)
3080         key = CKey(wKeyID, (BYTE)(255*fAmount), 0, 0.0, 0.0, 0.0, 0.0, frameTime);
3081       else if(wKeyID == KEY_BUTTON_RIGHT_ANALOG_TRIGGER)
3082         key = CKey(wKeyID, 0, (BYTE)(255*fAmount), 0.0, 0.0, 0.0, 0.0, frameTime);
3083       else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_LEFT)
3084         key = CKey(wKeyID, 0, 0, -fAmount, 0.0, 0.0, 0.0, frameTime);
3085       else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_RIGHT)
3086         key = CKey(wKeyID, 0, 0,  fAmount, 0.0, 0.0, 0.0, frameTime);
3087       else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_UP)
3088         key = CKey(wKeyID, 0, 0, 0.0,  fAmount, 0.0, 0.0, frameTime);
3089       else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_DOWN)
3090         key = CKey(wKeyID, 0, 0, 0.0, -fAmount, 0.0, 0.0, frameTime);
3091       else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_LEFT)
3092         key = CKey(wKeyID, 0, 0, 0.0, 0.0, -fAmount, 0.0, frameTime);
3093       else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT)
3094         key = CKey(wKeyID, 0, 0, 0.0, 0.0,  fAmount, 0.0, frameTime);
3095       else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_UP)
3096         key = CKey(wKeyID, 0, 0, 0.0, 0.0, 0.0,  fAmount, frameTime);
3097       else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_DOWN)
3098         key = CKey(wKeyID, 0, 0, 0.0, 0.0, 0.0, -fAmount, frameTime);
3099       else
3100         key = CKey(wKeyID);
3101       key.SetFromService(true);
3102       return OnKey(key);
3103     }
3104   }
3105
3106   if (m_lastAxisMap.size() > 0)
3107   {
3108     // Process all the stored axis.
3109     for (map<std::string, map<int, float> >::iterator iter = m_lastAxisMap.begin(); iter != m_lastAxisMap.end(); ++iter)
3110     {
3111       for (map<int, float>::iterator iterAxis = (*iter).second.begin(); iterAxis != (*iter).second.end(); ++iterAxis)
3112         ProcessJoystickEvent((*iter).first, (*iterAxis).first, true, (*iterAxis).second);
3113     }
3114   }
3115
3116   {
3117     CPoint pos;
3118     if (es->GetMousePos(pos.x, pos.y) && g_Mouse.IsEnabled())
3119       return OnAction(CAction(ACTION_MOUSE_MOVE, pos.x, pos.y));
3120   }
3121 #endif
3122   return false;
3123 }
3124
3125 bool CApplication::ProcessJoystickEvent(const std::string& joystickName, int wKeyID, bool isAxis, float fAmount, unsigned int holdTime /*=0*/)
3126 {
3127 #if defined(HAS_EVENT_SERVER)
3128   m_idleTimer.StartZero();
3129
3130    // Make sure to reset screen saver, mouse.
3131    ResetScreenSaver();
3132    if (WakeUpScreenSaverAndDPMS())
3133      return true;
3134
3135 #ifdef HAS_SDL_JOYSTICK
3136    g_Joystick.Reset();
3137 #endif
3138    g_Mouse.SetActive(false);
3139
3140    int iWin = GetActiveWindowID();
3141    int actionID;
3142    CStdString actionName;
3143    bool fullRange = false;
3144
3145    // Translate using regular joystick translator.
3146    if (CButtonTranslator::GetInstance().TranslateJoystickString(iWin, joystickName.c_str(), wKeyID, isAxis ? JACTIVE_AXIS : JACTIVE_BUTTON, actionID, actionName, fullRange))
3147      return ExecuteInputAction( CAction(actionID, fAmount, 0.0f, actionName, holdTime) );
3148    else
3149      CLog::Log(LOGDEBUG, "ERROR mapping joystick action. Joystick: %s %i",joystickName.c_str(), wKeyID);
3150 #endif
3151
3152    return false;
3153 }
3154
3155 bool CApplication::ExecuteInputAction(const CAction &action)
3156 {
3157   bool bResult = false;
3158
3159   // play sound before the action unless the button is held,
3160   // where we execute after the action as held actions aren't fired every time.
3161   if(action.GetHoldTime())
3162   {
3163     bResult = OnAction(action);
3164     if(bResult)
3165       g_audioManager.PlayActionSound(action);
3166   }
3167   else
3168   {
3169     g_audioManager.PlayActionSound(action);
3170     bResult = OnAction(action);
3171   }
3172   return bResult;
3173 }
3174
3175 int CApplication::GetActiveWindowID(void)
3176 {
3177   // Get the currently active window
3178   int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
3179
3180   // If there is a dialog active get the dialog id instead
3181   if (g_windowManager.HasModalDialog())
3182     iWin = g_windowManager.GetTopMostModalDialogID() & WINDOW_ID_MASK;
3183
3184   // If the window is FullScreenVideo check for special cases
3185   if (iWin == WINDOW_FULLSCREEN_VIDEO)
3186   {
3187     // check if we're in a DVD menu
3188     if(g_application.m_pPlayer->IsInMenu())
3189       iWin = WINDOW_VIDEO_MENU;
3190     // check for LiveTV and switch to it's virtual window
3191     else if (g_PVRManager.IsStarted() && g_application.CurrentFileItem().HasPVRChannelInfoTag())
3192       iWin = WINDOW_FULLSCREEN_LIVETV;
3193   }
3194
3195   // Return the window id
3196   return iWin;
3197 }
3198
3199 bool CApplication::Cleanup()
3200 {
3201   try
3202   {
3203     g_windowManager.Delete(WINDOW_MUSIC_PLAYLIST);
3204     g_windowManager.Delete(WINDOW_MUSIC_PLAYLIST_EDITOR);
3205     g_windowManager.Delete(WINDOW_MUSIC_FILES);
3206     g_windowManager.Delete(WINDOW_MUSIC_NAV);
3207     g_windowManager.Delete(WINDOW_DIALOG_MUSIC_INFO);
3208     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_INFO);
3209     g_windowManager.Delete(WINDOW_VIDEO_FILES);
3210     g_windowManager.Delete(WINDOW_VIDEO_PLAYLIST);
3211     g_windowManager.Delete(WINDOW_VIDEO_NAV);
3212     g_windowManager.Delete(WINDOW_FILES);
3213     g_windowManager.Delete(WINDOW_DIALOG_YES_NO);
3214     g_windowManager.Delete(WINDOW_DIALOG_PROGRESS);
3215     g_windowManager.Delete(WINDOW_DIALOG_NUMERIC);
3216     g_windowManager.Delete(WINDOW_DIALOG_GAMEPAD);
3217     g_windowManager.Delete(WINDOW_DIALOG_SUB_MENU);
3218     g_windowManager.Delete(WINDOW_DIALOG_BUTTON_MENU);
3219     g_windowManager.Delete(WINDOW_DIALOG_CONTEXT_MENU);
3220     g_windowManager.Delete(WINDOW_DIALOG_PLAYER_CONTROLS);
3221     g_windowManager.Delete(WINDOW_DIALOG_KARAOKE_SONGSELECT);
3222     g_windowManager.Delete(WINDOW_DIALOG_KARAOKE_SELECTOR);
3223     g_windowManager.Delete(WINDOW_DIALOG_MUSIC_OSD);
3224     g_windowManager.Delete(WINDOW_DIALOG_VIS_PRESET_LIST);
3225     g_windowManager.Delete(WINDOW_DIALOG_SELECT);
3226     g_windowManager.Delete(WINDOW_DIALOG_OK);
3227     g_windowManager.Delete(WINDOW_DIALOG_FILESTACKING);
3228     g_windowManager.Delete(WINDOW_DIALOG_KEYBOARD);
3229     g_windowManager.Delete(WINDOW_FULLSCREEN_VIDEO);
3230     g_windowManager.Delete(WINDOW_DIALOG_PROFILE_SETTINGS);
3231     g_windowManager.Delete(WINDOW_DIALOG_LOCK_SETTINGS);
3232     g_windowManager.Delete(WINDOW_DIALOG_NETWORK_SETUP);
3233     g_windowManager.Delete(WINDOW_DIALOG_MEDIA_SOURCE);
3234     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_OSD_SETTINGS);
3235     g_windowManager.Delete(WINDOW_DIALOG_AUDIO_OSD_SETTINGS);
3236     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_BOOKMARKS);
3237     g_windowManager.Delete(WINDOW_DIALOG_CONTENT_SETTINGS);
3238     g_windowManager.Delete(WINDOW_DIALOG_FAVOURITES);
3239     g_windowManager.Delete(WINDOW_DIALOG_SONG_INFO);
3240     g_windowManager.Delete(WINDOW_DIALOG_SMART_PLAYLIST_EDITOR);
3241     g_windowManager.Delete(WINDOW_DIALOG_SMART_PLAYLIST_RULE);
3242     g_windowManager.Delete(WINDOW_DIALOG_BUSY);
3243     g_windowManager.Delete(WINDOW_DIALOG_PICTURE_INFO);
3244     g_windowManager.Delete(WINDOW_DIALOG_ADDON_INFO);
3245     g_windowManager.Delete(WINDOW_DIALOG_ADDON_SETTINGS);
3246     g_windowManager.Delete(WINDOW_DIALOG_ACCESS_POINTS);
3247     g_windowManager.Delete(WINDOW_DIALOG_SLIDER);
3248     g_windowManager.Delete(WINDOW_DIALOG_MEDIA_FILTER);
3249
3250     /* Delete PVR related windows and dialogs */
3251     g_windowManager.Delete(WINDOW_PVR);
3252     g_windowManager.Delete(WINDOW_DIALOG_PVR_GUIDE_INFO);
3253     g_windowManager.Delete(WINDOW_DIALOG_PVR_RECORDING_INFO);
3254     g_windowManager.Delete(WINDOW_DIALOG_PVR_TIMER_SETTING);
3255     g_windowManager.Delete(WINDOW_DIALOG_PVR_GROUP_MANAGER);
3256     g_windowManager.Delete(WINDOW_DIALOG_PVR_CHANNEL_MANAGER);
3257     g_windowManager.Delete(WINDOW_DIALOG_PVR_GUIDE_SEARCH);
3258     g_windowManager.Delete(WINDOW_DIALOG_PVR_CHANNEL_SCAN);
3259     g_windowManager.Delete(WINDOW_DIALOG_PVR_UPDATE_PROGRESS);
3260     g_windowManager.Delete(WINDOW_DIALOG_PVR_OSD_CHANNELS);
3261     g_windowManager.Delete(WINDOW_DIALOG_PVR_OSD_GUIDE);
3262     g_windowManager.Delete(WINDOW_DIALOG_PVR_OSD_DIRECTOR);
3263     g_windowManager.Delete(WINDOW_DIALOG_PVR_OSD_CUTTER);
3264     g_windowManager.Delete(WINDOW_DIALOG_OSD_TELETEXT);
3265
3266     g_windowManager.Delete(WINDOW_DIALOG_TEXT_VIEWER);
3267     g_windowManager.Delete(WINDOW_DIALOG_PLAY_EJECT);
3268     g_windowManager.Delete(WINDOW_STARTUP_ANIM);
3269     g_windowManager.Delete(WINDOW_LOGIN_SCREEN);
3270     g_windowManager.Delete(WINDOW_VISUALISATION);
3271     g_windowManager.Delete(WINDOW_KARAOKELYRICS);
3272     g_windowManager.Delete(WINDOW_SETTINGS_MENU);
3273     g_windowManager.Delete(WINDOW_SETTINGS_PROFILES);
3274     g_windowManager.Delete(WINDOW_SETTINGS_MYPICTURES);  // all the settings categories
3275     g_windowManager.Delete(WINDOW_TEST_PATTERN);
3276     g_windowManager.Delete(WINDOW_SCREEN_CALIBRATION);
3277     g_windowManager.Delete(WINDOW_SYSTEM_INFORMATION);
3278     g_windowManager.Delete(WINDOW_SCREENSAVER);
3279     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_OSD);
3280     g_windowManager.Delete(WINDOW_DIALOG_MUSIC_OVERLAY);
3281     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_OVERLAY);
3282     g_windowManager.Delete(WINDOW_SLIDESHOW);
3283     g_windowManager.Delete(WINDOW_ADDON_BROWSER);
3284     g_windowManager.Delete(WINDOW_SKIN_SETTINGS);
3285
3286     g_windowManager.Delete(WINDOW_HOME);
3287     g_windowManager.Delete(WINDOW_PROGRAMS);
3288     g_windowManager.Delete(WINDOW_PICTURES);
3289     g_windowManager.Delete(WINDOW_WEATHER);
3290
3291     g_windowManager.Delete(WINDOW_SETTINGS_MYPICTURES);
3292     g_windowManager.Remove(WINDOW_SETTINGS_MYPROGRAMS);
3293     g_windowManager.Remove(WINDOW_SETTINGS_MYWEATHER);
3294     g_windowManager.Remove(WINDOW_SETTINGS_MYMUSIC);
3295     g_windowManager.Remove(WINDOW_SETTINGS_SYSTEM);
3296     g_windowManager.Remove(WINDOW_SETTINGS_MYVIDEOS);
3297     g_windowManager.Remove(WINDOW_SETTINGS_SERVICE);
3298     g_windowManager.Remove(WINDOW_SETTINGS_APPEARANCE);
3299     g_windowManager.Remove(WINDOW_SETTINGS_MYPVR);
3300     g_windowManager.Remove(WINDOW_DIALOG_KAI_TOAST);
3301
3302     g_windowManager.Remove(WINDOW_DIALOG_SEEK_BAR);
3303     g_windowManager.Remove(WINDOW_DIALOG_VOLUME_BAR);
3304
3305     CAddonMgr::Get().DeInit();
3306
3307 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
3308     CLog::Log(LOGNOTICE, "closing down remote control service");
3309     g_RemoteControl.Disconnect();
3310 #endif
3311
3312     CLog::Log(LOGNOTICE, "unload sections");
3313
3314 #ifdef HAS_PERFORMANCE_SAMPLE
3315     CLog::Log(LOGNOTICE, "performance statistics");
3316     m_perfStats.DumpStats();
3317 #endif
3318
3319     //  Shutdown as much as possible of the
3320     //  application, to reduce the leaks dumped
3321     //  to the vc output window before calling
3322     //  _CrtDumpMemoryLeaks(). Most of the leaks
3323     //  shown are no real leaks, as parts of the app
3324     //  are still allocated.
3325
3326     g_localizeStrings.Clear();
3327     g_LangCodeExpander.Clear();
3328     g_charsetConverter.clear();
3329     g_directoryCache.Clear();
3330     CButtonTranslator::GetInstance().Clear();
3331 #ifdef HAS_EVENT_SERVER
3332     CEventServer::RemoveInstance();
3333 #endif
3334     DllLoaderContainer::Clear();
3335     g_playlistPlayer.Clear();
3336     CSettings::Get().Uninitialize();
3337     g_advancedSettings.Clear();
3338
3339 #ifdef TARGET_POSIX
3340     CXHandle::DumpObjectTracker();
3341
3342 #ifdef HAS_DVD_DRIVE
3343     CLibcdio::ReleaseInstance();
3344 #endif
3345 #endif 
3346 #if defined(TARGET_ANDROID)
3347     // enable for all platforms once it's safe
3348     g_sectionLoader.UnloadAll();
3349 #endif
3350 #ifdef _CRTDBG_MAP_ALLOC
3351     _CrtDumpMemoryLeaks();
3352     while(1); // execution ends
3353 #endif
3354
3355     delete m_network;
3356     m_network = NULL;
3357
3358     return true;
3359   }
3360   catch (...)
3361   {
3362     CLog::Log(LOGERROR, "Exception in CApplication::Cleanup()");
3363     return false;
3364   }
3365 }
3366
3367 void CApplication::Stop(int exitCode)
3368 {
3369   try
3370   {
3371     CVariant vExitCode(exitCode);
3372     CAnnouncementManager::Announce(System, "xbmc", "OnQuit", vExitCode);
3373
3374     SaveFileState(true);
3375
3376     g_alarmClock.StopThread();
3377
3378     if( m_bSystemScreenSaverEnable )
3379       g_Windowing.EnableSystemScreenSaver(true);
3380
3381     CLog::Log(LOGNOTICE, "Storing total System Uptime");
3382     g_sysinfo.SetTotalUptime(g_sysinfo.GetTotalUptime() + (int)(CTimeUtils::GetFrameTime() / 60000));
3383
3384     // Update the settings information (volume, uptime etc. need saving)
3385     if (CFile::Exists(CProfilesManager::Get().GetSettingsFile()))
3386     {
3387       CLog::Log(LOGNOTICE, "Saving settings");
3388       CSettings::Get().Save();
3389     }
3390     else
3391       CLog::Log(LOGNOTICE, "Not saving settings (settings.xml is not present)");
3392
3393     m_bStop = true;
3394     m_AppFocused = false;
3395     m_ExitCode = exitCode;
3396     CLog::Log(LOGNOTICE, "stop all");
3397
3398     // cancel any jobs from the jobmanager
3399     CJobManager::GetInstance().CancelJobs();
3400
3401     // stop scanning before we kill the network and so on
3402     if (m_musicInfoScanner->IsScanning())
3403       m_musicInfoScanner->Stop();
3404
3405     if (m_videoInfoScanner->IsScanning())
3406       m_videoInfoScanner->Stop();
3407
3408     CApplicationMessenger::Get().Cleanup();
3409
3410     StopPVRManager();
3411     StopServices();
3412     //Sleep(5000);
3413
3414     CLog::Log(LOGNOTICE, "stop player");
3415     m_pPlayer->ClosePlayer();
3416
3417 #if HAS_FILESYTEM_DAAP
3418     CLog::Log(LOGNOTICE, "stop daap clients");
3419     g_DaapClient.Release();
3420 #endif
3421 #ifdef HAS_FILESYSTEM_SAP
3422     CLog::Log(LOGNOTICE, "stop sap announcement listener");
3423     g_sapsessions.StopThread();
3424 #endif
3425 #ifdef HAS_ZEROCONF
3426     if(CZeroconfBrowser::IsInstantiated())
3427     {
3428       CLog::Log(LOGNOTICE, "stop zeroconf browser");
3429       CZeroconfBrowser::GetInstance()->Stop();
3430       CZeroconfBrowser::ReleaseInstance();
3431     }
3432 #endif
3433
3434     CLog::Log(LOGNOTICE, "clean cached files!");
3435 #ifdef HAS_FILESYSTEM_RAR
3436     g_RarManager.ClearCache(true);
3437 #endif
3438
3439 #ifdef HAS_FILESYSTEM_SFTP
3440     CSFTPSessionManager::DisconnectAllSessions();
3441 #endif
3442
3443     CLog::Log(LOGNOTICE, "unload skin");
3444     UnloadSkin();
3445
3446 #if defined(TARGET_DARWIN_OSX)
3447     if (XBMCHelper::GetInstance().IsAlwaysOn() == false)
3448       XBMCHelper::GetInstance().Stop();
3449 #endif
3450
3451 #if defined(HAVE_LIBCRYSTALHD)
3452     CCrystalHD::RemoveInstance();
3453 #endif
3454
3455     g_mediaManager.Stop();
3456
3457     // Stop services before unloading Python
3458     CAddonMgr::Get().StopServices(false);
3459
3460     // stop all remaining scripts; must be done after skin has been unloaded,
3461     // not before some windows still need it when deinitializing during skin
3462     // unloading
3463     CScriptInvocationManager::Get().Uninitialize();
3464
3465     g_Windowing.DestroyRenderSystem();
3466     g_Windowing.DestroyWindow();
3467     g_Windowing.DestroyWindowSystem();
3468
3469     // shutdown the AudioEngine
3470     CAEFactory::Shutdown();
3471     CAEFactory::UnLoadEngine();
3472
3473     CLog::Log(LOGNOTICE, "stopped");
3474   }
3475   catch (...)
3476   {
3477     CLog::Log(LOGERROR, "Exception in CApplication::Stop()");
3478   }
3479
3480   // we may not get to finish the run cycle but exit immediately after a call to g_application.Stop()
3481   // so we may never get to Destroy() in CXBApplicationEx::Run(), we call it here.
3482   Destroy();
3483
3484   //
3485   Sleep(200);
3486 }
3487
3488 bool CApplication::PlayMedia(const CFileItem& item, int iPlaylist)
3489 {
3490   //If item is a plugin, expand out now and run ourselves again
3491   if (item.IsPlugin())
3492   {
3493     CFileItem item_new(item);
3494     if (XFILE::CPluginDirectory::GetPluginResult(item.GetPath(), item_new))
3495       return PlayMedia(item_new, iPlaylist);
3496     return false;
3497   }
3498   if (item.IsSmartPlayList())
3499   {
3500     CFileItemList items;
3501     CUtil::GetRecursiveListing(item.GetPath(), items, "");
3502     if (items.Size())
3503     {
3504       CSmartPlaylist smartpl;
3505       //get name and type of smartplaylist, this will always succeed as GetDirectory also did this.
3506       smartpl.OpenAndReadName(item.GetPath());
3507       CPlayList playlist;
3508       playlist.Add(items);
3509       return ProcessAndStartPlaylist(smartpl.GetName(), playlist, (smartpl.GetType() == "songs" || smartpl.GetType() == "albums") ? PLAYLIST_MUSIC:PLAYLIST_VIDEO);
3510     }
3511   }
3512   else if (item.IsPlayList() || item.IsInternetStream())
3513   {
3514     CGUIDialogCache* dlgCache = new CGUIDialogCache(5000, g_localizeStrings.Get(10214), item.GetLabel());
3515
3516     //is or could be a playlist
3517     auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(item));
3518     bool gotPlayList = (pPlayList.get() && pPlayList->Load(item.GetPath()));
3519
3520     if (dlgCache)
3521     {
3522        dlgCache->Close();
3523        if (dlgCache->IsCanceled())
3524           return true;
3525     }
3526
3527     if (gotPlayList)
3528     {
3529
3530       if (iPlaylist != PLAYLIST_NONE)
3531       {
3532         int track=0;
3533         if (item.HasProperty("playlist_starting_track"))
3534           track = (int)item.GetProperty("playlist_starting_track").asInteger();
3535         return ProcessAndStartPlaylist(item.GetPath(), *pPlayList, iPlaylist, track);
3536       }
3537       else
3538       {
3539         CLog::Log(LOGWARNING, "CApplication::PlayMedia called to play a playlist %s but no idea which playlist to use, playing first item", item.GetPath().c_str());
3540         if(pPlayList->size())
3541           return PlayFile(*(*pPlayList)[0], false) == PLAYBACK_OK;
3542       }
3543     }
3544   }
3545
3546   //nothing special just play
3547   return PlayFile(item, false) == PLAYBACK_OK;
3548 }
3549
3550 // PlayStack()
3551 // For playing a multi-file video.  Particularly inefficient
3552 // on startup, as we are required to calculate the length
3553 // of each video, so we open + close each one in turn.
3554 // A faster calculation of video time would improve this
3555 // substantially.
3556 // return value: same with PlayFile()
3557 PlayBackRet CApplication::PlayStack(const CFileItem& item, bool bRestart)
3558 {
3559   if (!item.IsStack())
3560     return PLAYBACK_FAIL;
3561
3562   CVideoDatabase dbs;
3563
3564   // case 1: stacked ISOs
3565   if (CFileItem(CStackDirectory::GetFirstStackedFile(item.GetPath()),false).IsDVDImage())
3566   {
3567     CStackDirectory dir;
3568     CFileItemList movieList;
3569     dir.GetDirectory(item.GetPath(), movieList);
3570
3571     // first assume values passed to the stack
3572     int selectedFile = item.m_lStartPartNumber;
3573     int startoffset = item.m_lStartOffset;
3574
3575     // check if we instructed the stack to resume from default
3576     if (startoffset == STARTOFFSET_RESUME) // selected file is not specified, pick the 'last' resume point
3577     {
3578       if (dbs.Open())
3579       {
3580         CBookmark bookmark;
3581         if (dbs.GetResumeBookMark(item.GetPath(), bookmark))
3582         {
3583           startoffset = (int)(bookmark.timeInSeconds*75);
3584           selectedFile = bookmark.partNumber;
3585         }
3586         dbs.Close();
3587       }
3588       else
3589         CLog::Log(LOGERROR, "%s - Cannot open VideoDatabase", __FUNCTION__);
3590     }
3591
3592     // make sure that the selected part is within the boundaries
3593     if (selectedFile <= 0)
3594     {
3595       CLog::Log(LOGWARNING, "%s - Selected part %d out of range, playing part 1", __FUNCTION__, selectedFile);
3596       selectedFile = 1;
3597     }
3598     else if (selectedFile > movieList.Size())
3599     {
3600       CLog::Log(LOGWARNING, "%s - Selected part %d out of range, playing part %d", __FUNCTION__, selectedFile, movieList.Size());
3601       selectedFile = movieList.Size();
3602     }
3603
3604     // set startoffset in movieitem, track stack item for updating purposes, and finally play disc part
3605     movieList[selectedFile - 1]->m_lStartOffset = startoffset > 0 ? STARTOFFSET_RESUME : 0;
3606     movieList[selectedFile - 1]->SetProperty("stackFileItemToUpdate", true);
3607     *m_stackFileItemToUpdate = item;
3608     return PlayFile(*(movieList[selectedFile - 1]));
3609   }
3610   // case 2: all other stacks
3611   else
3612   {
3613     // see if we have the info in the database
3614     // TODO: If user changes the time speed (FPS via framerate conversion stuff)
3615     //       then these times will be wrong.
3616     //       Also, this is really just a hack for the slow load up times we have
3617     //       A much better solution is a fast reader of FPS and fileLength
3618     //       that we can use on a file to get it's time.
3619     vector<int> times;
3620     bool haveTimes(false);
3621     CVideoDatabase dbs;
3622     if (dbs.Open())
3623     {
3624       dbs.GetVideoSettings(item.GetPath(), CMediaSettings::Get().GetCurrentVideoSettings());
3625       haveTimes = dbs.GetStackTimes(item.GetPath(), times);
3626       dbs.Close();
3627     }
3628
3629
3630     // calculate the total time of the stack
3631     CStackDirectory dir;
3632     dir.GetDirectory(item.GetPath(), *m_currentStack);
3633     long totalTime = 0;
3634     for (int i = 0; i < m_currentStack->Size(); i++)
3635     {
3636       if (haveTimes)
3637         (*m_currentStack)[i]->m_lEndOffset = times[i];
3638       else
3639       {
3640         int duration;
3641         if (!CDVDFileInfo::GetFileDuration((*m_currentStack)[i]->GetPath(), duration))
3642         {
3643           m_currentStack->Clear();
3644           return PLAYBACK_FAIL;
3645         }
3646         totalTime += duration / 1000;
3647         (*m_currentStack)[i]->m_lEndOffset = totalTime;
3648         times.push_back(totalTime);
3649       }
3650     }
3651
3652     double seconds = item.m_lStartOffset / 75.0;
3653
3654     if (!haveTimes || item.m_lStartOffset == STARTOFFSET_RESUME )
3655     {  // have our times now, so update the dB
3656       if (dbs.Open())
3657       {
3658         if( !haveTimes )
3659           dbs.SetStackTimes(item.GetPath(), times);
3660
3661         if( item.m_lStartOffset == STARTOFFSET_RESUME )
3662         {
3663           // can only resume seek here, not dvdstate
3664           CBookmark bookmark;
3665           if( dbs.GetResumeBookMark(item.GetPath(), bookmark) )
3666             seconds = bookmark.timeInSeconds;
3667           else
3668             seconds = 0.0f;
3669         }
3670         dbs.Close();
3671       }
3672     }
3673
3674     *m_itemCurrentFile = item;
3675     m_currentStackPosition = 0;
3676     m_pPlayer->ResetPlayer(); // must be reset on initial play otherwise last player will be used
3677
3678     if (seconds > 0)
3679     {
3680       // work out where to seek to
3681       for (int i = 0; i < m_currentStack->Size(); i++)
3682       {
3683         if (seconds < (*m_currentStack)[i]->m_lEndOffset)
3684         {
3685           CFileItem item(*(*m_currentStack)[i]);
3686           long start = (i > 0) ? (*m_currentStack)[i-1]->m_lEndOffset : 0;
3687           item.m_lStartOffset = (long)(seconds - start) * 75;
3688           m_currentStackPosition = i;
3689           return PlayFile(item, true);
3690         }
3691       }
3692     }
3693
3694     return PlayFile(*(*m_currentStack)[0], true);
3695   }
3696   return PLAYBACK_FAIL;
3697 }
3698
3699 PlayBackRet CApplication::PlayFile(const CFileItem& item, bool bRestart)
3700 {
3701   // Ensure the MIME type has been retrieved for http:// and shout:// streams
3702   if (item.GetMimeType().empty())
3703     const_cast<CFileItem&>(item).FillInMimeType();
3704
3705   if (!bRestart)
3706   {
3707     SaveCurrentFileSettings();
3708
3709     OutputDebugString("new file set audiostream:0\n");
3710     // Switch to default options
3711     CMediaSettings::Get().GetCurrentVideoSettings() = CMediaSettings::Get().GetDefaultVideoSettings();
3712     // see if we have saved options in the database
3713
3714     m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
3715     m_pPlayer->m_iPlaySpeed = 1;     // Reset both CApp's & Player's speed else we'll get confused
3716
3717     *m_itemCurrentFile = item;
3718     m_nextPlaylistItem = -1;
3719     m_currentStackPosition = 0;
3720     m_currentStack->Clear();
3721
3722     if (item.IsVideo())
3723       CUtil::ClearSubtitles();
3724   }
3725
3726   if (item.IsDiscStub())
3727   {
3728 #ifdef HAS_DVD_DRIVE
3729     // Display the Play Eject dialog if there is any optical disc drive
3730     if (g_mediaManager.HasOpticalDrive())
3731     {
3732       if (CGUIDialogPlayEject::ShowAndGetInput(item))
3733         // PlayDiscAskResume takes path to disc. No parameter means default DVD drive.
3734         // Can't do better as CGUIDialogPlayEject calls CMediaManager::IsDiscInDrive, which assumes default DVD drive anyway
3735         return MEDIA_DETECT::CAutorun::PlayDiscAskResume() ? PLAYBACK_OK : PLAYBACK_FAIL;
3736     }
3737     else
3738 #endif
3739       CGUIDialogOK::ShowAndGetInput(435, 0, 436, 0);
3740
3741     return PLAYBACK_OK;
3742   }
3743
3744   if (item.IsPlayList())
3745     return PLAYBACK_FAIL;
3746
3747   if (item.IsPlugin())
3748   { // we modify the item so that it becomes a real URL
3749     CFileItem item_new(item);
3750     if (XFILE::CPluginDirectory::GetPluginResult(item.GetPath(), item_new))
3751       return PlayFile(item_new, false);
3752     return PLAYBACK_FAIL;
3753   }
3754
3755 #ifdef HAS_UPNP
3756   if (URIUtils::IsUPnP(item.GetPath()))
3757   {
3758     CFileItem item_new(item);
3759     if (XFILE::CUPnPDirectory::GetResource(item.GetPath(), item_new))
3760       return PlayFile(item_new, false);
3761     return PLAYBACK_FAIL;
3762   }
3763 #endif
3764
3765   // if we have a stacked set of files, we need to setup our stack routines for
3766   // "seamless" seeking and total time of the movie etc.
3767   // will recall with restart set to true
3768   if (item.IsStack())
3769     return PlayStack(item, bRestart);
3770
3771   //Is TuxBox, this should probably be moved to CTuxBoxFile
3772   if(item.IsTuxBox())
3773   {
3774     CLog::Log(LOGDEBUG, "%s - TuxBox URL Detected %s",__FUNCTION__, item.GetPath().c_str());
3775
3776     if(g_tuxboxService.IsRunning())
3777       g_tuxboxService.Stop();
3778
3779     PlayBackRet ret = PLAYBACK_FAIL;
3780     CFileItem item_new;
3781     if(g_tuxbox.CreateNewItem(item, item_new))
3782     {
3783
3784       // Make sure it doesn't have a player
3785       // so we actually select one normally
3786       m_pPlayer->ResetPlayer();
3787
3788       // keep the tuxbox:// url as playing url
3789       // and give the new url to the player
3790       ret = PlayFile(item_new, true);
3791       if(ret == PLAYBACK_OK)
3792       {
3793         if(!g_tuxboxService.IsRunning())
3794           g_tuxboxService.Start();
3795       }
3796     }
3797     return ret;
3798   }
3799
3800   CPlayerOptions options;
3801
3802   if( item.HasProperty("StartPercent") )
3803   {
3804     double fallback = 0.0f;
3805     if(item.GetProperty("StartPercent").isString())
3806       fallback = (double)atof(item.GetProperty("StartPercent").asString().c_str());
3807     options.startpercent = item.GetProperty("StartPercent").asDouble(fallback);
3808   }
3809
3810   PLAYERCOREID eNewCore = EPC_NONE;
3811   if( bRestart )
3812   {
3813     // have to be set here due to playstack using this for starting the file
3814     options.starttime = item.m_lStartOffset / 75.0;
3815     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0 && m_itemCurrentFile->m_lStartOffset != 0)
3816       m_itemCurrentFile->m_lStartOffset = STARTOFFSET_RESUME; // to force fullscreen switching
3817
3818     if( m_eForcedNextPlayer != EPC_NONE )
3819       eNewCore = m_eForcedNextPlayer;
3820     else if( m_pPlayer->GetCurrentPlayer() == EPC_NONE )
3821       eNewCore = CPlayerCoreFactory::Get().GetDefaultPlayer(item);
3822     else
3823       eNewCore = m_pPlayer->GetCurrentPlayer();
3824   }
3825   else
3826   {
3827     options.starttime = item.m_lStartOffset / 75.0;
3828
3829     if (item.IsVideo())
3830     {
3831       // open the d/b and retrieve the bookmarks for the current movie
3832       CVideoDatabase dbs;
3833       dbs.Open();
3834       dbs.GetVideoSettings(item.GetPath(), CMediaSettings::Get().GetCurrentVideoSettings());
3835
3836       if( item.m_lStartOffset == STARTOFFSET_RESUME )
3837       {
3838         options.starttime = 0.0f;
3839         CBookmark bookmark;
3840         CStdString path = item.GetPath();
3841         if (item.HasVideoInfoTag() && item.GetVideoInfoTag()->m_strFileNameAndPath.Find("removable://") == 0)
3842           path = item.GetVideoInfoTag()->m_strFileNameAndPath;
3843         else if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
3844           path = item.GetProperty("original_listitem_url").asString();
3845         if(dbs.GetResumeBookMark(path, bookmark))
3846         {
3847           options.starttime = bookmark.timeInSeconds;
3848           options.state = bookmark.playerState;
3849         }
3850         /*
3851          override with information from the actual item if available.  We do this as the VFS (eg plugins)
3852          may set the resume point to override whatever XBMC has stored, yet we ignore it until now so that,
3853          should the playerState be required, it is fetched from the database.
3854          See the note in CGUIWindowVideoBase::ShowResumeMenu.
3855          */
3856         if (item.HasVideoInfoTag() && item.GetVideoInfoTag()->m_resumePoint.IsSet())
3857           options.starttime = item.GetVideoInfoTag()->m_resumePoint.timeInSeconds;
3858       }
3859       else if (item.HasVideoInfoTag())
3860       {
3861         const CVideoInfoTag *tag = item.GetVideoInfoTag();
3862
3863         if (tag->m_iBookmarkId != -1 && tag->m_iBookmarkId != 0)
3864         {
3865           CBookmark bookmark;
3866           dbs.GetBookMarkForEpisode(*tag, bookmark);
3867           options.starttime = bookmark.timeInSeconds;
3868           options.state = bookmark.playerState;
3869         }
3870       }
3871
3872       dbs.Close();
3873     }
3874
3875     if (m_eForcedNextPlayer != EPC_NONE)
3876       eNewCore = m_eForcedNextPlayer;
3877     else
3878       eNewCore = CPlayerCoreFactory::Get().GetDefaultPlayer(item);
3879   }
3880
3881   // this really aught to be inside !bRestart, but since PlayStack
3882   // uses that to init playback, we have to keep it outside
3883   int playlist = g_playlistPlayer.GetCurrentPlaylist();
3884   if (item.IsVideo() && g_playlistPlayer.GetPlaylist(playlist).size() > 1)
3885   { // playing from a playlist by the looks
3886     // don't switch to fullscreen if we are not playing the first item...
3887     options.fullscreen = !g_playlistPlayer.HasPlayedFirstFile() && g_advancedSettings.m_fullScreenOnMovieStart && !CMediaSettings::Get().DoesVideoStartWindowed();
3888   }
3889   else if(m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
3890   {
3891     // TODO - this will fail if user seeks back to first file in stack
3892     if(m_currentStackPosition == 0 || m_itemCurrentFile->m_lStartOffset == STARTOFFSET_RESUME)
3893       options.fullscreen = g_advancedSettings.m_fullScreenOnMovieStart && !CMediaSettings::Get().DoesVideoStartWindowed();
3894     else
3895       options.fullscreen = false;
3896     // reset this so we don't think we are resuming on seek
3897     m_itemCurrentFile->m_lStartOffset = 0;
3898   }
3899   else
3900     options.fullscreen = g_advancedSettings.m_fullScreenOnMovieStart && !CMediaSettings::Get().DoesVideoStartWindowed();
3901
3902   // reset VideoStartWindowed as it's a temp setting
3903   CMediaSettings::Get().SetVideoStartWindowed(false);
3904
3905 #ifdef HAS_KARAOKE
3906   //We have to stop parsing a cdg before mplayer is deallocated
3907   // WHY do we have to do this????
3908   if (m_pKaraokeMgr)
3909     m_pKaraokeMgr->Stop();
3910 #endif
3911
3912   {
3913     CSingleLock lock(m_playStateMutex);
3914     // tell system we are starting a file
3915     m_bPlaybackStarting = true;
3916     
3917     // for playing a new item, previous playing item's callback may already
3918     // pushed some delay message into the threadmessage list, they are not
3919     // expected be processed after or during the new item playback starting.
3920     // so we clean up previous playing item's playback callback delay messages here.
3921     int previousMsgsIgnoredByNewPlaying[] = {
3922       GUI_MSG_PLAYBACK_STARTED,
3923       GUI_MSG_PLAYBACK_ENDED,
3924       GUI_MSG_PLAYBACK_STOPPED,
3925       GUI_MSG_PLAYLIST_CHANGED,
3926       GUI_MSG_PLAYLISTPLAYER_STOPPED,
3927       GUI_MSG_PLAYLISTPLAYER_STARTED,
3928       GUI_MSG_PLAYLISTPLAYER_CHANGED,
3929       GUI_MSG_QUEUE_NEXT_ITEM,
3930       0
3931     };
3932     int dMsgCount = g_windowManager.RemoveThreadMessageByMessageIds(&previousMsgsIgnoredByNewPlaying[0]);
3933     if (dMsgCount > 0)
3934       CLog::Log(LOGDEBUG,"%s : Ignored %d playback thread messages", __FUNCTION__, dMsgCount);
3935   }
3936
3937   // We should restart the player, unless the previous and next tracks are using
3938   // one of the players that allows gapless playback (paplayer, dvdplayer)
3939   m_pPlayer->ClosePlayerGapless(eNewCore);
3940
3941   // now reset play state to starting, since we already stopped the previous playing item if there is.
3942   // and from now there should be no playback callback from previous playing item be called.
3943   m_ePlayState = PLAY_STATE_STARTING;
3944
3945   m_pPlayer->CreatePlayer(eNewCore, *this);
3946
3947   PlayBackRet iResult;
3948   if (m_pPlayer->HasPlayer())
3949   {
3950     /* When playing video pause any low priority jobs, they will be unpaused  when playback stops.
3951      * This should speed up player startup for files on internet filesystems (eg. webdav) and
3952      * increase performance on low powered systems (Atom/ARM).
3953      */
3954     if (item.IsVideo())
3955     {
3956       CJobManager::GetInstance().Pause(CJob::PRIORITY_LOW); // Pause any low priority jobs
3957     }
3958
3959     // don't hold graphicscontext here since player
3960     // may wait on another thread, that requires gfx
3961     CSingleExit ex(g_graphicsContext);
3962
3963     iResult = m_pPlayer->OpenFile(item, options);
3964   }
3965   else
3966   {
3967     CLog::Log(LOGERROR, "Error creating player for item %s (File doesn't exist?)", item.GetPath().c_str());
3968     iResult = PLAYBACK_FAIL;
3969   }
3970
3971   if(iResult == PLAYBACK_OK)
3972   {
3973     if (m_pPlayer->GetPlaySpeed() != 1)
3974     {
3975       int iSpeed = m_pPlayer->GetPlaySpeed();
3976       m_pPlayer->m_iPlaySpeed = 1;
3977       m_pPlayer->SetPlaySpeed(iSpeed, g_application.m_muted);
3978     }
3979
3980     // if player has volume control, set it.
3981     if (m_pPlayer->ControlsVolume())
3982     {
3983        m_pPlayer->SetVolume(m_volumeLevel);
3984        m_pPlayer->SetMute(m_muted);
3985     }
3986
3987     if( m_pPlayer->IsPlayingAudio() )
3988     {
3989       if (g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
3990         g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
3991     }
3992
3993 #ifdef HAS_VIDEO_PLAYBACK
3994     else if( m_pPlayer->IsPlayingVideo() )
3995     {
3996       if (g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION)
3997         g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
3998
3999       // if player didn't manange to switch to fullscreen by itself do it here
4000       if( options.fullscreen && g_renderManager.IsStarted()
4001        && g_windowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO )
4002        SwitchToFullScreen();
4003     }
4004 #endif
4005     else
4006     {
4007       if (g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION
4008       ||  g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
4009         g_windowManager.PreviousWindow();
4010
4011     }
4012
4013 #if !defined(TARGET_POSIX)
4014     g_audioManager.Enable(false);
4015 #endif
4016
4017     if (item.HasPVRChannelInfoTag())
4018       g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
4019   }
4020
4021   CSingleLock lock(m_playStateMutex);
4022   m_bPlaybackStarting = false;
4023
4024   if (iResult == PLAYBACK_OK)
4025   {
4026     // play state: none, starting; playing; stopped; ended.
4027     // last 3 states are set by playback callback, they are all ignored during starting,
4028     // but we recorded the state, here we can make up the callback for the state.
4029     CLog::Log(LOGDEBUG,"%s : OpenFile succeed, play state %d", __FUNCTION__, m_ePlayState);
4030     switch (m_ePlayState)
4031     {
4032       case PLAY_STATE_PLAYING:
4033         OnPlayBackStarted();
4034         break;
4035       // FIXME: it seems no meaning to callback started here if there was an started callback
4036       //        before this stopped/ended callback we recorded. if we callback started here
4037       //        first, it will delay send OnPlay announce, but then we callback stopped/ended
4038       //        which will send OnStop announce at once, so currently, just call stopped/ended.
4039       case PLAY_STATE_ENDED:
4040         OnPlayBackEnded();
4041         break;
4042       case PLAY_STATE_STOPPED:
4043         OnPlayBackStopped();
4044         break;
4045       case PLAY_STATE_STARTING:
4046         // neither started nor stopped/ended callback be called, that means the item still
4047         // not started, we need not make up any callback, just leave this and
4048         // let the player callback do its work.
4049         break;
4050       default:
4051         break;
4052     }
4053   }
4054   else if (iResult == PLAYBACK_FAIL)
4055   {
4056     // we send this if it isn't playlistplayer that is doing this
4057     int next = g_playlistPlayer.GetNextSong();
4058     int size = g_playlistPlayer.GetPlaylist(g_playlistPlayer.GetCurrentPlaylist()).size();
4059     if(next < 0
4060     || next >= size)
4061       OnPlayBackStopped();
4062     m_ePlayState = PLAY_STATE_NONE;
4063   }
4064
4065   return iResult;
4066 }
4067
4068 void CApplication::OnPlayBackEnded()
4069 {
4070   CSingleLock lock(m_playStateMutex);
4071   CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
4072   m_ePlayState = PLAY_STATE_ENDED;
4073   if(m_bPlaybackStarting)
4074     return;
4075
4076   // informs python script currently running playback has ended
4077   // (does nothing if python is not loaded)
4078 #ifdef HAS_PYTHON
4079   g_pythonParser.OnPlayBackEnded();
4080 #endif
4081
4082   CVariant data(CVariant::VariantTypeObject);
4083   data["end"] = true;
4084   CAnnouncementManager::Announce(Player, "xbmc", "OnStop", m_itemCurrentFile, data);
4085
4086   CGUIMessage msg(GUI_MSG_PLAYBACK_ENDED, 0, 0);
4087   g_windowManager.SendThreadMessage(msg);
4088 }
4089
4090 void CApplication::OnPlayBackStarted()
4091 {
4092   CSingleLock lock(m_playStateMutex);
4093   CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
4094   m_ePlayState = PLAY_STATE_PLAYING;
4095   if(m_bPlaybackStarting)
4096     return;
4097
4098 #ifdef HAS_PYTHON
4099   // informs python script currently running playback has started
4100   // (does nothing if python is not loaded)
4101   g_pythonParser.OnPlayBackStarted();
4102 #endif
4103
4104   CGUIMessage msg(GUI_MSG_PLAYBACK_STARTED, 0, 0);
4105   g_windowManager.SendThreadMessage(msg);
4106 }
4107
4108 void CApplication::OnQueueNextItem()
4109 {
4110   CSingleLock lock(m_playStateMutex);
4111   CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
4112   if(m_bPlaybackStarting)
4113     return;
4114   // informs python script currently running that we are requesting the next track
4115   // (does nothing if python is not loaded)
4116 #ifdef HAS_PYTHON
4117   g_pythonParser.OnQueueNextItem(); // currently unimplemented
4118 #endif
4119
4120   CGUIMessage msg(GUI_MSG_QUEUE_NEXT_ITEM, 0, 0);
4121   g_windowManager.SendThreadMessage(msg);
4122 }
4123
4124 void CApplication::OnPlayBackStopped()
4125 {
4126   CSingleLock lock(m_playStateMutex);
4127   CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
4128   m_ePlayState = PLAY_STATE_STOPPED;
4129   if(m_bPlaybackStarting)
4130     return;
4131
4132   // informs python script currently running playback has ended
4133   // (does nothing if python is not loaded)
4134 #ifdef HAS_PYTHON
4135   g_pythonParser.OnPlayBackStopped();
4136 #endif
4137
4138   CVariant data(CVariant::VariantTypeObject);
4139   data["end"] = false;
4140   CAnnouncementManager::Announce(Player, "xbmc", "OnStop", m_itemCurrentFile, data);
4141
4142   CGUIMessage msg( GUI_MSG_PLAYBACK_STOPPED, 0, 0 );
4143   g_windowManager.SendThreadMessage(msg);
4144 }
4145
4146 void CApplication::OnPlayBackPaused()
4147 {
4148 #ifdef HAS_PYTHON
4149   g_pythonParser.OnPlayBackPaused();
4150 #endif
4151
4152   CVariant param;
4153   param["player"]["speed"] = 0;
4154   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
4155   CAnnouncementManager::Announce(Player, "xbmc", "OnPause", m_itemCurrentFile, param);
4156 }
4157
4158 void CApplication::OnPlayBackResumed()
4159 {
4160 #ifdef HAS_PYTHON
4161   g_pythonParser.OnPlayBackResumed();
4162 #endif
4163
4164   CVariant param;
4165   param["player"]["speed"] = 1;
4166   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
4167   CAnnouncementManager::Announce(Player, "xbmc", "OnPlay", m_itemCurrentFile, param);
4168 }
4169
4170 void CApplication::OnPlayBackSpeedChanged(int iSpeed)
4171 {
4172 #ifdef HAS_PYTHON
4173   g_pythonParser.OnPlayBackSpeedChanged(iSpeed);
4174 #endif
4175
4176   CVariant param;
4177   param["player"]["speed"] = iSpeed;
4178   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
4179   CAnnouncementManager::Announce(Player, "xbmc", "OnSpeedChanged", m_itemCurrentFile, param);
4180 }
4181
4182 void CApplication::OnPlayBackSeek(int iTime, int seekOffset)
4183 {
4184 #ifdef HAS_PYTHON
4185   g_pythonParser.OnPlayBackSeek(iTime, seekOffset);
4186 #endif
4187
4188   CVariant param;
4189   CJSONUtils::MillisecondsToTimeObject(iTime, param["player"]["time"]);
4190   CJSONUtils::MillisecondsToTimeObject(seekOffset, param["player"]["seekoffset"]);;
4191   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
4192   param["player"]["speed"] = m_pPlayer->GetPlaySpeed();
4193   CAnnouncementManager::Announce(Player, "xbmc", "OnSeek", m_itemCurrentFile, param);
4194   g_infoManager.SetDisplayAfterSeek(2500, seekOffset/1000);
4195 }
4196
4197 void CApplication::OnPlayBackSeekChapter(int iChapter)
4198 {
4199 #ifdef HAS_PYTHON
4200   g_pythonParser.OnPlayBackSeekChapter(iChapter);
4201 #endif
4202 }
4203
4204 bool CApplication::IsPlayingFullScreenVideo() const
4205 {
4206   return m_pPlayer->IsPlayingVideo() && g_graphicsContext.IsFullScreenVideo();
4207 }
4208
4209 bool CApplication::IsFullScreen()
4210 {
4211   return IsPlayingFullScreenVideo() ||
4212         (g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION) ||
4213          g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW;
4214 }
4215
4216 void CApplication::SaveFileState(bool bForeground /* = false */)
4217 {
4218   if (m_progressTrackingItem->IsPVRChannel() || !CProfilesManager::Get().GetCurrentProfile().canWriteDatabases())
4219     return;
4220
4221   if (bForeground)
4222   {
4223     CSaveFileStateJob job(*m_progressTrackingItem,
4224     *m_stackFileItemToUpdate,
4225     m_progressTrackingVideoResumeBookmark,
4226     m_progressTrackingPlayCountUpdate);
4227
4228     // Run job in the foreground to make sure it finishes
4229     job.DoWork();
4230   }
4231   else
4232   {
4233     CJob* job = new CSaveFileStateJob(*m_progressTrackingItem,
4234         *m_stackFileItemToUpdate,
4235         m_progressTrackingVideoResumeBookmark,
4236         m_progressTrackingPlayCountUpdate);
4237     CJobManager::GetInstance().AddJob(job, NULL, CJob::PRIORITY_NORMAL);
4238   }
4239 }
4240
4241 void CApplication::UpdateFileState()
4242 {
4243   // Did the file change?
4244   if (m_progressTrackingItem->GetPath() != "" && m_progressTrackingItem->GetPath() != CurrentFile())
4245   {
4246     SaveFileState();
4247
4248     // Reset tracking item
4249     m_progressTrackingItem->Reset();
4250   }
4251   else
4252   {
4253     if (m_pPlayer->IsPlaying())
4254     {
4255       if (m_progressTrackingItem->GetPath() == "")
4256       {
4257         // Init some stuff
4258         *m_progressTrackingItem = CurrentFileItem();
4259         m_progressTrackingPlayCountUpdate = false;
4260       }
4261
4262       if ((m_progressTrackingItem->IsAudio() && g_advancedSettings.m_audioPlayCountMinimumPercent > 0 &&
4263           GetPercentage() >= g_advancedSettings.m_audioPlayCountMinimumPercent) ||
4264           (m_progressTrackingItem->IsVideo() && g_advancedSettings.m_videoPlayCountMinimumPercent > 0 &&
4265           GetPercentage() >= g_advancedSettings.m_videoPlayCountMinimumPercent))
4266       {
4267         m_progressTrackingPlayCountUpdate = true;
4268       }
4269
4270       // Check whether we're *really* playing video else we may race when getting eg. stream details
4271       if (m_pPlayer->IsPlayingVideo())
4272       {
4273         /* Always update streamdetails, except for DVDs where we only update
4274            streamdetails if title length > 15m (Should yield more correct info) */
4275         if (!(m_progressTrackingItem->IsDVDImage() || m_progressTrackingItem->IsDVDFile()) || m_pPlayer->GetTotalTime() > 15*60*1000)
4276         {
4277           CStreamDetails details;
4278           // Update with stream details from player, if any
4279           if (m_pPlayer->GetStreamDetails(details))
4280             m_progressTrackingItem->GetVideoInfoTag()->m_streamDetails = details;
4281         }
4282
4283         // Update bookmark for save
4284         m_progressTrackingVideoResumeBookmark.player = CPlayerCoreFactory::Get().GetPlayerName(m_pPlayer->GetCurrentPlayer());
4285         m_progressTrackingVideoResumeBookmark.playerState = m_pPlayer->GetPlayerState();
4286         m_progressTrackingVideoResumeBookmark.thumbNailImage.Empty();
4287
4288         if (g_advancedSettings.m_videoIgnorePercentAtEnd > 0 &&
4289             GetTotalTime() - GetTime() < 0.01f * g_advancedSettings.m_videoIgnorePercentAtEnd * GetTotalTime())
4290         {
4291           // Delete the bookmark
4292           m_progressTrackingVideoResumeBookmark.timeInSeconds = -1.0f;
4293         }
4294         else
4295         if (GetTime() > g_advancedSettings.m_videoIgnoreSecondsAtStart)
4296         {
4297           // Update the bookmark
4298           m_progressTrackingVideoResumeBookmark.timeInSeconds = GetTime();
4299           m_progressTrackingVideoResumeBookmark.totalTimeInSeconds = GetTotalTime();
4300         }
4301         else
4302         {
4303           // Do nothing
4304           m_progressTrackingVideoResumeBookmark.timeInSeconds = 0.0f;
4305         }
4306       }
4307     }
4308   }
4309 }
4310
4311 void CApplication::StopPlaying()
4312 {
4313   int iWin = g_windowManager.GetActiveWindow();
4314   if ( m_pPlayer->IsPlaying() )
4315   {
4316 #ifdef HAS_KARAOKE
4317     if( m_pKaraokeMgr )
4318       m_pKaraokeMgr->Stop();
4319 #endif
4320
4321     if (g_PVRManager.IsPlayingTV() || g_PVRManager.IsPlayingRadio())
4322       g_PVRManager.SaveCurrentChannelSettings();
4323
4324     m_pPlayer->CloseFile();
4325
4326     // turn off visualisation window when stopping
4327     if ((iWin == WINDOW_VISUALISATION
4328     ||  iWin == WINDOW_FULLSCREEN_VIDEO)
4329     && !m_bStop)
4330       g_windowManager.PreviousWindow();
4331
4332     g_partyModeManager.Disable();
4333   }
4334 }
4335
4336 void CApplication::ResetSystemIdleTimer()
4337 {
4338   // reset system idle timer
4339   m_idleTimer.StartZero();
4340 }
4341
4342 void CApplication::ResetScreenSaver()
4343 {
4344   // reset our timers
4345   m_shutdownTimer.StartZero();
4346
4347   // screen saver timer is reset only if we're not already in screensaver or
4348   // DPMS mode
4349   if ((!m_bScreenSave && m_iScreenSaveLock == 0) && !m_dpmsIsActive)
4350     ResetScreenSaverTimer();
4351 }
4352
4353 void CApplication::ResetScreenSaverTimer()
4354 {
4355   m_screenSaverTimer.StartZero();
4356 }
4357
4358 void CApplication::StopScreenSaverTimer()
4359 {
4360   m_screenSaverTimer.Stop();
4361 }
4362
4363 bool CApplication::ToggleDPMS(bool manual)
4364 {
4365   if (manual || (m_dpmsIsManual == manual))
4366   {
4367     if (m_dpmsIsActive)
4368     {
4369       m_dpmsIsActive = false;
4370       m_dpmsIsManual = false;
4371       return m_dpms->DisablePowerSaving();
4372     }
4373     else
4374     {
4375       if (m_dpms->EnablePowerSaving(m_dpms->GetSupportedModes()[0]))
4376       {
4377         m_dpmsIsActive = true;
4378         m_dpmsIsManual = manual;
4379         return true;
4380       }
4381     }
4382   }
4383   return false;
4384 }
4385
4386 bool CApplication::WakeUpScreenSaverAndDPMS(bool bPowerOffKeyPressed /* = false */)
4387 {
4388   bool result;
4389
4390   // First reset DPMS, if active
4391   if (m_dpmsIsActive)
4392   {
4393     if (m_dpmsIsManual)
4394       return false;
4395     // TODO: if screensaver lock is specified but screensaver is not active
4396     // (DPMS came first), activate screensaver now.
4397     ToggleDPMS(false);
4398     ResetScreenSaverTimer();
4399     result = !m_bScreenSave || WakeUpScreenSaver(bPowerOffKeyPressed);
4400   }
4401   else
4402     result = WakeUpScreenSaver(bPowerOffKeyPressed);
4403
4404   if(result)
4405   {
4406     // allow listeners to ignore the deactivation if it preceeds a powerdown/suspend etc
4407     CVariant data(bPowerOffKeyPressed);
4408     CAnnouncementManager::Announce(GUI, "xbmc", "OnScreensaverDeactivated", data);
4409   }
4410
4411   return result;
4412 }
4413
4414 bool CApplication::WakeUpScreenSaver(bool bPowerOffKeyPressed /* = false */)
4415 {
4416   if (m_iScreenSaveLock == 2)
4417     return false;
4418
4419   // if Screen saver is active
4420   if (m_bScreenSave && m_screenSaver)
4421   {
4422     if (m_iScreenSaveLock == 0)
4423       if (CProfilesManager::Get().GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE &&
4424           (CProfilesManager::Get().UsingLoginScreen() || CSettings::Get().GetBool("masterlock.startuplock")) &&
4425           CProfilesManager::Get().GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE &&
4426           m_screenSaver->ID() != "screensaver.xbmc.builtin.dim" && m_screenSaver->ID() != "screensaver.xbmc.builtin.black" && !m_screenSaver->ID().empty() && m_screenSaver->ID() != "visualization")
4427       {
4428         m_iScreenSaveLock = 2;
4429         CGUIMessage msg(GUI_MSG_CHECK_LOCK,0,0);
4430
4431         CGUIWindow* pWindow = g_windowManager.GetWindow(WINDOW_SCREENSAVER);
4432         if (pWindow)
4433           pWindow->OnMessage(msg);
4434       }
4435     if (m_iScreenSaveLock == -1)
4436     {
4437       m_iScreenSaveLock = 0;
4438       return true;
4439     }
4440
4441     // disable screensaver
4442     m_bScreenSave = false;
4443     m_iScreenSaveLock = 0;
4444     ResetScreenSaverTimer();
4445
4446     if (m_screenSaver->ID() == "visualization")
4447     {
4448       // we can just continue as usual from vis mode
4449       return false;
4450     }
4451     else if (m_screenSaver->ID() == "screensaver.xbmc.builtin.dim" || m_screenSaver->ID() == "screensaver.xbmc.builtin.black" || m_screenSaver->ID().empty())
4452       return true;
4453     else if (!m_screenSaver->ID().IsEmpty())
4454     { // we're in screensaver window
4455       if (g_windowManager.GetActiveWindow() == WINDOW_SCREENSAVER)
4456         g_windowManager.PreviousWindow();  // show the previous window
4457       if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW)
4458         CApplicationMessenger::Get().SendAction(CAction(ACTION_STOP), WINDOW_SLIDESHOW);
4459     }
4460     return true;
4461   }
4462   else
4463     return false;
4464 }
4465
4466 void CApplication::CheckScreenSaverAndDPMS()
4467 {
4468   if (m_bInBackground)
4469     return;
4470   if (!m_dpmsIsActive)
4471     g_Windowing.ResetOSScreensaver();
4472
4473   bool maybeScreensaver =
4474       !m_dpmsIsActive && !m_bScreenSave
4475       && !CSettings::Get().GetString("screensaver.mode").empty();
4476   bool maybeDPMS =
4477       !m_dpmsIsActive && m_dpms->IsSupported()
4478       && CSettings::Get().GetInt("powermanagement.displaysoff") > 0;
4479
4480   // Has the screen saver window become active?
4481   if (maybeScreensaver && g_windowManager.IsWindowActive(WINDOW_SCREENSAVER))
4482   {
4483     m_bScreenSave = true;
4484     maybeScreensaver = false;
4485   }
4486
4487   if (m_bScreenSave && m_pPlayer->IsPlayingVideo() && !m_pPlayer->IsPaused())
4488   {
4489     WakeUpScreenSaverAndDPMS();
4490     return;
4491   }
4492
4493   if (!maybeScreensaver && !maybeDPMS) return;  // Nothing to do.
4494
4495   // See if we need to reset timer.
4496   // * Are we playing a video and it is not paused?
4497   if ((m_pPlayer->IsPlayingVideo() && !m_pPlayer->IsPaused())
4498       // * Are we playing some music in fullscreen vis?
4499       || (m_pPlayer->IsPlayingAudio() && g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION
4500           && !CSettings::Get().GetString("musicplayer.visualisation").empty()))
4501   {
4502     ResetScreenSaverTimer();
4503     return;
4504   }
4505
4506   float elapsed = m_screenSaverTimer.GetElapsedSeconds();
4507
4508   // DPMS has priority (it makes the screensaver not needed)
4509   if (maybeDPMS
4510       && elapsed > CSettings::Get().GetInt("powermanagement.displaysoff") * 60)
4511   {
4512     ToggleDPMS(false);
4513     WakeUpScreenSaver();
4514   }
4515   else if (maybeScreensaver
4516            && elapsed > CSettings::Get().GetInt("screensaver.time") * 60)
4517   {
4518     ActivateScreenSaver();
4519   }
4520 }
4521
4522 // activate the screensaver.
4523 // if forceType is true, we ignore the various conditions that can alter
4524 // the type of screensaver displayed
4525 void CApplication::ActivateScreenSaver(bool forceType /*= false */)
4526 {
4527   m_bScreenSave = true;
4528
4529   // Get Screensaver Mode
4530   m_screenSaver.reset();
4531   if (!CAddonMgr::Get().GetAddon(CSettings::Get().GetString("screensaver.mode"), m_screenSaver))
4532     m_screenSaver.reset(new CScreenSaver(""));
4533
4534   CAnnouncementManager::Announce(GUI, "xbmc", "OnScreensaverActivated");
4535
4536   // disable screensaver lock from the login screen
4537   m_iScreenSaveLock = g_windowManager.GetActiveWindow() == WINDOW_LOGIN_SCREEN ? 1 : 0;
4538   if (!forceType)
4539   {
4540     // set to Dim in the case of a dialog on screen or playing video
4541     if (g_windowManager.HasModalDialog() || (m_pPlayer->IsPlayingVideo() && CSettings::Get().GetBool("screensaver.usedimonpause")) || g_PVRManager.IsRunningChannelScan())
4542     {
4543       if (!CAddonMgr::Get().GetAddon("screensaver.xbmc.builtin.dim", m_screenSaver))
4544         m_screenSaver.reset(new CScreenSaver(""));
4545     }
4546     // Check if we are Playing Audio and Vis instead Screensaver!
4547     else if (m_pPlayer->IsPlayingAudio() && CSettings::Get().GetBool("screensaver.usemusicvisinstead") && !CSettings::Get().GetString("musicplayer.visualisation").empty())
4548     { // activate the visualisation
4549       m_screenSaver.reset(new CScreenSaver("visualization"));
4550       g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
4551       return;
4552     }
4553   }
4554   if (m_screenSaver->ID() == "screensaver.xbmc.builtin.dim" || m_screenSaver->ID().empty())
4555     return;
4556   else if (m_screenSaver->ID() == "screensaver.xbmc.builtin.black")
4557     return;
4558   else if (!m_screenSaver->ID().IsEmpty())
4559     g_windowManager.ActivateWindow(WINDOW_SCREENSAVER);
4560 }
4561
4562 void CApplication::SetInBackground(bool background)
4563 {
4564   if (!background)
4565   {
4566     ResetScreenSaverTimer();
4567   }
4568   m_bInBackground = background;
4569 }
4570
4571 void CApplication::CheckShutdown()
4572 {
4573   // first check if we should reset the timer
4574   bool resetTimer = m_bInhibitIdleShutdown;
4575
4576   if (m_pPlayer->IsPlaying() || m_pPlayer->IsPausedPlayback()) // is something playing?
4577     resetTimer = true;
4578
4579   if (m_musicInfoScanner->IsScanning())
4580     resetTimer = true;
4581
4582   if (m_videoInfoScanner->IsScanning())
4583     resetTimer = true;
4584
4585   if (g_windowManager.IsWindowActive(WINDOW_DIALOG_PROGRESS)) // progress dialog is onscreen
4586     resetTimer = true;
4587
4588   if (CSettings::Get().GetBool("pvrmanager.enabled") &&  !g_PVRManager.IsIdle())
4589     resetTimer = true;
4590
4591   if (resetTimer)
4592   {
4593     m_shutdownTimer.StartZero();
4594     return;
4595   }
4596
4597   if ( m_shutdownTimer.GetElapsedSeconds() > CSettings::Get().GetInt("powermanagement.shutdowntime") * 60 )
4598   {
4599     // Since it is a sleep instead of a shutdown, let's set everything to reset when we wake up.
4600     m_shutdownTimer.Stop();
4601
4602     // Sleep the box
4603     CApplicationMessenger::Get().Shutdown();
4604   }
4605 }
4606
4607 void CApplication::InhibitIdleShutdown(bool inhibit)
4608 {
4609   m_bInhibitIdleShutdown = inhibit;
4610 }
4611
4612 bool CApplication::IsIdleShutdownInhibited() const
4613 {
4614   return m_bInhibitIdleShutdown;
4615 }
4616
4617 bool CApplication::OnMessage(CGUIMessage& message)
4618 {
4619   switch ( message.GetMessage() )
4620   {
4621   case GUI_MSG_NOTIFY_ALL:
4622     {
4623       if (message.GetParam1()==GUI_MSG_REMOVED_MEDIA)
4624       {
4625         // Update general playlist: Remove DVD playlist items
4626         int nRemoved = g_playlistPlayer.RemoveDVDItems();
4627         if ( nRemoved > 0 )
4628         {
4629           CGUIMessage msg( GUI_MSG_PLAYLIST_CHANGED, 0, 0 );
4630           g_windowManager.SendMessage( msg );
4631         }
4632         // stop the file if it's on dvd (will set the resume point etc)
4633         if (m_itemCurrentFile->IsOnDVD())
4634           StopPlaying();
4635       }
4636     }
4637     break;
4638
4639   case GUI_MSG_PLAYBACK_STARTED:
4640     {
4641 #ifdef TARGET_DARWIN
4642       DarwinSetScheduling(message.GetMessage());
4643 #endif
4644       // reset the seek handler
4645       m_seekHandler->Reset();
4646       CPlayList playList = g_playlistPlayer.GetPlaylist(g_playlistPlayer.GetCurrentPlaylist());
4647
4648       // Update our infoManager with the new details etc.
4649       if (m_nextPlaylistItem >= 0)
4650       { 
4651         // playing an item which is not in the list - player might be stopped already
4652         // so do nothing
4653         if (playList.size() <= m_nextPlaylistItem)
4654           return true;
4655
4656         // we've started a previously queued item
4657         CFileItemPtr item = playList[m_nextPlaylistItem];
4658         // update the playlist manager
4659         int currentSong = g_playlistPlayer.GetCurrentSong();
4660         int param = ((currentSong & 0xffff) << 16) | (m_nextPlaylistItem & 0xffff);
4661         CGUIMessage msg(GUI_MSG_PLAYLISTPLAYER_CHANGED, 0, 0, g_playlistPlayer.GetCurrentPlaylist(), param, item);
4662         g_windowManager.SendThreadMessage(msg);
4663         g_playlistPlayer.SetCurrentSong(m_nextPlaylistItem);
4664         *m_itemCurrentFile = *item;
4665       }
4666       g_infoManager.SetCurrentItem(*m_itemCurrentFile);
4667       g_partyModeManager.OnSongChange(true);
4668
4669       CVariant param;
4670       param["player"]["speed"] = 1;
4671       param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
4672       CAnnouncementManager::Announce(Player, "xbmc", "OnPlay", m_itemCurrentFile, param);
4673
4674       if (m_pPlayer->IsPlayingAudio())
4675       {
4676         // Start our cdg parser as appropriate
4677 #ifdef HAS_KARAOKE
4678         if (m_pKaraokeMgr && CSettings::Get().GetBool("karaoke.enabled") && !m_itemCurrentFile->IsInternetStream())
4679         {
4680           m_pKaraokeMgr->Stop();
4681           if (m_itemCurrentFile->IsMusicDb())
4682           {
4683             if (!m_itemCurrentFile->HasMusicInfoTag() || !m_itemCurrentFile->GetMusicInfoTag()->Loaded())
4684             {
4685               IMusicInfoTagLoader* tagloader = CMusicInfoTagLoaderFactory::CreateLoader(m_itemCurrentFile->GetPath());
4686               tagloader->Load(m_itemCurrentFile->GetPath(),*m_itemCurrentFile->GetMusicInfoTag());
4687               delete tagloader;
4688             }
4689             m_pKaraokeMgr->Start(m_itemCurrentFile->GetMusicInfoTag()->GetURL());
4690           }
4691           else
4692             m_pKaraokeMgr->Start(m_itemCurrentFile->GetPath());
4693         }
4694 #endif
4695       }
4696
4697       return true;
4698     }
4699     break;
4700
4701   case GUI_MSG_QUEUE_NEXT_ITEM:
4702     {
4703       // Check to see if our playlist player has a new item for us,
4704       // and if so, we check whether our current player wants the file
4705       int iNext = g_playlistPlayer.GetNextSong();
4706       CPlayList& playlist = g_playlistPlayer.GetPlaylist(g_playlistPlayer.GetCurrentPlaylist());
4707       if (iNext < 0 || iNext >= playlist.size())
4708       {
4709         m_pPlayer->OnNothingToQueueNotify();
4710         return true; // nothing to do
4711       }
4712
4713       // ok, grab the next song
4714       CFileItem file(*playlist[iNext]);
4715       // handle plugin://
4716       CURL url(file.GetPath());
4717       if (url.GetProtocol() == "plugin")
4718         XFILE::CPluginDirectory::GetPluginResult(url.Get(), file);
4719
4720 #ifdef HAS_UPNP
4721       if (URIUtils::IsUPnP(file.GetPath()))
4722       {
4723         if (!XFILE::CUPnPDirectory::GetResource(file.GetPath(), file))
4724           return true;
4725       }
4726 #endif
4727
4728       // ok - send the file to the player, if it accepts it
4729       if (m_pPlayer->QueueNextFile(file))
4730       {
4731         // player accepted the next file
4732         m_nextPlaylistItem = iNext;
4733       }
4734       else
4735       {
4736         /* Player didn't accept next file: *ALWAYS* advance playlist in this case so the player can
4737             queue the next (if it wants to) and it doesn't keep looping on this song */
4738         g_playlistPlayer.SetCurrentSong(iNext);
4739       }
4740
4741       return true;
4742     }
4743     break;
4744
4745   case GUI_MSG_PLAYBACK_STOPPED:
4746   case GUI_MSG_PLAYBACK_ENDED:
4747   case GUI_MSG_PLAYLISTPLAYER_STOPPED:
4748     {
4749 #ifdef HAS_KARAOKE
4750       if (m_pKaraokeMgr )
4751         m_pKaraokeMgr->Stop();
4752 #endif
4753 #ifdef TARGET_DARWIN
4754       DarwinSetScheduling(message.GetMessage());
4755 #endif
4756       // first check if we still have items in the stack to play
4757       if (message.GetMessage() == GUI_MSG_PLAYBACK_ENDED)
4758       {
4759         if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0 && m_currentStackPosition < m_currentStack->Size() - 1)
4760         { // just play the next item in the stack
4761           PlayFile(*(*m_currentStack)[++m_currentStackPosition], true);
4762           return true;
4763         }
4764       }
4765
4766       // In case playback ended due to user eg. skipping over the end, clear
4767       // our resume bookmark here
4768       if (message.GetMessage() == GUI_MSG_PLAYBACK_ENDED && m_progressTrackingPlayCountUpdate && g_advancedSettings.m_videoIgnorePercentAtEnd > 0)
4769       {
4770         // Delete the bookmark
4771         m_progressTrackingVideoResumeBookmark.timeInSeconds = -1.0f;
4772       }
4773
4774       // reset the current playing file
4775       m_itemCurrentFile->Reset();
4776       g_infoManager.ResetCurrentItem();
4777       m_currentStack->Clear();
4778
4779       if (message.GetMessage() == GUI_MSG_PLAYBACK_ENDED)
4780       {
4781         g_playlistPlayer.PlayNext(1, true);
4782       }
4783       else
4784       {
4785         // reset any forced player
4786         m_eForcedNextPlayer = EPC_NONE;
4787
4788         m_pPlayer->ClosePlayer();
4789
4790         // Reset playspeed
4791         m_pPlayer->m_iPlaySpeed = 1;
4792       }
4793
4794       if (!m_pPlayer->IsPlaying())
4795       {
4796         g_audioManager.Enable(true);
4797       }
4798
4799       if (!m_pPlayer->IsPlayingVideo())
4800       {
4801         if(g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
4802         {
4803           g_windowManager.PreviousWindow();
4804         }
4805         else
4806         {
4807           CSingleLock lock(g_graphicsContext);
4808           //  resets to res_desktop or look&feel resolution (including refreshrate)
4809           g_graphicsContext.SetFullScreenVideo(false);
4810         }
4811       }
4812
4813       if (!m_pPlayer->IsPlayingAudio() && g_playlistPlayer.GetCurrentPlaylist() == PLAYLIST_NONE && g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION)
4814       {
4815         CSettings::Get().Save();  // save vis settings
4816         WakeUpScreenSaverAndDPMS();
4817         g_windowManager.PreviousWindow();
4818       }
4819
4820       // DVD ejected while playing in vis ?
4821       if (!m_pPlayer->IsPlayingAudio() && (m_itemCurrentFile->IsCDDA() || m_itemCurrentFile->IsOnDVD()) && !g_mediaManager.IsDiscInDrive() && g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION)
4822       {
4823         // yes, disable vis
4824         CSettings::Get().Save();    // save vis settings
4825         WakeUpScreenSaverAndDPMS();
4826         g_windowManager.PreviousWindow();
4827       }
4828
4829       if (IsEnableTestMode())
4830         CApplicationMessenger::Get().Quit();
4831       return true;
4832     }
4833     break;
4834
4835   case GUI_MSG_PLAYLISTPLAYER_STARTED:
4836   case GUI_MSG_PLAYLISTPLAYER_CHANGED:
4837     {
4838       return true;
4839     }
4840     break;
4841   case GUI_MSG_FULLSCREEN:
4842     { // Switch to fullscreen, if we can
4843       SwitchToFullScreen();
4844       return true;
4845     }
4846     break;
4847   case GUI_MSG_EXECUTE:
4848     if (message.GetNumStringParams())
4849       return ExecuteXBMCAction(message.GetStringParam());
4850     break;
4851   }
4852   return false;
4853 }
4854
4855 bool CApplication::ExecuteXBMCAction(std::string actionStr)
4856 {
4857   // see if it is a user set string
4858   CLog::Log(LOGDEBUG,"%s : Translating %s", __FUNCTION__, actionStr.c_str());
4859   CGUIInfoLabel info(actionStr, "");
4860   actionStr = info.GetLabel(0);
4861   CLog::Log(LOGDEBUG,"%s : To %s", __FUNCTION__, actionStr.c_str());
4862
4863   // user has asked for something to be executed
4864   if (CBuiltins::HasCommand(actionStr))
4865     CBuiltins::Execute(actionStr);
4866   else
4867   {
4868     // try translating the action from our ButtonTranslator
4869     int actionID;
4870     if (CButtonTranslator::TranslateActionString(actionStr.c_str(), actionID))
4871     {
4872       OnAction(CAction(actionID));
4873       return true;
4874     }
4875     CFileItem item(actionStr, false);
4876 #ifdef HAS_PYTHON
4877     if (item.IsPythonScript())
4878     { // a python script
4879       CScriptInvocationManager::Get().Execute(item.GetPath());
4880     }
4881     else
4882 #endif
4883     if (item.IsAudio() || item.IsVideo())
4884     { // an audio or video file
4885       PlayFile(item);
4886     }
4887     else
4888       return false;
4889   }
4890   return true;
4891 }
4892
4893 void CApplication::Process()
4894 {
4895   MEASURE_FUNCTION;
4896
4897   // dispatch the messages generated by python or other threads to the current window
4898   g_windowManager.DispatchThreadMessages();
4899
4900   // process messages which have to be send to the gui
4901   // (this can only be done after g_windowManager.Render())
4902   CApplicationMessenger::Get().ProcessWindowMessages();
4903
4904   if (m_loggingIn)
4905   {
4906     m_loggingIn = false;
4907
4908     // autoexec.py - profile
4909     CStdString strAutoExecPy = CSpecialProtocol::TranslatePath("special://profile/autoexec.py");
4910
4911     if (XFILE::CFile::Exists(strAutoExecPy))
4912       CScriptInvocationManager::Get().Execute(strAutoExecPy);
4913     else
4914       CLog::Log(LOGDEBUG, "no profile autoexec.py (%s) found, skipping", strAutoExecPy.c_str());
4915   }
4916
4917   // handle any active scripts
4918   CScriptInvocationManager::Get().Process();
4919
4920   // process messages, even if a movie is playing
4921   CApplicationMessenger::Get().ProcessMessages();
4922   if (g_application.m_bStop) return; //we're done, everything has been unloaded
4923
4924   // check how far we are through playing the current item
4925   // and do anything that needs doing (playcount updates etc)
4926   CheckPlayingProgress();
4927
4928   // update sound
4929   m_pPlayer->DoAudioWork();
4930
4931   // do any processing that isn't needed on each run
4932   if( m_slowTimer.GetElapsedMilliseconds() > 500 )
4933   {
4934     m_slowTimer.Reset();
4935     ProcessSlow();
4936   }
4937
4938   g_cpuInfo.getUsedPercentage(); // must call it to recalculate pct values
4939 }
4940
4941 // We get called every 500ms
4942 void CApplication::ProcessSlow()
4943 {
4944   g_powerManager.ProcessEvents();
4945
4946 #if defined(TARGET_DARWIN_OSX)
4947   // There is an issue on OS X that several system services ask the cursor to become visible
4948   // during their startup routines.  Given that we can't control this, we hack it in by
4949   // forcing the
4950   if (g_Windowing.IsFullScreen())
4951   { // SDL thinks it's hidden
4952     Cocoa_HideMouse();
4953   }
4954 #endif
4955
4956   // Resume low priority jobs when current item is not video
4957   if (!CurrentFileItem().IsVideo())
4958   {
4959     CJobManager::GetInstance().UnPause(CJob::PRIORITY_LOW);
4960   }
4961
4962   // Store our file state for use on close()
4963   UpdateFileState();
4964
4965   // Check if we need to activate the screensaver / DPMS.
4966   CheckScreenSaverAndDPMS();
4967
4968   // Check if we need to shutdown (if enabled).
4969 #if defined(TARGET_DARWIN)
4970   if (CSettings::Get().GetInt("powermanagement.shutdowntime") && g_advancedSettings.m_fullScreen)
4971 #else
4972   if (CSettings::Get().GetInt("powermanagement.shutdowntime"))
4973 #endif
4974   {
4975     CheckShutdown();
4976   }
4977
4978   // check if we should restart the player
4979   CheckDelayedPlayerRestart();
4980
4981   //  check if we can unload any unreferenced dlls or sections
4982   if (!m_pPlayer->IsPlayingVideo())
4983     CSectionLoader::UnloadDelayed();
4984
4985   // check for any idle curl connections
4986   g_curlInterface.CheckIdle();
4987
4988   // check for any idle myth sessions
4989   CMythSession::CheckIdle();
4990
4991 #ifdef HAS_FILESYSTEM_HTSP
4992   // check for any idle htsp sessions
4993   HTSP::CHTSPDirectorySession::CheckIdle();
4994 #endif
4995
4996 #ifdef HAS_KARAOKE
4997   if ( m_pKaraokeMgr )
4998     m_pKaraokeMgr->ProcessSlow();
4999 #endif
5000
5001   if (!m_pPlayer->IsPlayingVideo())
5002     g_largeTextureManager.CleanupUnusedImages();
5003
5004   g_TextureManager.FreeUnusedTextures(5000);
5005
5006 #ifdef HAS_DVD_DRIVE
5007   // checks whats in the DVD drive and tries to autostart the content (xbox games, dvd, cdda, avi files...)
5008   if (!m_pPlayer->IsPlayingVideo())
5009     m_Autorun->HandleAutorun();
5010 #endif
5011
5012   // update upnp server/renderer states
5013 #ifdef HAS_UPNP
5014   if(UPNP::CUPnP::IsInstantiated())
5015     UPNP::CUPnP::GetInstance()->UpdateState();
5016 #endif
5017
5018 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
5019   smb.CheckIfIdle();
5020 #endif
5021
5022 #ifdef HAS_FILESYSTEM_NFS
5023   gNfsConnection.CheckIfIdle();
5024 #endif
5025
5026 #ifdef HAS_FILESYSTEM_AFP
5027   gAfpConnection.CheckIfIdle();
5028 #endif
5029
5030 #ifdef HAS_FILESYSTEM_SFTP
5031   CSFTPSessionManager::ClearOutIdleSessions();
5032 #endif
5033
5034   g_mediaManager.ProcessEvents();
5035
5036 #ifdef HAS_LIRC
5037   if (g_RemoteControl.IsInUse() && !g_RemoteControl.IsInitialized())
5038     g_RemoteControl.Initialize();
5039 #endif
5040
5041   if (!m_pPlayer->IsPlayingVideo())
5042     CAddonInstaller::Get().UpdateRepos();
5043
5044   CAEFactory::GarbageCollect();
5045 }
5046
5047 // Global Idle Time in Seconds
5048 // idle time will be resetet if on any OnKey()
5049 // int return: system Idle time in seconds! 0 is no idle!
5050 int CApplication::GlobalIdleTime()
5051 {
5052   if(!m_idleTimer.IsRunning())
5053   {
5054     m_idleTimer.Stop();
5055     m_idleTimer.StartZero();
5056   }
5057   return (int)m_idleTimer.GetElapsedSeconds();
5058 }
5059
5060 float CApplication::NavigationIdleTime()
5061 {
5062   if (!m_navigationTimer.IsRunning())
5063   {
5064     m_navigationTimer.Stop();
5065     m_navigationTimer.StartZero();
5066   }
5067   return m_navigationTimer.GetElapsedSeconds();
5068 }
5069
5070 void CApplication::DelayedPlayerRestart()
5071 {
5072   m_restartPlayerTimer.StartZero();
5073 }
5074
5075 void CApplication::CheckDelayedPlayerRestart()
5076 {
5077   if (m_restartPlayerTimer.GetElapsedSeconds() > 3)
5078   {
5079     m_restartPlayerTimer.Stop();
5080     m_restartPlayerTimer.Reset();
5081     Restart(true);
5082   }
5083 }
5084
5085 void CApplication::Restart(bool bSamePosition)
5086 {
5087   // this function gets called when the user changes a setting (like noninterleaved)
5088   // and which means we gotta close & reopen the current playing file
5089
5090   // first check if we're playing a file
5091   if ( !m_pPlayer->IsPlayingVideo() && !m_pPlayer->IsPlayingAudio())
5092     return ;
5093
5094   if( !m_pPlayer->HasPlayer() )
5095     return ;
5096
5097   SaveFileState();
5098
5099   // do we want to return to the current position in the file
5100   if (false == bSamePosition)
5101   {
5102     // no, then just reopen the file and start at the beginning
5103     PlayFile(*m_itemCurrentFile, true);
5104     return ;
5105   }
5106
5107   // else get current position
5108   double time = GetTime();
5109
5110   // get player state, needed for dvd's
5111   CStdString state = m_pPlayer->GetPlayerState();
5112
5113   // set the requested starttime
5114   m_itemCurrentFile->m_lStartOffset = (long)(time * 75.0);
5115
5116   // reopen the file
5117   if ( PlayFile(*m_itemCurrentFile, true) == PLAYBACK_OK )
5118     m_pPlayer->SetPlayerState(state);
5119 }
5120
5121 const CStdString& CApplication::CurrentFile()
5122 {
5123   return m_itemCurrentFile->GetPath();
5124 }
5125
5126 CFileItem& CApplication::CurrentFileItem()
5127 {
5128   return *m_itemCurrentFile;
5129 }
5130
5131 void CApplication::ShowVolumeBar(const CAction *action)
5132 {
5133   CGUIDialog *volumeBar = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_VOLUME_BAR);
5134   if (volumeBar)
5135   {
5136     volumeBar->Show();
5137     if (action)
5138       volumeBar->OnAction(*action);
5139   }
5140 }
5141
5142 bool CApplication::IsMuted() const
5143 {
5144   if (g_peripherals.IsMuted())
5145     return true;
5146   return CAEFactory::IsMuted();
5147 }
5148
5149 void CApplication::ToggleMute(void)
5150 {
5151   if (m_muted)
5152     UnMute();
5153   else
5154     Mute();
5155 }
5156
5157 void CApplication::SetMute(bool mute)
5158 {
5159   if (m_muted != mute)
5160   {
5161     ToggleMute();
5162     m_muted = mute;
5163   }
5164 }
5165
5166 void CApplication::Mute()
5167 {
5168   if (g_peripherals.Mute())
5169     return;
5170
5171   CAEFactory::SetMute(true);
5172   m_muted = true;
5173   VolumeChanged();
5174 }
5175
5176 void CApplication::UnMute()
5177 {
5178   if (g_peripherals.UnMute())
5179     return;
5180
5181   CAEFactory::SetMute(false);
5182   m_muted = false;
5183   VolumeChanged();
5184 }
5185
5186 void CApplication::SetVolume(float iValue, bool isPercentage/*=true*/)
5187 {
5188   float hardwareVolume = iValue;
5189
5190   if(isPercentage)
5191     hardwareVolume /= 100.0f;
5192
5193   SetHardwareVolume(hardwareVolume);
5194   VolumeChanged();
5195 }
5196
5197 void CApplication::SetHardwareVolume(float hardwareVolume)
5198 {
5199   hardwareVolume = std::max(VOLUME_MINIMUM, std::min(VOLUME_MAXIMUM, hardwareVolume));
5200   m_volumeLevel = hardwareVolume;
5201
5202   float value = 0.0f;
5203   if (hardwareVolume > VOLUME_MINIMUM)
5204   {
5205     float dB = CAEUtil::PercentToGain(hardwareVolume);
5206     value = CAEUtil::GainToScale(dB);
5207   }
5208   if (value >= 0.99f)
5209     value = 1.0f;
5210
5211   CAEFactory::SetVolume(value);
5212 }
5213
5214 float CApplication::GetVolume(bool percentage /* = true */) const
5215 {
5216   if (percentage)
5217   {
5218     // converts the hardware volume to a percentage
5219     return m_volumeLevel * 100.0f;
5220   }
5221   
5222   return m_volumeLevel;
5223 }
5224
5225 void CApplication::VolumeChanged() const
5226 {
5227   CVariant data(CVariant::VariantTypeObject);
5228   data["volume"] = GetVolume();
5229   data["muted"] = m_muted;
5230   CAnnouncementManager::Announce(Application, "xbmc", "OnVolumeChanged", data);
5231
5232   // if player has volume control, set it.
5233   if (m_pPlayer->ControlsVolume())
5234   {
5235      m_pPlayer->SetVolume(m_volumeLevel);
5236      m_pPlayer->SetMute(m_muted);
5237   }
5238 }
5239
5240 int CApplication::GetSubtitleDelay() const
5241 {
5242   // converts subtitle delay to a percentage
5243   return int(((float)(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleDelay + g_advancedSettings.m_videoSubsDelayRange)) / (2 * g_advancedSettings.m_videoSubsDelayRange)*100.0f + 0.5f);
5244 }
5245
5246 int CApplication::GetAudioDelay() const
5247 {
5248   // converts audio delay to a percentage
5249   return int(((float)(CMediaSettings::Get().GetCurrentVideoSettings().m_AudioDelay + g_advancedSettings.m_videoAudioDelayRange)) / (2 * g_advancedSettings.m_videoAudioDelayRange)*100.0f + 0.5f);
5250 }
5251
5252 // Returns the total time in seconds of the current media.  Fractional
5253 // portions of a second are possible - but not necessarily supported by the
5254 // player class.  This returns a double to be consistent with GetTime() and
5255 // SeekTime().
5256 double CApplication::GetTotalTime() const
5257 {
5258   double rc = 0.0;
5259
5260   if (m_pPlayer->IsPlaying())
5261   {
5262     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5263       rc = (*m_currentStack)[m_currentStack->Size() - 1]->m_lEndOffset;
5264     else
5265       rc = static_cast<double>(m_pPlayer->GetTotalTime() * 0.001f);
5266   }
5267
5268   return rc;
5269 }
5270
5271 void CApplication::StopShutdownTimer()
5272 {
5273   if (m_shutdownTimer.IsRunning())
5274     m_shutdownTimer.Stop();
5275 }
5276
5277 void CApplication::ResetShutdownTimers()
5278 {
5279   // reset system shutdown timer
5280   m_shutdownTimer.StartZero();
5281
5282   // delete custom shutdown timer
5283   if (g_alarmClock.HasAlarm("shutdowntimer"))
5284     g_alarmClock.Stop("shutdowntimer", true);
5285 }
5286
5287 // Returns the current time in seconds of the currently playing media.
5288 // Fractional portions of a second are possible.  This returns a double to
5289 // be consistent with GetTotalTime() and SeekTime().
5290 double CApplication::GetTime() const
5291 {
5292   double rc = 0.0;
5293
5294   if (m_pPlayer->IsPlaying())
5295   {
5296     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5297     {
5298       long startOfCurrentFile = (m_currentStackPosition > 0) ? (*m_currentStack)[m_currentStackPosition-1]->m_lEndOffset : 0;
5299       rc = (double)startOfCurrentFile + m_pPlayer->GetTime() * 0.001;
5300     }
5301     else
5302       rc = static_cast<double>(m_pPlayer->GetTime() * 0.001f);
5303   }
5304
5305   return rc;
5306 }
5307
5308 // Sets the current position of the currently playing media to the specified
5309 // time in seconds.  Fractional portions of a second are valid.  The passed
5310 // time is the time offset from the beginning of the file as opposed to a
5311 // delta from the current position.  This method accepts a double to be
5312 // consistent with GetTime() and GetTotalTime().
5313 void CApplication::SeekTime( double dTime )
5314 {
5315   if (m_pPlayer->IsPlaying() && (dTime >= 0.0))
5316   {
5317     if (!m_pPlayer->CanSeek()) return;
5318     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5319     {
5320       // find the item in the stack we are seeking to, and load the new
5321       // file if necessary, and calculate the correct seek within the new
5322       // file.  Otherwise, just fall through to the usual routine if the
5323       // time is higher than our total time.
5324       for (int i = 0; i < m_currentStack->Size(); i++)
5325       {
5326         if ((*m_currentStack)[i]->m_lEndOffset > dTime)
5327         {
5328           long startOfNewFile = (i > 0) ? (*m_currentStack)[i-1]->m_lEndOffset : 0;
5329           if (m_currentStackPosition == i)
5330             m_pPlayer->SeekTime((int64_t)((dTime - startOfNewFile) * 1000.0));
5331           else
5332           { // seeking to a new file
5333             m_currentStackPosition = i;
5334             CFileItem item(*(*m_currentStack)[i]);
5335             item.m_lStartOffset = (long)((dTime - startOfNewFile) * 75.0);
5336             // don't just call "PlayFile" here, as we are quite likely called from the
5337             // player thread, so we won't be able to delete ourselves.
5338             CApplicationMessenger::Get().PlayFile(item, true);
5339           }
5340           return;
5341         }
5342       }
5343     }
5344     // convert to milliseconds and perform seek
5345     m_pPlayer->SeekTime( static_cast<int64_t>( dTime * 1000.0 ) );
5346   }
5347 }
5348
5349 float CApplication::GetPercentage() const
5350 {
5351   if (m_pPlayer->IsPlaying())
5352   {
5353     if (m_pPlayer->GetTotalTime() == 0 && m_pPlayer->IsPlayingAudio() && m_itemCurrentFile->HasMusicInfoTag())
5354     {
5355       const CMusicInfoTag& tag = *m_itemCurrentFile->GetMusicInfoTag();
5356       if (tag.GetDuration() > 0)
5357         return (float)(GetTime() / tag.GetDuration() * 100);
5358     }
5359
5360     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5361     {
5362       double totalTime = GetTotalTime();
5363       if (totalTime > 0.0f)
5364         return (float)(GetTime() / totalTime * 100);
5365     }
5366     else
5367       return m_pPlayer->GetPercentage();
5368   }
5369   return 0.0f;
5370 }
5371
5372 float CApplication::GetCachePercentage() const
5373 {
5374   if (m_pPlayer->IsPlaying())
5375   {
5376     // Note that the player returns a relative cache percentage and we want an absolute percentage
5377     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5378     {
5379       float stackedTotalTime = (float) GetTotalTime();
5380       // We need to take into account the stack's total time vs. currently playing file's total time
5381       if (stackedTotalTime > 0.0f)
5382         return min( 100.0f, GetPercentage() + (m_pPlayer->GetCachePercentage() * m_pPlayer->GetTotalTime() * 0.001f / stackedTotalTime ) );
5383     }
5384     else
5385       return min( 100.0f, m_pPlayer->GetPercentage() + m_pPlayer->GetCachePercentage() );
5386   }
5387   return 0.0f;
5388 }
5389
5390 void CApplication::SeekPercentage(float percent)
5391 {
5392   if (m_pPlayer->IsPlaying() && (percent >= 0.0))
5393   {
5394     if (!m_pPlayer->CanSeek()) return;
5395     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5396       SeekTime(percent * 0.01 * GetTotalTime());
5397     else
5398       m_pPlayer->SeekPercentage(percent);
5399   }
5400 }
5401
5402 // SwitchToFullScreen() returns true if a switch is made, else returns false
5403 bool CApplication::SwitchToFullScreen()
5404 {
5405   // if playing from the video info window, close it first!
5406   if (g_windowManager.HasModalDialog() && g_windowManager.GetTopMostModalDialogID() == WINDOW_DIALOG_VIDEO_INFO)
5407   {
5408     CGUIDialogVideoInfo* pDialog = (CGUIDialogVideoInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_INFO);
5409     if (pDialog) pDialog->Close(true);
5410   }
5411
5412   // don't switch if there is a dialog on screen or the slideshow is active
5413   if (/*g_windowManager.HasModalDialog() ||*/ g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW)
5414     return false;
5415
5416   // See if we're playing a video, and are in GUI mode
5417   if ( m_pPlayer->IsPlayingVideo() && g_windowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO)
5418   {
5419     // then switch to fullscreen mode
5420     g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
5421     return true;
5422   }
5423   // special case for switching between GUI & visualisation mode. (only if we're playing an audio song)
5424   if (m_pPlayer->IsPlayingAudio() && g_windowManager.GetActiveWindow() != WINDOW_VISUALISATION)
5425   { // then switch to visualisation
5426     g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
5427     return true;
5428   }
5429   return false;
5430 }
5431
5432 void CApplication::Minimize()
5433 {
5434   g_Windowing.Minimize();
5435 }
5436
5437 PLAYERCOREID CApplication::GetCurrentPlayer()
5438 {
5439   return m_pPlayer->GetCurrentPlayer();
5440 }
5441
5442 void CApplication::UpdateLibraries()
5443 {
5444   if (CSettings::Get().GetBool("videolibrary.updateonstartup"))
5445   {
5446     CLog::Log(LOGNOTICE, "%s - Starting video library startup scan", __FUNCTION__);
5447     StartVideoScan("");
5448   }
5449
5450   if (CSettings::Get().GetBool("musiclibrary.updateonstartup"))
5451   {
5452     CLog::Log(LOGNOTICE, "%s - Starting music library startup scan", __FUNCTION__);
5453     StartMusicScan("");
5454   }
5455 }
5456
5457 bool CApplication::IsVideoScanning() const
5458 {
5459   return m_videoInfoScanner->IsScanning();
5460 }
5461
5462 bool CApplication::IsMusicScanning() const
5463 {
5464   return m_musicInfoScanner->IsScanning();
5465 }
5466
5467 void CApplication::StopVideoScan()
5468 {
5469   if (m_videoInfoScanner->IsScanning())
5470     m_videoInfoScanner->Stop();
5471 }
5472
5473 void CApplication::StopMusicScan()
5474 {
5475   if (m_musicInfoScanner->IsScanning())
5476     m_musicInfoScanner->Stop();
5477 }
5478
5479 void CApplication::StartVideoCleanup()
5480 {
5481   if (m_videoInfoScanner->IsScanning())
5482     return;
5483
5484   m_videoInfoScanner->CleanDatabase();
5485 }
5486
5487 void CApplication::StartVideoScan(const CStdString &strDirectory, bool scanAll)
5488 {
5489   if (m_videoInfoScanner->IsScanning())
5490     return;
5491
5492   m_videoInfoScanner->ShowDialog(true);
5493
5494   m_videoInfoScanner->Start(strDirectory,scanAll);
5495 }
5496
5497 void CApplication::StartMusicScan(const CStdString &strDirectory, int flags)
5498 {
5499   if (m_musicInfoScanner->IsScanning())
5500     return;
5501
5502   if (!flags)
5503   { // setup default flags
5504     if (CSettings::Get().GetBool("musiclibrary.downloadinfo"))
5505       flags |= CMusicInfoScanner::SCAN_ONLINE;
5506     if (CSettings::Get().GetBool("musiclibrary.backgroundupdate"))
5507       flags |= CMusicInfoScanner::SCAN_BACKGROUND;
5508   }
5509
5510   if (!(flags & CMusicInfoScanner::SCAN_BACKGROUND))
5511     m_musicInfoScanner->ShowDialog(true);
5512
5513   m_musicInfoScanner->Start(strDirectory, flags);
5514 }
5515
5516 void CApplication::StartMusicAlbumScan(const CStdString& strDirectory,
5517                                        bool refresh)
5518 {
5519   if (m_musicInfoScanner->IsScanning())
5520     return;
5521
5522   m_musicInfoScanner->ShowDialog(true);
5523
5524   m_musicInfoScanner->FetchAlbumInfo(strDirectory,refresh);
5525 }
5526
5527 void CApplication::StartMusicArtistScan(const CStdString& strDirectory,
5528                                         bool refresh)
5529 {
5530   if (m_musicInfoScanner->IsScanning())
5531     return;
5532
5533   m_musicInfoScanner->ShowDialog(true);
5534
5535   m_musicInfoScanner->FetchArtistInfo(strDirectory,refresh);
5536 }
5537
5538 void CApplication::CheckPlayingProgress()
5539 {
5540   // check if we haven't rewound past the start of the file
5541   if (m_pPlayer->IsPlaying())
5542   {
5543     int iSpeed = g_application.m_pPlayer->GetPlaySpeed();
5544     if (iSpeed < 1)
5545     {
5546       iSpeed *= -1;
5547       int iPower = 0;
5548       while (iSpeed != 1)
5549       {
5550         iSpeed >>= 1;
5551         iPower++;
5552       }
5553       if (g_infoManager.GetPlayTime() / 1000 < iPower)
5554       {
5555         g_application.m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
5556         g_application.SeekTime(0);
5557       }
5558     }
5559   }
5560 }
5561
5562 bool CApplication::ProcessAndStartPlaylist(const CStdString& strPlayList, CPlayList& playlist, int iPlaylist, int track)
5563 {
5564   CLog::Log(LOGDEBUG,"CApplication::ProcessAndStartPlaylist(%s, %i)",strPlayList.c_str(), iPlaylist);
5565
5566   // initial exit conditions
5567   // no songs in playlist just return
5568   if (playlist.size() == 0)
5569     return false;
5570
5571   // illegal playlist
5572   if (iPlaylist < PLAYLIST_MUSIC || iPlaylist > PLAYLIST_VIDEO)
5573     return false;
5574
5575   // setup correct playlist
5576   g_playlistPlayer.ClearPlaylist(iPlaylist);
5577
5578   // if the playlist contains an internet stream, this file will be used
5579   // to generate a thumbnail for musicplayer.cover
5580   g_application.m_strPlayListFile = strPlayList;
5581
5582   // add the items to the playlist player
5583   g_playlistPlayer.Add(iPlaylist, playlist);
5584
5585   // if we have a playlist
5586   if (g_playlistPlayer.GetPlaylist(iPlaylist).size())
5587   {
5588     // start playing it
5589     g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
5590     g_playlistPlayer.Reset();
5591     g_playlistPlayer.Play(track);
5592     return true;
5593   }
5594   return false;
5595 }
5596
5597 void CApplication::SaveCurrentFileSettings()
5598 {
5599   // don't store settings for PVR in video database
5600   if (m_itemCurrentFile->IsVideo() && !m_itemCurrentFile->IsPVRChannel())
5601   {
5602     // save video settings
5603     if (CMediaSettings::Get().GetCurrentVideoSettings() != CMediaSettings::Get().GetDefaultVideoSettings())
5604     {
5605       CVideoDatabase dbs;
5606       dbs.Open();
5607       dbs.SetVideoSettings(m_itemCurrentFile->GetPath(), CMediaSettings::Get().GetCurrentVideoSettings());
5608       dbs.Close();
5609     }
5610   }
5611   else if (m_itemCurrentFile->IsPVRChannel())
5612   {
5613     g_PVRManager.SaveCurrentChannelSettings();
5614   }
5615 }
5616
5617 bool CApplication::AlwaysProcess(const CAction& action)
5618 {
5619   // check if this button is mapped to a built-in function
5620   if (!action.GetName().IsEmpty())
5621   {
5622     CStdString builtInFunction;
5623     vector<CStdString> params;
5624     CUtil::SplitExecFunction(action.GetName(), builtInFunction, params);
5625     builtInFunction.ToLower();
5626
5627     // should this button be handled normally or just cancel the screensaver?
5628     if (   builtInFunction.Equals("powerdown")
5629         || builtInFunction.Equals("reboot")
5630         || builtInFunction.Equals("restart")
5631         || builtInFunction.Equals("restartapp")
5632         || builtInFunction.Equals("suspend")
5633         || builtInFunction.Equals("hibernate")
5634         || builtInFunction.Equals("quit")
5635         || builtInFunction.Equals("shutdown"))
5636     {
5637       return true;
5638     }
5639   }
5640
5641   return false;
5642 }
5643
5644 bool CApplication::IsCurrentThread() const
5645 {
5646   return CThread::IsCurrentThread(m_threadID);
5647 }
5648
5649 void CApplication::SetRenderGUI(bool renderGUI)
5650 {
5651   if (renderGUI && ! m_renderGUI)
5652     g_windowManager.MarkDirty();
5653   m_renderGUI = renderGUI;
5654 }
5655
5656 CNetwork& CApplication::getNetwork()
5657 {
5658   return *m_network;
5659 }
5660 #ifdef HAS_PERFORMANCE_SAMPLE
5661 CPerformanceStats &CApplication::GetPerformanceStats()
5662 {
5663   return m_perfStats;
5664 }
5665 #endif
5666
5667 bool CApplication::SetLanguage(const CStdString &strLanguage)
5668 {
5669   CStdString strPreviousLanguage = CSettings::Get().GetString("locale.language");
5670   CStdString strNewLanguage = strLanguage;
5671   if (strNewLanguage != strPreviousLanguage)
5672   {
5673     CStdString strLangInfoPath;
5674     strLangInfoPath.Format("special://xbmc/language/%s/langinfo.xml", strNewLanguage.c_str());
5675     if (!g_langInfo.Load(strLangInfoPath))
5676       return false;
5677
5678     if (g_langInfo.ForceUnicodeFont() && !g_fontManager.IsFontSetUnicode())
5679     {
5680       CLog::Log(LOGINFO, "Language needs a ttf font, loading first ttf font available");
5681       CStdString strFontSet;
5682       if (g_fontManager.GetFirstFontSetUnicode(strFontSet))
5683         strNewLanguage = strFontSet;
5684       else
5685         CLog::Log(LOGERROR, "No ttf font found but needed: %s", strFontSet.c_str());
5686     }
5687     CSettings::Get().SetString("locale.language", strNewLanguage);
5688
5689     g_charsetConverter.reset();
5690
5691     if (!g_localizeStrings.Load("special://xbmc/language/", strNewLanguage))
5692       return false;
5693
5694     // also tell our weather and skin to reload as these are localized
5695     g_weatherManager.Refresh();
5696     g_PVRManager.LocalizationChanged();
5697     ReloadSkin();
5698   }
5699
5700   return true;
5701 }
5702
5703 void CApplication::CloseNetworkShares()
5704 {
5705   CLog::Log(LOGDEBUG,"CApplication::CloseNetworkShares: Closing all network shares");
5706
5707 #if defined(HAS_FILESYSTEM_SMB) && !defined(TARGET_WINDOWS)
5708   smb.Deinit();
5709 #endif
5710   
5711 #ifdef HAS_FILESYSTEM_NFS
5712   gNfsConnection.Deinit();
5713 #endif
5714   
5715 #ifdef HAS_FILESYSTEM_AFP
5716   gAfpConnection.Deinit();
5717 #endif
5718   
5719 #ifdef HAS_FILESYSTEM_SFTP
5720   CSFTPSessionManager::DisconnectAllSessions();
5721 #endif
5722 }