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