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