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