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