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