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