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