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