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