Merge pull request #4957 from Memphiz/linusyangbp
[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 == "videoscreen.guicalibration")
1719     g_windowManager.ActivateWindow(WINDOW_SCREEN_CALIBRATION);
1720   else if (settingId == "videoscreen.testpattern")
1721     g_windowManager.ActivateWindow(WINDOW_TEST_PATTERN);
1722 }
1723
1724 bool CApplication::OnSettingUpdate(CSetting* &setting, const char *oldSettingId, const TiXmlNode *oldSettingNode)
1725 {
1726   if (setting == NULL)
1727     return false;
1728
1729   const std::string &settingId = setting->GetId();
1730   if (settingId == "audiooutput.channels")
1731   {
1732     // check if this is an update from Eden
1733     if (oldSettingId != NULL && oldSettingNode != NULL &&
1734         StringUtils::EqualsNoCase(oldSettingId, "audiooutput.channellayout"))
1735     {
1736       bool ret = false;
1737       CSettingInt* channels = (CSettingInt*)setting;
1738       if (channels->FromString(oldSettingNode->FirstChild()->ValueStr()) && channels->GetValue() < AE_CH_LAYOUT_MAX - 1)
1739         ret = channels->SetValue(channels->GetValue() + 1);
1740
1741       // let's just reset the audiodevice settings as well
1742       std::string audiodevice = CSettings::Get().GetString("audiooutput.audiodevice");
1743       CAEFactory::VerifyOutputDevice(audiodevice, false);
1744       ret |= CSettings::Get().SetString("audiooutput.audiodevice", audiodevice.c_str());
1745
1746       return ret;
1747     }
1748   }
1749   else if (settingId == "screensaver.mode")
1750   {
1751     CSettingString *screensaverMode = (CSettingString*)setting;
1752     // we no longer ship the built-in slideshow screensaver, replace it if it's still in use
1753     if (StringUtils::EqualsNoCase(screensaverMode->GetValue(), "screensaver.xbmc.builtin.slideshow"))
1754       return screensaverMode->SetValue("screensaver.xbmc.builtin.dim");
1755   }
1756   else if (settingId == "scrapers.musicvideosdefault")
1757   {
1758     CSettingAddon *musicvideoScraper = (CSettingAddon*)setting;
1759     if (StringUtils::EqualsNoCase(musicvideoScraper->GetValue(), "metadata.musicvideos.last.fm"))
1760     {
1761       musicvideoScraper->Reset();
1762       return true;
1763     }
1764   }
1765 #if defined(HAS_LIBAMCODEC)
1766   else if (settingId == "videoplayer.useamcodec")
1767   {
1768     // Do not permit amcodec to be used on non-aml platforms.
1769     // The setting will be hidden but the default value is true,
1770     // so change it to false.
1771     if (!aml_present())
1772     {
1773       CSettingBool *useamcodec = (CSettingBool*)setting;
1774       useamcodec->SetValue(false);
1775     }
1776   }
1777 #endif
1778 #if defined(TARGET_ANDROID)
1779   else if (settingId == "videoplayer.usemediacodec")
1780   {
1781     // Do not permit MediaCodec to be used Android platforms that do not have it.
1782     // The setting will be hidden but the default value is true,
1783     // so change it to false.
1784     if (CAndroidFeatures::GetVersion() < 16)
1785     {
1786       CSettingBool *usemediacodec = (CSettingBool*)setting;
1787       usemediacodec->SetValue(false);
1788     }
1789   }
1790   else if (settingId == "videoplayer.usestagefright")
1791   {
1792     CSettingBool *usestagefright = (CSettingBool*)setting;
1793     usestagefright->SetValue(false);
1794   }
1795 #endif
1796 #if defined(TARGET_DARWIN_OSX)
1797   else if (settingId == "audiooutput.audiodevice")
1798   {
1799     CSettingString *audioDevice = (CSettingString*)setting;
1800     // Gotham and older didn't enumerate audio devices per stream on osx
1801     // add stream0 per default which should be ok for all old settings.
1802     if (!StringUtils::EqualsNoCase(audioDevice->GetValue(), "DARWINOSX:default") && 
1803         StringUtils::FindWords(audioDevice->GetValue().c_str(), ":stream") == std::string::npos)
1804     {
1805       std::string newSetting = audioDevice->GetValue();
1806       newSetting += ":stream0";
1807       return audioDevice->SetValue(newSetting);
1808     }
1809   }
1810 #endif
1811
1812   return false;
1813 }
1814
1815 bool CApplication::OnSettingsSaving() const
1816 {
1817   // don't save settings when we're busy stopping the application
1818   // a lot of screens try to save settings on deinit and deinit is
1819   // called for every screen when the application is stopping
1820   if (m_bStop)
1821     return false;
1822
1823   return true;
1824 }
1825
1826 void CApplication::ReloadSkin(bool confirm/*=false*/)
1827 {
1828   std::string oldSkin = g_SkinInfo ? g_SkinInfo->ID() : "";
1829
1830   CGUIMessage msg(GUI_MSG_LOAD_SKIN, -1, g_windowManager.GetActiveWindow());
1831   g_windowManager.SendMessage(msg);
1832
1833   string newSkin = CSettings::Get().GetString("lookandfeel.skin");
1834   if (LoadSkin(newSkin))
1835   {
1836     /* The Reset() or SetString() below will cause recursion, so the m_skinReverting boolean is set so as to not prompt the
1837        user as to whether they want to keep the current skin. */
1838     if (confirm && !m_skinReverting)
1839     {
1840       bool cancelled;
1841       if (!CGUIDialogYesNo::ShowAndGetInput(13123, 13111, -1, -1, -1, -1, cancelled, 10000))
1842       {
1843         m_skinReverting = true;
1844         if (oldSkin.empty())
1845           CSettings::Get().GetSetting("lookandfeel.skin")->Reset();
1846         else
1847           CSettings::Get().SetString("lookandfeel.skin", oldSkin);
1848       }
1849     }
1850   }
1851   else
1852   {
1853     // skin failed to load - we revert to the default only if we didn't fail loading the default
1854     string defaultSkin = ((CSettingString*)CSettings::Get().GetSetting("lookandfeel.skin"))->GetDefault();
1855     if (newSkin != defaultSkin)
1856     {
1857       m_skinReverting = true;
1858       CSettings::Get().GetSetting("lookandfeel.skin")->Reset();
1859       CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(24102), g_localizeStrings.Get(24103));
1860     }
1861   }
1862   m_skinReverting = false;
1863 }
1864
1865 bool CApplication::Load(const TiXmlNode *settings)
1866 {
1867   if (settings == NULL)
1868     return false;
1869
1870   const TiXmlElement *audioElement = settings->FirstChildElement("audio");
1871   if (audioElement != NULL)
1872   {
1873     XMLUtils::GetBoolean(audioElement, "mute", m_muted);
1874     if (!XMLUtils::GetFloat(audioElement, "fvolumelevel", m_volumeLevel, VOLUME_MINIMUM, VOLUME_MAXIMUM))
1875       m_volumeLevel = VOLUME_MAXIMUM;
1876   }
1877
1878   return true;
1879 }
1880
1881 bool CApplication::Save(TiXmlNode *settings) const
1882 {
1883   if (settings == NULL)
1884     return false;
1885
1886   TiXmlElement volumeNode("audio");
1887   TiXmlNode *audioNode = settings->InsertEndChild(volumeNode);
1888   if (audioNode == NULL)
1889     return false;
1890
1891   XMLUtils::SetBoolean(audioNode, "mute", m_muted);
1892   XMLUtils::SetFloat(audioNode, "fvolumelevel", m_volumeLevel);
1893
1894   return true;
1895 }
1896
1897 bool CApplication::LoadSkin(const CStdString& skinID)
1898 {
1899   AddonPtr addon;
1900   if (CAddonMgr::Get().GetAddon(skinID, addon, ADDON_SKIN))
1901   {
1902     if (LoadSkin(boost::dynamic_pointer_cast<ADDON::CSkinInfo>(addon)))
1903       return true;
1904   }
1905   CLog::Log(LOGERROR, "failed to load requested skin '%s'", skinID.c_str());
1906   return false;
1907 }
1908
1909 bool CApplication::LoadSkin(const SkinPtr& skin)
1910 {
1911   if (!skin)
1912     return false;
1913
1914   skin->Start();
1915   if (!skin->HasSkinFile("Home.xml"))
1916     return false;
1917
1918   bool bPreviousPlayingState=false;
1919   bool bPreviousRenderingState=false;
1920   if (g_application.m_pPlayer->IsPlayingVideo())
1921   {
1922     bPreviousPlayingState = !g_application.m_pPlayer->IsPausedPlayback();
1923     if (bPreviousPlayingState)
1924       g_application.m_pPlayer->Pause();
1925 #ifdef HAS_VIDEO_PLAYBACK
1926     if (g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
1927     {
1928       g_windowManager.ActivateWindow(WINDOW_HOME);
1929       bPreviousRenderingState = true;
1930     }
1931 #endif
1932   }
1933   // close the music and video overlays (they're re-opened automatically later)
1934   CSingleLock lock(g_graphicsContext);
1935
1936   // save the current window details and focused control
1937   int currentWindow = g_windowManager.GetActiveWindow();
1938   int iCtrlID = -1;
1939   CGUIWindow* pWindow = g_windowManager.GetWindow(currentWindow);
1940   if (pWindow)
1941     iCtrlID = pWindow->GetFocusedControlID();
1942   vector<int> currentModelessWindows;
1943   g_windowManager.GetActiveModelessWindows(currentModelessWindows);
1944
1945   UnloadSkin();
1946
1947   CLog::Log(LOGINFO, "  load skin from: %s (version: %s)", skin->Path().c_str(), skin->Version().asString().c_str());
1948   g_SkinInfo = skin;
1949   g_SkinInfo->Start();
1950
1951   CLog::Log(LOGINFO, "  load fonts for skin...");
1952   g_graphicsContext.SetMediaDir(skin->Path());
1953   g_directoryCache.ClearSubPaths(skin->Path());
1954
1955   g_colorManager.Load(CSettings::Get().GetString("lookandfeel.skincolors"));
1956
1957   g_fontManager.LoadFonts(CSettings::Get().GetString("lookandfeel.font"));
1958
1959   // load in the skin strings
1960   CStdString langPath = URIUtils::AddFileToFolder(skin->Path(), "language");
1961   URIUtils::AddSlashAtEnd(langPath);
1962
1963   g_localizeStrings.LoadSkinStrings(langPath, CSettings::Get().GetString("locale.language"));
1964
1965   g_SkinInfo->LoadIncludes();
1966
1967   int64_t start;
1968   start = CurrentHostCounter();
1969
1970   CLog::Log(LOGINFO, "  load new skin...");
1971
1972   // Load the user windows
1973   LoadUserWindows();
1974
1975   int64_t end, freq;
1976   end = CurrentHostCounter();
1977   freq = CurrentHostFrequency();
1978   CLog::Log(LOGDEBUG,"Load Skin XML: %.2fms", 1000.f * (end - start) / freq);
1979
1980   CLog::Log(LOGINFO, "  initialize new skin...");
1981   g_windowManager.AddMsgTarget(this);
1982   g_windowManager.AddMsgTarget(&g_playlistPlayer);
1983   g_windowManager.AddMsgTarget(&g_infoManager);
1984   g_windowManager.AddMsgTarget(&g_fontManager);
1985   g_windowManager.AddMsgTarget(&CStereoscopicsManager::Get());
1986   g_windowManager.SetCallback(*this);
1987   g_windowManager.Initialize();
1988   CTextureCache::Get().Initialize();
1989   g_audioManager.Enable(true);
1990   g_audioManager.Load();
1991
1992   if (g_SkinInfo->HasSkinFile("DialogFullScreenInfo.xml"))
1993     g_windowManager.Add(new CGUIDialogFullScreenInfo);
1994
1995   { // we can't register visible condition in dialog's ctor because infomanager is cleared when unloading skin
1996     CGUIDialog *overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_OVERLAY);
1997     if (overlay) overlay->SetVisibleCondition("skin.hasvideooverlay");
1998     overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_OVERLAY);
1999     if (overlay) overlay->SetVisibleCondition("skin.hasmusicoverlay");
2000   }
2001
2002   CLog::Log(LOGINFO, "  skin loaded...");
2003
2004   // leave the graphics lock
2005   lock.Leave();
2006
2007   // restore windows
2008   if (currentWindow != WINDOW_INVALID)
2009   {
2010     g_windowManager.ActivateWindow(currentWindow);
2011     for (unsigned int i = 0; i < currentModelessWindows.size(); i++)
2012     {
2013       CGUIDialog *dialog = (CGUIDialog *)g_windowManager.GetWindow(currentModelessWindows[i]);
2014       if (dialog) dialog->Show();
2015     }
2016     if (iCtrlID != -1)
2017     {
2018       pWindow = g_windowManager.GetWindow(currentWindow);
2019       if (pWindow && pWindow->HasSaveLastControl())
2020       {
2021         CGUIMessage msg(GUI_MSG_SETFOCUS, currentWindow, iCtrlID, 0);
2022         pWindow->OnMessage(msg);
2023       }
2024     }
2025   }
2026
2027   if (g_application.m_pPlayer->IsPlayingVideo())
2028   {
2029     if (bPreviousPlayingState)
2030       g_application.m_pPlayer->Pause();
2031     if (bPreviousRenderingState)
2032       g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
2033   }
2034   return true;
2035 }
2036
2037 void CApplication::UnloadSkin(bool forReload /* = false */)
2038 {
2039   CLog::Log(LOGINFO, "Unloading old skin %s...", forReload ? "for reload " : "");
2040
2041   g_audioManager.Enable(false);
2042
2043   g_windowManager.DeInitialize();
2044   CTextureCache::Get().Deinitialize();
2045
2046   // remove the skin-dependent window
2047   g_windowManager.Delete(WINDOW_DIALOG_FULLSCREEN_INFO);
2048
2049   g_TextureManager.Cleanup();
2050   g_largeTextureManager.CleanupUnusedImages(true);
2051
2052   g_fontManager.Clear();
2053
2054   g_colorManager.Clear();
2055
2056   g_infoManager.Clear();
2057
2058 //  The g_SkinInfo boost shared_ptr ought to be reset here
2059 // but there are too many places it's used without checking for NULL
2060 // and as a result a race condition on exit can cause a crash.
2061 }
2062
2063 bool CApplication::LoadUserWindows()
2064 {
2065   // Start from wherever home.xml is
2066   std::vector<CStdString> vecSkinPath;
2067   g_SkinInfo->GetSkinPaths(vecSkinPath);
2068   for (unsigned int i = 0;i < vecSkinPath.size();++i)
2069   {
2070     CLog::Log(LOGINFO, "Loading user windows, path %s", vecSkinPath[i].c_str());
2071     CFileItemList items;
2072     if (CDirectory::GetDirectory(vecSkinPath[i], items, ".xml", DIR_FLAG_NO_FILE_DIRS))
2073     {
2074       for (int i = 0; i < items.Size(); ++i)
2075       {
2076         if (items[i]->m_bIsFolder)
2077           continue;
2078         CStdString skinFile = URIUtils::GetFileName(items[i]->GetPath());
2079         if (StringUtils::StartsWithNoCase(skinFile, "custom"))
2080         {
2081           CXBMCTinyXML xmlDoc;
2082           if (!xmlDoc.LoadFile(items[i]->GetPath()))
2083           {
2084             CLog::Log(LOGERROR, "unable to load: %s, Line %d\n%s", items[i]->GetPath().c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
2085             continue;
2086           }
2087
2088           // Root element should be <window>
2089           TiXmlElement* pRootElement = xmlDoc.RootElement();
2090           CStdString strValue = pRootElement->Value();
2091           if (!strValue.Equals("window"))
2092           {
2093             CLog::Log(LOGERROR, "file: %s doesnt contain <window>", skinFile.c_str());
2094             continue;
2095           }
2096
2097           // Read the <type> element to get the window type to create
2098           // If no type is specified, create a CGUIWindow as default
2099           CGUIWindow* pWindow = NULL;
2100           CStdString strType;
2101           if (pRootElement->Attribute("type"))
2102             strType = pRootElement->Attribute("type");
2103           else
2104           {
2105             const TiXmlNode *pType = pRootElement->FirstChild("type");
2106             if (pType && pType->FirstChild())
2107               strType = pType->FirstChild()->Value();
2108           }
2109           int id = WINDOW_INVALID;
2110           if (!pRootElement->Attribute("id", &id))
2111           {
2112             const TiXmlNode *pType = pRootElement->FirstChild("id");
2113             if (pType && pType->FirstChild())
2114               id = atol(pType->FirstChild()->Value());
2115           }
2116           CStdString visibleCondition;
2117           CGUIControlFactory::GetConditionalVisibility(pRootElement, visibleCondition);
2118
2119           if (strType.Equals("dialog"))
2120             pWindow = new CGUIDialog(id + WINDOW_HOME, skinFile);
2121           else if (strType.Equals("submenu"))
2122             pWindow = new CGUIDialogSubMenu(id + WINDOW_HOME, skinFile);
2123           else if (strType.Equals("buttonmenu"))
2124             pWindow = new CGUIDialogButtonMenu(id + WINDOW_HOME, skinFile);
2125           else
2126             pWindow = new CGUIWindow(id + WINDOW_HOME, skinFile);
2127
2128           // Check to make sure the pointer isn't still null
2129           if (pWindow == NULL)
2130           {
2131             CLog::Log(LOGERROR, "Out of memory / Failed to create new object in LoadUserWindows");
2132             return false;
2133           }
2134           if (id == WINDOW_INVALID || g_windowManager.GetWindow(WINDOW_HOME + id))
2135           {
2136             delete pWindow;
2137             continue;
2138           }
2139           pWindow->SetVisibleCondition(visibleCondition);
2140           pWindow->SetLoadType(CGUIWindow::KEEP_IN_MEMORY);
2141           g_windowManager.AddCustomWindow(pWindow);
2142         }
2143       }
2144     }
2145   }
2146   return true;
2147 }
2148
2149 bool CApplication::RenderNoPresent()
2150 {
2151   MEASURE_FUNCTION;
2152
2153 // DXMERGE: This may have been important?
2154 //  g_graphicsContext.AcquireCurrentContext();
2155
2156   g_graphicsContext.Lock();
2157
2158   // dont show GUI when playing full screen video
2159   if (g_graphicsContext.IsFullScreenVideo())
2160   {
2161     g_graphicsContext.SetRenderingResolution(g_graphicsContext.GetVideoResolution(), false);
2162     g_renderManager.Render(true, 0, 255);
2163
2164     // close window overlays
2165     CGUIDialog *overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_OVERLAY);
2166     if (overlay) overlay->Close(true);
2167     overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_OVERLAY);
2168     if (overlay) overlay->Close(true);
2169
2170   }
2171
2172   bool hasRendered = g_windowManager.Render();
2173
2174   g_graphicsContext.Unlock();
2175
2176   return hasRendered;
2177 }
2178
2179 float CApplication::GetDimScreenSaverLevel() const
2180 {
2181   if (!m_bScreenSave || !m_screenSaver ||
2182       (m_screenSaver->ID() != "screensaver.xbmc.builtin.dim" &&
2183        m_screenSaver->ID() != "screensaver.xbmc.builtin.black" &&
2184        !m_screenSaver->ID().empty()))
2185     return 0;
2186
2187   if (!m_screenSaver->GetSetting("level").empty())
2188     return 100.0f - (float)atof(m_screenSaver->GetSetting("level"));
2189   return 100.0f;
2190 }
2191
2192 void CApplication::Render()
2193 {
2194   // do not render if we are stopped or in background
2195   if (m_bStop)
2196     return;
2197
2198   MEASURE_FUNCTION;
2199
2200   int vsync_mode = CSettings::Get().GetInt("videoscreen.vsync");
2201
2202   bool hasRendered = false;
2203   bool limitFrames = false;
2204   unsigned int singleFrameTime = 10; // default limit 100 fps
2205
2206   {
2207     // Less fps in DPMS
2208     bool lowfps = m_dpmsIsActive || g_Windowing.EnableFrameLimiter();
2209     // Whether externalplayer is playing and we're unfocused
2210     bool extPlayerActive = m_pPlayer->GetCurrentPlayer() == EPC_EXTPLAYER && m_pPlayer->IsPlaying() && !m_AppFocused;
2211
2212     m_bPresentFrame = false;
2213     if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback() && g_renderManager.RendererHandlesPresent())
2214     {
2215       m_bPresentFrame = g_renderManager.FrameWait(100);
2216       hasRendered = true;
2217     }
2218     else
2219     {
2220       // engage the frame limiter as needed
2221       limitFrames = lowfps || extPlayerActive;
2222       // DXMERGE - we checked for g_videoConfig.GetVSyncMode() before this
2223       //           perhaps allowing it to be set differently than the UI option??
2224       if (vsync_mode == VSYNC_DISABLED || vsync_mode == VSYNC_VIDEO)
2225         limitFrames = true; // not using vsync.
2226       else if ((g_infoManager.GetFPS() > g_graphicsContext.GetFPS() + 10) && g_infoManager.GetFPS() > 1000 / singleFrameTime)
2227         limitFrames = true; // using vsync, but it isn't working.
2228
2229       if (limitFrames)
2230       {
2231         if (extPlayerActive)
2232         {
2233           ResetScreenSaver();  // Prevent screensaver dimming the screen
2234           singleFrameTime = 1000;  // 1 fps, high wakeup latency but v.low CPU usage
2235         }
2236         else if (lowfps)
2237           singleFrameTime = 200;  // 5 fps, <=200 ms latency to wake up
2238       }
2239
2240     }
2241   }
2242
2243   CSingleLock lock(g_graphicsContext);
2244   g_infoManager.UpdateFPS();
2245
2246   if (g_graphicsContext.IsFullScreenVideo() && m_pPlayer->IsPlaying() && vsync_mode == VSYNC_VIDEO)
2247     g_Windowing.SetVSync(true);
2248   else if (vsync_mode == VSYNC_ALWAYS)
2249     g_Windowing.SetVSync(true);
2250   else if (vsync_mode != VSYNC_DRIVER)
2251     g_Windowing.SetVSync(false);
2252
2253   if (m_bPresentFrame && m_pPlayer->IsPlaying() && !m_pPlayer->IsPaused())
2254     ResetScreenSaver();
2255
2256   if(!g_Windowing.BeginRender())
2257     return;
2258
2259   g_renderManager.FrameMove();
2260
2261   CDirtyRegionList dirtyRegions = g_windowManager.GetDirty();
2262   if(g_graphicsContext.GetStereoMode())
2263   {
2264     g_graphicsContext.SetStereoView(RENDER_STEREO_VIEW_LEFT);
2265     if(RenderNoPresent())
2266       hasRendered = true;
2267
2268     if(g_graphicsContext.GetStereoMode() != RENDER_STEREO_MODE_MONO)
2269     {
2270       g_graphicsContext.SetStereoView(RENDER_STEREO_VIEW_RIGHT);
2271       if(RenderNoPresent())
2272         hasRendered = true;
2273     }
2274     g_graphicsContext.SetStereoView(RENDER_STEREO_VIEW_OFF);
2275   }
2276   else
2277   {
2278     if(RenderNoPresent())
2279       hasRendered = true;
2280   }
2281
2282   g_renderManager.FrameFinish();
2283
2284   g_Windowing.EndRender();
2285
2286   // execute post rendering actions (finalize window closing)
2287   g_windowManager.AfterRender();
2288
2289   // reset our info cache - we do this at the end of Render so that it is
2290   // fresh for the next process(), or after a windowclose animation (where process()
2291   // isn't called)
2292   g_infoManager.ResetCache();
2293   lock.Leave();
2294
2295   unsigned int now = XbmcThreads::SystemClockMillis();
2296   if (hasRendered)
2297     m_lastRenderTime = now;
2298
2299   //when nothing has been rendered for m_guiDirtyRegionNoFlipTimeout milliseconds,
2300   //we don't call g_graphicsContext.Flip() anymore, this saves gpu and cpu usage
2301   bool flip;
2302   if (g_advancedSettings.m_guiDirtyRegionNoFlipTimeout >= 0)
2303     flip = hasRendered || (now - m_lastRenderTime) < (unsigned int)g_advancedSettings.m_guiDirtyRegionNoFlipTimeout;
2304   else
2305     flip = true;
2306
2307   //fps limiter, make sure each frame lasts at least singleFrameTime milliseconds
2308   if (limitFrames || !flip)
2309   {
2310     if (!limitFrames)
2311       singleFrameTime = 40; //if not flipping, loop at 25 fps
2312
2313     unsigned int frameTime = now - m_lastFrameTime;
2314     if (frameTime < singleFrameTime)
2315       Sleep(singleFrameTime - frameTime);
2316   }
2317   m_lastFrameTime = XbmcThreads::SystemClockMillis();
2318
2319   if (flip)
2320     g_graphicsContext.Flip(dirtyRegions);
2321   CTimeUtils::UpdateFrameTime(flip);
2322
2323   g_renderManager.UpdateResolution();
2324   g_renderManager.ManageCaptures();
2325 }
2326
2327 void CApplication::SetStandAlone(bool value)
2328 {
2329   g_advancedSettings.m_handleMounting = m_bStandalone = value;
2330 }
2331
2332 // OnKey() translates the key into a CAction which is sent on to our Window Manager.
2333 // The window manager will return true if the event is processed, false otherwise.
2334 // If not already processed, this routine handles global keypresses.  It returns
2335 // true if the key has been processed, false otherwise.
2336
2337 bool CApplication::OnKey(const CKey& key)
2338 {
2339
2340   // Turn the mouse off, as we've just got a keypress from controller or remote
2341   g_Mouse.SetActive(false);
2342
2343   // get the current active window
2344   int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
2345
2346   // this will be checked for certain keycodes that need
2347   // special handling if the screensaver is active
2348   CAction action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2349
2350   // a key has been pressed.
2351   // reset Idle Timer
2352   m_idleTimer.StartZero();
2353   bool processKey = AlwaysProcess(action);
2354
2355   if (StringUtils::StartsWithNoCase(action.GetName(),"CECToggleState") || StringUtils::StartsWithNoCase(action.GetName(),"CECStandby"))
2356   {
2357     bool ret = true;
2358
2359     CLog::Log(LOGDEBUG, "%s: action %s [%d], toggling state of playing device", __FUNCTION__, action.GetName().c_str(), action.GetID());
2360     // do not wake up the screensaver right after switching off the playing device
2361     if (StringUtils::StartsWithNoCase(action.GetName(),"CECToggleState"))
2362       ret = CApplicationMessenger::Get().CECToggleState();
2363     else
2364       ret = CApplicationMessenger::Get().CECStandby();
2365     if (!ret) /* display is switched off */
2366       return true;
2367   }
2368
2369   ResetScreenSaver();
2370
2371   // allow some keys to be processed while the screensaver is active
2372   if (WakeUpScreenSaverAndDPMS(processKey) && !processKey)
2373   {
2374     CLog::Log(LOGDEBUG, "%s: %s pressed, screen saver/dpms woken up", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str());
2375     return true;
2376   }
2377
2378   // change this if we have a dialog up
2379   if (g_windowManager.HasModalDialog())
2380   {
2381     iWin = g_windowManager.GetTopMostModalDialogID() & WINDOW_ID_MASK;
2382   }
2383   if (iWin == WINDOW_DIALOG_FULLSCREEN_INFO)
2384   { // fullscreen info dialog - special case
2385     action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2386
2387     if (!key.IsAnalogButton())
2388       CLog::Log(LOGDEBUG, "%s: %s pressed, trying fullscreen info action %s", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str(), action.GetName().c_str());
2389
2390     if (OnAction(action))
2391       return true;
2392
2393     // fallthrough to the main window
2394     iWin = WINDOW_FULLSCREEN_VIDEO;
2395   }
2396   if (iWin == WINDOW_FULLSCREEN_VIDEO)
2397   {
2398     // current active window is full screen video.
2399     if (g_application.m_pPlayer->IsInMenu())
2400     {
2401       // if player is in some sort of menu, (ie DVDMENU) map buttons differently
2402       action = CButtonTranslator::GetInstance().GetAction(WINDOW_VIDEO_MENU, key);
2403     }
2404     else if (g_PVRManager.IsStarted() && g_application.CurrentFileItem().HasPVRChannelInfoTag())
2405     {
2406       // check for PVR specific keymaps in FULLSCREEN_VIDEO window
2407       action = CButtonTranslator::GetInstance().GetAction(WINDOW_FULLSCREEN_LIVETV, key, false);
2408
2409       // if no PVR specific action/mapping is found, fall back to default
2410       if (action.GetID() == 0)
2411         action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2412     }
2413     else
2414     {
2415       // in any other case use the fullscreen window section of keymap.xml to map key->action
2416       action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2417     }
2418   }
2419   else
2420   {
2421     // current active window isnt the fullscreen window
2422     // just use corresponding section from keymap.xml
2423     // to map key->action
2424
2425     // first determine if we should use keyboard input directly
2426     bool useKeyboard = key.FromKeyboard() && (iWin == WINDOW_DIALOG_KEYBOARD || iWin == WINDOW_DIALOG_NUMERIC);
2427     CGUIWindow *window = g_windowManager.GetWindow(iWin);
2428     if (window)
2429     {
2430       CGUIControl *control = window->GetFocusedControl();
2431       if (control)
2432       {
2433         // If this is an edit control set usekeyboard to true. This causes the
2434         // keypress to be processed directly not through the key mappings.
2435         if (control->GetControlType() == CGUIControl::GUICONTROL_EDIT)
2436           useKeyboard = true;
2437
2438         // If the key pressed is shift-A to shift-Z set usekeyboard to true.
2439         // This causes the keypress to be used for list navigation.
2440         if (control->IsContainer() && key.GetModifiers() == CKey::MODIFIER_SHIFT && key.GetVKey() >= XBMCVK_A && key.GetVKey() <= XBMCVK_Z)
2441           useKeyboard = true;
2442       }
2443     }
2444     if (useKeyboard)
2445     {
2446       action = CAction(0); // reset our action
2447       if (CSettings::Get().GetBool("input.remoteaskeyboard"))
2448       {
2449         // users remote is executing keyboard commands, so use the virtualkeyboard section of keymap.xml
2450         // and send those rather than actual keyboard presses.  Only for navigation-type commands though
2451         action = CButtonTranslator::GetInstance().GetAction(WINDOW_DIALOG_KEYBOARD, key);
2452         if (!(action.GetID() == ACTION_MOVE_LEFT ||
2453               action.GetID() == ACTION_MOVE_RIGHT ||
2454               action.GetID() == ACTION_MOVE_UP ||
2455               action.GetID() == ACTION_MOVE_DOWN ||
2456               action.GetID() == ACTION_SELECT_ITEM ||
2457               action.GetID() == ACTION_ENTER ||
2458               action.GetID() == ACTION_PREVIOUS_MENU ||
2459               action.GetID() == ACTION_NAV_BACK))
2460         {
2461           // the action isn't plain navigation - check for a keyboard-specific keymap
2462           action = CButtonTranslator::GetInstance().GetAction(WINDOW_DIALOG_KEYBOARD, key, false);
2463           if (!(action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9) ||
2464                 action.GetID() == ACTION_BACKSPACE ||
2465                 action.GetID() == ACTION_SHIFT ||
2466                 action.GetID() == ACTION_SYMBOLS ||
2467                 action.GetID() == ACTION_CURSOR_LEFT ||
2468                 action.GetID() == ACTION_CURSOR_RIGHT)
2469             action = CAction(0); // don't bother with this action
2470         }
2471       }
2472       if (!action.GetID())
2473       {
2474         // keyboard entry - pass the keys through directly
2475         if (key.GetFromService())
2476           action = CAction(key.GetButtonCode() != KEY_INVALID ? key.GetButtonCode() : 0, key.GetUnicode());
2477         else
2478         {
2479           // Check for paste keypress
2480 #ifdef TARGET_WINDOWS
2481           // In Windows paste is ctrl-V
2482           if (key.GetVKey() == XBMCVK_V && key.GetModifiers() == CKey::MODIFIER_CTRL)
2483 #elif defined(TARGET_LINUX)
2484           // In Linux paste is ctrl-V
2485           if (key.GetVKey() == XBMCVK_V && key.GetModifiers() == CKey::MODIFIER_CTRL)
2486 #elif defined(TARGET_DARWIN_OSX)
2487           // In OSX paste is cmd-V
2488           if (key.GetVKey() == XBMCVK_V && key.GetModifiers() == CKey::MODIFIER_META)
2489 #else
2490           // Placeholder for other operating systems
2491           if (false)
2492 #endif
2493             action = CAction(ACTION_PASTE);
2494           // If the unicode is non-zero the keypress is a non-printing character
2495           else if (key.GetUnicode())
2496             action = CAction(key.GetAscii() | KEY_ASCII, key.GetUnicode());
2497           // The keypress is a non-printing character
2498           else
2499             action = CAction(key.GetVKey() | KEY_VKEY);
2500         }
2501       }
2502
2503       CLog::Log(LOGDEBUG, "%s: %s pressed, trying keyboard action %x", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str(), action.GetID());
2504
2505       if (OnAction(action))
2506         return true;
2507       // failed to handle the keyboard action, drop down through to standard action
2508     }
2509     if (key.GetFromService())
2510     {
2511       if (key.GetButtonCode() != KEY_INVALID)
2512         action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2513     }
2514     else
2515       action = CButtonTranslator::GetInstance().GetAction(iWin, key);
2516   }
2517   if (!key.IsAnalogButton())
2518     CLog::Log(LOGDEBUG, "%s: %s pressed, action is %s", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str(), action.GetName().c_str());
2519
2520   return ExecuteInputAction(action);
2521 }
2522
2523 // OnAppCommand is called in response to a XBMC_APPCOMMAND event.
2524 // This needs to return true if it processed the appcommand or false if it didn't
2525 bool CApplication::OnAppCommand(const CAction &action)
2526 {
2527   // Reset the screen saver
2528   ResetScreenSaver();
2529
2530   // If we were currently in the screen saver wake up and don't process the appcommand
2531   if (WakeUpScreenSaverAndDPMS())
2532     return true;
2533
2534   // The action ID is the APPCOMMAND code. We need to retrieve the action
2535   // associated with this appcommand from the mapping table.
2536   uint32_t appcmd = action.GetID();
2537   CKey key(appcmd | KEY_APPCOMMAND, (unsigned int) 0);
2538   int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
2539   CAction appcmdaction = CButtonTranslator::GetInstance().GetAction(iWin, key);
2540
2541   // If we couldn't find an action return false to indicate we have not
2542   // handled this appcommand
2543   if (!appcmdaction.GetID())
2544   {
2545     CLog::Log(LOGDEBUG, "%s: unknown appcommand %d", __FUNCTION__, appcmd);
2546     return false;
2547   }
2548
2549   // Process the appcommand
2550   CLog::Log(LOGDEBUG, "%s: appcommand %d, trying action %s", __FUNCTION__, appcmd, appcmdaction.GetName().c_str());
2551   OnAction(appcmdaction);
2552
2553   // Always return true regardless of whether the action succeeded or not.
2554   // This stops Windows handling the appcommand itself.
2555   return true;
2556 }
2557
2558 bool CApplication::OnAction(const CAction &action)
2559 {
2560   // special case for switching between GUI & fullscreen mode.
2561   if (action.GetID() == ACTION_SHOW_GUI)
2562   { // Switch to fullscreen mode if we can
2563     if (SwitchToFullScreen())
2564     {
2565       m_navigationTimer.StartZero();
2566       return true;
2567     }
2568   }
2569
2570   if (action.GetID() == ACTION_TOGGLE_FULLSCREEN)
2571   {
2572     g_graphicsContext.ToggleFullScreenRoot();
2573     return true;
2574   }
2575
2576   if (action.IsMouse())
2577     g_Mouse.SetActive(true);
2578
2579   
2580   if (action.GetID() == ACTION_CREATE_EPISODE_BOOKMARK)   
2581   {
2582     CGUIDialogVideoBookmarks::OnAddEpisodeBookmark();
2583   }
2584   if (action.GetID() == ACTION_CREATE_BOOKMARK)
2585   {
2586     CGUIDialogVideoBookmarks::OnAddBookmark();
2587   }
2588   
2589   // The action PLAYPAUSE behaves as ACTION_PAUSE if we are currently
2590   // playing or ACTION_PLAYER_PLAY if we are not playing.
2591   if (action.GetID() == ACTION_PLAYER_PLAYPAUSE)
2592   {
2593     if (m_pPlayer->IsPlaying())
2594       return OnAction(CAction(ACTION_PAUSE));
2595     else
2596       return OnAction(CAction(ACTION_PLAYER_PLAY));
2597   }
2598
2599   //if the action would start or stop inertial scrolling
2600   //by gesture - bypass the normal OnAction handler of current window
2601   if( !m_pInertialScrollingHandler->CheckForInertialScrolling(&action) )
2602   {
2603     // in normal case
2604     // just pass the action to the current window and let it handle it
2605     if (g_windowManager.OnAction(action))
2606     {
2607       m_navigationTimer.StartZero();
2608       return true;
2609     }
2610   }
2611
2612   // handle extra global presses
2613
2614   // screenshot : take a screenshot :)
2615   if (action.GetID() == ACTION_TAKE_SCREENSHOT)
2616   {
2617     CScreenShot::TakeScreenshot();
2618     return true;
2619   }
2620   // built in functions : execute the built-in
2621   if (action.GetID() == ACTION_BUILT_IN_FUNCTION)
2622   {
2623     CBuiltins::Execute(action.GetName());
2624     m_navigationTimer.StartZero();
2625     return true;
2626   }
2627
2628   // reload keymaps
2629   if (action.GetID() == ACTION_RELOAD_KEYMAPS)
2630   {
2631     CButtonTranslator::GetInstance().Clear();
2632     CButtonTranslator::GetInstance().Load();
2633   }
2634
2635   // show info : Shows the current video or song information
2636   if (action.GetID() == ACTION_SHOW_INFO)
2637   {
2638     g_infoManager.ToggleShowInfo();
2639     return true;
2640   }
2641
2642   // codec info : Shows the current song, video or picture codec information
2643   if (action.GetID() == ACTION_SHOW_CODEC)
2644   {
2645     g_infoManager.ToggleShowCodec();
2646     return true;
2647   }
2648
2649   if ((action.GetID() == ACTION_INCREASE_RATING || action.GetID() == ACTION_DECREASE_RATING) && m_pPlayer->IsPlayingAudio())
2650   {
2651     const CMusicInfoTag *tag = g_infoManager.GetCurrentSongTag();
2652     if (tag)
2653     {
2654       *m_itemCurrentFile->GetMusicInfoTag() = *tag;
2655       char rating = tag->GetRating();
2656       bool needsUpdate(false);
2657       if (rating > '0' && action.GetID() == ACTION_DECREASE_RATING)
2658       {
2659         m_itemCurrentFile->GetMusicInfoTag()->SetRating(rating - 1);
2660         needsUpdate = true;
2661       }
2662       else if (rating < '5' && action.GetID() == ACTION_INCREASE_RATING)
2663       {
2664         m_itemCurrentFile->GetMusicInfoTag()->SetRating(rating + 1);
2665         needsUpdate = true;
2666       }
2667       if (needsUpdate)
2668       {
2669         CMusicDatabase db;
2670         if (db.Open())      // OpenForWrite() ?
2671         {
2672           db.SetSongRating(m_itemCurrentFile->GetPath(), m_itemCurrentFile->GetMusicInfoTag()->GetRating());
2673           db.Close();
2674         }
2675         // send a message to all windows to tell them to update the fileitem (eg playlistplayer, media windows)
2676         CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_ITEM, 0, m_itemCurrentFile);
2677         g_windowManager.SendMessage(msg);
2678       }
2679     }
2680     return true;
2681   }
2682
2683   // Now check with the playlist player if action can be handled.
2684   // 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.
2685   if (!(action.GetID() == ACTION_PREV_ITEM && m_pPlayer->CanSeek() && GetTime() > 3) )
2686   {
2687     if (g_playlistPlayer.OnAction(action))
2688       return true;
2689   }
2690
2691   // Now check with the player if action can be handled.
2692   if (g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO ||
2693       (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)) ||
2694       action.GetID() == ACTION_STOP)
2695   {
2696     if (m_pPlayer->OnAction(action))
2697       return true;
2698     // Player ignored action; popup the OSD
2699     if ((action.GetID() == ACTION_MOUSE_MOVE && (action.GetAmount(2) || action.GetAmount(3)))  // filter "false" mouse move from touch
2700         || action.GetID() == ACTION_MOUSE_LEFT_CLICK)
2701       CApplicationMessenger::Get().SendAction(CAction(ACTION_TRIGGER_OSD), WINDOW_INVALID, false);
2702   }
2703
2704   // stop : stops playing current audio song
2705   if (action.GetID() == ACTION_STOP)
2706   {
2707     StopPlaying();
2708     return true;
2709   }
2710
2711   // In case the playlist player nor the player didn't handle PREV_ITEM, because we are past the 3 secs limit.
2712   // If so, we just jump to the start of the track.
2713   if (action.GetID() == ACTION_PREV_ITEM && m_pPlayer->CanSeek())
2714   {
2715     SeekTime(0);
2716     m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
2717     return true;
2718   }
2719
2720   // forward action to g_PVRManager and break if it was able to handle it
2721   if (g_PVRManager.OnAction(action))
2722     return true;
2723
2724   // forward action to graphic context and see if it can handle it
2725   if (CStereoscopicsManager::Get().OnAction(action))
2726     return true;
2727
2728   if (m_pPlayer->IsPlaying())
2729   {
2730     // forward channel switches to the player - he knows what to do
2731     if (action.GetID() == ACTION_CHANNEL_UP || action.GetID() == ACTION_CHANNEL_DOWN)
2732     {
2733       m_pPlayer->OnAction(action);
2734       return true;
2735     }
2736
2737     // pause : pauses current audio song
2738     if (action.GetID() == ACTION_PAUSE && m_pPlayer->GetPlaySpeed() == 1)
2739     {
2740       m_pPlayer->Pause();
2741 #ifdef HAS_KARAOKE
2742       m_pKaraokeMgr->SetPaused( m_pPlayer->IsPaused() );
2743 #endif
2744       if (!m_pPlayer->IsPaused())
2745       { // unpaused - set the playspeed back to normal
2746         m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
2747       }
2748       g_audioManager.Enable(m_pPlayer->IsPaused());
2749       return true;
2750     }
2751     if (!m_pPlayer->IsPaused())
2752     {
2753       // if we do a FF/RW in my music then map PLAY action togo back to normal speed
2754       // if we are playing at normal speed, then allow play to pause
2755       if (action.GetID() == ACTION_PLAYER_PLAY || action.GetID() == ACTION_PAUSE)
2756       {
2757         if (m_pPlayer->GetPlaySpeed() != 1)
2758         {
2759           m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
2760         }
2761         else
2762         {
2763           m_pPlayer->Pause();
2764         }
2765         return true;
2766       }
2767       if (action.GetID() == ACTION_PLAYER_FORWARD || action.GetID() == ACTION_PLAYER_REWIND)
2768       {
2769         int iPlaySpeed = m_pPlayer->GetPlaySpeed();
2770         if (action.GetID() == ACTION_PLAYER_REWIND && iPlaySpeed == 1) // Enables Rewinding
2771           iPlaySpeed *= -2;
2772         else if (action.GetID() == ACTION_PLAYER_REWIND && iPlaySpeed > 1) //goes down a notch if you're FFing
2773           iPlaySpeed /= 2;
2774         else if (action.GetID() == ACTION_PLAYER_FORWARD && iPlaySpeed < 1) //goes up a notch if you're RWing
2775           iPlaySpeed /= 2;
2776         else
2777           iPlaySpeed *= 2;
2778
2779         if (action.GetID() == ACTION_PLAYER_FORWARD && iPlaySpeed == -1) //sets iSpeed back to 1 if -1 (didn't plan for a -1)
2780           iPlaySpeed = 1;
2781         if (iPlaySpeed > 32 || iPlaySpeed < -32)
2782           iPlaySpeed = 1;
2783
2784         m_pPlayer->SetPlaySpeed(iPlaySpeed, g_application.m_muted);
2785         return true;
2786       }
2787       else if ((action.GetAmount() || m_pPlayer->GetPlaySpeed() != 1) && (action.GetID() == ACTION_ANALOG_REWIND || action.GetID() == ACTION_ANALOG_FORWARD))
2788       {
2789         // calculate the speed based on the amount the button is held down
2790         int iPower = (int)(action.GetAmount() * MAX_FFWD_SPEED + 0.5f);
2791         // returns 0 -> MAX_FFWD_SPEED
2792         int iSpeed = 1 << iPower;
2793         if (iSpeed != 1 && action.GetID() == ACTION_ANALOG_REWIND)
2794           iSpeed = -iSpeed;
2795         g_application.m_pPlayer->SetPlaySpeed(iSpeed, g_application.m_muted);
2796         if (iSpeed == 1)
2797           CLog::Log(LOGDEBUG,"Resetting playspeed");
2798         return true;
2799       }
2800     }
2801     // allow play to unpause
2802     else
2803     {
2804       if (action.GetID() == ACTION_PLAYER_PLAY)
2805       {
2806         // unpause, and set the playspeed back to normal
2807         m_pPlayer->Pause();
2808         g_audioManager.Enable(m_pPlayer->IsPaused());
2809
2810         g_application.m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
2811         return true;
2812       }
2813     }
2814
2815     // record current file
2816     if (action.GetID() == ACTION_RECORD)
2817     {
2818       if (m_pPlayer->CanRecord())
2819         m_pPlayer->Record(!m_pPlayer->IsRecording());
2820     }
2821
2822     if (m_playerController->OnAction(action))
2823       return true;
2824   }
2825
2826
2827   if (action.GetID() == ACTION_SWITCH_PLAYER)
2828   {
2829     if(m_pPlayer->IsPlaying())
2830     {
2831       VECPLAYERCORES cores;
2832       CFileItem item(*m_itemCurrentFile.get());
2833       CPlayerCoreFactory::Get().GetPlayers(item, cores);
2834       PLAYERCOREID core = CPlayerCoreFactory::Get().SelectPlayerDialog(cores);
2835       if(core != EPC_NONE)
2836       {
2837         g_application.m_eForcedNextPlayer = core;
2838         item.m_lStartOffset = (int)(GetTime() * 75);
2839         PlayFile(item, true);
2840       }
2841     }
2842     else
2843     {
2844       VECPLAYERCORES cores;
2845       CPlayerCoreFactory::Get().GetRemotePlayers(cores);
2846       PLAYERCOREID core = CPlayerCoreFactory::Get().SelectPlayerDialog(cores);
2847       if(core != EPC_NONE)
2848       {
2849         CFileItem item;
2850         g_application.m_eForcedNextPlayer = core;
2851         PlayFile(item, false);
2852       }
2853     }
2854   }
2855
2856   if (g_peripherals.OnAction(action))
2857     return true;
2858
2859   if (action.GetID() == ACTION_MUTE)
2860   {
2861     ToggleMute();
2862     return true;
2863   }
2864
2865   if (action.GetID() == ACTION_TOGGLE_DIGITAL_ANALOG)
2866   {
2867     bool passthrough = CSettings::Get().GetBool("audiooutput.passthrough");
2868     CSettings::Get().SetBool("audiooutput.passthrough", !passthrough);
2869
2870     if (g_windowManager.GetActiveWindow() == WINDOW_SETTINGS_SYSTEM)
2871     {
2872       CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0,0,WINDOW_INVALID,g_windowManager.GetActiveWindow());
2873       g_windowManager.SendMessage(msg);
2874     }
2875     return true;
2876   }
2877
2878   // Check for global volume control
2879   if (action.GetAmount() && (action.GetID() == ACTION_VOLUME_UP || action.GetID() == ACTION_VOLUME_DOWN))
2880   {
2881     if (!m_pPlayer->IsPassthrough())
2882     {
2883       if (m_muted)
2884         UnMute();
2885       float volume = m_volumeLevel;
2886 // Android has steps based on the max available volume level
2887 #if defined(TARGET_ANDROID)
2888       float step = (VOLUME_MAXIMUM - VOLUME_MINIMUM) / CXBMCApp::GetMaxSystemVolume();
2889 #else
2890       float step   = (VOLUME_MAXIMUM - VOLUME_MINIMUM) / VOLUME_CONTROL_STEPS;
2891
2892       if (action.GetRepeat())
2893         step *= action.GetRepeat() * 50; // 50 fps
2894 #endif
2895       if (action.GetID() == ACTION_VOLUME_UP)
2896         volume += (float)fabs(action.GetAmount()) * action.GetAmount() * step;
2897       else
2898         volume -= (float)fabs(action.GetAmount()) * action.GetAmount() * step;
2899       SetVolume(volume, false);
2900     }
2901     // show visual feedback of volume change...
2902     ShowVolumeBar(&action);
2903     return true;
2904   }
2905   // Check for global seek control
2906   if (m_pPlayer->IsPlaying() && action.GetAmount() && (action.GetID() == ACTION_ANALOG_SEEK_FORWARD || action.GetID() == ACTION_ANALOG_SEEK_BACK))
2907   {
2908     if (!m_pPlayer->CanSeek()) return false;
2909     m_seekHandler->Seek(action.GetID() == ACTION_ANALOG_SEEK_FORWARD, action.GetAmount(), action.GetRepeat());
2910     return true;
2911   }
2912   if (action.GetID() == ACTION_GUIPROFILE_BEGIN)
2913   {
2914     CGUIControlProfiler::Instance().SetOutputFile(CSpecialProtocol::TranslatePath("special://home/guiprofiler.xml"));
2915     CGUIControlProfiler::Instance().Start();
2916     return true;
2917   }
2918   if (action.GetID() == ACTION_SHOW_PLAYLIST)
2919   {
2920     int iPlaylist = g_playlistPlayer.GetCurrentPlaylist();
2921     if (iPlaylist == PLAYLIST_VIDEO && g_windowManager.GetActiveWindow() != WINDOW_VIDEO_PLAYLIST)
2922       g_windowManager.ActivateWindow(WINDOW_VIDEO_PLAYLIST);
2923     else if (iPlaylist == PLAYLIST_MUSIC && g_windowManager.GetActiveWindow() != WINDOW_MUSIC_PLAYLIST)
2924       g_windowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST);
2925     return true;
2926   }
2927   return false;
2928 }
2929
2930 void CApplication::FrameMove(bool processEvents, bool processGUI)
2931 {
2932   MEASURE_FUNCTION;
2933
2934   if (processEvents)
2935   {
2936     // currently we calculate the repeat time (ie time from last similar keypress) just global as fps
2937     float frameTime = m_frameTime.GetElapsedSeconds();
2938     m_frameTime.StartZero();
2939     // never set a frametime less than 2 fps to avoid problems when debuggin and on breaks
2940     if( frameTime > 0.5 ) frameTime = 0.5;
2941
2942     if (processGUI && m_renderGUI)
2943     {
2944       g_graphicsContext.Lock();
2945       // check if there are notifications to display
2946       CGUIDialogKaiToast *toast = (CGUIDialogKaiToast *)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST);
2947       if (toast && toast->DoWork())
2948       {
2949         if (!toast->IsDialogRunning())
2950         {
2951           toast->Show();
2952         }
2953       }
2954       g_graphicsContext.Unlock();
2955     }
2956     CWinEvents::MessagePump();
2957
2958 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
2959     // Read the input from a remote
2960     g_RemoteControl.Update();
2961 #endif
2962
2963     // process input actions
2964     ProcessRemote(frameTime);
2965     ProcessGamepad(frameTime);
2966     ProcessEventServer(frameTime);
2967     ProcessPeripherals(frameTime);
2968     if (processGUI && m_renderGUI)
2969     {
2970       m_pInertialScrollingHandler->ProcessInertialScroll(frameTime);
2971       m_seekHandler->Process();
2972     }
2973   }
2974   if (processGUI && m_renderGUI)
2975   {
2976     if (!m_bStop)
2977       g_windowManager.Process(CTimeUtils::GetFrameTime());
2978     g_windowManager.FrameMove();
2979   }
2980 }
2981
2982 bool CApplication::ProcessGamepad(float frameTime)
2983 {
2984 #ifdef HAS_SDL_JOYSTICK
2985   if (!m_AppFocused)
2986     return false;
2987
2988   int iWin = GetActiveWindowID();
2989   int bid = 0;
2990   g_Joystick.Update();
2991   if (g_Joystick.GetButton(bid))
2992   {
2993     // reset Idle Timer
2994     m_idleTimer.StartZero();
2995
2996     ResetScreenSaver();
2997     if (WakeUpScreenSaverAndDPMS())
2998     {
2999       g_Joystick.Reset(true);
3000       return true;
3001     }
3002
3003     int actionID;
3004     CStdString actionName;
3005     bool fullrange;
3006     if (CButtonTranslator::GetInstance().TranslateJoystickString(iWin, g_Joystick.GetJoystick().c_str(), bid, JACTIVE_BUTTON, actionID, actionName, fullrange))
3007     {
3008       CAction action(actionID, 1.0f, 0.0f, actionName);
3009       g_Joystick.Reset();
3010       g_Mouse.SetActive(false);
3011       return ExecuteInputAction(action);
3012     }
3013     else
3014     {
3015       g_Joystick.Reset();
3016     }
3017   }
3018   if (g_Joystick.GetAxis(bid))
3019   {
3020     if (g_Joystick.GetAmount() < 0)
3021     {
3022       bid = -bid;
3023     }
3024
3025     int actionID;
3026     CStdString actionName;
3027     bool fullrange;
3028     if (CButtonTranslator::GetInstance().TranslateJoystickString(iWin, g_Joystick.GetJoystick().c_str(), bid, JACTIVE_AXIS, actionID, actionName, fullrange))
3029     {
3030       ResetScreenSaver();
3031       if (WakeUpScreenSaverAndDPMS())
3032       {
3033         return true;
3034       }
3035
3036       CAction action(actionID, fullrange ? (g_Joystick.GetAmount() + 1.0f)/2.0f : fabs(g_Joystick.GetAmount()), 0.0f, actionName);
3037       g_Joystick.Reset();
3038       g_Mouse.SetActive(false);
3039       return ExecuteInputAction(action);
3040     }
3041     else
3042     {
3043       g_Joystick.ResetAxis(abs(bid));
3044     }
3045   }
3046   int position = 0;
3047   if (g_Joystick.GetHat(bid, position))
3048   {
3049     // reset Idle Timer
3050     m_idleTimer.StartZero();
3051
3052     ResetScreenSaver();
3053     if (WakeUpScreenSaverAndDPMS())
3054     {
3055       g_Joystick.Reset();
3056       return true;
3057     }
3058
3059     int actionID;
3060     CStdString actionName;
3061     bool fullrange;
3062
3063     bid = position<<16|bid;
3064
3065     if (bid && CButtonTranslator::GetInstance().TranslateJoystickString(iWin, g_Joystick.GetJoystick().c_str(), bid, JACTIVE_HAT, actionID, actionName, fullrange))
3066     {
3067       CAction action(actionID, 1.0f, 0.0f, actionName);
3068       g_Joystick.Reset();
3069       g_Mouse.SetActive(false);
3070       return ExecuteInputAction(action);
3071     }
3072   }
3073 #endif
3074   return false;
3075 }
3076
3077 bool CApplication::ProcessRemote(float frameTime)
3078 {
3079 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
3080   if (g_RemoteControl.GetButton())
3081   {
3082     CKey key(g_RemoteControl.GetButton(), g_RemoteControl.GetHoldTime());
3083     g_RemoteControl.Reset();
3084     return OnKey(key);
3085   }
3086 #endif
3087   return false;
3088 }
3089
3090 bool CApplication::ProcessPeripherals(float frameTime)
3091 {
3092   CKey key;
3093   if (g_peripherals.GetNextKeypress(frameTime, key))
3094     return OnKey(key);
3095   return false;
3096 }
3097
3098 bool CApplication::ProcessMouse()
3099 {
3100   MEASURE_FUNCTION;
3101
3102   if (!g_Mouse.IsActive() || !m_AppFocused)
3103     return false;
3104
3105   // Get the mouse command ID
3106   uint32_t mousecommand = g_Mouse.GetAction();
3107   if (mousecommand == ACTION_NOOP)
3108     return true;
3109
3110   // Reset the screensaver and idle timers
3111   m_idleTimer.StartZero();
3112   ResetScreenSaver();
3113   if (WakeUpScreenSaverAndDPMS())
3114     return true;
3115
3116   // Retrieve the corresponding action
3117   int iWin = GetActiveWindowID();
3118   CKey key(mousecommand | KEY_MOUSE, (unsigned int) 0);
3119   CAction mouseaction = CButtonTranslator::GetInstance().GetAction(iWin, key);
3120
3121   // Deactivate mouse if non-mouse action
3122   if (!mouseaction.IsMouse())
3123     g_Mouse.SetActive(false);
3124
3125   // Consume ACTION_NOOP.
3126   // Some views or dialogs gets closed after any ACTION and
3127   // a sensitive mouse might cause problems.
3128   if (mouseaction.GetID() == ACTION_NOOP)
3129     return false;
3130
3131   // If we couldn't find an action return false to indicate we have not
3132   // handled this mouse action
3133   if (!mouseaction.GetID())
3134   {
3135     CLog::Log(LOGDEBUG, "%s: unknown mouse command %d", __FUNCTION__, mousecommand);
3136     return false;
3137   }
3138
3139   // Log mouse actions except for move and noop
3140   if (mouseaction.GetID() != ACTION_MOUSE_MOVE && mouseaction.GetID() != ACTION_NOOP)
3141     CLog::Log(LOGDEBUG, "%s: trying mouse action %s", __FUNCTION__, mouseaction.GetName().c_str());
3142
3143   // The action might not be a mouse action. For example wheel moves might
3144   // be mapped to volume up/down in mouse.xml. In this case we do not want
3145   // the mouse position saved in the action.
3146   if (!mouseaction.IsMouse())
3147     return OnAction(mouseaction);
3148
3149   // This is a mouse action so we need to record the mouse position
3150   return OnAction(CAction(mouseaction.GetID(),
3151                           g_Mouse.GetHold(MOUSE_LEFT_BUTTON),
3152                           (float)g_Mouse.GetX(),
3153                           (float)g_Mouse.GetY(),
3154                           (float)g_Mouse.GetDX(),
3155                           (float)g_Mouse.GetDY(),
3156                           mouseaction.GetName()));
3157 }
3158
3159 bool CApplication::ProcessEventServer(float frameTime)
3160 {
3161 #ifdef HAS_EVENT_SERVER
3162   CEventServer* es = CEventServer::GetInstance();
3163   if (!es || !es->Running() || es->GetNumberOfClients()==0)
3164     return false;
3165
3166   // process any queued up actions
3167   if (es->ExecuteNextAction())
3168   {
3169     // reset idle timers
3170     m_idleTimer.StartZero();
3171     ResetScreenSaver();
3172     WakeUpScreenSaverAndDPMS();
3173   }
3174
3175   // now handle any buttons or axis
3176   std::string joystickName;
3177   bool isAxis = false;
3178   float fAmount = 0.0;
3179
3180   // es->ExecuteNextAction() invalidates the ref to the CEventServer instance
3181   // when the action exits XBMC
3182   es = CEventServer::GetInstance();
3183   if (!es || !es->Running() || es->GetNumberOfClients()==0)
3184     return false;
3185   unsigned int wKeyID = es->GetButtonCode(joystickName, isAxis, fAmount);
3186
3187   if (wKeyID)
3188   {
3189     if (joystickName.length() > 0)
3190     {
3191       if (isAxis == true)
3192       {
3193         if (fabs(fAmount) >= 0.08)
3194           m_lastAxisMap[joystickName][wKeyID] = fAmount;
3195         else
3196           m_lastAxisMap[joystickName].erase(wKeyID);
3197       }
3198
3199       return ProcessJoystickEvent(joystickName, wKeyID, isAxis ? JACTIVE_AXIS : JACTIVE_BUTTON, fAmount);
3200     }
3201     else
3202     {
3203       CKey key;
3204       if (wKeyID & ES_FLAG_UNICODE)
3205       {
3206         key = CKey((uint8_t)0, wKeyID & ~ES_FLAG_UNICODE, 0, 0, 0);
3207         return OnKey(key);
3208       }
3209
3210       if(wKeyID == KEY_BUTTON_LEFT_ANALOG_TRIGGER)
3211         key = CKey(wKeyID, (BYTE)(255*fAmount), 0, 0.0, 0.0, 0.0, 0.0, frameTime);
3212       else if(wKeyID == KEY_BUTTON_RIGHT_ANALOG_TRIGGER)
3213         key = CKey(wKeyID, 0, (BYTE)(255*fAmount), 0.0, 0.0, 0.0, 0.0, frameTime);
3214       else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_LEFT)
3215         key = CKey(wKeyID, 0, 0, -fAmount, 0.0, 0.0, 0.0, frameTime);
3216       else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_RIGHT)
3217         key = CKey(wKeyID, 0, 0,  fAmount, 0.0, 0.0, 0.0, frameTime);
3218       else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_UP)
3219         key = CKey(wKeyID, 0, 0, 0.0,  fAmount, 0.0, 0.0, frameTime);
3220       else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_DOWN)
3221         key = CKey(wKeyID, 0, 0, 0.0, -fAmount, 0.0, 0.0, frameTime);
3222       else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_LEFT)
3223         key = CKey(wKeyID, 0, 0, 0.0, 0.0, -fAmount, 0.0, frameTime);
3224       else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT)
3225         key = CKey(wKeyID, 0, 0, 0.0, 0.0,  fAmount, 0.0, frameTime);
3226       else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_UP)
3227         key = CKey(wKeyID, 0, 0, 0.0, 0.0, 0.0,  fAmount, frameTime);
3228       else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_DOWN)
3229         key = CKey(wKeyID, 0, 0, 0.0, 0.0, 0.0, -fAmount, frameTime);
3230       else
3231         key = CKey(wKeyID);
3232       key.SetFromService(true);
3233       return OnKey(key);
3234     }
3235   }
3236
3237   if (m_lastAxisMap.size() > 0)
3238   {
3239     // Process all the stored axis.
3240     for (map<std::string, map<int, float> >::iterator iter = m_lastAxisMap.begin(); iter != m_lastAxisMap.end(); ++iter)
3241     {
3242       for (map<int, float>::iterator iterAxis = (*iter).second.begin(); iterAxis != (*iter).second.end(); ++iterAxis)
3243         ProcessJoystickEvent((*iter).first, (*iterAxis).first, JACTIVE_AXIS, (*iterAxis).second);
3244     }
3245   }
3246
3247   {
3248     CPoint pos;
3249     if (es->GetMousePos(pos.x, pos.y) && g_Mouse.IsEnabled())
3250     {
3251       XBMC_Event newEvent;
3252       newEvent.type = XBMC_MOUSEMOTION;
3253       newEvent.motion.xrel = 0;
3254       newEvent.motion.yrel = 0;
3255       newEvent.motion.state = 0;
3256       newEvent.motion.which = 0x10;  // just a different value to distinguish between mouse and event client device.
3257       newEvent.motion.x = (uint16_t)pos.x;
3258       newEvent.motion.y = (uint16_t)pos.y;
3259       OnEvent(newEvent);  // had to call this to update g_Mouse position
3260       return OnAction(CAction(ACTION_MOUSE_MOVE, pos.x, pos.y));
3261     }
3262   }
3263 #endif
3264   return false;
3265 }
3266
3267 bool CApplication::ProcessJoystickEvent(const std::string& joystickName, int wKeyID, short inputType, float fAmount, unsigned int holdTime /*=0*/)
3268 {
3269 #if defined(HAS_EVENT_SERVER)
3270   m_idleTimer.StartZero();
3271
3272    // Make sure to reset screen saver, mouse.
3273    ResetScreenSaver();
3274    if (WakeUpScreenSaverAndDPMS())
3275      return true;
3276
3277 #ifdef HAS_SDL_JOYSTICK
3278    g_Joystick.Reset();
3279 #endif
3280    g_Mouse.SetActive(false);
3281
3282    int iWin = GetActiveWindowID();
3283    int actionID;
3284    CStdString actionName;
3285    bool fullRange = false;
3286
3287    // Translate using regular joystick translator.
3288    if (CButtonTranslator::GetInstance().TranslateJoystickString(iWin, joystickName.c_str(), wKeyID, inputType, actionID, actionName, fullRange))
3289      return ExecuteInputAction( CAction(actionID, fAmount, 0.0f, actionName, holdTime) );
3290    else
3291      CLog::Log(LOGDEBUG, "ERROR mapping joystick action. Joystick: %s %i",joystickName.c_str(), wKeyID);
3292 #endif
3293
3294    return false;
3295 }
3296
3297 bool CApplication::ExecuteInputAction(const CAction &action)
3298 {
3299   bool bResult = false;
3300
3301   // play sound before the action unless the button is held,
3302   // where we execute after the action as held actions aren't fired every time.
3303   if(action.GetHoldTime())
3304   {
3305     bResult = OnAction(action);
3306     if(bResult)
3307       g_audioManager.PlayActionSound(action);
3308   }
3309   else
3310   {
3311     g_audioManager.PlayActionSound(action);
3312     bResult = OnAction(action);
3313   }
3314   return bResult;
3315 }
3316
3317 int CApplication::GetActiveWindowID(void)
3318 {
3319   // Get the currently active window
3320   int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
3321
3322   // If there is a dialog active get the dialog id instead
3323   if (g_windowManager.HasModalDialog())
3324     iWin = g_windowManager.GetTopMostModalDialogID() & WINDOW_ID_MASK;
3325
3326   // If the window is FullScreenVideo check for special cases
3327   if (iWin == WINDOW_FULLSCREEN_VIDEO)
3328   {
3329     // check if we're in a DVD menu
3330     if(g_application.m_pPlayer->IsInMenu())
3331       iWin = WINDOW_VIDEO_MENU;
3332     // check for LiveTV and switch to it's virtual window
3333     else if (g_PVRManager.IsStarted() && g_application.CurrentFileItem().HasPVRChannelInfoTag())
3334       iWin = WINDOW_FULLSCREEN_LIVETV;
3335   }
3336
3337   // Return the window id
3338   return iWin;
3339 }
3340
3341 bool CApplication::Cleanup()
3342 {
3343   try
3344   {
3345     g_windowManager.Delete(WINDOW_MUSIC_PLAYLIST);
3346     g_windowManager.Delete(WINDOW_MUSIC_PLAYLIST_EDITOR);
3347     g_windowManager.Delete(WINDOW_MUSIC_FILES);
3348     g_windowManager.Delete(WINDOW_MUSIC_NAV);
3349     g_windowManager.Delete(WINDOW_DIALOG_MUSIC_INFO);
3350     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_INFO);
3351     g_windowManager.Delete(WINDOW_VIDEO_FILES);
3352     g_windowManager.Delete(WINDOW_VIDEO_PLAYLIST);
3353     g_windowManager.Delete(WINDOW_VIDEO_NAV);
3354     g_windowManager.Delete(WINDOW_FILES);
3355     g_windowManager.Delete(WINDOW_DIALOG_YES_NO);
3356     g_windowManager.Delete(WINDOW_DIALOG_PROGRESS);
3357     g_windowManager.Delete(WINDOW_DIALOG_NUMERIC);
3358     g_windowManager.Delete(WINDOW_DIALOG_GAMEPAD);
3359     g_windowManager.Delete(WINDOW_DIALOG_SUB_MENU);
3360     g_windowManager.Delete(WINDOW_DIALOG_BUTTON_MENU);
3361     g_windowManager.Delete(WINDOW_DIALOG_CONTEXT_MENU);
3362     g_windowManager.Delete(WINDOW_DIALOG_PLAYER_CONTROLS);
3363     g_windowManager.Delete(WINDOW_DIALOG_KARAOKE_SONGSELECT);
3364     g_windowManager.Delete(WINDOW_DIALOG_KARAOKE_SELECTOR);
3365     g_windowManager.Delete(WINDOW_DIALOG_MUSIC_OSD);
3366     g_windowManager.Delete(WINDOW_DIALOG_VIS_PRESET_LIST);
3367     g_windowManager.Delete(WINDOW_DIALOG_SELECT);
3368     g_windowManager.Delete(WINDOW_DIALOG_OK);
3369     g_windowManager.Delete(WINDOW_DIALOG_FILESTACKING);
3370     g_windowManager.Delete(WINDOW_DIALOG_KEYBOARD);
3371     g_windowManager.Delete(WINDOW_FULLSCREEN_VIDEO);
3372     g_windowManager.Delete(WINDOW_DIALOG_PROFILE_SETTINGS);
3373     g_windowManager.Delete(WINDOW_DIALOG_LOCK_SETTINGS);
3374     g_windowManager.Delete(WINDOW_DIALOG_NETWORK_SETUP);
3375     g_windowManager.Delete(WINDOW_DIALOG_MEDIA_SOURCE);
3376     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_OSD_SETTINGS);
3377     g_windowManager.Delete(WINDOW_DIALOG_AUDIO_OSD_SETTINGS);
3378     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_BOOKMARKS);
3379     g_windowManager.Delete(WINDOW_DIALOG_CONTENT_SETTINGS);
3380     g_windowManager.Delete(WINDOW_DIALOG_FAVOURITES);
3381     g_windowManager.Delete(WINDOW_DIALOG_SONG_INFO);
3382     g_windowManager.Delete(WINDOW_DIALOG_SMART_PLAYLIST_EDITOR);
3383     g_windowManager.Delete(WINDOW_DIALOG_SMART_PLAYLIST_RULE);
3384     g_windowManager.Delete(WINDOW_DIALOG_BUSY);
3385     g_windowManager.Delete(WINDOW_DIALOG_PICTURE_INFO);
3386     g_windowManager.Delete(WINDOW_DIALOG_ADDON_INFO);
3387     g_windowManager.Delete(WINDOW_DIALOG_ADDON_SETTINGS);
3388     g_windowManager.Delete(WINDOW_DIALOG_ACCESS_POINTS);
3389     g_windowManager.Delete(WINDOW_DIALOG_SLIDER);
3390     g_windowManager.Delete(WINDOW_DIALOG_MEDIA_FILTER);
3391     g_windowManager.Delete(WINDOW_DIALOG_SUBTITLES);
3392
3393     /* Delete PVR related windows and dialogs */
3394     g_windowManager.Delete(WINDOW_PVR);
3395     g_windowManager.Delete(WINDOW_DIALOG_PVR_GUIDE_INFO);
3396     g_windowManager.Delete(WINDOW_DIALOG_PVR_RECORDING_INFO);
3397     g_windowManager.Delete(WINDOW_DIALOG_PVR_TIMER_SETTING);
3398     g_windowManager.Delete(WINDOW_DIALOG_PVR_GROUP_MANAGER);
3399     g_windowManager.Delete(WINDOW_DIALOG_PVR_CHANNEL_MANAGER);
3400     g_windowManager.Delete(WINDOW_DIALOG_PVR_GUIDE_SEARCH);
3401     g_windowManager.Delete(WINDOW_DIALOG_PVR_CHANNEL_SCAN);
3402     g_windowManager.Delete(WINDOW_DIALOG_PVR_UPDATE_PROGRESS);
3403     g_windowManager.Delete(WINDOW_DIALOG_PVR_OSD_CHANNELS);
3404     g_windowManager.Delete(WINDOW_DIALOG_PVR_OSD_GUIDE);
3405     g_windowManager.Delete(WINDOW_DIALOG_PVR_OSD_DIRECTOR);
3406     g_windowManager.Delete(WINDOW_DIALOG_PVR_OSD_CUTTER);
3407     g_windowManager.Delete(WINDOW_DIALOG_OSD_TELETEXT);
3408
3409     g_windowManager.Delete(WINDOW_DIALOG_TEXT_VIEWER);
3410     g_windowManager.Delete(WINDOW_DIALOG_PLAY_EJECT);
3411     g_windowManager.Delete(WINDOW_STARTUP_ANIM);
3412     g_windowManager.Delete(WINDOW_LOGIN_SCREEN);
3413     g_windowManager.Delete(WINDOW_VISUALISATION);
3414     g_windowManager.Delete(WINDOW_KARAOKELYRICS);
3415     g_windowManager.Delete(WINDOW_SETTINGS_MENU);
3416     g_windowManager.Delete(WINDOW_SETTINGS_PROFILES);
3417     g_windowManager.Delete(WINDOW_SETTINGS_MYPICTURES);  // all the settings categories
3418     g_windowManager.Delete(WINDOW_TEST_PATTERN);
3419     g_windowManager.Delete(WINDOW_SCREEN_CALIBRATION);
3420     g_windowManager.Delete(WINDOW_SYSTEM_INFORMATION);
3421     g_windowManager.Delete(WINDOW_SCREENSAVER);
3422     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_OSD);
3423     g_windowManager.Delete(WINDOW_DIALOG_MUSIC_OVERLAY);
3424     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_OVERLAY);
3425     g_windowManager.Delete(WINDOW_SLIDESHOW);
3426     g_windowManager.Delete(WINDOW_ADDON_BROWSER);
3427     g_windowManager.Delete(WINDOW_SKIN_SETTINGS);
3428
3429     g_windowManager.Delete(WINDOW_HOME);
3430     g_windowManager.Delete(WINDOW_PROGRAMS);
3431     g_windowManager.Delete(WINDOW_PICTURES);
3432     g_windowManager.Delete(WINDOW_WEATHER);
3433
3434     g_windowManager.Delete(WINDOW_SETTINGS_MYPICTURES);
3435     g_windowManager.Remove(WINDOW_SETTINGS_MYPROGRAMS);
3436     g_windowManager.Remove(WINDOW_SETTINGS_MYWEATHER);
3437     g_windowManager.Remove(WINDOW_SETTINGS_MYMUSIC);
3438     g_windowManager.Remove(WINDOW_SETTINGS_SYSTEM);
3439     g_windowManager.Remove(WINDOW_SETTINGS_MYVIDEOS);
3440     g_windowManager.Remove(WINDOW_SETTINGS_SERVICE);
3441     g_windowManager.Remove(WINDOW_SETTINGS_APPEARANCE);
3442     g_windowManager.Remove(WINDOW_SETTINGS_MYPVR);
3443     g_windowManager.Remove(WINDOW_DIALOG_KAI_TOAST);
3444
3445     g_windowManager.Remove(WINDOW_DIALOG_SEEK_BAR);
3446     g_windowManager.Remove(WINDOW_DIALOG_VOLUME_BAR);
3447
3448     CAddonMgr::Get().DeInit();
3449
3450 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
3451     CLog::Log(LOGNOTICE, "closing down remote control service");
3452     g_RemoteControl.Disconnect();
3453 #endif
3454
3455     CLog::Log(LOGNOTICE, "unload sections");
3456
3457 #ifdef HAS_PERFORMANCE_SAMPLE
3458     CLog::Log(LOGNOTICE, "performance statistics");
3459     m_perfStats.DumpStats();
3460 #endif
3461
3462     //  Shutdown as much as possible of the
3463     //  application, to reduce the leaks dumped
3464     //  to the vc output window before calling
3465     //  _CrtDumpMemoryLeaks(). Most of the leaks
3466     //  shown are no real leaks, as parts of the app
3467     //  are still allocated.
3468
3469     g_localizeStrings.Clear();
3470     g_LangCodeExpander.Clear();
3471     g_charsetConverter.clear();
3472     g_directoryCache.Clear();
3473     CButtonTranslator::GetInstance().Clear();
3474 #ifdef HAS_EVENT_SERVER
3475     CEventServer::RemoveInstance();
3476 #endif
3477     DllLoaderContainer::Clear();
3478     g_playlistPlayer.Clear();
3479     CSettings::Get().Uninitialize();
3480     g_advancedSettings.Clear();
3481
3482 #ifdef TARGET_POSIX
3483     CXHandle::DumpObjectTracker();
3484
3485 #ifdef HAS_DVD_DRIVE
3486     CLibcdio::ReleaseInstance();
3487 #endif
3488 #endif 
3489 #if defined(TARGET_ANDROID)
3490     // enable for all platforms once it's safe
3491     g_sectionLoader.UnloadAll();
3492 #endif
3493 #ifdef _CRTDBG_MAP_ALLOC
3494     _CrtDumpMemoryLeaks();
3495     while(1); // execution ends
3496 #endif
3497
3498     delete m_network;
3499     m_network = NULL;
3500
3501     return true;
3502   }
3503   catch (...)
3504   {
3505     CLog::Log(LOGERROR, "Exception in CApplication::Cleanup()");
3506     return false;
3507   }
3508 }
3509
3510 void CApplication::Stop(int exitCode)
3511 {
3512   try
3513   {
3514     CVariant vExitCode(exitCode);
3515     CAnnouncementManager::Get().Announce(System, "xbmc", "OnQuit", vExitCode);
3516
3517     SaveFileState(true);
3518
3519     g_alarmClock.StopThread();
3520
3521     if( m_bSystemScreenSaverEnable )
3522       g_Windowing.EnableSystemScreenSaver(true);
3523
3524     CLog::Log(LOGNOTICE, "Storing total System Uptime");
3525     g_sysinfo.SetTotalUptime(g_sysinfo.GetTotalUptime() + (int)(CTimeUtils::GetFrameTime() / 60000));
3526
3527     // Update the settings information (volume, uptime etc. need saving)
3528     if (CFile::Exists(CProfilesManager::Get().GetSettingsFile()))
3529     {
3530       CLog::Log(LOGNOTICE, "Saving settings");
3531       CSettings::Get().Save();
3532     }
3533     else
3534       CLog::Log(LOGNOTICE, "Not saving settings (settings.xml is not present)");
3535
3536     m_bStop = true;
3537     m_AppFocused = false;
3538     m_ExitCode = exitCode;
3539     CLog::Log(LOGNOTICE, "stop all");
3540
3541     // cancel any jobs from the jobmanager
3542     CJobManager::GetInstance().CancelJobs();
3543
3544     // stop scanning before we kill the network and so on
3545     if (m_musicInfoScanner->IsScanning())
3546       m_musicInfoScanner->Stop();
3547
3548     if (m_videoInfoScanner->IsScanning())
3549       m_videoInfoScanner->Stop();
3550
3551     CApplicationMessenger::Get().Cleanup();
3552
3553     CLog::Log(LOGNOTICE, "stop player");
3554     m_pPlayer->ClosePlayer();
3555
3556     CAnnouncementManager::Get().Deinitialize();
3557
3558     StopPVRManager();
3559     StopServices();
3560     //Sleep(5000);
3561
3562 #if HAS_FILESYTEM_DAAP
3563     CLog::Log(LOGNOTICE, "stop daap clients");
3564     g_DaapClient.Release();
3565 #endif
3566 #ifdef HAS_FILESYSTEM_SAP
3567     CLog::Log(LOGNOTICE, "stop sap announcement listener");
3568     g_sapsessions.StopThread();
3569 #endif
3570 #ifdef HAS_ZEROCONF
3571     if(CZeroconfBrowser::IsInstantiated())
3572     {
3573       CLog::Log(LOGNOTICE, "stop zeroconf browser");
3574       CZeroconfBrowser::GetInstance()->Stop();
3575       CZeroconfBrowser::ReleaseInstance();
3576     }
3577 #endif
3578
3579     CLog::Log(LOGNOTICE, "clean cached files!");
3580 #ifdef HAS_FILESYSTEM_RAR
3581     g_RarManager.ClearCache(true);
3582 #endif
3583
3584 #ifdef HAS_FILESYSTEM_SFTP
3585     CSFTPSessionManager::DisconnectAllSessions();
3586 #endif
3587
3588     CLog::Log(LOGNOTICE, "unload skin");
3589     UnloadSkin();
3590
3591 #if defined(TARGET_DARWIN_OSX)
3592     if (XBMCHelper::GetInstance().IsAlwaysOn() == false)
3593       XBMCHelper::GetInstance().Stop();
3594 #endif
3595
3596 #if defined(HAVE_LIBCRYSTALHD)
3597     CCrystalHD::RemoveInstance();
3598 #endif
3599
3600     g_mediaManager.Stop();
3601
3602     // Stop services before unloading Python
3603     CAddonMgr::Get().StopServices(false);
3604
3605     // stop all remaining scripts; must be done after skin has been unloaded,
3606     // not before some windows still need it when deinitializing during skin
3607     // unloading
3608     CScriptInvocationManager::Get().Uninitialize();
3609
3610     g_Windowing.DestroyRenderSystem();
3611     g_Windowing.DestroyWindow();
3612     g_Windowing.DestroyWindowSystem();
3613
3614     // shutdown the AudioEngine
3615     CAEFactory::Shutdown();
3616     CAEFactory::UnLoadEngine();
3617
3618     // unregister ffmpeg lock manager call back
3619     av_lockmgr_register(NULL);
3620
3621     CLog::Log(LOGNOTICE, "stopped");
3622   }
3623   catch (...)
3624   {
3625     CLog::Log(LOGERROR, "Exception in CApplication::Stop()");
3626   }
3627
3628   // we may not get to finish the run cycle but exit immediately after a call to g_application.Stop()
3629   // so we may never get to Destroy() in CXBApplicationEx::Run(), we call it here.
3630   Destroy();
3631
3632   //
3633   Sleep(200);
3634 }
3635
3636 bool CApplication::PlayMedia(const CFileItem& item, int iPlaylist)
3637 {
3638   //If item is a plugin, expand out now and run ourselves again
3639   if (item.IsPlugin())
3640   {
3641     CFileItem item_new(item);
3642     if (XFILE::CPluginDirectory::GetPluginResult(item.GetPath(), item_new))
3643       return PlayMedia(item_new, iPlaylist);
3644     return false;
3645   }
3646   if (item.IsSmartPlayList())
3647   {
3648     CFileItemList items;
3649     CUtil::GetRecursiveListing(item.GetPath(), items, "", DIR_FLAG_NO_FILE_DIRS);
3650     if (items.Size())
3651     {
3652       CSmartPlaylist smartpl;
3653       //get name and type of smartplaylist, this will always succeed as GetDirectory also did this.
3654       smartpl.OpenAndReadName(item.GetURL());
3655       CPlayList playlist;
3656       playlist.Add(items);
3657       return ProcessAndStartPlaylist(smartpl.GetName(), playlist, (smartpl.GetType() == "songs" || smartpl.GetType() == "albums") ? PLAYLIST_MUSIC:PLAYLIST_VIDEO);
3658     }
3659   }
3660   else if (item.IsPlayList() || item.IsInternetStream())
3661   {
3662     CGUIDialogCache* dlgCache = new CGUIDialogCache(5000, g_localizeStrings.Get(10214), item.GetLabel());
3663
3664     //is or could be a playlist
3665     auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(item));
3666     bool gotPlayList = (pPlayList.get() && pPlayList->Load(item.GetPath()));
3667
3668     if (dlgCache)
3669     {
3670        dlgCache->Close();
3671        if (dlgCache->IsCanceled())
3672           return true;
3673     }
3674
3675     if (gotPlayList)
3676     {
3677
3678       if (iPlaylist != PLAYLIST_NONE)
3679       {
3680         int track=0;
3681         if (item.HasProperty("playlist_starting_track"))
3682           track = (int)item.GetProperty("playlist_starting_track").asInteger();
3683         return ProcessAndStartPlaylist(item.GetPath(), *pPlayList, iPlaylist, track);
3684       }
3685       else
3686       {
3687         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());
3688         if(pPlayList->size())
3689           return PlayFile(*(*pPlayList)[0], false) == PLAYBACK_OK;
3690       }
3691     }
3692   }
3693
3694   //nothing special just play
3695   return PlayFile(item, false) == PLAYBACK_OK;
3696 }
3697
3698 // PlayStack()
3699 // For playing a multi-file video.  Particularly inefficient
3700 // on startup, as we are required to calculate the length
3701 // of each video, so we open + close each one in turn.
3702 // A faster calculation of video time would improve this
3703 // substantially.
3704 // return value: same with PlayFile()
3705 PlayBackRet CApplication::PlayStack(const CFileItem& item, bool bRestart)
3706 {
3707   if (!item.IsStack())
3708     return PLAYBACK_FAIL;
3709
3710   CVideoDatabase dbs;
3711
3712   // case 1: stacked ISOs
3713   if (CFileItem(CStackDirectory::GetFirstStackedFile(item.GetPath()),false).IsDVDImage())
3714   {
3715     CStackDirectory dir;
3716     CFileItemList movieList;
3717     dir.GetDirectory(item.GetURL(), movieList);
3718
3719     // first assume values passed to the stack
3720     int selectedFile = item.m_lStartPartNumber;
3721     int startoffset = item.m_lStartOffset;
3722
3723     // check if we instructed the stack to resume from default
3724     if (startoffset == STARTOFFSET_RESUME) // selected file is not specified, pick the 'last' resume point
3725     {
3726       if (dbs.Open())
3727       {
3728         CBookmark bookmark;
3729         CStdString path = item.GetPath();
3730         if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
3731           path = item.GetProperty("original_listitem_url").asString();
3732         if( dbs.GetResumeBookMark(path, bookmark) )
3733         {
3734           startoffset = (int)(bookmark.timeInSeconds*75);
3735           selectedFile = bookmark.partNumber;
3736         }
3737         dbs.Close();
3738       }
3739       else
3740         CLog::Log(LOGERROR, "%s - Cannot open VideoDatabase", __FUNCTION__);
3741     }
3742
3743     // make sure that the selected part is within the boundaries
3744     if (selectedFile <= 0)
3745     {
3746       CLog::Log(LOGWARNING, "%s - Selected part %d out of range, playing part 1", __FUNCTION__, selectedFile);
3747       selectedFile = 1;
3748     }
3749     else if (selectedFile > movieList.Size())
3750     {
3751       CLog::Log(LOGWARNING, "%s - Selected part %d out of range, playing part %d", __FUNCTION__, selectedFile, movieList.Size());
3752       selectedFile = movieList.Size();
3753     }
3754
3755     // set startoffset in movieitem, track stack item for updating purposes, and finally play disc part
3756     movieList[selectedFile - 1]->m_lStartOffset = startoffset > 0 ? STARTOFFSET_RESUME : 0;
3757     movieList[selectedFile - 1]->SetProperty("stackFileItemToUpdate", true);
3758     *m_stackFileItemToUpdate = item;
3759     return PlayFile(*(movieList[selectedFile - 1]));
3760   }
3761   // case 2: all other stacks
3762   else
3763   {
3764     // see if we have the info in the database
3765     // TODO: If user changes the time speed (FPS via framerate conversion stuff)
3766     //       then these times will be wrong.
3767     //       Also, this is really just a hack for the slow load up times we have
3768     //       A much better solution is a fast reader of FPS and fileLength
3769     //       that we can use on a file to get it's time.
3770     vector<int> times;
3771     bool haveTimes(false);
3772     CVideoDatabase dbs;
3773     if (dbs.Open())
3774     {
3775       dbs.GetVideoSettings(item.GetPath(), CMediaSettings::Get().GetCurrentVideoSettings());
3776       haveTimes = dbs.GetStackTimes(item.GetPath(), times);
3777       dbs.Close();
3778     }
3779
3780
3781     // calculate the total time of the stack
3782     CStackDirectory dir;
3783     dir.GetDirectory(item.GetURL(), *m_currentStack);
3784     long totalTime = 0;
3785     for (int i = 0; i < m_currentStack->Size(); i++)
3786     {
3787       if (haveTimes)
3788         (*m_currentStack)[i]->m_lEndOffset = times[i];
3789       else
3790       {
3791         int duration;
3792         if (!CDVDFileInfo::GetFileDuration((*m_currentStack)[i]->GetPath(), duration))
3793         {
3794           m_currentStack->Clear();
3795           return PLAYBACK_FAIL;
3796         }
3797         totalTime += duration / 1000;
3798         (*m_currentStack)[i]->m_lEndOffset = totalTime;
3799         times.push_back(totalTime);
3800       }
3801     }
3802
3803     double seconds = item.m_lStartOffset / 75.0;
3804
3805     if (!haveTimes || item.m_lStartOffset == STARTOFFSET_RESUME )
3806     {  // have our times now, so update the dB
3807       if (dbs.Open())
3808       {
3809         if( !haveTimes )
3810           dbs.SetStackTimes(item.GetPath(), times);
3811
3812         if( item.m_lStartOffset == STARTOFFSET_RESUME )
3813         {
3814           // can only resume seek here, not dvdstate
3815           CBookmark bookmark;
3816           CStdString path = item.GetPath();
3817           if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
3818             path = item.GetProperty("original_listitem_url").asString();
3819           if( dbs.GetResumeBookMark(path, bookmark) )
3820             seconds = bookmark.timeInSeconds;
3821           else
3822             seconds = 0.0f;
3823         }
3824         dbs.Close();
3825       }
3826     }
3827
3828     *m_itemCurrentFile = item;
3829     m_currentStackPosition = 0;
3830     m_pPlayer->ResetPlayer(); // must be reset on initial play otherwise last player will be used
3831
3832     if (seconds > 0)
3833     {
3834       // work out where to seek to
3835       for (int i = 0; i < m_currentStack->Size(); i++)
3836       {
3837         if (seconds < (*m_currentStack)[i]->m_lEndOffset)
3838         {
3839           CFileItem item(*(*m_currentStack)[i]);
3840           long start = (i > 0) ? (*m_currentStack)[i-1]->m_lEndOffset : 0;
3841           item.m_lStartOffset = (long)(seconds - start) * 75;
3842           m_currentStackPosition = i;
3843           return PlayFile(item, true);
3844         }
3845       }
3846     }
3847
3848     return PlayFile(*(*m_currentStack)[0], true);
3849   }
3850   return PLAYBACK_FAIL;
3851 }
3852
3853 PlayBackRet CApplication::PlayFile(const CFileItem& item, bool bRestart)
3854 {
3855   // Ensure the MIME type has been retrieved for http:// and shout:// streams
3856   if (item.GetMimeType().empty())
3857     const_cast<CFileItem&>(item).FillInMimeType();
3858
3859   if (!bRestart)
3860   {
3861     SaveCurrentFileSettings();
3862
3863     OutputDebugString("new file set audiostream:0\n");
3864     // Switch to default options
3865     CMediaSettings::Get().GetCurrentVideoSettings() = CMediaSettings::Get().GetDefaultVideoSettings();
3866     // see if we have saved options in the database
3867
3868     m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
3869     m_pPlayer->m_iPlaySpeed = 1;     // Reset both CApp's & Player's speed else we'll get confused
3870
3871     *m_itemCurrentFile = item;
3872     m_nextPlaylistItem = -1;
3873     m_currentStackPosition = 0;
3874     m_currentStack->Clear();
3875
3876     if (item.IsVideo())
3877       CUtil::ClearSubtitles();
3878   }
3879
3880   if (item.IsDiscStub())
3881   {
3882 #ifdef HAS_DVD_DRIVE
3883     // Display the Play Eject dialog if there is any optical disc drive
3884     if (g_mediaManager.HasOpticalDrive())
3885     {
3886       if (CGUIDialogPlayEject::ShowAndGetInput(item))
3887         // PlayDiscAskResume takes path to disc. No parameter means default DVD drive.
3888         // Can't do better as CGUIDialogPlayEject calls CMediaManager::IsDiscInDrive, which assumes default DVD drive anyway
3889         return MEDIA_DETECT::CAutorun::PlayDiscAskResume() ? PLAYBACK_OK : PLAYBACK_FAIL;
3890     }
3891     else
3892 #endif
3893       CGUIDialogOK::ShowAndGetInput(435, 0, 436, 0);
3894
3895     return PLAYBACK_OK;
3896   }
3897
3898   if (item.IsPlayList())
3899     return PLAYBACK_FAIL;
3900
3901   if (item.IsPlugin())
3902   { // we modify the item so that it becomes a real URL
3903     CFileItem item_new(item);
3904     if (XFILE::CPluginDirectory::GetPluginResult(item.GetPath(), item_new))
3905       return PlayFile(item_new, false);
3906     return PLAYBACK_FAIL;
3907   }
3908
3909 #ifdef HAS_UPNP
3910   if (URIUtils::IsUPnP(item.GetPath()))
3911   {
3912     CFileItem item_new(item);
3913     if (XFILE::CUPnPDirectory::GetResource(item.GetURL(), item_new))
3914       return PlayFile(item_new, false);
3915     return PLAYBACK_FAIL;
3916   }
3917 #endif
3918
3919   // if we have a stacked set of files, we need to setup our stack routines for
3920   // "seamless" seeking and total time of the movie etc.
3921   // will recall with restart set to true
3922   if (item.IsStack())
3923     return PlayStack(item, bRestart);
3924
3925   //Is TuxBox, this should probably be moved to CTuxBoxFile
3926   if(item.IsTuxBox())
3927   {
3928     CLog::Log(LOGDEBUG, "%s - TuxBox URL Detected %s",__FUNCTION__, item.GetPath().c_str());
3929
3930     if(g_tuxboxService.IsRunning())
3931       g_tuxboxService.Stop();
3932
3933     PlayBackRet ret = PLAYBACK_FAIL;
3934     CFileItem item_new;
3935     if(g_tuxbox.CreateNewItem(item, item_new))
3936     {
3937
3938       // Make sure it doesn't have a player
3939       // so we actually select one normally
3940       m_pPlayer->ResetPlayer();
3941
3942       // keep the tuxbox:// url as playing url
3943       // and give the new url to the player
3944       ret = PlayFile(item_new, true);
3945       if(ret == PLAYBACK_OK)
3946       {
3947         if(!g_tuxboxService.IsRunning())
3948           g_tuxboxService.Start();
3949       }
3950     }
3951     return ret;
3952   }
3953
3954   CPlayerOptions options;
3955
3956   if( item.HasProperty("StartPercent") )
3957   {
3958     double fallback = 0.0f;
3959     if(item.GetProperty("StartPercent").isString())
3960       fallback = (double)atof(item.GetProperty("StartPercent").asString().c_str());
3961     options.startpercent = item.GetProperty("StartPercent").asDouble(fallback);
3962   }
3963
3964   PLAYERCOREID eNewCore = EPC_NONE;
3965   if( bRestart )
3966   {
3967     // have to be set here due to playstack using this for starting the file
3968     options.starttime = item.m_lStartOffset / 75.0;
3969     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0 && m_itemCurrentFile->m_lStartOffset != 0)
3970       m_itemCurrentFile->m_lStartOffset = STARTOFFSET_RESUME; // to force fullscreen switching
3971
3972     if( m_eForcedNextPlayer != EPC_NONE )
3973       eNewCore = m_eForcedNextPlayer;
3974     else if( m_pPlayer->GetCurrentPlayer() == EPC_NONE )
3975       eNewCore = CPlayerCoreFactory::Get().GetDefaultPlayer(item);
3976     else
3977       eNewCore = m_pPlayer->GetCurrentPlayer();
3978   }
3979   else
3980   {
3981     options.starttime = item.m_lStartOffset / 75.0;
3982
3983     if (item.IsVideo())
3984     {
3985       // open the d/b and retrieve the bookmarks for the current movie
3986       CVideoDatabase dbs;
3987       dbs.Open();
3988       dbs.GetVideoSettings(item.GetPath(), CMediaSettings::Get().GetCurrentVideoSettings());
3989
3990       if( item.m_lStartOffset == STARTOFFSET_RESUME )
3991       {
3992         options.starttime = 0.0f;
3993         CBookmark bookmark;
3994         CStdString path = item.GetPath();
3995         if (item.HasVideoInfoTag() && StringUtils::StartsWith(item.GetVideoInfoTag()->m_strFileNameAndPath, "removable://"))
3996           path = item.GetVideoInfoTag()->m_strFileNameAndPath;
3997         else if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
3998           path = item.GetProperty("original_listitem_url").asString();
3999         if(dbs.GetResumeBookMark(path, bookmark))
4000         {
4001           options.starttime = bookmark.timeInSeconds;
4002           options.state = bookmark.playerState;
4003         }
4004         /*
4005          override with information from the actual item if available.  We do this as the VFS (eg plugins)
4006          may set the resume point to override whatever XBMC has stored, yet we ignore it until now so that,
4007          should the playerState be required, it is fetched from the database.
4008          See the note in CGUIWindowVideoBase::ShowResumeMenu.
4009          */
4010         if (item.IsResumePointSet())
4011           options.starttime = item.GetCurrentResumeTime();
4012       }
4013       else if (item.HasVideoInfoTag())
4014       {
4015         const CVideoInfoTag *tag = item.GetVideoInfoTag();
4016
4017         if (tag->m_iBookmarkId != -1 && tag->m_iBookmarkId != 0)
4018         {
4019           CBookmark bookmark;
4020           dbs.GetBookMarkForEpisode(*tag, bookmark);
4021           options.starttime = bookmark.timeInSeconds;
4022           options.state = bookmark.playerState;
4023         }
4024       }
4025
4026       dbs.Close();
4027     }
4028
4029     if (m_eForcedNextPlayer != EPC_NONE)
4030       eNewCore = m_eForcedNextPlayer;
4031     else
4032       eNewCore = CPlayerCoreFactory::Get().GetDefaultPlayer(item);
4033   }
4034
4035   // this really aught to be inside !bRestart, but since PlayStack
4036   // uses that to init playback, we have to keep it outside
4037   int playlist = g_playlistPlayer.GetCurrentPlaylist();
4038   if (item.IsVideo() && playlist == PLAYLIST_VIDEO && g_playlistPlayer.GetPlaylist(playlist).size() > 1)
4039   { // playing from a playlist by the looks
4040     // don't switch to fullscreen if we are not playing the first item...
4041     options.fullscreen = !g_playlistPlayer.HasPlayedFirstFile() && g_advancedSettings.m_fullScreenOnMovieStart && !CMediaSettings::Get().DoesVideoStartWindowed();
4042   }
4043   else if(m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
4044   {
4045     // TODO - this will fail if user seeks back to first file in stack
4046     if(m_currentStackPosition == 0 || m_itemCurrentFile->m_lStartOffset == STARTOFFSET_RESUME)
4047       options.fullscreen = g_advancedSettings.m_fullScreenOnMovieStart && !CMediaSettings::Get().DoesVideoStartWindowed();
4048     else
4049       options.fullscreen = false;
4050     // reset this so we don't think we are resuming on seek
4051     m_itemCurrentFile->m_lStartOffset = 0;
4052   }
4053   else
4054     options.fullscreen = g_advancedSettings.m_fullScreenOnMovieStart && !CMediaSettings::Get().DoesVideoStartWindowed();
4055
4056   // reset VideoStartWindowed as it's a temp setting
4057   CMediaSettings::Get().SetVideoStartWindowed(false);
4058
4059 #ifdef HAS_KARAOKE
4060   //We have to stop parsing a cdg before mplayer is deallocated
4061   // WHY do we have to do this????
4062   if (m_pKaraokeMgr)
4063     m_pKaraokeMgr->Stop();
4064 #endif
4065
4066   {
4067     CSingleLock lock(m_playStateMutex);
4068     // tell system we are starting a file
4069     m_bPlaybackStarting = true;
4070     
4071     // for playing a new item, previous playing item's callback may already
4072     // pushed some delay message into the threadmessage list, they are not
4073     // expected be processed after or during the new item playback starting.
4074     // so we clean up previous playing item's playback callback delay messages here.
4075     int previousMsgsIgnoredByNewPlaying[] = {
4076       GUI_MSG_PLAYBACK_STARTED,
4077       GUI_MSG_PLAYBACK_ENDED,
4078       GUI_MSG_PLAYBACK_STOPPED,
4079       GUI_MSG_PLAYLIST_CHANGED,
4080       GUI_MSG_PLAYLISTPLAYER_STOPPED,
4081       GUI_MSG_PLAYLISTPLAYER_STARTED,
4082       GUI_MSG_PLAYLISTPLAYER_CHANGED,
4083       GUI_MSG_QUEUE_NEXT_ITEM,
4084       0
4085     };
4086     int dMsgCount = g_windowManager.RemoveThreadMessageByMessageIds(&previousMsgsIgnoredByNewPlaying[0]);
4087     if (dMsgCount > 0)
4088       CLog::Log(LOGDEBUG,"%s : Ignored %d playback thread messages", __FUNCTION__, dMsgCount);
4089   }
4090
4091   // We should restart the player, unless the previous and next tracks are using
4092   // one of the players that allows gapless playback (paplayer, dvdplayer)
4093   m_pPlayer->ClosePlayerGapless(eNewCore);
4094
4095   // now reset play state to starting, since we already stopped the previous playing item if there is.
4096   // and from now there should be no playback callback from previous playing item be called.
4097   m_ePlayState = PLAY_STATE_STARTING;
4098
4099   m_pPlayer->CreatePlayer(eNewCore, *this);
4100
4101   PlayBackRet iResult;
4102   if (m_pPlayer->HasPlayer())
4103   {
4104     /* When playing video pause any low priority jobs, they will be unpaused  when playback stops.
4105      * This should speed up player startup for files on internet filesystems (eg. webdav) and
4106      * increase performance on low powered systems (Atom/ARM).
4107      */
4108     if (item.IsVideo())
4109     {
4110       CJobManager::GetInstance().PauseJobs();
4111     }
4112
4113     // don't hold graphicscontext here since player
4114     // may wait on another thread, that requires gfx
4115     CSingleExit ex(g_graphicsContext);
4116
4117     iResult = m_pPlayer->OpenFile(item, options);
4118   }
4119   else
4120   {
4121     CLog::Log(LOGERROR, "Error creating player for item %s (File doesn't exist?)", item.GetPath().c_str());
4122     iResult = PLAYBACK_FAIL;
4123   }
4124
4125   if(iResult == PLAYBACK_OK)
4126   {
4127     if (m_pPlayer->GetPlaySpeed() != 1)
4128     {
4129       int iSpeed = m_pPlayer->GetPlaySpeed();
4130       m_pPlayer->m_iPlaySpeed = 1;
4131       m_pPlayer->SetPlaySpeed(iSpeed, g_application.m_muted);
4132     }
4133
4134     // if player has volume control, set it.
4135     if (m_pPlayer->ControlsVolume())
4136     {
4137        m_pPlayer->SetVolume(m_volumeLevel);
4138        m_pPlayer->SetMute(m_muted);
4139     }
4140
4141     if( m_pPlayer->IsPlayingAudio() )
4142     {
4143       if (g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
4144         g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
4145     }
4146
4147 #ifdef HAS_VIDEO_PLAYBACK
4148     else if( m_pPlayer->IsPlayingVideo() )
4149     {
4150       if (g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION)
4151         g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
4152
4153       // if player didn't manange to switch to fullscreen by itself do it here
4154       if( options.fullscreen && g_renderManager.IsStarted()
4155        && g_windowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO )
4156        SwitchToFullScreen();
4157     }
4158 #endif
4159     else
4160     {
4161       if (g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION
4162       ||  g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
4163         g_windowManager.PreviousWindow();
4164
4165     }
4166
4167 #if !defined(TARGET_POSIX)
4168     g_audioManager.Enable(false);
4169 #endif
4170
4171     if (item.HasPVRChannelInfoTag())
4172       g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
4173   }
4174
4175   CSingleLock lock(m_playStateMutex);
4176   m_bPlaybackStarting = false;
4177
4178   if (iResult == PLAYBACK_OK)
4179   {
4180     // play state: none, starting; playing; stopped; ended.
4181     // last 3 states are set by playback callback, they are all ignored during starting,
4182     // but we recorded the state, here we can make up the callback for the state.
4183     CLog::Log(LOGDEBUG,"%s : OpenFile succeed, play state %d", __FUNCTION__, m_ePlayState);
4184     switch (m_ePlayState)
4185     {
4186       case PLAY_STATE_PLAYING:
4187         OnPlayBackStarted();
4188         break;
4189       // FIXME: it seems no meaning to callback started here if there was an started callback
4190       //        before this stopped/ended callback we recorded. if we callback started here
4191       //        first, it will delay send OnPlay announce, but then we callback stopped/ended
4192       //        which will send OnStop announce at once, so currently, just call stopped/ended.
4193       case PLAY_STATE_ENDED:
4194         OnPlayBackEnded();
4195         break;
4196       case PLAY_STATE_STOPPED:
4197         OnPlayBackStopped();
4198         break;
4199       case PLAY_STATE_STARTING:
4200         // neither started nor stopped/ended callback be called, that means the item still
4201         // not started, we need not make up any callback, just leave this and
4202         // let the player callback do its work.
4203         break;
4204       default:
4205         break;
4206     }
4207   }
4208   else if (iResult == PLAYBACK_FAIL)
4209   {
4210     // we send this if it isn't playlistplayer that is doing this
4211     int next = g_playlistPlayer.GetNextSong();
4212     int size = g_playlistPlayer.GetPlaylist(g_playlistPlayer.GetCurrentPlaylist()).size();
4213     if(next < 0
4214     || next >= size)
4215       OnPlayBackStopped();
4216     m_ePlayState = PLAY_STATE_NONE;
4217   }
4218
4219   return iResult;
4220 }
4221
4222 void CApplication::OnPlayBackEnded()
4223 {
4224   CSingleLock lock(m_playStateMutex);
4225   CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
4226   m_ePlayState = PLAY_STATE_ENDED;
4227   if(m_bPlaybackStarting)
4228     return;
4229
4230   // informs python script currently running playback has ended
4231   // (does nothing if python is not loaded)
4232 #ifdef HAS_PYTHON
4233   g_pythonParser.OnPlayBackEnded();
4234 #endif
4235
4236   CVariant data(CVariant::VariantTypeObject);
4237   data["end"] = true;
4238   CAnnouncementManager::Get().Announce(Player, "xbmc", "OnStop", m_itemCurrentFile, data);
4239
4240   CGUIMessage msg(GUI_MSG_PLAYBACK_ENDED, 0, 0);
4241   g_windowManager.SendThreadMessage(msg);
4242 }
4243
4244 void CApplication::OnPlayBackStarted()
4245 {
4246   CSingleLock lock(m_playStateMutex);
4247   CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
4248   m_ePlayState = PLAY_STATE_PLAYING;
4249   if(m_bPlaybackStarting)
4250     return;
4251
4252 #ifdef HAS_PYTHON
4253   // informs python script currently running playback has started
4254   // (does nothing if python is not loaded)
4255   g_pythonParser.OnPlayBackStarted();
4256 #endif
4257
4258   CGUIMessage msg(GUI_MSG_PLAYBACK_STARTED, 0, 0);
4259   g_windowManager.SendThreadMessage(msg);
4260 }
4261
4262 void CApplication::OnQueueNextItem()
4263 {
4264   CSingleLock lock(m_playStateMutex);
4265   CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
4266   if(m_bPlaybackStarting)
4267     return;
4268   // informs python script currently running that we are requesting the next track
4269   // (does nothing if python is not loaded)
4270 #ifdef HAS_PYTHON
4271   g_pythonParser.OnQueueNextItem(); // currently unimplemented
4272 #endif
4273
4274   CGUIMessage msg(GUI_MSG_QUEUE_NEXT_ITEM, 0, 0);
4275   g_windowManager.SendThreadMessage(msg);
4276 }
4277
4278 void CApplication::OnPlayBackStopped()
4279 {
4280   CSingleLock lock(m_playStateMutex);
4281   CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
4282   m_ePlayState = PLAY_STATE_STOPPED;
4283   if(m_bPlaybackStarting)
4284     return;
4285
4286   // informs python script currently running playback has ended
4287   // (does nothing if python is not loaded)
4288 #ifdef HAS_PYTHON
4289   g_pythonParser.OnPlayBackStopped();
4290 #endif
4291
4292   CVariant data(CVariant::VariantTypeObject);
4293   data["end"] = false;
4294   CAnnouncementManager::Get().Announce(Player, "xbmc", "OnStop", m_itemCurrentFile, data);
4295
4296   CGUIMessage msg( GUI_MSG_PLAYBACK_STOPPED, 0, 0 );
4297   g_windowManager.SendThreadMessage(msg);
4298 }
4299
4300 void CApplication::OnPlayBackPaused()
4301 {
4302 #ifdef HAS_PYTHON
4303   g_pythonParser.OnPlayBackPaused();
4304 #endif
4305
4306   CVariant param;
4307   param["player"]["speed"] = 0;
4308   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
4309   CAnnouncementManager::Get().Announce(Player, "xbmc", "OnPause", m_itemCurrentFile, param);
4310 }
4311
4312 void CApplication::OnPlayBackResumed()
4313 {
4314 #ifdef HAS_PYTHON
4315   g_pythonParser.OnPlayBackResumed();
4316 #endif
4317
4318   CVariant param;
4319   param["player"]["speed"] = 1;
4320   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
4321   CAnnouncementManager::Get().Announce(Player, "xbmc", "OnPlay", m_itemCurrentFile, param);
4322 }
4323
4324 void CApplication::OnPlayBackSpeedChanged(int iSpeed)
4325 {
4326 #ifdef HAS_PYTHON
4327   g_pythonParser.OnPlayBackSpeedChanged(iSpeed);
4328 #endif
4329
4330   CVariant param;
4331   param["player"]["speed"] = iSpeed;
4332   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
4333   CAnnouncementManager::Get().Announce(Player, "xbmc", "OnSpeedChanged", m_itemCurrentFile, param);
4334 }
4335
4336 void CApplication::OnPlayBackSeek(int iTime, int seekOffset)
4337 {
4338 #ifdef HAS_PYTHON
4339   g_pythonParser.OnPlayBackSeek(iTime, seekOffset);
4340 #endif
4341
4342   CVariant param;
4343   CJSONUtils::MillisecondsToTimeObject(iTime, param["player"]["time"]);
4344   CJSONUtils::MillisecondsToTimeObject(seekOffset, param["player"]["seekoffset"]);;
4345   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
4346   param["player"]["speed"] = m_pPlayer->GetPlaySpeed();
4347   CAnnouncementManager::Get().Announce(Player, "xbmc", "OnSeek", m_itemCurrentFile, param);
4348   g_infoManager.SetDisplayAfterSeek(2500, seekOffset/1000);
4349 }
4350
4351 void CApplication::OnPlayBackSeekChapter(int iChapter)
4352 {
4353 #ifdef HAS_PYTHON
4354   g_pythonParser.OnPlayBackSeekChapter(iChapter);
4355 #endif
4356 }
4357
4358 bool CApplication::IsPlayingFullScreenVideo() const
4359 {
4360   return m_pPlayer->IsPlayingVideo() && g_graphicsContext.IsFullScreenVideo();
4361 }
4362
4363 bool CApplication::IsFullScreen()
4364 {
4365   return IsPlayingFullScreenVideo() ||
4366         (g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION) ||
4367          g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW;
4368 }
4369
4370 void CApplication::SaveFileState(bool bForeground /* = false */)
4371 {
4372   if (m_progressTrackingItem->IsPVRChannel() || !CProfilesManager::Get().GetCurrentProfile().canWriteDatabases())
4373     return;
4374
4375   if (bForeground)
4376   {
4377     CSaveFileStateJob job(*m_progressTrackingItem,
4378     *m_stackFileItemToUpdate,
4379     m_progressTrackingVideoResumeBookmark,
4380     m_progressTrackingPlayCountUpdate);
4381
4382     // Run job in the foreground to make sure it finishes
4383     job.DoWork();
4384   }
4385   else
4386   {
4387     CJob* job = new CSaveFileStateJob(*m_progressTrackingItem,
4388         *m_stackFileItemToUpdate,
4389         m_progressTrackingVideoResumeBookmark,
4390         m_progressTrackingPlayCountUpdate);
4391     CJobManager::GetInstance().AddJob(job, NULL, CJob::PRIORITY_NORMAL);
4392   }
4393 }
4394
4395 void CApplication::UpdateFileState()
4396 {
4397   // Did the file change?
4398   if (m_progressTrackingItem->GetPath() != "" && m_progressTrackingItem->GetPath() != CurrentFile())
4399   {
4400     SaveFileState();
4401
4402     // Reset tracking item
4403     m_progressTrackingItem->Reset();
4404   }
4405   else
4406   {
4407     if (m_pPlayer->IsPlaying())
4408     {
4409       if (m_progressTrackingItem->GetPath() == "")
4410       {
4411         // Init some stuff
4412         *m_progressTrackingItem = CurrentFileItem();
4413         m_progressTrackingPlayCountUpdate = false;
4414       }
4415
4416       if ((m_progressTrackingItem->IsAudio() && g_advancedSettings.m_audioPlayCountMinimumPercent > 0 &&
4417           GetPercentage() >= g_advancedSettings.m_audioPlayCountMinimumPercent) ||
4418           (m_progressTrackingItem->IsVideo() && g_advancedSettings.m_videoPlayCountMinimumPercent > 0 &&
4419           GetPercentage() >= g_advancedSettings.m_videoPlayCountMinimumPercent))
4420       {
4421         m_progressTrackingPlayCountUpdate = true;
4422       }
4423
4424       // Check whether we're *really* playing video else we may race when getting eg. stream details
4425       if (m_pPlayer->IsPlayingVideo())
4426       {
4427         /* Always update streamdetails, except for DVDs where we only update
4428            streamdetails if title length > 15m (Should yield more correct info) */
4429         if (!(m_progressTrackingItem->IsDVDImage() || m_progressTrackingItem->IsDVDFile()) || m_pPlayer->GetTotalTime() > 15*60*1000)
4430         {
4431           CStreamDetails details;
4432           // Update with stream details from player, if any
4433           if (m_pPlayer->GetStreamDetails(details))
4434             m_progressTrackingItem->GetVideoInfoTag()->m_streamDetails = details;
4435
4436           if (m_progressTrackingItem->IsStack())
4437             m_progressTrackingItem->GetVideoInfoTag()->m_streamDetails.SetVideoDuration(0, (int)GetTotalTime()); // Overwrite with CApp's totaltime as it takes into account total stack time
4438         }
4439
4440         // Update bookmark for save
4441         m_progressTrackingVideoResumeBookmark.player = CPlayerCoreFactory::Get().GetPlayerName(m_pPlayer->GetCurrentPlayer());
4442         m_progressTrackingVideoResumeBookmark.playerState = m_pPlayer->GetPlayerState();
4443         m_progressTrackingVideoResumeBookmark.thumbNailImage.clear();
4444
4445         if (g_advancedSettings.m_videoIgnorePercentAtEnd > 0 &&
4446             GetTotalTime() - GetTime() < 0.01f * g_advancedSettings.m_videoIgnorePercentAtEnd * GetTotalTime())
4447         {
4448           // Delete the bookmark
4449           m_progressTrackingVideoResumeBookmark.timeInSeconds = -1.0f;
4450         }
4451         else
4452         if (GetTime() > g_advancedSettings.m_videoIgnoreSecondsAtStart)
4453         {
4454           // Update the bookmark
4455           m_progressTrackingVideoResumeBookmark.timeInSeconds = GetTime();
4456           m_progressTrackingVideoResumeBookmark.totalTimeInSeconds = GetTotalTime();
4457         }
4458         else
4459         {
4460           // Do nothing
4461           m_progressTrackingVideoResumeBookmark.timeInSeconds = 0.0f;
4462         }
4463       }
4464     }
4465   }
4466 }
4467
4468 void CApplication::StopPlaying()
4469 {
4470   int iWin = g_windowManager.GetActiveWindow();
4471   if ( m_pPlayer->IsPlaying() )
4472   {
4473 #ifdef HAS_KARAOKE
4474     if( m_pKaraokeMgr )
4475       m_pKaraokeMgr->Stop();
4476 #endif
4477
4478     if (g_PVRManager.IsPlayingTV() || g_PVRManager.IsPlayingRadio())
4479       g_PVRManager.SaveCurrentChannelSettings();
4480
4481     m_pPlayer->CloseFile();
4482
4483     // turn off visualisation window when stopping
4484     if ((iWin == WINDOW_VISUALISATION
4485     ||  iWin == WINDOW_FULLSCREEN_VIDEO)
4486     && !m_bStop)
4487       g_windowManager.PreviousWindow();
4488
4489     g_partyModeManager.Disable();
4490   }
4491 }
4492
4493 void CApplication::ResetSystemIdleTimer()
4494 {
4495   // reset system idle timer
4496   m_idleTimer.StartZero();
4497 }
4498
4499 void CApplication::ResetScreenSaver()
4500 {
4501   // reset our timers
4502   m_shutdownTimer.StartZero();
4503
4504   // screen saver timer is reset only if we're not already in screensaver or
4505   // DPMS mode
4506   if ((!m_bScreenSave && m_iScreenSaveLock == 0) && !m_dpmsIsActive)
4507     ResetScreenSaverTimer();
4508 }
4509
4510 void CApplication::ResetScreenSaverTimer()
4511 {
4512   m_screenSaverTimer.StartZero();
4513 }
4514
4515 void CApplication::StopScreenSaverTimer()
4516 {
4517   m_screenSaverTimer.Stop();
4518 }
4519
4520 bool CApplication::ToggleDPMS(bool manual)
4521 {
4522   if (manual || (m_dpmsIsManual == manual))
4523   {
4524     if (m_dpmsIsActive)
4525     {
4526       m_dpmsIsActive = false;
4527       m_dpmsIsManual = false;
4528       CAnnouncementManager::Get().Announce(GUI, "xbmc", "OnDPMSDeactivated");
4529       return m_dpms->DisablePowerSaving();
4530     }
4531     else
4532     {
4533       if (m_dpms->EnablePowerSaving(m_dpms->GetSupportedModes()[0]))
4534       {
4535         m_dpmsIsActive = true;
4536         m_dpmsIsManual = manual;
4537         CAnnouncementManager::Get().Announce(GUI, "xbmc", "OnDPMSActivated");
4538         return true;
4539       }
4540     }
4541   }
4542   return false;
4543 }
4544
4545 bool CApplication::WakeUpScreenSaverAndDPMS(bool bPowerOffKeyPressed /* = false */)
4546 {
4547   bool result;
4548
4549   // First reset DPMS, if active
4550   if (m_dpmsIsActive)
4551   {
4552     if (m_dpmsIsManual)
4553       return false;
4554     // TODO: if screensaver lock is specified but screensaver is not active
4555     // (DPMS came first), activate screensaver now.
4556     ToggleDPMS(false);
4557     ResetScreenSaverTimer();
4558     result = !m_bScreenSave || WakeUpScreenSaver(bPowerOffKeyPressed);
4559   }
4560   else
4561     result = WakeUpScreenSaver(bPowerOffKeyPressed);
4562
4563   if(result)
4564   {
4565     // allow listeners to ignore the deactivation if it preceeds a powerdown/suspend etc
4566     CVariant data(bPowerOffKeyPressed);
4567     CAnnouncementManager::Get().Announce(GUI, "xbmc", "OnScreensaverDeactivated", data);
4568   }
4569
4570   return result;
4571 }
4572
4573 bool CApplication::WakeUpScreenSaver(bool bPowerOffKeyPressed /* = false */)
4574 {
4575   if (m_iScreenSaveLock == 2)
4576     return false;
4577
4578   // if Screen saver is active
4579   if (m_bScreenSave && m_screenSaver)
4580   {
4581     if (m_iScreenSaveLock == 0)
4582       if (CProfilesManager::Get().GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE &&
4583           (CProfilesManager::Get().UsingLoginScreen() || CSettings::Get().GetBool("masterlock.startuplock")) &&
4584           CProfilesManager::Get().GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE &&
4585           m_screenSaver->ID() != "screensaver.xbmc.builtin.dim" && m_screenSaver->ID() != "screensaver.xbmc.builtin.black" && !m_screenSaver->ID().empty() && m_screenSaver->ID() != "visualization")
4586       {
4587         m_iScreenSaveLock = 2;
4588         CGUIMessage msg(GUI_MSG_CHECK_LOCK,0,0);
4589
4590         CGUIWindow* pWindow = g_windowManager.GetWindow(WINDOW_SCREENSAVER);
4591         if (pWindow)
4592           pWindow->OnMessage(msg);
4593       }
4594     if (m_iScreenSaveLock == -1)
4595     {
4596       m_iScreenSaveLock = 0;
4597       return true;
4598     }
4599
4600     // disable screensaver
4601     m_bScreenSave = false;
4602     m_iScreenSaveLock = 0;
4603     ResetScreenSaverTimer();
4604
4605     if (m_screenSaver->ID() == "visualization")
4606     {
4607       // we can just continue as usual from vis mode
4608       return false;
4609     }
4610     else if (m_screenSaver->ID() == "screensaver.xbmc.builtin.dim" || m_screenSaver->ID() == "screensaver.xbmc.builtin.black" || m_screenSaver->ID().empty())
4611       return true;
4612     else if (!m_screenSaver->ID().empty())
4613     { // we're in screensaver window
4614       if (g_windowManager.GetActiveWindow() == WINDOW_SCREENSAVER)
4615         g_windowManager.PreviousWindow();  // show the previous window
4616       if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW)
4617         CApplicationMessenger::Get().SendAction(CAction(ACTION_STOP), WINDOW_SLIDESHOW);
4618     }
4619     return true;
4620   }
4621   else
4622     return false;
4623 }
4624
4625 void CApplication::CheckScreenSaverAndDPMS()
4626 {
4627   if (!m_dpmsIsActive)
4628     g_Windowing.ResetOSScreensaver();
4629
4630   bool maybeScreensaver =
4631       !m_dpmsIsActive && !m_bScreenSave
4632       && !CSettings::Get().GetString("screensaver.mode").empty();
4633   bool maybeDPMS =
4634       !m_dpmsIsActive && m_dpms->IsSupported()
4635       && CSettings::Get().GetInt("powermanagement.displaysoff") > 0;
4636
4637   // Has the screen saver window become active?
4638   if (maybeScreensaver && g_windowManager.IsWindowActive(WINDOW_SCREENSAVER))
4639   {
4640     m_bScreenSave = true;
4641     maybeScreensaver = false;
4642   }
4643
4644   if (m_bScreenSave && m_pPlayer->IsPlayingVideo() && !m_pPlayer->IsPaused())
4645   {
4646     WakeUpScreenSaverAndDPMS();
4647     return;
4648   }
4649
4650   if (!maybeScreensaver && !maybeDPMS) return;  // Nothing to do.
4651
4652   // See if we need to reset timer.
4653   // * Are we playing a video and it is not paused?
4654   if ((m_pPlayer->IsPlayingVideo() && !m_pPlayer->IsPaused())
4655       // * Are we playing some music in fullscreen vis?
4656       || (m_pPlayer->IsPlayingAudio() && g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION
4657           && !CSettings::Get().GetString("musicplayer.visualisation").empty()))
4658   {
4659     ResetScreenSaverTimer();
4660     return;
4661   }
4662
4663   float elapsed = m_screenSaverTimer.GetElapsedSeconds();
4664
4665   // DPMS has priority (it makes the screensaver not needed)
4666   if (maybeDPMS
4667       && elapsed > CSettings::Get().GetInt("powermanagement.displaysoff") * 60)
4668   {
4669     ToggleDPMS(false);
4670     WakeUpScreenSaver();
4671   }
4672   else if (maybeScreensaver
4673            && elapsed > CSettings::Get().GetInt("screensaver.time") * 60)
4674   {
4675     ActivateScreenSaver();
4676   }
4677 }
4678
4679 // activate the screensaver.
4680 // if forceType is true, we ignore the various conditions that can alter
4681 // the type of screensaver displayed
4682 void CApplication::ActivateScreenSaver(bool forceType /*= false */)
4683 {
4684   if (m_pPlayer->IsPlayingAudio() && CSettings::Get().GetBool("screensaver.usemusicvisinstead") && !CSettings::Get().GetString("musicplayer.visualisation").empty())
4685   { // just activate the visualisation if user toggled the usemusicvisinstead option
4686     g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
4687     return;
4688   }
4689
4690   m_bScreenSave = true;
4691
4692   // Get Screensaver Mode
4693   m_screenSaver.reset();
4694   if (!CAddonMgr::Get().GetAddon(CSettings::Get().GetString("screensaver.mode"), m_screenSaver))
4695     m_screenSaver.reset(new CScreenSaver(""));
4696
4697   CAnnouncementManager::Get().Announce(GUI, "xbmc", "OnScreensaverActivated");
4698
4699   // disable screensaver lock from the login screen
4700   m_iScreenSaveLock = g_windowManager.GetActiveWindow() == WINDOW_LOGIN_SCREEN ? 1 : 0;
4701   if (!forceType)
4702   {
4703     // set to Dim in the case of a dialog on screen or playing video
4704     if (g_windowManager.HasModalDialog() || (m_pPlayer->IsPlayingVideo() && CSettings::Get().GetBool("screensaver.usedimonpause")) || g_PVRManager.IsRunningChannelScan())
4705     {
4706       if (!CAddonMgr::Get().GetAddon("screensaver.xbmc.builtin.dim", m_screenSaver))
4707         m_screenSaver.reset(new CScreenSaver(""));
4708     }
4709   }
4710   if (m_screenSaver->ID() == "screensaver.xbmc.builtin.dim" || m_screenSaver->ID().empty())
4711     return;
4712   else if (m_screenSaver->ID() == "screensaver.xbmc.builtin.black")
4713     return;
4714   else if (!m_screenSaver->ID().empty())
4715     g_windowManager.ActivateWindow(WINDOW_SCREENSAVER);
4716 }
4717
4718 void CApplication::CheckShutdown()
4719 {
4720   // first check if we should reset the timer
4721   if (m_bInhibitIdleShutdown
4722       || m_pPlayer->IsPlaying() || m_pPlayer->IsPausedPlayback() // is something playing?
4723       || m_musicInfoScanner->IsScanning()
4724       || m_videoInfoScanner->IsScanning()
4725       || g_windowManager.IsWindowActive(WINDOW_DIALOG_PROGRESS) // progress dialog is onscreen
4726       || (CSettings::Get().GetBool("pvrmanager.enabled") && !g_PVRManager.IsIdle()))
4727   {
4728     m_shutdownTimer.StartZero();
4729     return;
4730   }
4731
4732   if ( m_shutdownTimer.GetElapsedSeconds() > CSettings::Get().GetInt("powermanagement.shutdowntime") * 60 )
4733   {
4734     // Since it is a sleep instead of a shutdown, let's set everything to reset when we wake up.
4735     m_shutdownTimer.Stop();
4736
4737     // Sleep the box
4738     CApplicationMessenger::Get().Shutdown();
4739   }
4740 }
4741
4742 void CApplication::InhibitIdleShutdown(bool inhibit)
4743 {
4744   m_bInhibitIdleShutdown = inhibit;
4745 }
4746
4747 bool CApplication::IsIdleShutdownInhibited() const
4748 {
4749   return m_bInhibitIdleShutdown;
4750 }
4751
4752 bool CApplication::OnMessage(CGUIMessage& message)
4753 {
4754   switch ( message.GetMessage() )
4755   {
4756   case GUI_MSG_NOTIFY_ALL:
4757     {
4758       if (message.GetParam1()==GUI_MSG_REMOVED_MEDIA)
4759       {
4760         // Update general playlist: Remove DVD playlist items
4761         int nRemoved = g_playlistPlayer.RemoveDVDItems();
4762         if ( nRemoved > 0 )
4763         {
4764           CGUIMessage msg( GUI_MSG_PLAYLIST_CHANGED, 0, 0 );
4765           g_windowManager.SendMessage( msg );
4766         }
4767         // stop the file if it's on dvd (will set the resume point etc)
4768         if (m_itemCurrentFile->IsOnDVD())
4769           StopPlaying();
4770       }
4771     }
4772     break;
4773
4774   case GUI_MSG_PLAYBACK_STARTED:
4775     {
4776 #ifdef TARGET_DARWIN
4777       DarwinSetScheduling(message.GetMessage());
4778 #endif
4779       // reset the seek handler
4780       m_seekHandler->Reset();
4781       CPlayList playList = g_playlistPlayer.GetPlaylist(g_playlistPlayer.GetCurrentPlaylist());
4782
4783       // Update our infoManager with the new details etc.
4784       if (m_nextPlaylistItem >= 0)
4785       { 
4786         // playing an item which is not in the list - player might be stopped already
4787         // so do nothing
4788         if (playList.size() <= m_nextPlaylistItem)
4789           return true;
4790
4791         // we've started a previously queued item
4792         CFileItemPtr item = playList[m_nextPlaylistItem];
4793         // update the playlist manager
4794         int currentSong = g_playlistPlayer.GetCurrentSong();
4795         int param = ((currentSong & 0xffff) << 16) | (m_nextPlaylistItem & 0xffff);
4796         CGUIMessage msg(GUI_MSG_PLAYLISTPLAYER_CHANGED, 0, 0, g_playlistPlayer.GetCurrentPlaylist(), param, item);
4797         g_windowManager.SendThreadMessage(msg);
4798         g_playlistPlayer.SetCurrentSong(m_nextPlaylistItem);
4799         *m_itemCurrentFile = *item;
4800       }
4801       g_infoManager.SetCurrentItem(*m_itemCurrentFile);
4802       g_partyModeManager.OnSongChange(true);
4803
4804       CVariant param;
4805       param["player"]["speed"] = 1;
4806       param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
4807       CAnnouncementManager::Get().Announce(Player, "xbmc", "OnPlay", m_itemCurrentFile, param);
4808
4809       if (m_pPlayer->IsPlayingAudio())
4810       {
4811         // Start our cdg parser as appropriate
4812 #ifdef HAS_KARAOKE
4813         if (m_pKaraokeMgr && CSettings::Get().GetBool("karaoke.enabled") && !m_itemCurrentFile->IsInternetStream())
4814         {
4815           m_pKaraokeMgr->Stop();
4816           if (m_itemCurrentFile->IsMusicDb())
4817           {
4818             if (!m_itemCurrentFile->HasMusicInfoTag() || !m_itemCurrentFile->GetMusicInfoTag()->Loaded())
4819             {
4820               IMusicInfoTagLoader* tagloader = CMusicInfoTagLoaderFactory::CreateLoader(m_itemCurrentFile->GetPath());
4821               tagloader->Load(m_itemCurrentFile->GetPath(),*m_itemCurrentFile->GetMusicInfoTag());
4822               delete tagloader;
4823             }
4824             m_pKaraokeMgr->Start(m_itemCurrentFile->GetMusicInfoTag()->GetURL());
4825           }
4826           else
4827             m_pKaraokeMgr->Start(m_itemCurrentFile->GetPath());
4828         }
4829 #endif
4830       }
4831
4832       return true;
4833     }
4834     break;
4835
4836   case GUI_MSG_QUEUE_NEXT_ITEM:
4837     {
4838       // Check to see if our playlist player has a new item for us,
4839       // and if so, we check whether our current player wants the file
4840       int iNext = g_playlistPlayer.GetNextSong();
4841       CPlayList& playlist = g_playlistPlayer.GetPlaylist(g_playlistPlayer.GetCurrentPlaylist());
4842       if (iNext < 0 || iNext >= playlist.size())
4843       {
4844         m_pPlayer->OnNothingToQueueNotify();
4845         return true; // nothing to do
4846       }
4847
4848       // ok, grab the next song
4849       CFileItem file(*playlist[iNext]);
4850       // handle plugin://
4851       CURL url(file.GetPath());
4852       if (url.GetProtocol() == "plugin")
4853         XFILE::CPluginDirectory::GetPluginResult(url.Get(), file);
4854
4855 #ifdef HAS_UPNP
4856       if (URIUtils::IsUPnP(file.GetPath()))
4857       {
4858         if (!XFILE::CUPnPDirectory::GetResource(file.GetURL(), file))
4859           return true;
4860       }
4861 #endif
4862
4863       // ok - send the file to the player, if it accepts it
4864       if (m_pPlayer->QueueNextFile(file))
4865       {
4866         // player accepted the next file
4867         m_nextPlaylistItem = iNext;
4868       }
4869       else
4870       {
4871         /* Player didn't accept next file: *ALWAYS* advance playlist in this case so the player can
4872             queue the next (if it wants to) and it doesn't keep looping on this song */
4873         g_playlistPlayer.SetCurrentSong(iNext);
4874       }
4875
4876       return true;
4877     }
4878     break;
4879
4880   case GUI_MSG_PLAYBACK_STOPPED:
4881   case GUI_MSG_PLAYBACK_ENDED:
4882   case GUI_MSG_PLAYLISTPLAYER_STOPPED:
4883     {
4884 #ifdef HAS_KARAOKE
4885       if (m_pKaraokeMgr )
4886         m_pKaraokeMgr->Stop();
4887 #endif
4888 #ifdef TARGET_DARWIN
4889       DarwinSetScheduling(message.GetMessage());
4890 #endif
4891       // first check if we still have items in the stack to play
4892       if (message.GetMessage() == GUI_MSG_PLAYBACK_ENDED)
4893       {
4894         if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0 && m_currentStackPosition < m_currentStack->Size() - 1)
4895         { // just play the next item in the stack
4896           PlayFile(*(*m_currentStack)[++m_currentStackPosition], true);
4897           return true;
4898         }
4899       }
4900
4901       // In case playback ended due to user eg. skipping over the end, clear
4902       // our resume bookmark here
4903       if (message.GetMessage() == GUI_MSG_PLAYBACK_ENDED && m_progressTrackingPlayCountUpdate && g_advancedSettings.m_videoIgnorePercentAtEnd > 0)
4904       {
4905         // Delete the bookmark
4906         m_progressTrackingVideoResumeBookmark.timeInSeconds = -1.0f;
4907       }
4908
4909       // reset the current playing file
4910       m_itemCurrentFile->Reset();
4911       g_infoManager.ResetCurrentItem();
4912       m_currentStack->Clear();
4913
4914       if (message.GetMessage() == GUI_MSG_PLAYBACK_ENDED)
4915       {
4916         g_playlistPlayer.PlayNext(1, true);
4917       }
4918       else
4919       {
4920         // reset any forced player
4921         m_eForcedNextPlayer = EPC_NONE;
4922
4923         m_pPlayer->ClosePlayer();
4924
4925         // Reset playspeed
4926         m_pPlayer->m_iPlaySpeed = 1;
4927       }
4928
4929       if (!m_pPlayer->IsPlaying())
4930       {
4931         g_audioManager.Enable(true);
4932       }
4933
4934       if (!m_pPlayer->IsPlayingVideo())
4935       {
4936         if(g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
4937         {
4938           g_windowManager.PreviousWindow();
4939         }
4940         else
4941         {
4942           CSingleLock lock(g_graphicsContext);
4943           //  resets to res_desktop or look&feel resolution (including refreshrate)
4944           g_graphicsContext.SetFullScreenVideo(false);
4945         }
4946       }
4947
4948       if (!m_pPlayer->IsPlayingAudio() && g_playlistPlayer.GetCurrentPlaylist() == PLAYLIST_NONE && g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION)
4949       {
4950         CSettings::Get().Save();  // save vis settings
4951         WakeUpScreenSaverAndDPMS();
4952         g_windowManager.PreviousWindow();
4953       }
4954
4955       // DVD ejected while playing in vis ?
4956       if (!m_pPlayer->IsPlayingAudio() && (m_itemCurrentFile->IsCDDA() || m_itemCurrentFile->IsOnDVD()) && !g_mediaManager.IsDiscInDrive() && g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION)
4957       {
4958         // yes, disable vis
4959         CSettings::Get().Save();    // save vis settings
4960         WakeUpScreenSaverAndDPMS();
4961         g_windowManager.PreviousWindow();
4962       }
4963
4964       if (IsEnableTestMode())
4965         CApplicationMessenger::Get().Quit();
4966       return true;
4967     }
4968     break;
4969
4970   case GUI_MSG_PLAYLISTPLAYER_STARTED:
4971   case GUI_MSG_PLAYLISTPLAYER_CHANGED:
4972     {
4973       return true;
4974     }
4975     break;
4976   case GUI_MSG_FULLSCREEN:
4977     { // Switch to fullscreen, if we can
4978       SwitchToFullScreen();
4979       return true;
4980     }
4981     break;
4982   case GUI_MSG_EXECUTE:
4983     if (message.GetNumStringParams())
4984       return ExecuteXBMCAction(message.GetStringParam());
4985     break;
4986   }
4987   return false;
4988 }
4989
4990 bool CApplication::ExecuteXBMCAction(std::string actionStr)
4991 {
4992   // see if it is a user set string
4993
4994   //We don't know if there is unsecure information in this yet, so we
4995   //postpone any logging
4996   const std::string in_actionStr(actionStr);
4997   CGUIInfoLabel info(actionStr, "");
4998   actionStr = info.GetLabel(0);
4999
5000   // user has asked for something to be executed
5001   if (CBuiltins::HasCommand(actionStr))
5002     CBuiltins::Execute(actionStr);
5003   else
5004   {
5005     // try translating the action from our ButtonTranslator
5006     int actionID;
5007     if (CButtonTranslator::TranslateActionString(actionStr.c_str(), actionID))
5008     {
5009       OnAction(CAction(actionID));
5010       return true;
5011     }
5012     CFileItem item(actionStr, false);
5013 #ifdef HAS_PYTHON
5014     if (item.IsPythonScript())
5015     { // a python script
5016       CScriptInvocationManager::Get().Execute(item.GetPath());
5017     }
5018     else
5019 #endif
5020     if (item.IsAudio() || item.IsVideo())
5021     { // an audio or video file
5022       PlayFile(item);
5023     }
5024     else
5025     {
5026       //At this point we have given up to translate, so even though
5027       //there may be insecure information, we log it.
5028       CLog::Log(LOGDEBUG,"%s : Tried translating, but failed to understand %s", __FUNCTION__, in_actionStr.c_str());
5029       return false;
5030     }
5031   }
5032   return true;
5033 }
5034
5035 void CApplication::Process()
5036 {
5037   MEASURE_FUNCTION;
5038
5039   // dispatch the messages generated by python or other threads to the current window
5040   g_windowManager.DispatchThreadMessages();
5041
5042   // process messages which have to be send to the gui
5043   // (this can only be done after g_windowManager.Render())
5044   CApplicationMessenger::Get().ProcessWindowMessages();
5045
5046   if (m_loggingIn)
5047   {
5048     m_loggingIn = false;
5049
5050     // autoexec.py - profile
5051     CStdString strAutoExecPy = CSpecialProtocol::TranslatePath("special://profile/autoexec.py");
5052
5053     if (XFILE::CFile::Exists(strAutoExecPy))
5054       CScriptInvocationManager::Get().Execute(strAutoExecPy);
5055     else
5056       CLog::Log(LOGDEBUG, "no profile autoexec.py (%s) found, skipping", strAutoExecPy.c_str());
5057   }
5058
5059   // handle any active scripts
5060   CScriptInvocationManager::Get().Process();
5061
5062   // process messages, even if a movie is playing
5063   CApplicationMessenger::Get().ProcessMessages();
5064   if (g_application.m_bStop) return; //we're done, everything has been unloaded
5065
5066   // check how far we are through playing the current item
5067   // and do anything that needs doing (playcount updates etc)
5068   CheckPlayingProgress();
5069
5070   // update sound
5071   m_pPlayer->DoAudioWork();
5072
5073   // do any processing that isn't needed on each run
5074   if( m_slowTimer.GetElapsedMilliseconds() > 500 )
5075   {
5076     m_slowTimer.Reset();
5077     ProcessSlow();
5078   }
5079
5080   g_cpuInfo.getUsedPercentage(); // must call it to recalculate pct values
5081 }
5082
5083 // We get called every 500ms
5084 void CApplication::ProcessSlow()
5085 {
5086   g_powerManager.ProcessEvents();
5087
5088 #if defined(TARGET_DARWIN_OSX)
5089   // There is an issue on OS X that several system services ask the cursor to become visible
5090   // during their startup routines.  Given that we can't control this, we hack it in by
5091   // forcing the
5092   if (g_Windowing.IsFullScreen())
5093   { // SDL thinks it's hidden
5094     Cocoa_HideMouse();
5095   }
5096 #endif
5097
5098   // Temporarely pause pausable jobs when viewing video/picture
5099   int currentWindow = g_windowManager.GetActiveWindow();
5100   if (CurrentFileItem().IsVideo() || CurrentFileItem().IsPicture() || currentWindow == WINDOW_FULLSCREEN_VIDEO || currentWindow == WINDOW_SLIDESHOW)
5101   {
5102     CJobManager::GetInstance().PauseJobs();
5103   }
5104   else
5105   {
5106     CJobManager::GetInstance().UnPauseJobs();
5107   }
5108
5109   // Store our file state for use on close()
5110   UpdateFileState();
5111
5112   // Check if we need to activate the screensaver / DPMS.
5113   CheckScreenSaverAndDPMS();
5114
5115   // Check if we need to shutdown (if enabled).
5116 #if defined(TARGET_DARWIN)
5117   if (CSettings::Get().GetInt("powermanagement.shutdowntime") && g_advancedSettings.m_fullScreen)
5118 #else
5119   if (CSettings::Get().GetInt("powermanagement.shutdowntime"))
5120 #endif
5121   {
5122     CheckShutdown();
5123   }
5124
5125   // check if we should restart the player
5126   CheckDelayedPlayerRestart();
5127
5128   //  check if we can unload any unreferenced dlls or sections
5129   if (!m_pPlayer->IsPlayingVideo())
5130     CSectionLoader::UnloadDelayed();
5131
5132   // check for any idle curl connections
5133   g_curlInterface.CheckIdle();
5134
5135   // check for any idle myth sessions
5136   CMythSession::CheckIdle();
5137
5138 #ifdef HAS_FILESYSTEM_HTSP
5139   // check for any idle htsp sessions
5140   HTSP::CHTSPDirectorySession::CheckIdle();
5141 #endif
5142
5143 #ifdef HAS_KARAOKE
5144   if ( m_pKaraokeMgr )
5145     m_pKaraokeMgr->ProcessSlow();
5146 #endif
5147
5148   if (!m_pPlayer->IsPlayingVideo())
5149     g_largeTextureManager.CleanupUnusedImages();
5150
5151   g_TextureManager.FreeUnusedTextures(5000);
5152
5153 #ifdef HAS_DVD_DRIVE
5154   // checks whats in the DVD drive and tries to autostart the content (xbox games, dvd, cdda, avi files...)
5155   if (!m_pPlayer->IsPlayingVideo())
5156     m_Autorun->HandleAutorun();
5157 #endif
5158
5159   // update upnp server/renderer states
5160 #ifdef HAS_UPNP
5161   if(UPNP::CUPnP::IsInstantiated())
5162     UPNP::CUPnP::GetInstance()->UpdateState();
5163 #endif
5164
5165 #if defined(TARGET_POSIX) && defined(HAS_FILESYSTEM_SMB)
5166   smb.CheckIfIdle();
5167 #endif
5168
5169 #ifdef HAS_FILESYSTEM_NFS
5170   gNfsConnection.CheckIfIdle();
5171 #endif
5172
5173 #ifdef HAS_FILESYSTEM_AFP
5174   gAfpConnection.CheckIfIdle();
5175 #endif
5176
5177 #ifdef HAS_FILESYSTEM_SFTP
5178   CSFTPSessionManager::ClearOutIdleSessions();
5179 #endif
5180
5181   g_mediaManager.ProcessEvents();
5182
5183 #ifdef HAS_LIRC
5184   if (g_RemoteControl.IsInUse() && !g_RemoteControl.IsInitialized())
5185     g_RemoteControl.Initialize();
5186 #endif
5187
5188   if (!m_pPlayer->IsPlayingVideo() &&
5189       CSettings::Get().GetInt("general.addonupdates") != AUTO_UPDATES_NEVER)
5190     CAddonInstaller::Get().UpdateRepos();
5191
5192   CAEFactory::GarbageCollect();
5193
5194   // if we don't render the gui there's no reason to start the screensaver.
5195   // that way the screensaver won't kick in if we maximize the XBMC window
5196   // after the screensaver start time.
5197   if(!m_renderGUI)
5198     ResetScreenSaverTimer();
5199 }
5200
5201 // Global Idle Time in Seconds
5202 // idle time will be resetet if on any OnKey()
5203 // int return: system Idle time in seconds! 0 is no idle!
5204 int CApplication::GlobalIdleTime()
5205 {
5206   if(!m_idleTimer.IsRunning())
5207   {
5208     m_idleTimer.Stop();
5209     m_idleTimer.StartZero();
5210   }
5211   return (int)m_idleTimer.GetElapsedSeconds();
5212 }
5213
5214 float CApplication::NavigationIdleTime()
5215 {
5216   if (!m_navigationTimer.IsRunning())
5217   {
5218     m_navigationTimer.Stop();
5219     m_navigationTimer.StartZero();
5220   }
5221   return m_navigationTimer.GetElapsedSeconds();
5222 }
5223
5224 void CApplication::DelayedPlayerRestart()
5225 {
5226   m_restartPlayerTimer.StartZero();
5227 }
5228
5229 void CApplication::CheckDelayedPlayerRestart()
5230 {
5231   if (m_restartPlayerTimer.GetElapsedSeconds() > 3)
5232   {
5233     m_restartPlayerTimer.Stop();
5234     m_restartPlayerTimer.Reset();
5235     Restart(true);
5236   }
5237 }
5238
5239 void CApplication::Restart(bool bSamePosition)
5240 {
5241   // this function gets called when the user changes a setting (like noninterleaved)
5242   // and which means we gotta close & reopen the current playing file
5243
5244   // first check if we're playing a file
5245   if ( !m_pPlayer->IsPlayingVideo() && !m_pPlayer->IsPlayingAudio())
5246     return ;
5247
5248   if( !m_pPlayer->HasPlayer() )
5249     return ;
5250
5251   SaveFileState();
5252
5253   // do we want to return to the current position in the file
5254   if (false == bSamePosition)
5255   {
5256     // no, then just reopen the file and start at the beginning
5257     PlayFile(*m_itemCurrentFile, true);
5258     return ;
5259   }
5260
5261   // else get current position
5262   double time = GetTime();
5263
5264   // get player state, needed for dvd's
5265   CStdString state = m_pPlayer->GetPlayerState();
5266
5267   // set the requested starttime
5268   m_itemCurrentFile->m_lStartOffset = (long)(time * 75.0);
5269
5270   // reopen the file
5271   if ( PlayFile(*m_itemCurrentFile, true) == PLAYBACK_OK )
5272     m_pPlayer->SetPlayerState(state);
5273 }
5274
5275 const CStdString& CApplication::CurrentFile()
5276 {
5277   return m_itemCurrentFile->GetPath();
5278 }
5279
5280 CFileItem& CApplication::CurrentFileItem()
5281 {
5282   return *m_itemCurrentFile;
5283 }
5284
5285 CFileItem& CApplication::CurrentUnstackedItem()
5286 {
5287   if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5288     return *(*m_currentStack)[m_currentStackPosition];
5289   else
5290     return *m_itemCurrentFile;
5291 }
5292
5293 void CApplication::ShowVolumeBar(const CAction *action)
5294 {
5295   CGUIDialog *volumeBar = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_VOLUME_BAR);
5296   if (volumeBar)
5297   {
5298     volumeBar->Show();
5299     if (action)
5300       volumeBar->OnAction(*action);
5301   }
5302 }
5303
5304 bool CApplication::IsMuted() const
5305 {
5306   if (g_peripherals.IsMuted())
5307     return true;
5308   return CAEFactory::IsMuted();
5309 }
5310
5311 void CApplication::ToggleMute(void)
5312 {
5313   if (m_muted)
5314     UnMute();
5315   else
5316     Mute();
5317 }
5318
5319 void CApplication::SetMute(bool mute)
5320 {
5321   if (m_muted != mute)
5322   {
5323     ToggleMute();
5324     m_muted = mute;
5325   }
5326 }
5327
5328 void CApplication::Mute()
5329 {
5330   if (g_peripherals.Mute())
5331     return;
5332
5333   CAEFactory::SetMute(true);
5334   m_muted = true;
5335   VolumeChanged();
5336 }
5337
5338 void CApplication::UnMute()
5339 {
5340   if (g_peripherals.UnMute())
5341     return;
5342
5343   CAEFactory::SetMute(false);
5344   m_muted = false;
5345   VolumeChanged();
5346 }
5347
5348 void CApplication::SetVolume(float iValue, bool isPercentage/*=true*/)
5349 {
5350   float hardwareVolume = iValue;
5351
5352   if(isPercentage)
5353     hardwareVolume /= 100.0f;
5354
5355   SetHardwareVolume(hardwareVolume);
5356   VolumeChanged();
5357 }
5358
5359 void CApplication::SetHardwareVolume(float hardwareVolume)
5360 {
5361   hardwareVolume = std::max(VOLUME_MINIMUM, std::min(VOLUME_MAXIMUM, hardwareVolume));
5362   m_volumeLevel = hardwareVolume;
5363
5364   CAEFactory::SetVolume(hardwareVolume);
5365 }
5366
5367 float CApplication::GetVolume(bool percentage /* = true */) const
5368 {
5369   if (percentage)
5370   {
5371     // converts the hardware volume to a percentage
5372     return m_volumeLevel * 100.0f;
5373   }
5374   
5375   return m_volumeLevel;
5376 }
5377
5378 void CApplication::VolumeChanged() const
5379 {
5380   CVariant data(CVariant::VariantTypeObject);
5381   data["volume"] = GetVolume();
5382   data["muted"] = m_muted;
5383   CAnnouncementManager::Get().Announce(Application, "xbmc", "OnVolumeChanged", data);
5384
5385   // if player has volume control, set it.
5386   if (m_pPlayer->ControlsVolume())
5387   {
5388      m_pPlayer->SetVolume(m_volumeLevel);
5389      m_pPlayer->SetMute(m_muted);
5390   }
5391 }
5392
5393 int CApplication::GetSubtitleDelay() const
5394 {
5395   // converts subtitle delay to a percentage
5396   return int(((float)(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleDelay + g_advancedSettings.m_videoSubsDelayRange)) / (2 * g_advancedSettings.m_videoSubsDelayRange)*100.0f + 0.5f);
5397 }
5398
5399 int CApplication::GetAudioDelay() const
5400 {
5401   // converts audio delay to a percentage
5402   return int(((float)(CMediaSettings::Get().GetCurrentVideoSettings().m_AudioDelay + g_advancedSettings.m_videoAudioDelayRange)) / (2 * g_advancedSettings.m_videoAudioDelayRange)*100.0f + 0.5f);
5403 }
5404
5405 // Returns the total time in seconds of the current media.  Fractional
5406 // portions of a second are possible - but not necessarily supported by the
5407 // player class.  This returns a double to be consistent with GetTime() and
5408 // SeekTime().
5409 double CApplication::GetTotalTime() const
5410 {
5411   double rc = 0.0;
5412
5413   if (m_pPlayer->IsPlaying())
5414   {
5415     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5416       rc = (*m_currentStack)[m_currentStack->Size() - 1]->m_lEndOffset;
5417     else
5418       rc = static_cast<double>(m_pPlayer->GetTotalTime() * 0.001f);
5419   }
5420
5421   return rc;
5422 }
5423
5424 void CApplication::StopShutdownTimer()
5425 {
5426   if (m_shutdownTimer.IsRunning())
5427     m_shutdownTimer.Stop();
5428 }
5429
5430 void CApplication::ResetShutdownTimers()
5431 {
5432   // reset system shutdown timer
5433   m_shutdownTimer.StartZero();
5434
5435   // delete custom shutdown timer
5436   if (g_alarmClock.HasAlarm("shutdowntimer"))
5437     g_alarmClock.Stop("shutdowntimer", true);
5438 }
5439
5440 // Returns the current time in seconds of the currently playing media.
5441 // Fractional portions of a second are possible.  This returns a double to
5442 // be consistent with GetTotalTime() and SeekTime().
5443 double CApplication::GetTime() const
5444 {
5445   double rc = 0.0;
5446
5447   if (m_pPlayer->IsPlaying())
5448   {
5449     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5450     {
5451       long startOfCurrentFile = (m_currentStackPosition > 0) ? (*m_currentStack)[m_currentStackPosition-1]->m_lEndOffset : 0;
5452       rc = (double)startOfCurrentFile + m_pPlayer->GetTime() * 0.001;
5453     }
5454     else
5455       rc = static_cast<double>(m_pPlayer->GetTime() * 0.001f);
5456   }
5457
5458   return rc;
5459 }
5460
5461 // Sets the current position of the currently playing media to the specified
5462 // time in seconds.  Fractional portions of a second are valid.  The passed
5463 // time is the time offset from the beginning of the file as opposed to a
5464 // delta from the current position.  This method accepts a double to be
5465 // consistent with GetTime() and GetTotalTime().
5466 void CApplication::SeekTime( double dTime )
5467 {
5468   if (m_pPlayer->IsPlaying() && (dTime >= 0.0))
5469   {
5470     if (!m_pPlayer->CanSeek()) return;
5471     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5472     {
5473       // find the item in the stack we are seeking to, and load the new
5474       // file if necessary, and calculate the correct seek within the new
5475       // file.  Otherwise, just fall through to the usual routine if the
5476       // time is higher than our total time.
5477       for (int i = 0; i < m_currentStack->Size(); i++)
5478       {
5479         if ((*m_currentStack)[i]->m_lEndOffset > dTime)
5480         {
5481           long startOfNewFile = (i > 0) ? (*m_currentStack)[i-1]->m_lEndOffset : 0;
5482           if (m_currentStackPosition == i)
5483             m_pPlayer->SeekTime((int64_t)((dTime - startOfNewFile) * 1000.0));
5484           else
5485           { // seeking to a new file
5486             m_currentStackPosition = i;
5487             CFileItem item(*(*m_currentStack)[i]);
5488             item.m_lStartOffset = (long)((dTime - startOfNewFile) * 75.0);
5489             // don't just call "PlayFile" here, as we are quite likely called from the
5490             // player thread, so we won't be able to delete ourselves.
5491             CApplicationMessenger::Get().PlayFile(item, true);
5492           }
5493           return;
5494         }
5495       }
5496     }
5497     // convert to milliseconds and perform seek
5498     m_pPlayer->SeekTime( static_cast<int64_t>( dTime * 1000.0 ) );
5499   }
5500 }
5501
5502 float CApplication::GetPercentage() const
5503 {
5504   if (m_pPlayer->IsPlaying())
5505   {
5506     if (m_pPlayer->GetTotalTime() == 0 && m_pPlayer->IsPlayingAudio() && m_itemCurrentFile->HasMusicInfoTag())
5507     {
5508       const CMusicInfoTag& tag = *m_itemCurrentFile->GetMusicInfoTag();
5509       if (tag.GetDuration() > 0)
5510         return (float)(GetTime() / tag.GetDuration() * 100);
5511     }
5512
5513     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5514     {
5515       double totalTime = GetTotalTime();
5516       if (totalTime > 0.0f)
5517         return (float)(GetTime() / totalTime * 100);
5518     }
5519     else
5520       return m_pPlayer->GetPercentage();
5521   }
5522   return 0.0f;
5523 }
5524
5525 float CApplication::GetCachePercentage() const
5526 {
5527   if (m_pPlayer->IsPlaying())
5528   {
5529     // Note that the player returns a relative cache percentage and we want an absolute percentage
5530     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5531     {
5532       float stackedTotalTime = (float) GetTotalTime();
5533       // We need to take into account the stack's total time vs. currently playing file's total time
5534       if (stackedTotalTime > 0.0f)
5535         return min( 100.0f, GetPercentage() + (m_pPlayer->GetCachePercentage() * m_pPlayer->GetTotalTime() * 0.001f / stackedTotalTime ) );
5536     }
5537     else
5538       return min( 100.0f, m_pPlayer->GetPercentage() + m_pPlayer->GetCachePercentage() );
5539   }
5540   return 0.0f;
5541 }
5542
5543 void CApplication::SeekPercentage(float percent)
5544 {
5545   if (m_pPlayer->IsPlaying() && (percent >= 0.0))
5546   {
5547     if (!m_pPlayer->CanSeek()) return;
5548     if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
5549       SeekTime(percent * 0.01 * GetTotalTime());
5550     else
5551       m_pPlayer->SeekPercentage(percent);
5552   }
5553 }
5554
5555 // SwitchToFullScreen() returns true if a switch is made, else returns false
5556 bool CApplication::SwitchToFullScreen()
5557 {
5558   // if playing from the video info window, close it first!
5559   if (g_windowManager.HasModalDialog() && g_windowManager.GetTopMostModalDialogID() == WINDOW_DIALOG_VIDEO_INFO)
5560   {
5561     CGUIDialogVideoInfo* pDialog = (CGUIDialogVideoInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_INFO);
5562     if (pDialog) pDialog->Close(true);
5563   }
5564
5565   // don't switch if there is a dialog on screen or the slideshow is active
5566   if (/*g_windowManager.HasModalDialog() ||*/ g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW)
5567     return false;
5568
5569   // See if we're playing a video, and are in GUI mode
5570   if ( m_pPlayer->IsPlayingVideo() && g_windowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO)
5571   {
5572     // then switch to fullscreen mode
5573     g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
5574     return true;
5575   }
5576   // special case for switching between GUI & visualisation mode. (only if we're playing an audio song)
5577   if (m_pPlayer->IsPlayingAudio() && g_windowManager.GetActiveWindow() != WINDOW_VISUALISATION)
5578   { // then switch to visualisation
5579     g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
5580     return true;
5581   }
5582   return false;
5583 }
5584
5585 void CApplication::Minimize()
5586 {
5587   g_Windowing.Minimize();
5588 }
5589
5590 PLAYERCOREID CApplication::GetCurrentPlayer()
5591 {
5592   return m_pPlayer->GetCurrentPlayer();
5593 }
5594
5595 void CApplication::UpdateLibraries()
5596 {
5597   if (CSettings::Get().GetBool("videolibrary.updateonstartup"))
5598   {
5599     CLog::Log(LOGNOTICE, "%s - Starting video library startup scan", __FUNCTION__);
5600     StartVideoScan("");
5601   }
5602
5603   if (CSettings::Get().GetBool("musiclibrary.updateonstartup"))
5604   {
5605     CLog::Log(LOGNOTICE, "%s - Starting music library startup scan", __FUNCTION__);
5606     StartMusicScan("");
5607   }
5608 }
5609
5610 bool CApplication::IsVideoScanning() const
5611 {
5612   return m_videoInfoScanner->IsScanning();
5613 }
5614
5615 bool CApplication::IsMusicScanning() const
5616 {
5617   return m_musicInfoScanner->IsScanning();
5618 }
5619
5620 void CApplication::StopVideoScan()
5621 {
5622   if (m_videoInfoScanner->IsScanning())
5623     m_videoInfoScanner->Stop();
5624 }
5625
5626 void CApplication::StopMusicScan()
5627 {
5628   if (m_musicInfoScanner->IsScanning())
5629     m_musicInfoScanner->Stop();
5630 }
5631
5632 void CApplication::StartVideoCleanup()
5633 {
5634   if (m_videoInfoScanner->IsScanning())
5635     return;
5636
5637   m_videoInfoScanner->CleanDatabase();
5638 }
5639
5640 void CApplication::StartVideoScan(const CStdString &strDirectory, bool scanAll)
5641 {
5642   if (m_videoInfoScanner->IsScanning())
5643     return;
5644
5645   m_videoInfoScanner->ShowDialog(true);
5646
5647   m_videoInfoScanner->Start(strDirectory,scanAll);
5648 }
5649
5650 void CApplication::StartMusicScan(const CStdString &strDirectory, int flags)
5651 {
5652   if (m_musicInfoScanner->IsScanning())
5653     return;
5654
5655   if (!flags)
5656   { // setup default flags
5657     if (CSettings::Get().GetBool("musiclibrary.downloadinfo"))
5658       flags |= CMusicInfoScanner::SCAN_ONLINE;
5659     if (CSettings::Get().GetBool("musiclibrary.backgroundupdate"))
5660       flags |= CMusicInfoScanner::SCAN_BACKGROUND;
5661   }
5662
5663   if (!(flags & CMusicInfoScanner::SCAN_BACKGROUND))
5664     m_musicInfoScanner->ShowDialog(true);
5665
5666   m_musicInfoScanner->Start(strDirectory, flags);
5667 }
5668
5669 void CApplication::StartMusicAlbumScan(const CStdString& strDirectory,
5670                                        bool refresh)
5671 {
5672   if (m_musicInfoScanner->IsScanning())
5673     return;
5674
5675   m_musicInfoScanner->ShowDialog(true);
5676
5677   m_musicInfoScanner->FetchAlbumInfo(strDirectory,refresh);
5678 }
5679
5680 void CApplication::StartMusicArtistScan(const CStdString& strDirectory,
5681                                         bool refresh)
5682 {
5683   if (m_musicInfoScanner->IsScanning())
5684     return;
5685
5686   m_musicInfoScanner->ShowDialog(true);
5687
5688   m_musicInfoScanner->FetchArtistInfo(strDirectory,refresh);
5689 }
5690
5691 void CApplication::CheckPlayingProgress()
5692 {
5693   // check if we haven't rewound past the start of the file
5694   if (m_pPlayer->IsPlaying())
5695   {
5696     int iSpeed = g_application.m_pPlayer->GetPlaySpeed();
5697     if (iSpeed < 1)
5698     {
5699       iSpeed *= -1;
5700       int iPower = 0;
5701       while (iSpeed != 1)
5702       {
5703         iSpeed >>= 1;
5704         iPower++;
5705       }
5706       if (g_infoManager.GetPlayTime() / 1000 < iPower)
5707       {
5708         g_application.m_pPlayer->SetPlaySpeed(1, g_application.m_muted);
5709         g_application.SeekTime(0);
5710       }
5711     }
5712   }
5713 }
5714
5715 bool CApplication::ProcessAndStartPlaylist(const CStdString& strPlayList, CPlayList& playlist, int iPlaylist, int track)
5716 {
5717   CLog::Log(LOGDEBUG,"CApplication::ProcessAndStartPlaylist(%s, %i)",strPlayList.c_str(), iPlaylist);
5718
5719   // initial exit conditions
5720   // no songs in playlist just return
5721   if (playlist.size() == 0)
5722     return false;
5723
5724   // illegal playlist
5725   if (iPlaylist < PLAYLIST_MUSIC || iPlaylist > PLAYLIST_VIDEO)
5726     return false;
5727
5728   // setup correct playlist
5729   g_playlistPlayer.ClearPlaylist(iPlaylist);
5730
5731   // if the playlist contains an internet stream, this file will be used
5732   // to generate a thumbnail for musicplayer.cover
5733   g_application.m_strPlayListFile = strPlayList;
5734
5735   // add the items to the playlist player
5736   g_playlistPlayer.Add(iPlaylist, playlist);
5737
5738   // if we have a playlist
5739   if (g_playlistPlayer.GetPlaylist(iPlaylist).size())
5740   {
5741     // start playing it
5742     g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
5743     g_playlistPlayer.Reset();
5744     g_playlistPlayer.Play(track);
5745     return true;
5746   }
5747   return false;
5748 }
5749
5750 void CApplication::SaveCurrentFileSettings()
5751 {
5752   // don't store settings for PVR in video database
5753   if (m_itemCurrentFile->IsVideo() && !m_itemCurrentFile->IsPVRChannel())
5754   {
5755     // save video settings
5756     if (CMediaSettings::Get().GetCurrentVideoSettings() != CMediaSettings::Get().GetDefaultVideoSettings())
5757     {
5758       CVideoDatabase dbs;
5759       dbs.Open();
5760       dbs.SetVideoSettings(m_itemCurrentFile->GetPath(), CMediaSettings::Get().GetCurrentVideoSettings());
5761       dbs.Close();
5762     }
5763   }
5764   else if (m_itemCurrentFile->IsPVRChannel())
5765   {
5766     g_PVRManager.SaveCurrentChannelSettings();
5767   }
5768 }
5769
5770 bool CApplication::AlwaysProcess(const CAction& action)
5771 {
5772   // check if this button is mapped to a built-in function
5773   if (!action.GetName().empty())
5774   {
5775     CStdString builtInFunction;
5776     vector<string> params;
5777     CUtil::SplitExecFunction(action.GetName(), builtInFunction, params);
5778     StringUtils::ToLower(builtInFunction);
5779
5780     // should this button be handled normally or just cancel the screensaver?
5781     if (   builtInFunction.Equals("powerdown")
5782         || builtInFunction.Equals("reboot")
5783         || builtInFunction.Equals("restart")
5784         || builtInFunction.Equals("restartapp")
5785         || builtInFunction.Equals("suspend")
5786         || builtInFunction.Equals("hibernate")
5787         || builtInFunction.Equals("quit")
5788         || builtInFunction.Equals("shutdown"))
5789     {
5790       return true;
5791     }
5792   }
5793
5794   return false;
5795 }
5796
5797 bool CApplication::IsCurrentThread() const
5798 {
5799   return CThread::IsCurrentThread(m_threadID);
5800 }
5801
5802 void CApplication::SetRenderGUI(bool renderGUI)
5803 {
5804   if (renderGUI && ! m_renderGUI)
5805     g_windowManager.MarkDirty();
5806   m_renderGUI = renderGUI;
5807 }
5808
5809 CNetwork& CApplication::getNetwork()
5810 {
5811   return *m_network;
5812 }
5813 #ifdef HAS_PERFORMANCE_SAMPLE
5814 CPerformanceStats &CApplication::GetPerformanceStats()
5815 {
5816   return m_perfStats;
5817 }
5818 #endif
5819
5820 bool CApplication::SetLanguage(const CStdString &strLanguage)
5821 {
5822   CStdString strPreviousLanguage = CSettings::Get().GetString("locale.language");
5823   if (strLanguage != strPreviousLanguage)
5824   {
5825     CStdString strLangInfoPath = StringUtils::Format("special://xbmc/language/%s/langinfo.xml", strLanguage.c_str());
5826     if (!g_langInfo.Load(strLangInfoPath))
5827       return false;
5828
5829     CSettings::Get().SetString("locale.language", strLanguage);
5830
5831     if (!g_localizeStrings.Load("special://xbmc/language/", strLanguage))
5832       return false;
5833
5834     // also tell our weather and skin to reload as these are localized
5835     g_weatherManager.Refresh();
5836     g_PVRManager.LocalizationChanged();
5837     ReloadSkin();
5838   }
5839
5840   return true;
5841 }
5842
5843 void CApplication::CloseNetworkShares()
5844 {
5845   CLog::Log(LOGDEBUG,"CApplication::CloseNetworkShares: Closing all network shares");
5846
5847 #if defined(HAS_FILESYSTEM_SMB) && !defined(TARGET_WINDOWS)
5848   smb.Deinit();
5849 #endif
5850   
5851 #ifdef HAS_FILESYSTEM_NFS
5852   gNfsConnection.Deinit();
5853 #endif
5854   
5855 #ifdef HAS_FILESYSTEM_AFP
5856   gAfpConnection.Deinit();
5857 #endif
5858   
5859 #ifdef HAS_FILESYSTEM_SFTP
5860   CSFTPSessionManager::DisconnectAllSessions();
5861 #endif
5862 }