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