Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: bd9b6c6b87
Fetching contributors…

Cannot retrieve contributors at this time

5749 lines (5015 sloc) 178.132 kb
/*
* Copyright (C) 2005-2008 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "threads/SystemClock.h"
#include "system.h"
#include "Application.h"
#include "interfaces/Builtins.h"
#include "utils/Variant.h"
#include "utils/Splash.h"
#include "input/KeyboardLayoutConfiguration.h"
#include "LangInfo.h"
#include "Util.h"
#include "pictures/Picture.h"
#include "guilib/TextureManager.h"
#include "cores/dvdplayer/DVDFileInfo.h"
#include "cores/AudioEngine/AEFactory.h"
#include "cores/AudioEngine/Utils/AEUtil.h"
#include "PlayListPlayer.h"
#include "Autorun.h"
#include "video/Bookmark.h"
#ifdef HAS_WEB_SERVER
#include "network/WebServer.h"
#include "network/httprequesthandler/HTTPImageHandler.h"
#include "network/httprequesthandler/HTTPVfsHandler.h"
#ifdef HAS_HTTPAPI
#include "network/httprequesthandler/HTTPApiHandler.h"
#endif
#ifdef HAS_JSONRPC
#include "network/httprequesthandler/HTTPJsonRpcHandler.h"
#endif
#ifdef HAS_WEB_INTERFACE
#include "network/httprequesthandler/HTTPWebinterfaceHandler.h"
#include "network/httprequesthandler/HTTPWebinterfaceAddonsHandler.h"
#endif
#endif
#ifdef HAS_LCD
#include "utils/LCDFactory.h"
#endif
#include "guilib/GUIControlProfiler.h"
#include "utils/LangCodeExpander.h"
#include "GUIInfoManager.h"
#include "playlists/PlayListFactory.h"
#include "guilib/GUIFontManager.h"
#include "guilib/GUIColorManager.h"
#include "guilib/GUITextLayout.h"
#include "addons/Skin.h"
#ifdef HAS_PYTHON
#include "interfaces/python/XBPython.h"
#endif
#include "input/ButtonTranslator.h"
#include "guilib/GUIAudioManager.h"
#include "network/libscrobbler/lastfmscrobbler.h"
#include "network/libscrobbler/librefmscrobbler.h"
#include "GUIPassword.h"
#include "input/InertialScrollingHandler.h"
#include "ApplicationMessenger.h"
#include "SectionLoader.h"
#include "cores/DllLoader/DllLoaderContainer.h"
#include "GUIUserMessages.h"
#include "filesystem/DirectoryCache.h"
#include "filesystem/StackDirectory.h"
#include "filesystem/SpecialProtocol.h"
#include "filesystem/DllLibCurl.h"
#include "filesystem/MythSession.h"
#include "filesystem/PluginDirectory.h"
#ifdef HAS_FILESYSTEM_SAP
#include "filesystem/SAPDirectory.h"
#endif
#ifdef HAS_FILESYSTEM_HTSP
#include "filesystem/HTSPDirectory.h"
#endif
#include "utils/TuxBoxUtil.h"
#include "utils/SystemInfo.h"
#include "utils/TimeUtils.h"
#include "GUILargeTextureManager.h"
#include "TextureCache.h"
#include "music/LastFmManager.h"
#include "playlists/SmartPlayList.h"
#ifdef HAS_FILESYSTEM_RAR
#include "filesystem/RarManager.h"
#endif
#include "playlists/PlayList.h"
#include "windowing/WindowingFactory.h"
#include "powermanagement/PowerManager.h"
#include "powermanagement/DPMSSupport.h"
#include "settings/Settings.h"
#include "settings/AdvancedSettings.h"
#include "guilib/LocalizeStrings.h"
#include "utils/CPUInfo.h"
#include "input/KeyboardStat.h"
#include "input/XBMC_vkeys.h"
#include "input/MouseStat.h"
#ifdef HAS_SDL
#include <SDL/SDL.h>
#endif
#if defined(FILESYSTEM) && !defined(_LINUX)
#include "filesystem/FileDAAP.h"
#endif
#ifdef HAS_UPNP
#include "network/UPnP.h"
#include "filesystem/UPnPDirectory.h"
#endif
#if defined(_LINUX) && defined(HAS_FILESYSTEM_SMB)
#include "filesystem/SMBDirectory.h"
#endif
#ifdef HAS_FILESYSTEM_NFS
#include "filesystem/NFSFile.h"
#endif
#ifdef HAS_FILESYSTEM_AFP
#include "filesystem/AFPFile.h"
#endif
#ifdef HAS_FILESYSTEM_SFTP
#include "filesystem/SFTPFile.h"
#endif
#include "PartyModeManager.h"
#ifdef HAS_VIDEO_PLAYBACK
#include "cores/VideoRenderers/RenderManager.h"
#endif
#ifdef HAS_KARAOKE
#include "music/karaoke/karaokelyricsmanager.h"
#include "music/karaoke/GUIDialogKaraokeSongSelector.h"
#include "music/karaoke/GUIWindowKaraokeLyrics.h"
#endif
#include "guilib/GUIFontTTF.h"
#include "network/Network.h"
#include "storage/IoSupport.h"
#include "network/Zeroconf.h"
#include "network/ZeroconfBrowser.h"
#ifndef _LINUX
#include "threads/platform/win/Win32Exception.h"
#endif
#ifdef HAS_EVENT_SERVER
#include "network/EventServer.h"
#endif
#ifdef HAS_JSONRPC
#include "interfaces/json-rpc/InputOperations.h"
#endif
#ifdef HAS_DBUS
#include <dbus/dbus.h>
#endif
#ifdef HAS_HTTPAPI
#include "interfaces/http-api/XBMChttp.h"
#endif
#ifdef HAS_JSONRPC
#include "interfaces/json-rpc/JSONRPC.h"
#include "network/TCPServer.h"
#endif
#ifdef HAS_AIRPLAY
#include "network/AirPlayServer.h"
#endif
#ifdef HAS_AIRTUNES
#include "network/AirTunesServer.h"
#endif
#if defined(HAVE_LIBCRYSTALHD)
#include "cores/dvdplayer/DVDCodecs/Video/CrystalHD.h"
#endif
#include "interfaces/AnnouncementManager.h"
#include "peripherals/Peripherals.h"
#include "peripherals/dialogs/GUIDialogPeripheralManager.h"
#include "peripherals/dialogs/GUIDialogPeripheralSettings.h"
// Windows includes
#include "guilib/GUIWindowManager.h"
#include "windows/GUIWindowHome.h"
#include "guilib/GUIStandardWindow.h"
#include "settings/GUIWindowSettings.h"
#include "windows/GUIWindowFileManager.h"
#include "settings/GUIWindowSettingsCategory.h"
#include "music/windows/GUIWindowMusicPlaylist.h"
#include "music/windows/GUIWindowMusicSongs.h"
#include "music/windows/GUIWindowMusicNav.h"
#include "music/windows/GUIWindowMusicPlaylistEditor.h"
#include "video/windows/GUIWindowVideoPlaylist.h"
#include "music/dialogs/GUIDialogMusicInfo.h"
#include "video/dialogs/GUIDialogVideoInfo.h"
#include "video/windows/GUIWindowVideoNav.h"
#include "settings/GUIWindowSettingsProfile.h"
#ifdef HAS_GL
#include "rendering/gl/GUIWindowTestPatternGL.h"
#endif
#ifdef HAS_DX
#include "rendering/dx/GUIWindowTestPatternDX.h"
#endif
#include "settings/GUIWindowSettingsScreenCalibration.h"
#include "programs/GUIWindowPrograms.h"
#include "pictures/GUIWindowPictures.h"
#include "windows/GUIWindowWeather.h"
#include "windows/GUIWindowLoginScreen.h"
#include "addons/GUIWindowAddonBrowser.h"
#include "music/windows/GUIWindowVisualisation.h"
#include "windows/GUIWindowDebugInfo.h"
#include "windows/GUIWindowPointer.h"
#include "windows/GUIWindowSystemInfo.h"
#include "windows/GUIWindowScreensaver.h"
#include "windows/GUIWindowScreensaverDim.h"
#include "pictures/GUIWindowSlideShow.h"
#include "windows/GUIWindowStartup.h"
#include "video/windows/GUIWindowFullScreen.h"
#include "video/dialogs/GUIDialogVideoOSD.h"
#include "music/dialogs/GUIDialogMusicOverlay.h"
#include "video/dialogs/GUIDialogVideoOverlay.h"
// Dialog includes
#include "music/dialogs/GUIDialogMusicOSD.h"
#include "music/dialogs/GUIDialogVisualisationPresetList.h"
#include "dialogs/GUIDialogTextViewer.h"
#include "network/GUIDialogNetworkSetup.h"
#include "dialogs/GUIDialogMediaSource.h"
#include "video/dialogs/GUIDialogVideoSettings.h"
#include "video/dialogs/GUIDialogAudioSubtitleSettings.h"
#include "video/dialogs/GUIDialogVideoBookmarks.h"
#include "settings/GUIDialogProfileSettings.h"
#include "settings/GUIDialogLockSettings.h"
#include "settings/GUIDialogContentSettings.h"
#include "video/dialogs/GUIDialogVideoScan.h"
#include "dialogs/GUIDialogBusy.h"
#include "dialogs/GUIDialogKeyboard.h"
#include "dialogs/GUIDialogYesNo.h"
#include "dialogs/GUIDialogOK.h"
#include "dialogs/GUIDialogProgress.h"
#include "dialogs/GUIDialogSelect.h"
#include "dialogs/GUIDialogSeekBar.h"
#include "dialogs/GUIDialogKaiToast.h"
#include "dialogs/GUIDialogVolumeBar.h"
#include "dialogs/GUIDialogMuteBug.h"
#include "video/dialogs/GUIDialogFileStacking.h"
#include "dialogs/GUIDialogNumeric.h"
#include "dialogs/GUIDialogGamepad.h"
#include "dialogs/GUIDialogSubMenu.h"
#include "dialogs/GUIDialogFavourites.h"
#include "dialogs/GUIDialogButtonMenu.h"
#include "dialogs/GUIDialogContextMenu.h"
#include "music/dialogs/GUIDialogMusicScan.h"
#include "dialogs/GUIDialogPlayerControls.h"
#include "music/dialogs/GUIDialogSongInfo.h"
#include "dialogs/GUIDialogSmartPlaylistEditor.h"
#include "dialogs/GUIDialogSmartPlaylistRule.h"
#include "pictures/GUIDialogPictureInfo.h"
#include "addons/GUIDialogAddonSettings.h"
#include "addons/GUIDialogAddonInfo.h"
#ifdef HAS_LINUX_NETWORK
#include "network/GUIDialogAccessPoints.h"
#endif
#include "video/dialogs/GUIDialogFullScreenInfo.h"
#include "video/dialogs/GUIDialogTeletext.h"
#include "dialogs/GUIDialogSlider.h"
#include "guilib/GUIControlFactory.h"
#include "dialogs/GUIDialogCache.h"
#include "dialogs/GUIDialogPlayEject.h"
#include "utils/XMLUtils.h"
#include "addons/AddonInstaller.h"
#ifdef HAS_PERFORMANCE_SAMPLE
#include "utils/PerformanceSample.h"
#else
#define MEASURE_FUNCTION
#endif
#ifdef TARGET_WINDOWS
#include <shlobj.h>
#include "win32util.h"
#endif
#ifdef HAS_XRANDR
#include "windowing/X11/XRandR.h"
#endif
#ifdef TARGET_DARWIN_OSX
#include "CocoaInterface.h"
#include "XBMCHelper.h"
#endif
#ifdef TARGET_DARWIN
#include "DarwinUtils.h"
#endif
#ifdef HAS_DVD_DRIVE
#include <cdio/logging.h>
#endif
#ifdef HAS_HAL
#include "linux/HALManager.h"
#endif
#include "storage/MediaManager.h"
#include "utils/JobManager.h"
#include "utils/SaveFileStateJob.h"
#include "utils/AlarmClock.h"
#include "utils/StringUtils.h"
#ifdef _LINUX
#include "XHandle.h"
#endif
#ifdef HAS_LIRC
#include "input/linux/LIRC.h"
#endif
#ifdef HAS_IRSERVERSUITE
#include "input/windows/IRServerSuite.h"
#endif
#if defined(TARGET_WINDOWS)
#include "input/windows/WINJoystick.h"
#elif defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER)
#include "input/SDLJoystick.h"
#endif
using namespace std;
using namespace ADDON;
using namespace XFILE;
#ifdef HAS_DVD_DRIVE
using namespace MEDIA_DETECT;
#endif
using namespace PLAYLIST;
using namespace VIDEO;
using namespace MUSIC_INFO;
#ifdef HAS_EVENT_SERVER
using namespace EVENTSERVER;
#endif
#ifdef HAS_JSONRPC
using namespace JSONRPC;
#endif
using namespace ANNOUNCEMENT;
using namespace PERIPHERALS;
using namespace XbmcThreads;
// uncomment this if you want to use release libs in the debug build.
// Atm this saves you 7 mb of memory
#define USE_RELEASE_LIBS
#define MAX_FFWD_SPEED 5
//extern IDirectSoundRenderer* m_pAudioDecoder;
CApplication::CApplication(void)
: m_pPlayer(NULL)
#ifdef HAS_WEB_SERVER
, m_WebServer(*new CWebServer)
, m_httpImageHandler(*new CHTTPImageHandler)
, m_httpVfsHandler(*new CHTTPVfsHandler)
#ifdef HAS_JSONRPC
, m_httpJsonRpcHandler(*new CHTTPJsonRpcHandler)
#endif
#ifdef HAS_HTTPAPI
, m_httpApiHandler(*new CHTTPApiHandler)
#endif
#ifdef HAS_WEB_INTERFACE
, m_httpWebinterfaceHandler(*new CHTTPWebinterfaceHandler)
, m_httpWebinterfaceAddonsHandler(*new CHTTPWebinterfaceAddonsHandler)
#endif
#endif
, m_itemCurrentFile(new CFileItem)
, m_progressTrackingVideoResumeBookmark(*new CBookmark)
, m_progressTrackingItem(new CFileItem)
, m_videoInfoScanner(new CVideoInfoScanner)
, m_musicInfoScanner(new CMusicInfoScanner)
{
TiXmlBase::SetCondenseWhiteSpace(false);
m_iPlaySpeed = 1;
m_bScreenSave = false;
m_dpms = NULL;
m_dpmsIsActive = false;
m_dpmsIsManual = false;
m_iScreenSaveLock = 0;
m_bInitializing = true;
m_eForcedNextPlayer = EPC_NONE;
m_strPlayListFile = "";
m_nextPlaylistItem = -1;
m_bPlaybackStarting = false;
m_skinReloading = false;
#ifdef HAS_GLX
XInitThreads();
#endif
//true while we in IsPaused mode! Workaround for OnPaused, which must be add. after v2.0
m_bIsPaused = false;
/* for now always keep this around */
#ifdef HAS_KARAOKE
m_pKaraokeMgr = new CKaraokeLyricsManager();
#endif
m_currentStack = new CFileItemList;
m_frameCount = 0;
m_bPresentFrame = false;
m_bPlatformDirectories = true;
m_bStandalone = false;
m_bEnableLegacyRes = false;
m_bSystemScreenSaverEnable = false;
m_pInertialScrollingHandler = new CInertialScrollingHandler();
#ifdef HAS_DVD_DRIVE
m_Autorun = new CAutorun();
#endif
}
CApplication::~CApplication(void)
{
#ifdef HAS_WEB_SERVER
delete &m_WebServer;
delete &m_httpImageHandler;
delete &m_httpVfsHandler;
#ifdef HAS_HTTPAPI
delete &m_httpApiHandler;
#endif
#ifdef HAS_JSONRPC
delete &m_httpJsonRpcHandler;
#endif
#ifdef HAS_WEB_INTERFACE
delete &m_httpWebinterfaceHandler;
delete &m_httpWebinterfaceAddonsHandler;
#endif
#endif
delete &m_progressTrackingVideoResumeBookmark;
#ifdef HAS_DVD_DRIVE
delete m_Autorun;
#endif
delete m_currentStack;
#ifdef HAS_KARAOKE
delete m_pKaraokeMgr;
#endif
delete m_dpms;
delete m_pInertialScrollingHandler;
}
bool CApplication::OnEvent(XBMC_Event& newEvent)
{
switch(newEvent.type)
{
case XBMC_QUIT:
if (!g_application.m_bStop)
g_application.getApplicationMessenger().Quit();
break;
case XBMC_KEYDOWN:
g_application.OnKey(g_Keyboard.ProcessKeyDown(newEvent.key.keysym));
break;
case XBMC_KEYUP:
g_Keyboard.ProcessKeyUp();
break;
case XBMC_MOUSEBUTTONDOWN:
case XBMC_MOUSEBUTTONUP:
case XBMC_MOUSEMOTION:
g_Mouse.HandleEvent(newEvent);
g_application.ProcessMouse();
break;
case XBMC_VIDEORESIZE:
if (!g_application.m_bInitializing &&
!g_advancedSettings.m_fullScreen)
{
g_Windowing.SetWindowResolution(newEvent.resize.w, newEvent.resize.h);
g_graphicsContext.SetVideoResolution(RES_WINDOW, true);
g_guiSettings.SetInt("window.width", newEvent.resize.w);
g_guiSettings.SetInt("window.height", newEvent.resize.h);
g_settings.Save();
}
break;
case XBMC_VIDEOMOVE:
#ifdef TARGET_WINDOWS
if (g_advancedSettings.m_fullScreen)
{
// when fullscreen, remain fullscreen and resize to the dimensions of the new screen
RESOLUTION newRes = (RESOLUTION) g_Windowing.DesktopResolution(g_Windowing.GetCurrentScreen());
if (newRes != g_graphicsContext.GetVideoResolution())
{
g_guiSettings.SetResolution(newRes);
g_graphicsContext.SetVideoResolution(newRes);
}
}
else
#endif
{
g_Windowing.OnMove(newEvent.move.x, newEvent.move.y);
}
break;
case XBMC_USEREVENT:
g_application.getApplicationMessenger().UserEvent(newEvent.user.code);
break;
case XBMC_APPCOMMAND:
return g_application.OnAppCommand(newEvent.appcommand.action);
}
return true;
}
// This function does not return!
void CApplication::FatalErrorHandler(bool WindowSystemInitialized, bool MapDrives, bool InitNetwork)
{
fprintf(stderr, "Fatal error encountered, aborting\n");
fprintf(stderr, "Error log at %sxbmc.log\n", g_settings.m_logFolder.c_str());
abort();
}
extern "C" void __stdcall init_emu_environ();
extern "C" void __stdcall update_emu_environ();
//
// Utility function used to copy files from the application bundle
// over to the user data directory in Application Support/XBMC.
//
static void CopyUserDataIfNeeded(const CStdString &strPath, const CStdString &file)
{
CStdString destPath = URIUtils::AddFileToFolder(strPath, file);
if (!CFile::Exists(destPath))
{
// need to copy it across
CStdString srcPath = URIUtils::AddFileToFolder("special://xbmc/userdata/", file);
CFile::Cache(srcPath, destPath);
}
}
void CApplication::Preflight()
{
#ifdef HAS_DBUS
// call 'dbus_threads_init_default' before any other dbus calls in order to
// avoid race conditions with other threads using dbus connections
dbus_threads_init_default();
#endif
// run any platform preflight scripts.
#if defined(TARGET_DARWIN_OSX)
CStdString install_path;
CUtil::GetHomePath(install_path);
setenv("XBMC_HOME", install_path.c_str(), 0);
install_path += "/tools/darwin/runtime/preflight";
system(install_path.c_str());
#endif
}
bool CApplication::Create()
{
Preflight();
g_settings.Initialize(); //Initialize default AdvancedSettings
#ifdef _LINUX
tzset(); // Initialize timezone information variables
#endif
// Grab a handle to our thread to be used later in identifying the render thread.
m_threadID = CThread::GetCurrentThreadId();
#ifndef _LINUX
//floating point precision to 24 bits (faster performance)
_controlfp(_PC_24, _MCW_PC);
/* install win32 exception translator, win32 exceptions
* can now be caught using c++ try catch */
win32_exception::install_handler();
#endif
// only the InitDirectories* for the current platform should return true
// putting this before the first log entries saves another ifdef for g_settings.m_logFolder
bool inited = InitDirectoriesLinux();
if (!inited)
inited = InitDirectoriesOSX();
if (!inited)
inited = InitDirectoriesWin32();
// copy required files
CopyUserDataIfNeeded("special://masterprofile/", "RssFeeds.xml");
CopyUserDataIfNeeded("special://masterprofile/", "favourites.xml");
CopyUserDataIfNeeded("special://masterprofile/", "Lircmap.xml");
CopyUserDataIfNeeded("special://masterprofile/", "LCD.xml");
if (!CLog::Init(CSpecialProtocol::TranslatePath(g_settings.m_logFolder).c_str()))
{
fprintf(stderr,"Could not init logging classes. Permission errors on ~/.xbmc (%s)\n",
CSpecialProtocol::TranslatePath(g_settings.m_logFolder).c_str());
return false;
}
// Init our DllLoaders emu env
init_emu_environ();
g_settings.LoadProfiles(PROFILES_FILE);
CLog::Log(LOGNOTICE, "-----------------------------------------------------------------------");
#if defined(TARGET_DARWIN_OSX)
CLog::Log(LOGNOTICE, "Starting XBMC (%s), Platform: Darwin OSX (%s). Built on %s", g_infoManager.GetVersion().c_str(), g_sysinfo.GetUnameVersion().c_str(), __DATE__);
#elif defined(TARGET_DARWIN_IOS)
CLog::Log(LOGNOTICE, "Starting XBMC (%s), Platform: Darwin iOS (%s). Built on %s", g_infoManager.GetVersion().c_str(), g_sysinfo.GetUnameVersion().c_str(), __DATE__);
#elif defined(__FreeBSD__)
CLog::Log(LOGNOTICE, "Starting XBMC (%s), Platform: FreeBSD (%s). Built on %s", g_infoManager.GetVersion().c_str(), g_sysinfo.GetUnameVersion().c_str(), __DATE__);
#elif defined(_LINUX)
CLog::Log(LOGNOTICE, "Starting XBMC (%s), Platform: Linux (%s, %s). Built on %s", g_infoManager.GetVersion().c_str(), g_sysinfo.GetLinuxDistro().c_str(), g_sysinfo.GetUnameVersion().c_str(), __DATE__);
#elif defined(_WIN32)
CLog::Log(LOGNOTICE, "Starting XBMC (%s), Platform: %s. Built on %s (compiler %i)", g_infoManager.GetVersion().c_str(), g_sysinfo.GetKernelVersion().c_str(), __DATE__, _MSC_VER);
CLog::Log(LOGNOTICE, g_cpuInfo.getCPUModel().c_str());
CLog::Log(LOGNOTICE, CWIN32Util::GetResInfoString());
CLog::Log(LOGNOTICE, "Running with %s rights", (CWIN32Util::IsCurrentUserLocalAdministrator() == TRUE) ? "administrator" : "restricted");
CLog::Log(LOGNOTICE, "Aero is %s", (g_sysinfo.IsAeroDisabled() == true) ? "disabled" : "enabled");
#endif
CSpecialProtocol::LogPaths();
CStdString executable = CUtil::ResolveExecutablePath();
CLog::Log(LOGNOTICE, "The executable running is: %s", executable.c_str());
CLog::Log(LOGNOTICE, "Local hostname: %s", m_network.GetHostName().c_str());
CLog::Log(LOGNOTICE, "Log File is located: %sxbmc.log", g_settings.m_logFolder.c_str());
CLog::Log(LOGNOTICE, "-----------------------------------------------------------------------");
CStdString strExecutablePath;
CUtil::GetHomePath(strExecutablePath);
// if we are running from DVD our UserData location will be TDATA
if (URIUtils::IsDVD(strExecutablePath))
{
// TODO: Should we copy over any UserData folder from the DVD?
if (!CFile::Exists("special://masterprofile/guisettings.xml")) // first run - cache userdata folder
{
CFileItemList items;
CUtil::GetRecursiveListing("special://xbmc/userdata",items,"");
for (int i=0;i<items.Size();++i)
CFile::Cache(items[i]->GetPath(),"special://masterprofile/"+URIUtils::GetFileName(items[i]->GetPath()));
}
g_settings.m_logFolder = "special://masterprofile/";
}
#ifdef HAS_XRANDR
g_xrandr.LoadCustomModeLinesToAllOutputs();
#endif
// for python scripts that check the OS
#if defined(TARGET_DARWIN)
setenv("OS","OS X",true);
#elif defined(_LINUX)
setenv("OS","Linux",true);
#elif defined(_WIN32)
SetEnvironmentVariable("OS","win32");
#endif
g_powerManager.Initialize();
// Load the AudioEngine before settings as they need to query the engine
if (!CAEFactory::LoadEngine())
{
CLog::Log(LOGFATAL, "CApplication::Create: Failed to load an AudioEngine");
FatalErrorHandler(true, true, true);
}
CLog::Log(LOGNOTICE, "load settings...");
g_guiSettings.Initialize(); // Initialize default Settings - don't move
g_powerManager.SetDefaults();
if (!g_settings.Load())
FatalErrorHandler(true, true, true);
CLog::Log(LOGINFO, "creating subdirectories");
CLog::Log(LOGINFO, "userdata folder: %s", g_settings.GetProfileUserDataFolder().c_str());
CLog::Log(LOGINFO, "recording folder: %s", g_guiSettings.GetString("audiocds.recordingpath",false).c_str());
CLog::Log(LOGINFO, "screenshots folder: %s", g_guiSettings.GetString("debug.screenshotpath",false).c_str());
CDirectory::Create(g_settings.GetUserDataFolder());
CDirectory::Create(g_settings.GetProfileUserDataFolder());
g_settings.CreateProfileFolders();
update_emu_environ();//apply the GUI settings
// initialize our charset converter
g_charsetConverter.reset();
// Load the langinfo to have user charset <-> utf-8 conversion
CStdString strLanguage = g_guiSettings.GetString("locale.language");
strLanguage[0] = toupper(strLanguage[0]);
CStdString strLangInfoPath;
strLangInfoPath.Format("special://xbmc/language/%s/langinfo.xml", strLanguage.c_str());
CLog::Log(LOGINFO, "load language info file: %s", strLangInfoPath.c_str());
g_langInfo.Load(strLangInfoPath);
CStdString strLanguagePath = "special://xbmc/language/";
CLog::Log(LOGINFO, "load %s language file, from path: %s", strLanguage.c_str(), strLanguagePath.c_str());
if (!g_localizeStrings.Load(strLanguagePath, strLanguage))
FatalErrorHandler(false, false, true);
// start the AudioEngine
if (!CAEFactory::StartEngine())
{
CLog::Log(LOGFATAL, "CApplication::Create: Failed to start the AudioEngine");
FatalErrorHandler(true, true, true);
}
// restore AE's previous volume state
SetHardwareVolume(g_settings.m_fVolumeLevel);
CAEFactory::SetMute (g_settings.m_bMute);
CAEFactory::SetSoundMode(g_guiSettings.GetInt("audiooutput.guisoundmode"));
// start-up Addons Framework
// currently bails out if either cpluff Dll is unavailable or system dir can not be scanned
if (!CAddonMgr::Get().Init())
{
CLog::Log(LOGFATAL, "CApplication::Create: Unable to start CAddonMgr");
FatalErrorHandler(true, true, true);
}
g_peripherals.Initialise();
// Create the Mouse, Keyboard, Remote, and Joystick devices
// Initialize after loading settings to get joystick deadzone setting
g_Mouse.Initialize();
g_Mouse.SetEnabled(g_guiSettings.GetBool("input.enablemouse"));
g_Keyboard.Initialize();
#if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
g_RemoteControl.Initialize();
#endif
#if defined(TARGET_DARWIN_OSX)
// Configure and possible manually start the helper.
XBMCHelper::GetInstance().Configure();
#endif
CUtil::InitRandomSeed();
g_mediaManager.Initialize();
m_lastFrameTime = XbmcThreads::SystemClockMillis();
m_lastRenderTime = m_lastFrameTime;
return true;
}
bool CApplication::CreateGUI()
{
#ifdef HAS_SDL
CLog::Log(LOGNOTICE, "Setup SDL");
/* Clean up on exit, exit on window close and interrupt */
atexit(SDL_Quit);
uint32_t sdlFlags = 0;
#if defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)
sdlFlags |= SDL_INIT_VIDEO;
#endif
#if defined(HAS_SDL_JOYSTICK) && !defined(TARGET_WINDOWS)
sdlFlags |= SDL_INIT_JOYSTICK;
#endif
//depending on how it's compiled, SDL periodically calls XResetScreenSaver when it's fullscreen
//this might bring the monitor out of standby, so we have to disable it explicitly
//by passing 0 for overwrite to setsenv, the user can still override this by setting the environment variable
#if defined(_LINUX) && !defined(TARGET_DARWIN)
setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0);
#endif
#endif // HAS_SDL
#ifdef _LINUX
// for nvidia cards - vsync currently ALWAYS enabled.
// the reason is that after screen has been setup changing this env var will make no difference.
setenv("__GL_SYNC_TO_VBLANK", "1", 0);
setenv("__GL_YIELD", "USLEEP", 0);
#endif
m_bSystemScreenSaverEnable = g_Windowing.IsSystemScreenSaverEnabled();
g_Windowing.EnableSystemScreenSaver(false);
#ifdef HAS_SDL
if (SDL_Init(sdlFlags) != 0)
{
CLog::Log(LOGFATAL, "XBAppEx: Unable to initialize SDL: %s", SDL_GetError());
return false;
}
#if defined(TARGET_DARWIN)
// SDL_Init will install a handler for segfaults, restore the default handler.
signal(SIGSEGV, SIG_DFL);
#endif
#endif
// Initialize core peripheral port support. Note: If these parameters
// are 0 and NULL, respectively, then the default number and types of
// controllers will be initialized.
if (!g_Windowing.InitWindowSystem())
{
CLog::Log(LOGFATAL, "CApplication::Create: Unable to init windowing system");
return false;
}
// Retrieve the matching resolution based on GUI settings
g_guiSettings.m_LookAndFeelResolution = g_guiSettings.GetResolution();
CLog::Log(LOGNOTICE, "Checking resolution %i", g_guiSettings.m_LookAndFeelResolution);
if (!g_graphicsContext.IsValidResolution(g_guiSettings.m_LookAndFeelResolution))
{
CLog::Log(LOGNOTICE, "Setting safe mode %i", RES_DESKTOP);
g_guiSettings.SetResolution(RES_DESKTOP);
}
// update the window resolution
g_Windowing.SetWindowResolution(g_guiSettings.GetInt("window.width"), g_guiSettings.GetInt("window.height"));
if (g_advancedSettings.m_startFullScreen && g_guiSettings.m_LookAndFeelResolution == RES_WINDOW)
g_guiSettings.m_LookAndFeelResolution = RES_DESKTOP;
if (!g_graphicsContext.IsValidResolution(g_guiSettings.m_LookAndFeelResolution))
{
// Oh uh - doesn't look good for starting in their wanted screenmode
CLog::Log(LOGERROR, "The screen resolution requested is not valid, resetting to a valid mode");
g_guiSettings.m_LookAndFeelResolution = RES_DESKTOP;
}
if (!InitWindow())
{
return false;
}
if (g_advancedSettings.m_splashImage)
{
CStdString strUserSplash = "special://home/media/Splash.png";
if (CFile::Exists(strUserSplash))
{
CLog::Log(LOGINFO, "load user splash image: %s", CSpecialProtocol::TranslatePath(strUserSplash).c_str());
m_splash = new CSplash(strUserSplash);
}
else
{
CLog::Log(LOGINFO, "load default splash image: %s", CSpecialProtocol::TranslatePath("special://xbmc/media/Splash.png").c_str());
m_splash = new CSplash("special://xbmc/media/Splash.png");
}
m_splash->Show();
}
// The key mappings may already have been loaded by a peripheral
CLog::Log(LOGINFO, "load keymapping");
if (!CButtonTranslator::GetInstance().Load())
FatalErrorHandler(false, false, true);
int iResolution = g_graphicsContext.GetVideoResolution();
CLog::Log(LOGINFO, "GUI format %ix%i %s",
g_settings.m_ResInfo[iResolution].iWidth,
g_settings.m_ResInfo[iResolution].iHeight,
g_settings.m_ResInfo[iResolution].strMode.c_str());
g_windowManager.Initialize();
return true;
}
bool CApplication::InitWindow()
{
#ifdef TARGET_DARWIN_OSX
// force initial window creation to be windowed, if fullscreen, it will switch to it below
// fixes the white screen of death if starting fullscreen and switching to windowed.
bool bFullScreen = false;
if (!g_Windowing.CreateNewWindow("XBMC", bFullScreen, g_settings.m_ResInfo[RES_WINDOW], OnEvent))
{
CLog::Log(LOGFATAL, "CApplication::Create: Unable to create window");
return false;
}
#else
bool bFullScreen = g_guiSettings.m_LookAndFeelResolution != RES_WINDOW;
if (!g_Windowing.CreateNewWindow("XBMC", bFullScreen, g_settings.m_ResInfo[g_guiSettings.m_LookAndFeelResolution], OnEvent))
{
CLog::Log(LOGFATAL, "CApplication::Create: Unable to create window");
return false;
}
#endif
if (!g_Windowing.InitRenderSystem())
{
CLog::Log(LOGFATAL, "CApplication::Create: Unable to init rendering system");
return false;
}
// set GUI res and force the clear of the screen
g_graphicsContext.SetVideoResolution(g_guiSettings.m_LookAndFeelResolution);
return true;
}
bool CApplication::DestroyWindow()
{
g_Windowing.DestroyRenderSystem();
return g_Windowing.DestroyWindow();
}
bool CApplication::InitDirectoriesLinux()
{
/*
The following is the directory mapping for Platform Specific Mode:
special://xbmc/ => [read-only] system directory (/usr/share/xbmc)
special://home/ => [read-write] user's directory that will override special://xbmc/ system-wide
installations like skins, screensavers, etc.
($HOME/.xbmc)
NOTE: XBMC will look in both special://xbmc/addons and special://home/addons for addons.
special://masterprofile/ => [read-write] userdata of master profile. It will by default be
mapped to special://home/userdata ($HOME/.xbmc/userdata)
special://profile/ => [read-write] current profile's userdata directory.
Generally special://masterprofile for the master profile or
special://masterprofile/profiles/<profile_name> for other profiles.
NOTE: All these root directories are lowercase. Some of the sub-directories
might be mixed case.
*/
#if defined(_LINUX) && !defined(TARGET_DARWIN)
CStdString userName;
if (getenv("USER"))
userName = getenv("USER");
else
userName = "root";
CStdString userHome;
if (getenv("HOME"))
userHome = getenv("HOME");
else
userHome = "/root";
CStdString xbmcBinPath, xbmcPath;
CUtil::GetHomePath(xbmcBinPath, "XBMC_BIN_HOME");
xbmcPath = getenv("XBMC_HOME");
if (xbmcPath.IsEmpty())
{
xbmcPath = xbmcBinPath;
/* Check if xbmc binaries and arch independent data files are being kept in
* separate locations. */
if (!CFile::Exists(URIUtils::AddFileToFolder(xbmcPath, "language")))
{
/* Attempt to locate arch independent data files. */
CUtil::GetHomePath(xbmcPath);
if (!CFile::Exists(URIUtils::AddFileToFolder(xbmcPath, "language")))
{
fprintf(stderr, "Unable to find path to XBMC data files!\n");
exit(1);
}
}
}
/* Set some environment variables */
setenv("XBMC_BIN_HOME", xbmcBinPath.c_str(), 0);
setenv("XBMC_HOME", xbmcPath.c_str(), 0);
if (m_bPlatformDirectories)
{
// map our special drives
CSpecialProtocol::SetXBMCBinPath(xbmcBinPath);
CSpecialProtocol::SetXBMCPath(xbmcPath);
CSpecialProtocol::SetHomePath(userHome + "/.xbmc");
CSpecialProtocol::SetMasterProfilePath(userHome + "/.xbmc/userdata");
CStdString strTempPath = URIUtils::AddFileToFolder(userHome, ".xbmc/temp");
CSpecialProtocol::SetTempPath(strTempPath);
URIUtils::AddSlashAtEnd(strTempPath);
g_settings.m_logFolder = strTempPath;
CreateUserDirs();
}
else
{
URIUtils::AddSlashAtEnd(xbmcPath);
g_settings.m_logFolder = xbmcPath;
CSpecialProtocol::SetXBMCBinPath(xbmcBinPath);
CSpecialProtocol::SetXBMCPath(xbmcPath);
CSpecialProtocol::SetHomePath(URIUtils::AddFileToFolder(xbmcPath, "portable_data"));
CSpecialProtocol::SetMasterProfilePath(URIUtils::AddFileToFolder(xbmcPath, "portable_data/userdata"));
CStdString strTempPath = URIUtils::AddFileToFolder(xbmcPath, "portable_data/temp");
CSpecialProtocol::SetTempPath(strTempPath);
CreateUserDirs();
URIUtils::AddSlashAtEnd(strTempPath);
g_settings.m_logFolder = strTempPath;
}
return true;
#else
return false;
#endif
}
bool CApplication::InitDirectoriesOSX()
{
#if defined(TARGET_DARWIN)
CStdString userName;
if (getenv("USER"))
userName = getenv("USER");
else
userName = "root";
CStdString userHome;
if (getenv("HOME"))
userHome = getenv("HOME");
else
userHome = "/root";
CStdString xbmcPath;
CUtil::GetHomePath(xbmcPath);
setenv("XBMC_HOME", xbmcPath.c_str(), 0);
#if defined(TARGET_DARWIN_IOS)
CStdString fontconfigPath;
fontconfigPath = xbmcPath + "/system/players/dvdplayer/etc/fonts/fonts.conf";
setenv("FONTCONFIG_FILE", fontconfigPath.c_str(), 0);
#endif
// setup path to our internal dylibs so loader can find them
CStdString frameworksPath = CUtil::GetFrameworksPath();
CSpecialProtocol::SetXBMCFrameworksPath(frameworksPath);
// OSX always runs with m_bPlatformDirectories == true
if (m_bPlatformDirectories)
{
// map our special drives
CSpecialProtocol::SetXBMCBinPath(xbmcPath);
CSpecialProtocol::SetXBMCPath(xbmcPath);
#if defined(TARGET_DARWIN_IOS)
CSpecialProtocol::SetHomePath(userHome + "/Library/Preferences/XBMC");
CSpecialProtocol::SetMasterProfilePath(userHome + "/Library/Preferences/XBMC/userdata");
#else
CSpecialProtocol::SetHomePath(userHome + "/Library/Application Support/XBMC");
CSpecialProtocol::SetMasterProfilePath(userHome + "/Library/Application Support/XBMC/userdata");
#endif
// location for temp files
#if defined(TARGET_DARWIN_IOS)
CStdString strTempPath = URIUtils::AddFileToFolder(userHome, "Library/Preferences/XBMC/temp");
#else
CStdString strTempPath = URIUtils::AddFileToFolder(userHome, ".xbmc/");
CDirectory::Create(strTempPath);
strTempPath = URIUtils::AddFileToFolder(userHome, ".xbmc/temp");
#endif
CSpecialProtocol::SetTempPath(strTempPath);
// xbmc.log file location
#if defined(TARGET_DARWIN_IOS)
strTempPath = userHome + "/Library/Preferences";
#else
strTempPath = userHome + "/Library/Logs";
#endif
URIUtils::AddSlashAtEnd(strTempPath);
g_settings.m_logFolder = strTempPath;
CreateUserDirs();
}
else
{
URIUtils::AddSlashAtEnd(xbmcPath);
g_settings.m_logFolder = xbmcPath;
CSpecialProtocol::SetXBMCBinPath(xbmcPath);
CSpecialProtocol::SetXBMCPath(xbmcPath);
CSpecialProtocol::SetHomePath(URIUtils::AddFileToFolder(xbmcPath, "portable_data"));
CSpecialProtocol::SetMasterProfilePath(URIUtils::AddFileToFolder(xbmcPath, "portable_data/userdata"));
CStdString strTempPath = URIUtils::AddFileToFolder(xbmcPath, "portable_data/temp");
CSpecialProtocol::SetTempPath(strTempPath);
URIUtils::AddSlashAtEnd(strTempPath);
g_settings.m_logFolder = strTempPath;
}
return true;
#else
return false;
#endif
}
bool CApplication::InitDirectoriesWin32()
{
#ifdef _WIN32
CStdString xbmcPath;
CUtil::GetHomePath(xbmcPath);
SetEnvironmentVariable("XBMC_HOME", xbmcPath.c_str());
CSpecialProtocol::SetXBMCBinPath(xbmcPath);
CSpecialProtocol::SetXBMCPath(xbmcPath);
CStdString strWin32UserFolder = CWIN32Util::GetProfilePath();
g_settings.m_logFolder = strWin32UserFolder;
CSpecialProtocol::SetHomePath(strWin32UserFolder);
CSpecialProtocol::SetMasterProfilePath(URIUtils::AddFileToFolder(strWin32UserFolder, "userdata"));
CSpecialProtocol::SetTempPath(URIUtils::AddFileToFolder(strWin32UserFolder,"cache"));
SetEnvironmentVariable("XBMC_PROFILE_USERDATA",CSpecialProtocol::TranslatePath("special://masterprofile/").c_str());
CreateUserDirs();
// Expand the DLL search path with our directories
CWIN32Util::ExtendDllPath();
return true;
#else
return false;
#endif
}
void CApplication::CreateUserDirs()
{
CDirectory::Create("special://home/");
CDirectory::Create("special://home/addons");
CDirectory::Create("special://home/addons/packages");
CDirectory::Create("special://home/media");
CDirectory::Create("special://home/sounds");
CDirectory::Create("special://home/system");
CDirectory::Create("special://masterprofile/");
CDirectory::Create("special://temp/");
CDirectory::Create("special://temp/temp"); // temp directory for python and dllGetTempPathA
}
bool CApplication::Initialize()
{
#if defined(HAS_DVD_DRIVE) && !defined(_WIN32) // somehow this throws an "unresolved external symbol" on win32
// turn off cdio logging
cdio_loglevel_default = CDIO_LOG_ERROR;
#endif
#ifdef _LINUX // TODO: Win32 has no special://home/ mapping by default, so we
// must create these here. Ideally this should be using special://home/ and
// be platform agnostic (i.e. unify the InitDirectories*() functions)
if (!m_bPlatformDirectories)
#endif
{
CDirectory::Create("special://xbmc/language");
CDirectory::Create("special://xbmc/addons");
CDirectory::Create("special://xbmc/sounds");
}
// Load curl so curl_global_init gets called before any service threads
// are started. Unloading will have no effect as curl is never fully unloaded.
// To quote man curl_global_init:
// "This function is not thread safe. You must not call it when any other
// thread in the program (i.e. a thread sharing the same memory) is running.
// This doesn't just mean no other thread that is using libcurl. Because
// curl_global_init() calls functions of other libraries that are similarly
// thread unsafe, it could conflict with any other thread that
// uses these other libraries."
g_curlInterface.Load();
g_curlInterface.Unload();
#ifdef HAS_WEB_SERVER
CWebServer::RegisterRequestHandler(&m_httpImageHandler);
CWebServer::RegisterRequestHandler(&m_httpVfsHandler);
#ifdef HAS_JSONRPC
CWebServer::RegisterRequestHandler(&m_httpJsonRpcHandler);
#endif
#ifdef HAS_HTTPAPI
CWebServer::RegisterRequestHandler(&m_httpApiHandler);
#endif
#ifdef HAS_WEB_INTERFACE
CWebServer::RegisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
CWebServer::RegisterRequestHandler(&m_httpWebinterfaceHandler);
#endif
#endif
StartServices();
// Init DPMS, before creating the corresponding setting control.
m_dpms = new DPMSSupport();
if (g_windowManager.Initialized())
{
g_guiSettings.GetSetting("powermanagement.displaysoff")->SetVisible(m_dpms->IsSupported());
g_windowManager.Add(new CGUIWindowHome); // window id = 0
g_windowManager.Add(new CGUIWindowPrograms); // window id = 1
g_windowManager.Add(new CGUIWindowPictures); // window id = 2
g_windowManager.Add(new CGUIWindowFileManager); // window id = 3
g_windowManager.Add(new CGUIWindowSettings); // window id = 4
g_windowManager.Add(new CGUIWindowSystemInfo); // window id = 7
#ifdef HAS_GL
g_windowManager.Add(new CGUIWindowTestPatternGL); // window id = 8
#endif
#ifdef HAS_DX
g_windowManager.Add(new CGUIWindowTestPatternDX); // window id = 8
#endif
g_windowManager.Add(new CGUIDialogTeletext); // window id =
g_windowManager.Add(new CGUIWindowSettingsScreenCalibration); // window id = 11
g_windowManager.Add(new CGUIWindowSettingsCategory); // window id = 12 slideshow:window id 2007
g_windowManager.Add(new CGUIWindowVideoNav); // window id = 36
g_windowManager.Add(new CGUIWindowVideoPlaylist); // window id = 28
g_windowManager.Add(new CGUIWindowLoginScreen); // window id = 29
g_windowManager.Add(new CGUIWindowSettingsProfile); // window id = 34
g_windowManager.Add(new CGUIWindowAddonBrowser); // window id = 40
g_windowManager.Add(new CGUIWindowScreensaverDim); // window id = 97
g_windowManager.Add(new CGUIWindowDebugInfo); // window id = 98
g_windowManager.Add(new CGUIWindowPointer); // window id = 99
g_windowManager.Add(new CGUIDialogYesNo); // window id = 100
g_windowManager.Add(new CGUIDialogProgress); // window id = 101
g_windowManager.Add(new CGUIDialogKeyboard); // window id = 103
g_windowManager.Add(new CGUIDialogVolumeBar); // window id = 104
g_windowManager.Add(new CGUIDialogSeekBar); // window id = 115
g_windowManager.Add(new CGUIDialogSubMenu); // window id = 105
g_windowManager.Add(new CGUIDialogContextMenu); // window id = 106
g_windowManager.Add(new CGUIDialogKaiToast); // window id = 107
g_windowManager.Add(new CGUIDialogNumeric); // window id = 109
g_windowManager.Add(new CGUIDialogGamepad); // window id = 110
g_windowManager.Add(new CGUIDialogButtonMenu); // window id = 111
g_windowManager.Add(new CGUIDialogMusicScan); // window id = 112
g_windowManager.Add(new CGUIDialogMuteBug); // window id = 113
g_windowManager.Add(new CGUIDialogPlayerControls); // window id = 114
#ifdef HAS_KARAOKE
g_windowManager.Add(new CGUIDialogKaraokeSongSelectorSmall); // window id 143
g_windowManager.Add(new CGUIDialogKaraokeSongSelectorLarge); // window id 144
#endif
g_windowManager.Add(new CGUIDialogSlider); // window id = 145
g_windowManager.Add(new CGUIDialogMusicOSD); // window id = 120
g_windowManager.Add(new CGUIDialogVisualisationPresetList); // window id = 122
g_windowManager.Add(new CGUIDialogVideoSettings); // window id = 123
g_windowManager.Add(new CGUIDialogAudioSubtitleSettings); // window id = 124
g_windowManager.Add(new CGUIDialogVideoBookmarks); // window id = 125
// Don't add the filebrowser dialog - it's created and added when it's needed
g_windowManager.Add(new CGUIDialogNetworkSetup); // window id = 128
g_windowManager.Add(new CGUIDialogMediaSource); // window id = 129
g_windowManager.Add(new CGUIDialogProfileSettings); // window id = 130
g_windowManager.Add(new CGUIDialogVideoScan); // window id = 133
g_windowManager.Add(new CGUIDialogFavourites); // window id = 134
g_windowManager.Add(new CGUIDialogSongInfo); // window id = 135
g_windowManager.Add(new CGUIDialogSmartPlaylistEditor); // window id = 136
g_windowManager.Add(new CGUIDialogSmartPlaylistRule); // window id = 137
g_windowManager.Add(new CGUIDialogBusy); // window id = 138
g_windowManager.Add(new CGUIDialogPictureInfo); // window id = 139
g_windowManager.Add(new CGUIDialogAddonInfo);
g_windowManager.Add(new CGUIDialogAddonSettings); // window id = 140
#ifdef HAS_LINUX_NETWORK
g_windowManager.Add(new CGUIDialogAccessPoints); // window id = 141
#endif
g_windowManager.Add(new CGUIDialogLockSettings); // window id = 131
g_windowManager.Add(new CGUIDialogContentSettings); // window id = 132
g_windowManager.Add(new CGUIDialogPlayEject);
g_windowManager.Add(new CGUIDialogPeripheralManager);
g_windowManager.Add(new CGUIDialogPeripheralSettings);
g_windowManager.Add(new CGUIWindowMusicPlayList); // window id = 500
g_windowManager.Add(new CGUIWindowMusicSongs); // window id = 501
g_windowManager.Add(new CGUIWindowMusicNav); // window id = 502
g_windowManager.Add(new CGUIWindowMusicPlaylistEditor); // window id = 503
g_windowManager.Add(new CGUIDialogSelect); // window id = 2000
g_windowManager.Add(new CGUIDialogMusicInfo); // window id = 2001
g_windowManager.Add(new CGUIDialogOK); // window id = 2002
g_windowManager.Add(new CGUIDialogVideoInfo); // window id = 2003
g_windowManager.Add(new CGUIDialogTextViewer);
g_windowManager.Add(new CGUIWindowFullScreen); // window id = 2005
g_windowManager.Add(new CGUIWindowVisualisation); // window id = 2006
g_windowManager.Add(new CGUIWindowSlideShow); // window id = 2007
g_windowManager.Add(new CGUIDialogFileStacking); // window id = 2008
#ifdef HAS_KARAOKE
g_windowManager.Add(new CGUIWindowKaraokeLyrics); // window id = 2009
#endif
g_windowManager.Add(new CGUIDialogVideoOSD); // window id = 2901
g_windowManager.Add(new CGUIDialogMusicOverlay); // window id = 2903
g_windowManager.Add(new CGUIDialogVideoOverlay); // window id = 2904
g_windowManager.Add(new CGUIWindowScreensaver); // window id = 2900 Screensaver
g_windowManager.Add(new CGUIWindowWeather); // window id = 2600 WEATHER
g_windowManager.Add(new CGUIWindowStartup); // startup window (id 2999)
/* window id's 3000 - 3100 are reserved for python */
// Make sure we have at least the default skin
if (!LoadSkin(g_guiSettings.GetString("lookandfeel.skin")) && !LoadSkin(DEFAULT_SKIN))
{
CLog::Log(LOGERROR, "Default skin '%s' not found! Terminating..", DEFAULT_SKIN);
FatalErrorHandler(true, true, true);
}
if (g_advancedSettings.m_splashImage)
SAFE_DELETE(m_splash);
if (g_guiSettings.GetBool("masterlock.startuplock") &&
g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE &&
!g_settings.GetMasterProfile().getLockCode().IsEmpty())
{
g_passwordManager.CheckStartUpLock();
}
// check if we should use the login screen
if (g_settings.UsingLoginScreen())
g_windowManager.ActivateWindow(WINDOW_LOGIN_SCREEN);
else
{
#ifdef HAS_JSONRPC
CJSONRPC::Initialize();
#endif
ADDON::CAddonMgr::Get().StartServices(false);
g_windowManager.ActivateWindow(g_SkinInfo->GetFirstWindow());
}
}
else //No GUI Created
{
#ifdef HAS_JSONRPC
CJSONRPC::Initialize();
#endif
ADDON::CAddonMgr::Get().StartServices(false);
}
g_sysinfo.Refresh();
CLog::Log(LOGINFO, "removing tempfiles");
CUtil::RemoveTempFiles();
// if the user shutoff the xbox during music scan
// restore the settings
if (g_settings.m_bMyMusicIsScanning)
{
CLog::Log(LOGWARNING,"System rebooted during music scan! ... restoring UseTags and FindRemoteThumbs");
RestoreMusicScanSettings();
}
if (!g_settings.UsingLoginScreen())
{
UpdateLibraries();
#ifdef HAS_PYTHON
g_pythonParser.m_bLogin = true;
#endif
}
m_slowTimer.StartZero();
#if defined(HAVE_LIBCRYSTALHD)
CCrystalHD::GetInstance();
#endif
CAddonMgr::Get().StartServices(true);
CLog::Log(LOGNOTICE, "initialize done");
m_bInitializing = false;
// reset our screensaver (starts timers etc.)
ResetScreenSaver();
#ifdef HAS_SDL_JOYSTICK
g_Joystick.SetEnabled(g_guiSettings.GetBool("input.enablejoystick"));
#endif
return true;
}
bool CApplication::StartWebServer()
{
#ifdef HAS_WEB_SERVER
if (g_guiSettings.GetBool("services.webserver") && m_network.IsAvailable())
{
int webPort = atoi(g_guiSettings.GetString("services.webserverport"));
CLog::Log(LOGNOTICE, "Webserver: Starting...");
#ifdef _LINUX
if (webPort < 1024 && !CUtil::CanBindPrivileged())
{
CLog::Log(LOGERROR, "Cannot start Web Server on port %i, no permission to bind to ports below 1024", webPort);
return false;
}
#endif
bool started = false;
if (m_WebServer.Start(webPort, g_guiSettings.GetString("services.webserverusername"), g_guiSettings.GetString("services.webserverpassword")))
{
std::map<std::string, std::string> txt;
started = true;
// publish web frontend and API services
#ifdef HAS_WEB_INTERFACE
CZeroconf::GetInstance()->PublishService("servers.webserver", "_http._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), webPort, txt);
#endif
#ifdef HAS_HTTPAPI
CZeroconf::GetInstance()->PublishService("servers.webapi", "_xbmc-web._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), webPort, txt);
#endif
#ifdef HAS_JSONRPC
CZeroconf::GetInstance()->PublishService("servers.jsonrpc-http", "_xbmc-jsonrpc-h._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), webPort, txt);
#endif
}
#ifdef HAS_HTTPAPI
if (g_settings.m_HttpApiBroadcastLevel >= 1)
getApplicationMessenger().HttpApi("broadcastlevel; StartUp;1");
#endif
return started;
}
#endif
return true;
}
void CApplication::StopWebServer()
{
#ifdef HAS_WEB_SERVER
if (m_WebServer.IsStarted())
{
CLog::Log(LOGNOTICE, "Webserver: Stopping...");
m_WebServer.Stop();
if(! m_WebServer.IsStarted() )
{
CLog::Log(LOGNOTICE, "Webserver: Stopped...");
CZeroconf::GetInstance()->RemoveService("servers.webserver");
CZeroconf::GetInstance()->RemoveService("servers.jsonrpc-http");
CZeroconf::GetInstance()->RemoveService("servers.webapi");
} else
CLog::Log(LOGWARNING, "Webserver: Failed to stop.");
}
#endif
}
void CApplication::StartAirplayServer()
{
#ifdef HAS_AIRPLAY
if (g_guiSettings.GetBool("services.airplay") && m_network.IsAvailable())
{
int listenPort = g_advancedSettings.m_airPlayPort;
CStdString password = g_guiSettings.GetString("services.airplaypassword");
bool usePassword = g_guiSettings.GetBool("services.useairplaypassword");
if (CAirPlayServer::StartServer(listenPort, true))
{
CAirPlayServer::SetCredentials(usePassword, password);
std::map<std::string, std::string> txt;
CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
if (iface)
{
txt["deviceid"] = iface->GetMacAddress();
}
else
{
txt["deviceid"] = "FF:FF:FF:FF:FF:F2";
}
txt["features"] = "0x77";
txt["model"] = "AppleTV2,1";
txt["srcvers"] = AIRPLAY_SERVER_VERSION_STR;
CZeroconf::GetInstance()->PublishService("servers.airplay", "_airplay._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), listenPort, txt);
}
}
#endif
#ifdef HAS_AIRTUNES
if (g_guiSettings.GetBool("services.airplay") && m_network.IsAvailable())
{
int listenPort = g_advancedSettings.m_airTunesPort;
CStdString password = g_guiSettings.GetString("services.airplaypassword");
bool usePassword = g_guiSettings.GetBool("services.useairplaypassword");
if (!CAirTunesServer::StartServer(listenPort, true, usePassword, password))
{
CLog::Log(LOGERROR, "Failed to start AirTunes Server");
}
}
#endif
}
void CApplication::StopAirplayServer(bool bWait)
{
#ifdef HAS_AIRPLAY
CAirPlayServer::StopServer(bWait);
CZeroconf::GetInstance()->RemoveService("servers.airplay");
#endif
#ifdef HAS_AIRTUNES
CAirTunesServer::StopServer(bWait);
#endif
}
bool CApplication::StartJSONRPCServer()
{
#ifdef HAS_JSONRPC
if (g_guiSettings.GetBool("services.esenabled"))
{
if (CTCPServer::StartServer(g_advancedSettings.m_jsonTcpPort, g_guiSettings.GetBool("services.esallinterfaces")))
{
std::map<std::string, std::string> txt;
CZeroconf::GetInstance()->PublishService("servers.jsonrpc-tpc", "_xbmc-jsonrpc._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), g_advancedSettings.m_jsonTcpPort, txt);
return true;
}
else
return false;
}
#endif
return true;
}
void CApplication::StopJSONRPCServer(bool bWait)
{
#ifdef HAS_JSONRPC
CTCPServer::StopServer(bWait);
CZeroconf::GetInstance()->RemoveService("servers.jsonrpc-tcp");
#endif
}
void CApplication::StartUPnP()
{
#ifdef HAS_UPNP
StartUPnPServer();
StartUPnPRenderer();
#endif
}
void CApplication::StopUPnP(bool bWait)
{
#ifdef HAS_UPNP
if (CUPnP::IsInstantiated())
{
CLog::Log(LOGNOTICE, "stopping upnp");
CUPnP::ReleaseInstance(bWait);
}
#endif
}
bool CApplication::StartEventServer()
{
#ifdef HAS_EVENT_SERVER
CEventServer* server = CEventServer::GetInstance();
if (!server)
{
CLog::Log(LOGERROR, "ES: Out of memory");
return false;
}
if (g_guiSettings.GetBool("services.esenabled"))
{
CLog::Log(LOGNOTICE, "ES: Starting event server");
server->StartServer();
return true;
}
#endif
return true;
}
bool CApplication::StopEventServer(bool bWait, bool promptuser)
{
#ifdef HAS_EVENT_SERVER
CEventServer* server = CEventServer::GetInstance();
if (!server)
{
CLog::Log(LOGERROR, "ES: Out of memory");
return false;
}
if (promptuser)
{
if (server->GetNumberOfClients() > 0)
{
bool cancelled = false;
if (!CGUIDialogYesNo::ShowAndGetInput(13140, 13141, 13142, 20022,
-1, -1, cancelled, 10000)
|| cancelled)
{
CLog::Log(LOGNOTICE, "ES: Not stopping event server");
return false;
}
}
CLog::Log(LOGNOTICE, "ES: Stopping event server with confirmation");
CEventServer::GetInstance()->StopServer(true);
}
else
{
if (!bWait)
CLog::Log(LOGNOTICE, "ES: Stopping event server");
CEventServer::GetInstance()->StopServer(bWait);
}
return true;
#endif
}
void CApplication::RefreshEventServer()
{
#ifdef HAS_EVENT_SERVER
if (g_guiSettings.GetBool("services.esenabled"))
{
CEventServer::GetInstance()->RefreshSettings();
}
#endif
}
void CApplication::StartUPnPRenderer()
{
#ifdef HAS_UPNP
if (g_guiSettings.GetBool("services.upnprenderer"))
{
CLog::Log(LOGNOTICE, "starting upnp renderer");
CUPnP::GetInstance()->StartRenderer();
}
#endif
}
void CApplication::StopUPnPRenderer()
{
#ifdef HAS_UPNP
if (CUPnP::IsInstantiated())
{
CLog::Log(LOGNOTICE, "stopping upnp renderer");
CUPnP::GetInstance()->StopRenderer();
}
#endif
}
void CApplication::StartUPnPServer()
{
#ifdef HAS_UPNP
if (g_guiSettings.GetBool("services.upnpserver"))
{
CLog::Log(LOGNOTICE, "starting upnp server");
CUPnP::GetInstance()->StartServer();
}
#endif
}
void CApplication::StopUPnPServer()
{
#ifdef HAS_UPNP
if (CUPnP::IsInstantiated())
{
CLog::Log(LOGNOTICE, "stopping upnp server");
CUPnP::GetInstance()->StopServer();
}
#endif
}
void CApplication::StartZeroconf()
{
#ifdef HAS_ZEROCONF
//entry in guisetting only present if HAS_ZEROCONF is set
if(g_guiSettings.GetBool("services.zeroconf"))
{
CLog::Log(LOGNOTICE, "starting zeroconf publishing");
CZeroconf::GetInstance()->Start();
}
#endif
}
void CApplication::StopZeroconf()
{
#ifdef HAS_ZEROCONF
if(CZeroconf::IsInstantiated())
{
CLog::Log(LOGNOTICE, "stopping zeroconf publishing");
CZeroconf::GetInstance()->Stop();
}
#endif
}
void CApplication::DimLCDOnPlayback(bool dim)
{
#ifdef HAS_LCD
if (g_lcd)
{
if (dim)
g_lcd->DisableOnPlayback(IsPlayingVideo(), IsPlayingAudio());
else
g_lcd->SetBackLight(1);
}
#endif
}
void CApplication::StartServices()
{
#if !defined(_WIN32) && defined(HAS_DVD_DRIVE)
// Start Thread for DVD Mediatype detection
CLog::Log(LOGNOTICE, "start dvd mediatype detection");
m_DetectDVDType.Create(false, THREAD_MINSTACKSIZE);
#endif
CLog::Log(LOGNOTICE, "initializing playlistplayer");
g_playlistPlayer.SetRepeat(PLAYLIST_MUSIC, g_settings.m_bMyMusicPlaylistRepeat ? PLAYLIST::REPEAT_ALL : PLAYLIST::REPEAT_NONE);
g_playlistPlayer.SetShuffle(PLAYLIST_MUSIC, g_settings.m_bMyMusicPlaylistShuffle);
g_playlistPlayer.SetRepeat(PLAYLIST_VIDEO, g_settings.m_bMyVideoPlaylistRepeat ? PLAYLIST::REPEAT_ALL : PLAYLIST::REPEAT_NONE);
g_playlistPlayer.SetShuffle(PLAYLIST_VIDEO, g_settings.m_bMyVideoPlaylistShuffle);
CLog::Log(LOGNOTICE, "DONE initializing playlistplayer");
#ifdef HAS_LCD
CLCDFactory factory;
g_lcd = factory.Create();
if (g_lcd)
{
g_lcd->Initialize();
}
#endif
}
void CApplication::StopServices()
{
m_network.NetworkMessage(CNetwork::SERVICES_DOWN, 0);
#if !defined(_WIN32) && defined(HAS_DVD_DRIVE)
CLog::Log(LOGNOTICE, "stop dvd detect media");
m_DetectDVDType.StopThread();
#endif
g_peripherals.Clear();
}
void CApplication::ReloadSkin()
{
m_skinReloading = false;
CGUIMessage msg(GUI_MSG_LOAD_SKIN, -1, g_windowManager.GetActiveWindow());
g_windowManager.SendMessage(msg);
// Reload the skin, restoring the previously focused control. We need this as
// the window unload will reset all control states.
CGUIWindow* pWindow = g_windowManager.GetWindow(g_windowManager.GetActiveWindow());
int iCtrlID = pWindow->GetFocusedControlID();
g_application.LoadSkin(g_guiSettings.GetString("lookandfeel.skin"));
pWindow = g_windowManager.GetWindow(g_windowManager.GetActiveWindow());
if (pWindow && pWindow->HasSaveLastControl())
{
CGUIMessage msg3(GUI_MSG_SETFOCUS, g_windowManager.GetActiveWindow(), iCtrlID, 0);
pWindow->OnMessage(msg3);
}
}
bool CApplication::LoadSkin(const CStdString& skinID)
{
if (m_skinReloading)
return false;
AddonPtr addon;
if (CAddonMgr::Get().GetAddon(skinID, addon, ADDON_SKIN))
{
LoadSkin(boost::dynamic_pointer_cast<ADDON::CSkinInfo>(addon));
return true;
}
return false;
}
void CApplication::LoadSkin(const SkinPtr& skin)
{
if (!skin)
{
CLog::Log(LOGERROR, "failed to load requested skin, fallback to \"%s\" skin", DEFAULT_SKIN);
g_guiSettings.SetString("lookandfeel.skin", DEFAULT_SKIN);
LoadSkin(DEFAULT_SKIN);
return ;
}
bool bPreviousPlayingState=false;
bool bPreviousRenderingState=false;
if (g_application.m_pPlayer && g_application.IsPlayingVideo())
{
bPreviousPlayingState = !g_application.m_pPlayer->IsPaused();
if (bPreviousPlayingState)
g_application.m_pPlayer->Pause();
#ifdef HAS_VIDEO_PLAYBACK
if (!g_renderManager.Paused())
{
if (g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
{
g_windowManager.ActivateWindow(WINDOW_HOME);
bPreviousRenderingState = true;
}
}
#endif
}
// close the music and video overlays (they're re-opened automatically later)
CSingleLock lock(g_graphicsContext);
// save the current window details
int currentWindow = g_windowManager.GetActiveWindow();
vector<int> currentModelessWindows;
g_windowManager.GetActiveModelessWindows(currentModelessWindows);
UnloadSkin();
CLog::Log(LOGINFO, " load skin from: %s", skin->Path().c_str());
g_SkinInfo = skin;
g_SkinInfo->Start();
CLog::Log(LOGINFO, " load fonts for skin...");
g_graphicsContext.SetMediaDir(skin->Path());
g_directoryCache.ClearSubPaths(skin->Path());
if (g_langInfo.ForceUnicodeFont() && !g_fontManager.IsFontSetUnicode(g_guiSettings.GetString("lookandfeel.font")))
{
CLog::Log(LOGINFO, " language needs a ttf font, loading first ttf font available");
CStdString strFontSet;
if (g_fontManager.GetFirstFontSetUnicode(strFontSet))
{
CLog::Log(LOGINFO, " new font is '%s'", strFontSet.c_str());
g_guiSettings.SetString("lookandfeel.font", strFontSet);
g_settings.Save();
}
else
CLog::Log(LOGERROR, " no ttf font found, but needed for the language %s.", g_guiSettings.GetString("locale.language").c_str());
}
g_colorManager.Load(g_guiSettings.GetString("lookandfeel.skincolors"));
g_fontManager.LoadFonts(g_guiSettings.GetString("lookandfeel.font"));
// load in the skin strings
CStdString langPath;
URIUtils::AddFileToFolder(skin->Path(), "language", langPath);
URIUtils::AddSlashAtEnd(langPath);
g_localizeStrings.LoadSkinStrings(langPath, g_guiSettings.GetString("locale.language"));
g_SkinInfo->LoadIncludes();
int64_t start;
start = CurrentHostCounter();
CLog::Log(LOGINFO, " load new skin...");
CGUIWindowHome *pHome = (CGUIWindowHome *)g_windowManager.GetWindow(WINDOW_HOME);
if (!pHome || !pHome->Load("Home.xml"))
{
// failed to load home.xml
// fallback to default skin
if ( strcmpi(skin->ID().c_str(), DEFAULT_SKIN) != 0)
{
CLog::Log(LOGERROR, "failed to load home.xml for skin: %s, fallback to \"%s\" skin", skin->ID().c_str(), DEFAULT_SKIN);
g_guiSettings.SetString("lookandfeel.skin", DEFAULT_SKIN);
LoadSkin(DEFAULT_SKIN);
return ;
}
}
// Load the user windows
LoadUserWindows();
int64_t end, freq;
end = CurrentHostCounter();
freq = CurrentHostFrequency();
CLog::Log(LOGDEBUG,"Load Skin XML: %.2fms", 1000.f * (end - start) / freq);
CLog::Log(LOGINFO, " initialize new skin...");
g_windowManager.AddMsgTarget(this);
g_windowManager.AddMsgTarget(&g_playlistPlayer);
g_windowManager.AddMsgTarget(&g_infoManager);
g_windowManager.AddMsgTarget(&g_fontManager);
g_windowManager.SetCallback(*this);
g_windowManager.Initialize();
CTextureCache::Get().Initialize();
g_audioManager.Enable(true);
g_audioManager.Load();
if (g_SkinInfo->HasSkinFile("DialogFullScreenInfo.xml"))
g_windowManager.Add(new CGUIDialogFullScreenInfo);
{ // we can't register visible condition in dialog's ctor because infomanager is cleared when unloading skin
CGUIDialog *overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_OVERLAY);
if (overlay) overlay->SetVisibleCondition("skin.hasvideooverlay");
overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_OVERLAY);
if (overlay) overlay->SetVisibleCondition("skin.hasmusicoverlay");
}
CLog::Log(LOGINFO, " skin loaded...");
// leave the graphics lock
lock.Leave();
// restore windows
if (currentWindow != WINDOW_INVALID)
{
g_windowManager.ActivateWindow(currentWindow);
for (unsigned int i = 0; i < currentModelessWindows.size(); i++)
{
CGUIDialog *dialog = (CGUIDialog *)g_windowManager.GetWindow(currentModelessWindows[i]);
if (dialog) dialog->Show();
}
}
if (g_application.m_pPlayer && g_application.IsPlayingVideo())
{
if (bPreviousPlayingState)
g_application.m_pPlayer->Pause();
if (bPreviousRenderingState)
g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
}
}
void CApplication::UnloadSkin(bool forReload /* = false */)
{
m_skinReloading = forReload;
CLog::Log(LOGINFO, "Unloading old skin %s...", forReload ? "for reload " : "");
g_audioManager.Enable(false);
g_windowManager.DeInitialize();
CTextureCache::Get().Deinitialize();
// remove the skin-dependent window
g_windowManager.Delete(WINDOW_DIALOG_FULLSCREEN_INFO);
g_TextureManager.Cleanup();
g_largeTextureManager.CleanupUnusedImages(true);
g_fontManager.Clear();
g_colorManager.Clear();
g_charsetConverter.reset();
g_infoManager.Clear();
}
bool CApplication::LoadUserWindows()
{
// Start from wherever home.xml is
std::vector<CStdString> vecSkinPath;
g_SkinInfo->GetSkinPaths(vecSkinPath);
for (unsigned int i = 0;i < vecSkinPath.size();++i)
{
CLog::Log(LOGINFO, "Loading user windows, path %s", vecSkinPath[i].c_str());
CFileItemList items;
if (CDirectory::GetDirectory(vecSkinPath[i], items, ".xml", DIR_FLAG_NO_FILE_DIRS))
{
for (int i = 0; i < items.Size(); ++i)
{
if (items[i]->m_bIsFolder)
continue;
CStdString skinFile = URIUtils::GetFileName(items[i]->GetPath());
if (skinFile.Left(6).CompareNoCase("custom") == 0)
{
CXBMCTinyXML xmlDoc;
if (!xmlDoc.LoadFile(items[i]->GetPath()))
{
CLog::Log(LOGERROR, "unable to load: %s, Line %d\n%s", items[i]->GetPath().c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
continue;
}
// Root element should be <window>
TiXmlElement* pRootElement = xmlDoc.RootElement();
CStdString strValue = pRootElement->Value();
if (!strValue.Equals("window"))
{
CLog::Log(LOGERROR, "file: %s doesnt contain <window>", skinFile.c_str());
continue;
}
// Read the <type> element to get the window type to create
// If no type is specified, create a CGUIWindow as default
CGUIWindow* pWindow = NULL;
CStdString strType;
if (pRootElement->Attribute("type"))
strType = pRootElement->Attribute("type");
else
{
const TiXmlNode *pType = pRootElement->FirstChild("type");
if (pType && pType->FirstChild())
strType = pType->FirstChild()->Value();
}
int id = WINDOW_INVALID;
if (!pRootElement->Attribute("id", &id))
{
const TiXmlNode *pType = pRootElement->FirstChild("id");
if (pType && pType->FirstChild())
id = atol(pType->FirstChild()->Value());
}
CStdString visibleCondition;
CGUIControlFactory::GetConditionalVisibility(pRootElement, visibleCondition);
if (strType.Equals("dialog"))
pWindow = new CGUIDialog(id + WINDOW_HOME, skinFile);
else if (strType.Equals("submenu"))
pWindow = new CGUIDialogSubMenu(id + WINDOW_HOME, skinFile);
else if (strType.Equals("buttonmenu"))
pWindow = new CGUIDialogButtonMenu(id + WINDOW_HOME, skinFile);
else
pWindow = new CGUIStandardWindow(id + WINDOW_HOME, skinFile);
// Check to make sure the pointer isn't still null
if (pWindow == NULL)
{
CLog::Log(LOGERROR, "Out of memory / Failed to create new object in LoadUserWindows");
return false;
}
if (id == WINDOW_INVALID || g_windowManager.GetWindow(WINDOW_HOME + id))
{
delete pWindow;
continue;
}
pWindow->SetVisibleCondition(visibleCondition);
g_windowManager.AddCustomWindow(pWindow);
}
}
}
}
return true;
}
bool CApplication::RenderNoPresent()
{
MEASURE_FUNCTION;
// DXMERGE: This may have been important?
// g_graphicsContext.AcquireCurrentContext();
g_graphicsContext.Lock();
// dont show GUI when playing full screen video
if (g_graphicsContext.IsFullScreenVideo())
{
if (m_bPresentFrame && IsPlaying() && !IsPaused())
{
ResetScreenSaver();
g_renderManager.Present();
}
else
g_renderManager.RenderUpdate(true);
// close window overlays
CGUIDialog *overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_OVERLAY);
if (overlay) overlay->Close(true);
overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_OVERLAY);
if (overlay) overlay->Close(true);
}
bool hasRendered = g_windowManager.Render();
// if we're recording an audio stream then show blinking REC
if (!g_graphicsContext.IsFullScreenVideo())
{
if (m_pPlayer && m_pPlayer->IsRecording() )
{
static int iBlinkRecord = 0;
iBlinkRecord++;
if (iBlinkRecord > 25)
{
CGUIFont* pFont = g_fontManager.GetFont("font13");
CGUITextLayout::DrawText(pFont, 60, 50, 0xffff0000, 0, "REC", 0);
}
if (iBlinkRecord > 50)
iBlinkRecord = 0;
}
}
g_graphicsContext.Unlock();
return hasRendered;
}
float CApplication::GetDimScreenSaverLevel() const
{
if (!m_bScreenSave || !m_screenSaver ||
(m_screenSaver->ID() != "screensaver.xbmc.builtin.dim" &&
m_screenSaver->ID() != "screensaver.xbmc.builtin.black" &&
m_screenSaver->ID() != "screensaver.xbmc.builtin.slideshow"))
return 0;
if (!m_screenSaver->GetSetting("level").IsEmpty())
return 100.0f - (float)atof(m_screenSaver->GetSetting("level"));
return 100.0f;
}
bool CApplication::WaitFrame(unsigned int timeout)
{
bool done = false;
// Wait for all other frames to be presented
CSingleLock lock(m_frameMutex);
//wait until event is set, but modify remaining time
TightConditionVariable<InversePredicate<int&> > cv(m_frameCond, InversePredicate<int&>(m_frameCount));
cv.wait(lock,timeout);
done = m_frameCount == 0;
return done;
}
void CApplication::NewFrame()
{
// We just posted another frame. Keep track and notify.
{
CSingleLock lock(m_frameMutex);
m_frameCount++;
}
m_frameCond.notifyAll();
}
void CApplication::Render()
{
// do not render if we are stopped
if (m_bStop)
return;
if (!m_AppActive && !m_bStop && (!IsPlayingVideo() || IsPaused()))
{
Sleep(1);
ResetScreenSaver();
return;
}
MEASURE_FUNCTION;
int vsync_mode = g_guiSettings.GetInt("videoscreen.vsync");
bool decrement = false;
bool hasRendered = false;
bool limitFrames = false;
unsigned int singleFrameTime = 10; // default limit 100 fps
{
// Less fps in DPMS
bool lowfps = m_dpmsIsActive;
// Whether externalplayer is playing and we're unfocused
bool extPlayerActive = m_eCurrentPlayer >= EPC_EXTPLAYER && IsPlaying() && !m_AppFocused;
m_bPresentFrame = false;
if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !IsPaused())
{
CSingleLock lock(m_frameMutex);
TightConditionVariable<int&> cv(m_frameCond,m_frameCount);
cv.wait(lock,100);
m_bPresentFrame = m_frameCount > 0;
decrement = m_bPresentFrame;
hasRendered = true;
}
else
{
// engage the frame limiter as needed
limitFrames = lowfps || extPlayerActive;
// DXMERGE - we checked for g_videoConfig.GetVSyncMode() before this
// perhaps allowing it to be set differently than the UI option??
if (vsync_mode == VSYNC_DISABLED || vsync_mode == VSYNC_VIDEO)
limitFrames = true; // not using vsync.
else if ((g_infoManager.GetFPS() > g_graphicsContext.GetFPS() + 10) && g_infoManager.GetFPS() > 1000 / singleFrameTime)
limitFrames = true; // using vsync, but it isn't working.
if (limitFrames)
{
if (extPlayerActive)
{
ResetScreenSaver(); // Prevent screensaver dimming the screen
singleFrameTime = 1000; // 1 fps, high wakeup latency but v.low CPU usage
}
else if (lowfps)
singleFrameTime = 200; // 5 fps, <=200 ms latency to wake up
}
decrement = true;
}
}
CSingleLock lock(g_graphicsContext);
g_infoManager.UpdateFPS();
if (g_graphicsContext.IsFullScreenVideo() && IsPlaying() && vsync_mode == VSYNC_VIDEO)
g_Windowing.SetVSync(true);
else if (vsync_mode == VSYNC_ALWAYS)
g_Windowing.SetVSync(true);
else if (vsync_mode != VSYNC_DRIVER)
g_Windowing.SetVSync(false);
if(!g_Windowing.BeginRender())
return;
CDirtyRegionList dirtyRegions = g_windowManager.GetDirty();
if (RenderNoPresent())
hasRendered = true;
g_Windowing.EndRender();
g_TextureManager.FreeUnusedTextures();
// reset our info cache - we do this at the end of Render so that it is
// fresh for the next process(), or after a windowclose animation (where process()
// isn't called)
g_infoManager.ResetCache();
lock.Leave();
unsigned int now = XbmcThreads::SystemClockMillis();
if (hasRendered)
m_lastRenderTime = now;
//when nothing has been rendered for m_guiDirtyRegionNoFlipTimeout milliseconds,
//we don't call g_graphicsContext.Flip() anymore, this saves gpu and cpu usage
bool flip;
if (g_advancedSettings.m_guiDirtyRegionNoFlipTimeout >= 0)
flip = hasRendered || (now - m_lastRenderTime) < (unsigned int)g_advancedSettings.m_guiDirtyRegionNoFlipTimeout;
else
flip = true;
//fps limiter, make sure each frame lasts at least singleFrameTime milliseconds
if (limitFrames || !flip)
{
if (!limitFrames)
singleFrameTime = 40; //if not flipping, loop at 25 fps
unsigned int frameTime = now - m_lastFrameTime;
if (frameTime < singleFrameTime)
Sleep(singleFrameTime - frameTime);
}
m_lastFrameTime = XbmcThreads::SystemClockMillis();
if (flip)
g_graphicsContext.Flip(dirtyRegions);
CTimeUtils::UpdateFrameTime(flip);
g_renderManager.UpdateResolution();
g_renderManager.ManageCaptures();
{
CSingleLock lock(m_frameMutex);
if(m_frameCount > 0 && decrement)
m_frameCount--;
}
m_frameCond.notifyAll();
}
void CApplication::SetStandAlone(bool value)
{
g_advancedSettings.m_handleMounting = m_bStandalone = value;
}
// OnKey() translates the key into a CAction which is sent on to our Window Manager.
// The window manager will return true if the event is processed, false otherwise.
// If not already processed, this routine handles global keypresses. It returns
// true if the key has been processed, false otherwise.
bool CApplication::OnKey(const CKey& key)
{
// Turn the mouse off, as we've just got a keypress from controller or remote
g_Mouse.SetActive(false);
// get the current active window
int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
// this will be checked for certain keycodes that need
// special handling if the screensaver is active
CAction action = CButtonTranslator::GetInstance().GetAction(iWin, key);
// a key has been pressed.
// reset Idle Timer
m_idleTimer.StartZero();
bool processKey = AlwaysProcess(action);
ResetScreenSaver();
// allow some keys to be processed while the screensaver is active
if (WakeUpScreenSaverAndDPMS() && !processKey)
{
CLog::Log(LOGDEBUG, "%s: %s pressed, screen saver/dpms woken up", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str());
return true;
}
// change this if we have a dialog up
if (g_windowManager.HasModalDialog())
{
iWin = g_windowManager.GetTopMostModalDialogID() & WINDOW_ID_MASK;
}
if (iWin == WINDOW_DIALOG_FULLSCREEN_INFO)
{ // fullscreen info dialog - special case
action = CButtonTranslator::GetInstance().GetAction(iWin, key);
if (!key.IsAnalogButton())
CLog::Log(LOGDEBUG, "%s: %s pressed, trying fullscreen info action %s", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str(), action.GetName().c_str());
if (OnAction(action))
return true;
// fallthrough to the main window
iWin = WINDOW_FULLSCREEN_VIDEO;
}
if (iWin == WINDOW_FULLSCREEN_VIDEO)
{
// current active window is full screen video.
if (g_application.m_pPlayer && g_application.m_pPlayer->IsInMenu())
{
// if player is in some sort of menu, (ie DVDMENU) map buttons differently
action = CButtonTranslator::GetInstance().GetAction(WINDOW_VIDEO_MENU, key);
}
else
{
// no then use the fullscreen window section of keymap.xml to map key->action
action = CButtonTranslator::GetInstance().GetAction(iWin, key);
}
}
else
{
// current active window isnt the fullscreen window
// just use corresponding section from keymap.xml
// to map key->action
// first determine if we should use keyboard input directly
bool useKeyboard = key.FromKeyboard() && (iWin == WINDOW_DIALOG_KEYBOARD || iWin == WINDOW_DIALOG_NUMERIC);
CGUIWindow *window = g_windowManager.GetWindow(iWin);
if (window)
{
CGUIControl *control = window->GetFocusedControl();
if (control)
{
// If this is an edit control set usekeyboard to true. This causes the
// keypress to be processed directly not through the key mappings.
if (control->GetControlType() == CGUIControl::GUICONTROL_EDIT)
useKeyboard = true;
// If the key pressed is shift-A to shift-Z set usekeyboard to true.
// This causes the keypress to be used for list navigation.
if (control->IsContainer() && key.GetModifiers() == CKey::MODIFIER_SHIFT && key.GetVKey() >= XBMCVK_A && key.GetVKey() <= XBMCVK_Z)
useKeyboard = true;
}
}
if (useKeyboard)
{
action = CAction(0); // reset our action
if (g_guiSettings.GetBool("input.remoteaskeyboard"))
{
// users remote is executing keyboard commands, so use the virtualkeyboard section of keymap.xml
// and send those rather than actual keyboard presses. Only for navigation-type commands though
action = CButtonTranslator::GetInstance().GetAction(WINDOW_DIALOG_KEYBOARD, key);
if (!(action.GetID() == ACTION_MOVE_LEFT ||
action.GetID() == ACTION_MOVE_RIGHT ||
action.GetID() == ACTION_MOVE_UP ||
action.GetID() == ACTION_MOVE_DOWN ||
action.GetID() == ACTION_SELECT_ITEM ||
action.GetID() == ACTION_ENTER ||
action.GetID() == ACTION_PREVIOUS_MENU ||
action.GetID() == ACTION_NAV_BACK))
{
// the action isn't plain navigation - check for a keyboard-specific keymap
action = CButtonTranslator::GetInstance().GetAction(WINDOW_DIALOG_KEYBOARD, key, false);
if (!(action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9) ||
action.GetID() == ACTION_BACKSPACE ||
action.GetID() == ACTION_SHIFT ||
action.GetID() == ACTION_SYMBOLS ||
action.GetID() == ACTION_CURSOR_LEFT ||
action.GetID() == ACTION_CURSOR_RIGHT)
action = CAction(0); // don't bother with this action
}
}
if (!action.GetID())
{
// keyboard entry - pass the keys through directly
if (key.GetFromService())
action = CAction(key.GetButtonCode() != KEY_INVALID ? key.GetButtonCode() : 0, key.GetUnicode());
else
{ // see if we've got an ascii key
if (key.GetUnicode())
action = CAction(key.GetAscii() | KEY_ASCII, key.GetUnicode());
else
action = CAction(key.GetVKey() | KEY_VKEY);
}
}
CLog::Log(LOGDEBUG, "%s: %s pressed, trying keyboard action %i", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str(), action.GetID());
if (OnAction(action))
return true;
// failed to handle the keyboard action, drop down through to standard action
}
if (key.GetFromService())
{
if (key.GetButtonCode() != KEY_INVALID)
action = CButtonTranslator::GetInstance().GetAction(iWin, key);
}
else
action = CButtonTranslator::GetInstance().GetAction(iWin, key);
}
if (!key.IsAnalogButton())
CLog::Log(LOGDEBUG, "%s: %s pressed, action is %s", __FUNCTION__, g_Keyboard.GetKeyName((int) key.GetButtonCode()).c_str(), action.GetName().c_str());
// Play a sound based on the action
g_audioManager.PlayActionSound(action);
return OnAction(action);
}
// OnAppCommand is called in response to a XBMC_APPCOMMAND event.
// This needs to return true if it processed the appcommand or false if it didn't
bool CApplication::OnAppCommand(const CAction &action)
{
// Reset the screen saver
ResetScreenSaver();
// If we were currently in the screen saver wake up and don't process the appcommand
if (WakeUpScreenSaverAndDPMS())
return true;
// The action ID is the APPCOMMAND code. We need to retrieve the action
// associated with this appcommand from the mapping table.
uint32_t appcmd = action.GetID();
CKey key(appcmd | KEY_APPCOMMAND, (unsigned int) 0);
int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
CAction appcmdaction = CButtonTranslator::GetInstance().GetAction(iWin, key);
// If we couldn't find an action return false to indicate we have not
// handled this appcommand
if (!appcmdaction.GetID())
{
CLog::Log(LOGDEBUG, "%s: unknown appcommand %d", __FUNCTION__, appcmd);
return false;
}
// Process the appcommand
CLog::Log(LOGDEBUG, "%s: appcommand %d, trying action %s", __FUNCTION__, appcmd, appcmdaction.GetName().c_str());
OnAction(appcmdaction);
// Always return true regardless of whether the action succeeded or not.
// This stops Windows handling the appcommand itself.
return true;
}
bool CApplication::OnAction(const CAction &action)
{
#ifdef HAS_HTTPAPI
// Let's tell the outside world about this action, ignoring mouse moves
if (g_settings.m_HttpApiBroadcastLevel>=2 && action.GetID() != ACTION_MOUSE_MOVE)
{
CStdString tmp;
tmp.Format("%i",action.GetID());
getApplicationMessenger().HttpApi("broadcastlevel; OnAction:"+tmp+";2");
}
#endif
// special case for switching between GUI & fullscreen mode.
if (action.GetID() == ACTION_SHOW_GUI)
{ // Switch to fullscreen mode if we can
if (SwitchToFullScreen())
{
m_navigationTimer.StartZero();
return true;
}
}
if (action.GetID() == ACTION_TOGGLE_FULLSCREEN)
{
g_graphicsContext.ToggleFullScreenRoot();
return true;
}
if (action.IsMouse())
g_Mouse.SetActive(true);
// The action PLAYPAUSE behaves as ACTION_PAUSE if we are currently
// playing or ACTION_PLAYER_PLAY if we are not playing.
if (action.GetID() == ACTION_PLAYER_PLAYPAUSE)
{
if (IsPlaying())
return OnAction(CAction(ACTION_PAUSE));
else
return OnAction(CAction(ACTION_PLAYER_PLAY));
}
//if the action would start or stop inertial scrolling
//by gesture - bypass the normal OnAction handler of current window
if( !m_pInertialScrollingHandler->CheckForInertialScrolling(&action) )
{
// in normal case
// just pass the action to the current window and let it handle it
if (g_windowManager.OnAction(action))
{
m_navigationTimer.StartZero();
return true;
}
}
// handle extra global presses
// screenshot : take a screenshot :)
if (action.GetID() == ACTION_TAKE_SCREENSHOT)
{
CUtil::TakeScreenshot();
return true;
}
// built in functions : execute the built-in
if (action.GetID() == ACTION_BUILT_IN_FUNCTION)
{
CBuiltins::Execute(action.GetName());
m_navigationTimer.StartZero();
return true;
}
// reload keymaps
if (action.GetID() == ACTION_RELOAD_KEYMAPS)
{
CButtonTranslator::GetInstance().Clear();
CButtonTranslator::GetInstance().Load();
}
// show info : Shows the current video or song information
if (action.GetID() == ACTION_SHOW_INFO)
{
g_infoManager.ToggleShowInfo();
return true;
}
// codec info : Shows the current song, video or picture codec information
if (action.GetID() == ACTION_SHOW_CODEC)
{
g_infoManager.ToggleShowCodec();
return true;
}
if ((action.GetID() == ACTION_INCREASE_RATING || action.GetID() == ACTION_DECREASE_RATING) && IsPlayingAudio())
{
const CMusicInfoTag *tag = g_infoManager.GetCurrentSongTag();
if (tag)
{
*m_itemCurrentFile->GetMusicInfoTag() = *tag;
char rating = tag->GetRating();
bool needsUpdate(false);
if (rating > '0' && action.GetID() == ACTION_DECREASE_RATING)
{
m_itemCurrentFile->GetMusicInfoTag()->SetRating(rating - 1);
needsUpdate = true;
}
else if (rating < '5' && action.GetID() == ACTION_INCREASE_RATING)
{
m_itemCurrentFile->GetMusicInfoTag()->SetRating(rating + 1);
needsUpdate = true;
}
if (needsUpdate)
{
CMusicDatabase db;
if (db.Open()) // OpenForWrite() ?
{
db.SetSongRating(m_itemCurrentFile->GetPath(), m_itemCurrentFile->GetMusicInfoTag()->GetRating());
db.Close();
}
// send a message to all windows to tell them to update the fileitem (eg playlistplayer, media windows)
CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_ITEM, 0, m_itemCurrentFile);
g_windowManager.SendMessage(msg);
}
}
return true;
}
// stop : stops playing current audio song
if (action.GetID() == ACTION_STOP)
{
StopPlaying();
return true;
}
// previous : play previous song from playlist
if (action.GetID() == ACTION_PREV_ITEM)
{
// first check whether we're within 3 seconds of the start of the track
// if not, we just revert to the start of the track
if (m_pPlayer && m_pPlayer->CanSeek() && GetTime() > 3)
{
SeekTime(0);
SetPlaySpeed(1);
}
else
{
g_playlistPlayer.PlayPrevious();
}
return true;
}
// next : play next song from playlist
if (action.GetID() == ACTION_NEXT_ITEM)
{
if (IsPlaying() && m_pPlayer->SkipNext())
return true;
g_playlistPlayer.PlayNext();
return true;
}
if ( IsPlaying())
{
// pause : pauses current audio song
if (action.GetID() == ACTION_PAUSE && m_iPlaySpeed == 1)
{
m_pPlayer->Pause();
#ifdef HAS_KARAOKE
m_pKaraokeMgr->SetPaused( m_pPlayer->IsPaused() );
#endif
if (!m_pPlayer->IsPaused())
{ // unpaused - set the playspeed back to normal
SetPlaySpeed(1);
}
g_audioManager.Enable(m_pPlayer->IsPaused());
return true;
}
if (!m_pPlayer->IsPaused())
{
// if we do a FF/RW in my music then map PLAY action togo back to normal speed
// if we are playing at normal speed, then allow play to pause
if (action.GetID() == ACTION_PLAYER_PLAY || action.GetID() == ACTION_PAUSE)
{
if (m_iPlaySpeed != 1)
{
SetPlaySpeed(1);
}
else
{
m_pPlayer->Pause();
}
return true;
}
if (action.GetID() == ACTION_PLAYER_FORWARD || action.GetID() == ACTION_PLAYER_REWIND)
{
int iPlaySpeed = m_iPlaySpeed;
if (action.GetID() == ACTION_PLAYER_REWIND && iPlaySpeed == 1) // Enables Rewinding
iPlaySpeed *= -2;
else if (action.GetID() == ACTION_PLAYER_REWIND && iPlaySpeed > 1) //goes down a notch if you're FFing
iPlaySpeed /= 2;
else if (action.GetID() == ACTION_PLAYER_FORWARD && iPlaySpeed < 1) //goes up a notch if you're RWing
iPlaySpeed /= 2;
else
iPlaySpeed *= 2;
if (action.GetID() == ACTION_PLAYER_FORWARD && iPlaySpeed == -1) //sets iSpeed back to 1 if -1 (didn't plan for a -1)
iPlaySpeed = 1;
if (iPlaySpeed > 32 || iPlaySpeed < -32)
iPlaySpeed = 1;
SetPlaySpeed(iPlaySpeed);
return true;
}
else if ((action.GetAmount() || GetPlaySpeed() != 1) && (action.GetID() == ACTION_ANALOG_REWIND || action.GetID() == ACTION_ANALOG_FORWARD))
{
// calculate the speed based on the amount the button is held down
int iPower = (int)(action.GetAmount() * MAX_FFWD_SPEED + 0.5f);
// returns 0 -> MAX_FFWD_SPEED
int iSpeed = 1 << iPower;
if (iSpeed != 1 && action.GetID() == ACTION_ANALOG_REWIND)
iSpeed = -iSpeed;
g_application.SetPlaySpeed(iSpeed);
if (iSpeed == 1)
CLog::Log(LOGDEBUG,"Resetting playspeed");
return true;
}
}
// allow play to unpause
else
{
if (action.GetID() == ACTION_PLAYER_PLAY)
{
// unpause, and set the playspeed back to normal
m_pPlayer->Pause();
g_audioManager.Enable(m_pPlayer->IsPaused());
g_application.SetPlaySpeed(1);
return true;
}
}
}
if (g_peripherals.OnAction(action))
return true;
if (action.GetID() == ACTION_MUTE)
{
ToggleMute();
return true;
}
if (action.GetID() == ACTION_TOGGLE_DIGITAL_ANALOG)
{
switch(g_guiSettings.GetInt("audiooutput.mode"))
{
case AUDIO_ANALOG: g_guiSettings.SetInt("audiooutput.mode", AUDIO_IEC958); break;
case AUDIO_IEC958: g_guiSettings.SetInt("audiooutput.mode", AUDIO_HDMI ); break;
case AUDIO_HDMI : g_guiSettings.SetInt("audiooutput.mode", AUDIO_ANALOG); break;
}
g_application.Restart();
if (g_windowManager.GetActiveWindow() == WINDOW_SETTINGS_SYSTEM)
{
CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0,0,WINDOW_INVALID,g_windowManager.GetActiveWindow());
g_windowManager.SendMessage(msg);
}
return true;
}
// Check for global volume control
if (action.GetAmount() && (action.GetID() == ACTION_VOLUME_UP || action.GetID() == ACTION_VOLUME_DOWN))
{
if (!m_pPlayer || !m_pPlayer->IsPassthrough())
{
if (g_settings.m_bMute)
UnMute();
float volume = g_settings.m_fVolumeLevel;
float step = (VOLUME_MAXIMUM - VOLUME_MINIMUM) / VOLUME_CONTROL_STEPS;
if (action.GetRepeat())
step *= action.GetRepeat() * 50; // 50 fps
if (action.GetID() == ACTION_VOLUME_UP)
volume += (float)fabs(action.GetAmount()) * action.GetAmount() * step;
else
volume -= (float)fabs(action.GetAmount()) * action.GetAmount() * step;
SetVolume(volume, false);
}
// show visual feedback of volume change...
ShowVolumeBar(&action);
return true;
}
// Check for global seek control
if (IsPlaying() && action.GetAmount() && (action.GetID() == ACTION_ANALOG_SEEK_FORWARD || action.GetID() == ACTION_ANALOG_SEEK_BACK))
{
if (!m_pPlayer->CanSeek()) return false;
CGUIWindow *seekBar = g_windowManager.GetWindow(WINDOW_DIALOG_SEEK_BAR);
if (seekBar)
seekBar->OnAction(action);
return true;
}
if (action.GetID() == ACTION_GUIPROFILE_BEGIN)
{
CGUIControlProfiler::Instance().SetOutputFile(CSpecialProtocol::TranslatePath("special://home/guiprofiler.xml"));
CGUIControlProfiler::Instance().Start();
return true;
}
if (action.GetID() == ACTION_SHOW_PLAYLIST)
{
int iPlaylist = g_playlistPlayer.GetCurrentPlaylist();
if (iPlaylist == PLAYLIST_VIDEO)
g_windowManager.ActivateWindow(WINDOW_VIDEO_PLAYLIST);
else if (iPlaylist == PLAYLIST_MUSIC)
g_windowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST);
return true;
}
return false;
}
void CApplication::UpdateLCD()
{
#ifdef HAS_LCD
static unsigned int lTickCount = 0;
if (!g_lcd || !g_guiSettings.GetBool("videoscreen.haslcd"))
return ;
unsigned int lTimeOut = 1000;
if ( m_iPlaySpeed != 1)
lTimeOut = 0;
if ( (XbmcThreads::SystemClockMillis() - lTickCount) >= lTimeOut)
{
if (g_application.NavigationIdleTime() < 5)
g_lcd->Render(ILCD::LCD_MODE_NAVIGATION);
else if (IsPlayingVideo())
g_lcd->Render(ILCD::LCD_MODE_VIDEO);
else if (IsPlayingAudio())
g_lcd->Render(ILCD::LCD_MODE_MUSIC);
else if (IsInScreenSaver())
g_lcd->Render(ILCD::LCD_MODE_SCREENSAVER);
else
g_lcd->Render(ILCD::LCD_MODE_GENERAL);
// reset tick count
lTickCount = XbmcThreads::SystemClockMillis();
}
#endif
}
void CApplication::FrameMove(bool processEvents, bool processGUI)
{
MEASURE_FUNCTION;
if (processEvents)
{
// currently we calculate the repeat time (ie time from last similar keypress) just global as fps
float frameTime = m_frameTime.GetElapsedSeconds();
m_frameTime.StartZero();
// never set a frametime less than 2 fps to avoid problems when debuggin and on breaks
if( frameTime > 0.5 ) frameTime = 0.5;
if (processGUI)
{
g_graphicsContext.Lock();
// check if there are notifications to display
CGUIDialogKaiToast *toast = (CGUIDialogKaiToast *)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST);
if (toast && toast->DoWork())
{
if (!toast->IsDialogRunning())
{
toast->Show();
}
}
g_graphicsContext.Unlock();
CWinEvents::MessagePump();
}
UpdateLCD();
#if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
// Read the input from a remote
g_RemoteControl.Update();
#endif
// process input actions
ProcessHTTPApiButtons();
ProcessJsonRpcButtons();
ProcessRemote(frameTime);
ProcessGamepad(frameTime);
ProcessEventServer(frameTime);
ProcessPeripherals(frameTime);
if (processGUI)
m_pInertialScrollingHandler->ProcessInertialScroll(frameTime);
}
if (processGUI)
{
if (!m_bStop)
g_windowManager.Process(CTimeUtils::GetFrameTime());
g_windowManager.FrameMove();
}
}
bool CApplication::ProcessGamepad(float frameTime)
{
#ifdef HAS_SDL_JOYSTICK
if (!m_AppFocused)
return false;
int iWin = GetActiveWindowID();
int bid = 0;
g_Joystick.Update();
if (g_Joystick.GetButton(bid))
{
// reset Idle Timer
m_idleTimer.StartZero();
ResetScreenSaver();
if (WakeUpScreenSaverAndDPMS())
{
g_Joystick.Reset(true);
return true;
}
int actionID;
CStdString actionName;
bool fullrange;
if (CButtonTranslator::GetInstance().TranslateJoystickString(iWin, g_Joystick.GetJoystick().c_str(), bid, JACTIVE_BUTTON, actionID, actionName, fullrange))
{
CAction action(actionID, 1.0f, 0.0f, actionName);
g_audioManager.PlayActionSound(action);
g_Joystick.Reset();
g_Mouse.SetActive(false);
return OnAction(action);
}
else
{
g_Joystick.Reset();
}
}
if (g_Joystick.GetAxis(bid))
{
if (g_Joystick.GetAmount() < 0)
{
bid = -bid;
}
int actionID;
CStdString actionName;
bool fullrange;
if (CButtonTranslator::GetInstance().TranslateJoystickString(iWin, g_Joystick.GetJoystick().c_str(), bid, JACTIVE_AXIS, actionID, actionName, fullrange))
{
ResetScreenSaver();
if (WakeUpScreenSaverAndDPMS())
{
return true;
}
CAction action(actionID, fullrange ? (g_Joystick.GetAmount() + 1.0f)/2.0f : fabs(g_Joystick.GetAmount()), 0.0f, actionName);
g_audioManager.PlayActionSound(action);
g_Joystick.Reset();
g_Mouse.SetActive(false);
return OnAction(action);
}
else
{
g_Joystick.ResetAxis(abs(bid));
}
}
int position = 0;
if (g_Joystick.GetHat(bid, position))
{
// reset Idle Timer
m_idleTimer.StartZero();
ResetScreenSaver();
if (WakeUpScreenSaverAndDPMS())
{
g_Joystick.Reset();
return true;
}
int actionID;
CStdString actionName;
bool fullrange;
bid = position<<16|bid;
if (bid && CButtonTranslator::GetInstance().TranslateJoystickString(iWin, g_Joystick.GetJoystick().c_str(), bid, JACTIVE_HAT, actionID, actionName, fullrange))
{
CAction action(actionID, 1.0f, 0.0f, actionName);
g_audioManager.PlayActionSound(action);
g_Joystick.Reset();
g_Mouse.SetActive(false);
return OnAction(action);
}
}
#endif
return false;
}
bool CApplication::ProcessRemote(float frameTime)
{
#if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
if (g_RemoteControl.GetButton())
{
CKey key(g_RemoteControl.GetButton(), g_RemoteControl.GetHoldTime());
g_RemoteControl.Reset();
return OnKey(key);
}
#endif
return false;
}
bool CApplication::ProcessPeripherals(float frameTime)
{
CKey key;
if (g_peripherals.GetNextKeypress(frameTime, key))
return OnKey(key);
return false;
}
bool CApplication::ProcessMouse()
{
MEASURE_FUNCTION;
if (!g_Mouse.IsActive() || !m_AppFocused)
return false;
// Get the mouse command ID
uint32_t mousecommand = g_Mouse.GetAction();
if (mousecommand == ACTION_NOOP)
return true;
// Reset the screensaver and idle timers
m_idleTimer.StartZero();
ResetScreenSaver();
if (WakeUpScreenSaverAndDPMS())
return true;
// Retrieve the corresponding action
int iWin;
CKey key(mousecommand | KEY_MOUSE, (unsigned int) 0);
if (g_windowManager.HasModalDialog())
iWin = g_windowManager.GetTopMostModalDialogID() & WINDOW_ID_MASK;
else
iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
CAction mouseaction = CButtonTranslator::GetInstance().GetAction(iWin, key);
// If we couldn't find an action return false to indicate we have not
// handled this mouse action
if (!mouseaction.GetID())
{
CLog::Log(LOGDEBUG, "%s: unknown mouse command %d", __FUNCTION__, mousecommand);
return false;
}
// Log mouse actions except for move and noop
if (mouseaction.GetID() != ACTION_MOUSE_MOVE && mouseaction.GetID() != ACTION_NOOP)
CLog::Log(LOGDEBUG, "%s: trying mouse action %s", __FUNCTION__, mouseaction.GetName().c_str());
// The action might not be a mouse action. For example wheel moves might
// be mapped to volume up/down in mouse.xml. In this case we do not want
// the mouse position saved in the action.
if (!mouseaction.IsMouse())
return OnAction(mouseaction);
// This is a mouse action so we need to record the mouse position
return OnAction(CAction(mouseaction.GetID(),
g_Mouse.GetHold(MOUSE_LEFT_BUTTON),
(float)g_Mouse.GetX(),
(float)g_Mouse.GetY(),
(float)g_Mouse.GetDX(),
(float)g_Mouse.GetDY(),
mouseaction.GetName()));
}
void CApplication::CheckForTitleChange()
{
#ifdef HAS_HTTPAPI
if (g_settings.m_HttpApiBroadcastLevel>=1)
{
if (IsPlayingVideo())
{
const CVideoInfoTag* tagVal = g_infoManager.GetCurrentMovieTag();
if (m_pXbmcHttp && tagVal && !(tagVal->m_strTitle.IsEmpty()))
{
CStdString msg=m_pXbmcHttp->GetOpenTag()+"MovieTitle:"+tagVal->m_strTitle+m_pXbmcHttp->GetCloseTag();
if (m_prevMedia!=msg && g_settings.m_HttpApiBroadcastLevel>=1)
{
getApplicationMessenger().HttpApi("broadcastlevel; MediaChanged:"+msg+";1");
m_prevMedia=msg;
}
}
}
else if (IsPlayingAudio())
{
const CMusicInfoTag* tagVal=g_infoManager.GetCurrentSongTag();
if (m_pXbmcHttp && tagVal)
{
CStdString msg="";
if (!tagVal->GetTitle().IsEmpty())
msg=m_pXbmcHttp->GetOpenTag()+"AudioTitle:"+tagVal->GetTitle()+m_pXbmcHttp->GetCloseTag();
if (!tagVal->GetArtist().empty())
msg+=m_pXbmcHttp->GetOpenTag()+"AudioArtist:"+StringUtils::Join(tagVal->GetArtist(), g_advancedSettings.m_musicItemSeparator)+m_pXbmcHttp->GetCloseTag();
if (m_prevMedia!=msg)
{
getApplicationMessenger().HttpApi("broadcastlevel; MediaChanged:"+msg+";1");
m_prevMedia=msg;
}
}
}
}
#endif
}
bool CApplication::ProcessHTTPApiButtons()
{
#ifdef HAS_HTTPAPI
if (m_pXbmcHttp)
{
// copy key from webserver, and reset it in case we're called again before
// whatever happens in OnKey()
CKey keyHttp(m_pXbmcHttp->GetKey());
m_pXbmcHttp->ResetKey();
if (keyHttp.GetButtonCode() != KEY_INVALID)
{
if (keyHttp.GetButtonCode() == KEY_VMOUSE) //virtual mouse
{
int actionID = ACTION_MOUSE_MOVE;
if (keyHttp.GetLeftTrigger() == 1)
actionID = ACTION_MOUSE_LEFT_CLICK;
else if (keyHttp.GetLeftTrigger() == 2)
actionID = ACTION_MOUSE_RIGHT_CLICK;
else if (keyHttp.GetLeftTrigger() == 3)
actionID = ACTION_MOUSE_MIDDLE_CLICK;
else if (keyHttp.GetRightTrigger() == 1)
actionID = ACTION_MOUSE_DOUBLE_CLICK;
CAction action(actionID, keyHttp.GetLeftThumbX(), keyHttp.GetLeftThumbY());
OnAction(action);
}
else
OnKey(keyHttp);
return true;
}
}
#endif
return false;
}
bool CApplication::ProcessJsonRpcButtons()
{
#ifdef HAS_JSONRPC
CKey tempKey(JSONRPC::CInputOperations::GetKey());
if (tempKey.GetButtonCode() != KEY_INVALID)
{
tempKey.SetFromService(true);
return OnKey(tempKey);
}
#endif
return false;
}
bool CApplication::ProcessEventServer(float frameTime)
{
#ifdef HAS_EVENT_SERVER
CEventServer* es = CEventServer::GetInstance();
if (!es || !es->Running() || es->GetNumberOfClients()==0)
return false;
// process any queued up actions
if (es->ExecuteNextAction())
{
// reset idle timers
m_idleTimer.StartZero();
ResetScreenSaver();
WakeUpScreenSaverAndDPMS();
}
// now handle any buttons or axis
std::string joystickName;
bool isAxis = false;
float fAmount = 0.0;
// es->ExecuteNextAction() invalidates the ref to the CEventServer instance
// when the action exits XBMC
es = CEventServer::GetInstance();
if (!es || !es->Running() || es->GetNumberOfClients()==0)
return false;
WORD wKeyID = es->GetButtonCode(joystickName, isAxis, fAmount);
if (wKeyID)
{
if (joystickName.length() > 0)
{
if (isAxis == true)
{
if (fabs(fAmount) >= 0.08)
m_lastAxisMap[joystickName][wKeyID] = fAmount;
else
m_lastAxisMap[joystickName].erase(wKeyID);
}
return ProcessJoystickEvent(joystickName, wKeyID, isAxis, fAmount);
}
else
{
CKey key;
if(wKeyID == KEY_BUTTON_LEFT_ANALOG_TRIGGER)
key = CKey(wKeyID, (BYTE)(255*fAmount), 0, 0.0, 0.0, 0.0, 0.0, frameTime);
else if(wKeyID == KEY_BUTTON_RIGHT_ANALOG_TRIGGER)
key = CKey(wKeyID, 0, (BYTE)(255*fAmount), 0.0, 0.0, 0.0, 0.0, frameTime);
else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_LEFT)
key = CKey(wKeyID, 0, 0, -fAmount, 0.0, 0.0, 0.0, frameTime);
else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_RIGHT)
key = CKey(wKeyID, 0, 0, fAmount, 0.0, 0.0, 0.0, frameTime);
else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_UP)
key = CKey(wKeyID, 0, 0, 0.0, fAmount, 0.0, 0.0, frameTime);
else if(wKeyID == KEY_BUTTON_LEFT_THUMB_STICK_DOWN)
key = CKey(wKeyID, 0, 0, 0.0, -fAmount, 0.0, 0.0, frameTime);
else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_LEFT)
key = CKey(wKeyID, 0, 0, 0.0, 0.0, -fAmount, 0.0, frameTime);
else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT)
key = CKey(wKeyID, 0, 0, 0.0, 0.0, fAmount, 0.0, frameTime);
else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_UP)
key = CKey(wKeyID, 0, 0, 0.0, 0.0, 0.0, fAmount, frameTime);
else if(wKeyID == KEY_BUTTON_RIGHT_THUMB_STICK_DOWN)
key = CKey(wKeyID, 0, 0, 0.0, 0.0, 0.0, -fAmount, frameTime);
else
key = CKey(wKeyID);
key.SetFromService(true);
return OnKey(key);
}
}
if (m_lastAxisMap.size() > 0)
{
// Process all the stored axis.
for (map<std::string, map<int, float> >::iterator iter = m_lastAxisMap.begin(); iter != m_lastAxisMap.end(); ++iter)
{
for (map<int, float>::iterator iterAxis = (*iter).second.begin(); iterAxis != (*iter).second.end(); ++iterAxis)
ProcessJoystickEvent((*iter).first, (*iterAxis).first, true, (*iterAxis).second);
}
}
{
CPoint pos;
if (es->GetMousePos(pos.x, pos.y) && g_Mouse.IsEnabled())
return OnAction(CAction(ACTION_MOUSE_MOVE, pos.x, pos.y));
}
#endif
return false;
}
bool CApplication::ProcessJoystickEvent(const std::string& joystickName, int wKeyID, bool isAxis, float fAmount, unsigned int holdTime /*=0*/)
{
#if defined(HAS_EVENT_SERVER)
m_idleTimer.StartZero();
// Make sure to reset screen saver, mouse.
ResetScreenSaver();
if (WakeUpScreenSaverAndDPMS())
return true;
#ifdef HAS_SDL_JOYSTICK
g_Joystick.Reset();
#endif
g_Mouse.SetActive(false);
int iWin = GetActiveWindowID();
int actionID;
CStdString actionName;
bool fullRange = false;
// Translate using regular joystick translator.
if (CButtonTranslator::GetInstance().TranslateJoystickString(iWin, joystickName.c_str(), wKeyID, isAxis ? JACTIVE_AXIS : JACTIVE_BUTTON, actionID, actionName, fullRange))
{
CAction action(actionID, fAmount, 0.0f, actionName, holdTime);
g_audioManager.PlayActionSound(action);
return OnAction(action);
}
else
{
CLog::Log(LOGDEBUG, "ERROR mapping joystick action. Joystick: %s %i",joystickName.c_str(), wKeyID);
}
#endif
return false;
}
int CApplication::GetActiveWindowID(void)
{
// Get the currently active window
int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
// If there is a dialog active get the dialog id instead
if (g_windowManager.HasModalDialog())
iWin = g_windowManager.GetTopMostModalDialogID() & WINDOW_ID_MASK;
// If the window is FullScreenVideo check if we're in a DVD menu
if (iWin == WINDOW_FULLSCREEN_VIDEO && g_application.m_pPlayer && g_application.m_pPlayer->IsInMenu())
iWin = WINDOW_VIDEO_MENU;
// Return the window id
return iWin;
}
bool CApplication::Cleanup()
{
try
{
g_windowManager.Delete(WINDOW_MUSIC_PLAYLIST);
g_windowManager.Delete(WINDOW_MUSIC_PLAYLIST_EDITOR);
g_windowManager.Delete(WINDOW_MUSIC_FILES);
g_windowManager.Delete(WINDOW_MUSIC_NAV);
g_windowManager.Delete(WINDOW_DIALOG_MUSIC_INFO);
g_windowManager.Delete(WINDOW_DIALOG_VIDEO_INFO);
g_windowManager.Delete(WINDOW_VIDEO_FILES);
g_windowManager.Delete(WINDOW_VIDEO_PLAYLIST);
g_windowManager.Delete(WINDOW_VIDEO_NAV);
g_windowManager.Delete(WINDOW_FILES);
g_windowManager.Delete(WINDOW_DIALOG_YES_NO);
g_windowManager.Delete(WINDOW_DIALOG_PROGRESS);
g_windowManager.Delete(WINDOW_DIALOG_NUMERIC);
g_windowManager.Delete(WINDOW_DIALOG_GAMEPAD);
g_windowManager.Delete(WINDOW_DIALOG_SUB_MENU);
g_windowManager.Delete(WINDOW_DIALOG_BUTTON_MENU);
g_windowManager.Delete(WINDOW_DIALOG_CONTEXT_MENU);
g_windowManager.Delete(WINDOW_DIALOG_MUSIC_SCAN);
g_windowManager.Delete(WINDOW_DIALOG_PLAYER_CONTROLS);
g_windowManager.Delete(WINDOW_DIALOG_KARAOKE_SONGSELECT);
g_windowManager.Delete(WINDOW_DIALOG_KARAOKE_SELECTOR);
g_windowManager.Delete(WINDOW_DIALOG_MUSIC_OSD);
g_windowManager.Delete(WINDOW_DIALOG_VIS_PRESET_LIST);
g_windowManager.Delete(WINDOW_DIALOG_SELECT);
g_windowManager.Delete(WINDOW_DIALOG_OK);
g_windowManager.Delete(WINDOW_DIALOG_FILESTACKING);
g_windowManager.Delete(WINDOW_DIALOG_KEYBOARD);
g_windowManager.Delete(WINDOW_FULLSCREEN_VIDEO);
g_windowManager.Delete(WINDOW_DIALOG_PROFILE_SETTINGS);
g_windowManager.Delete(WINDOW_DIALOG_LOCK_SETTINGS);
g_windowManager.Delete(WINDOW_DIALOG_NETWORK_SETUP);
g_windowManager.Delete(WINDOW_DIALOG_MEDIA_SOURCE);
g_windowManager.Delete(WINDOW_DIALOG_VIDEO_OSD_SETTINGS);
g_windowManager.Delete(WINDOW_DIALOG_AUDIO_OSD_SETTINGS);
g_windowManager.Delete(WINDOW_DIALOG_VIDEO_BOOKMARKS);
g_windowManager.Delete(WINDOW_DIALOG_VIDEO_SCAN);
g_windowManager.Delete(WINDOW_DIALOG_CONTENT_SETTINGS);
g_windowManager.Delete(WINDOW_DIALOG_FAVOURITES);
g_windowManager.Delete(WINDOW_DIALOG_SONG_INFO);
g_windowManager.Delete(WINDOW_DIALOG_SMART_PLAYLIST_EDITOR);
g_windowManager.Delete(WINDOW_DIALOG_SMART_PLAYLIST_RULE);
g_windowManager.Delete(WINDOW_DIALOG_BUSY);
g_windowManager.Delete(WINDOW_DIALOG_PICTURE_INFO);
g_windowManager.Delete(WINDOW_DIALOG_ADDON_INFO);
g_windowManager.Delete(WINDOW_DIALOG_ADDON_SETTINGS);
g_windowManager.Delete(WINDOW_DIALOG_ACCESS_POINTS);
g_windowManager.Delete(WINDOW_DIALOG_SLIDER);
g_windowManager.Delete(WINDOW_DIALOG_OSD_TELETEXT);
g_windowManager.Delete(WINDOW_DIALOG_TEXT_VIEWER);
g_windowManager.Delete(WINDOW_DIALOG_PLAY_EJECT);
g_windowManager.Delete(WINDOW_STARTUP_ANIM);
g_windowManager.Delete(WINDOW_LOGIN_SCREEN);
g_windowManager.Delete(WINDOW_VISUALISATION);
g_windowManager.Delete(WINDOW_KARAOKELYRICS);
g_windowManager.Delete(WINDOW_SETTINGS_MENU);
g_windowManager.Delete(WINDOW_SETTINGS_PROFILES);
g_windowManager.Delete(WINDOW_SETTINGS_MYPICTURES); // all the settings categories
g_windowManager.Delete(WINDOW_TEST_PATTERN);
g_windowManager.Delete(WINDOW_SCREEN_CALIBRATION);
g_windowManager.Delete(WINDOW_SYSTEM_INFORMATION);
g_windowManager.Delete(WINDOW_SCREENSAVER);
g_windowManager.Delete(WINDOW_DIALOG_VIDEO_OSD);
g_windowManager.Delete(WINDOW_DIALOG_MUSIC_OVERLAY);
g_windowManager.Delete(WINDOW_DIALOG_VIDEO_OVERLAY);
g_windowManager.Delete(WINDOW_SLIDESHOW);
g_windowManager.Delete(WINDOW_HOME);
g_windowManager.Delete(WINDOW_PROGRAMS);
g_windowManager.Delete(WINDOW_PICTURES);
g_windowManager.Delete(WINDOW_WEATHER);
g_windowManager.Delete(WINDOW_SETTINGS_MYPICTURES);
g_windowManager.Remove(WINDOW_SETTINGS_MYPROGRAMS);
g_windowManager.Remove(WINDOW_SETTINGS_MYWEATHER);
g_windowManager.Remove(WINDOW_SETTINGS_MYMUSIC);
g_windowManager.Remove(WINDOW_SETTINGS_SYSTEM);
g_windowManager.Remove(WINDOW_SETTINGS_MYVIDEOS);
g_windowManager.Remove(WINDOW_SETTINGS_SERVICE);
g_windowManager.Remove(WINDOW_SETTINGS_APPEARANCE);
g_windowManager.Remove(WINDOW_DIALOG_KAI_TOAST);
g_windowManager.Remove(WINDOW_DIALOG_SEEK_BAR);
g_windowManager.Remove(WINDOW_DIALOG_VOLUME_BAR);
CAddonMgr::Get().DeInit();
#if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
CLog::Log(LOGNOTICE, "closing down remote control service");
g_RemoteControl.Disconnect();
#endif
CLog::Log(LOGNOTICE, "unload sections");
#ifdef HAS_PERFORMANCE_SAMPLE
CLog::Log(LOGNOTICE, "performance statistics");
m_perfStats.DumpStats();
#endif
// Shutdown as much as possible of the
// application, to reduce the leaks dumped
// to the vc output window before calling
// _CrtDumpMemoryLeaks(). Most of the leaks
// shown are no real leaks, as parts of the app
// are still allocated.
g_localizeStrings.Clear();
g_LangCodeExpander.Clear();
g_charsetConverter.clear();
g_directoryCache.Clear();
CButtonTranslator::GetInstance().Clear();
CLastfmScrobbler::RemoveInstance();
CLibrefmScrobbler::RemoveInstance();
CLastFmManager::RemoveInstance();
#ifdef HAS_EVENT_SERVER
CEventServer::RemoveInstance();
#endif
DllLoaderContainer::Clear();
g_playlistPlayer.Clear();
g_settings.Clear();
g_guiSettings.Clear();
g_advancedSettings.Clear();
#ifdef _LINUX
CXHandle::DumpObjectTracker();
#endif
#ifdef _CRTDBG_MAP_ALLOC
_CrtDumpMemoryLeaks();
while(1); // execution ends
#endif
return true;
}
catch (...)
{
CLog::Log(LOGERROR, "Exception in CApplication::Cleanup()");
return false;
}
}
void CApplication::Stop(int exitCode)
{
try
{
CVariant vExitCode(exitCode);
CAnnouncementManager::Announce(System, "xbmc", "OnQuit", vExitCode);
SaveFileState(true);
// cancel any jobs from the jobmanager
CJobManager::GetInstance().CancelJobs();
g_alarmClock.StopThread();
#ifdef HAS_HTTPAPI
if (m_pXbmcHttp)
{
if (g_settings.m_HttpApiBroadcastLevel >= 1)
getApplicationMessenger().HttpApi("broadcastlevel; ShutDown;1");
m_pXbmcHttp->shuttingDown = true;
}
#endif
if( m_bSystemScreenSaverEnable )
g_Windowing.EnableSystemScreenSaver(true);
CLog::Log(LOGNOTICE, "Storing total System Uptime");
g_settings.m_iSystemTimeTotalUp = g_settings.m_iSystemTimeTotalUp + (int)(CTimeUtils::GetFrameTime() / 60000);
// Update the settings information (volume, uptime etc. need saving)
if (CFile::Exists(g_settings.GetSettingsFile()))
{
CLog::Log(LOGNOTICE, "Saving settings");
g_settings.Save();
}
else
CLog::Log(LOGNOTICE, "Not saving settings (settings.xml is not present)");
m_bStop = true;
m_AppActive = false;
m_AppFocused = false;
m_ExitCode = exitCode;
CLog::Log(LOGNOTICE, "stop all");
// stop scanning before we kill the network and so on
if (m_musicInfoScanner->IsScanning())
m_musicInfoScanner->Stop();
if (m_videoInfoScanner->IsScanning())
m_videoInfoScanner->Stop();
m_applicationMessenger.Cleanup();
StopServices();
//Sleep(5000);
#ifdef HAS_WEB_SERVER
CWebServer::UnregisterRequestHandler(&m_httpImageHandler);
CWebServer::UnregisterRequestHandler(&m_httpVfsHandler);
#ifdef HAS_JSONRPC
CWebServer::UnregisterRequestHandler(&m_httpJsonRpcHandler);
#endif
#ifdef HAS_HTTPAPI
CWebServer::UnregisterRequestHandler(&m_httpApiHandler);
#endif
#ifdef HAS_WEB_INTERFACE
CWebServer::UnregisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
CWebServer::UnregisterRequestHandler(&m_httpWebinterfaceHandler);
#endif
#endif
if (m_pPlayer)
{
CLog::Log(LOGNOTICE, "stop player");
delete m_pPlayer;
m_pPlayer = NULL;
}
#if HAS_FILESYTEM_DAAP
CLog::Log(LOGNOTICE, "stop daap clients");
g_DaapClient.Release();
#endif
#ifdef HAS_FILESYSTEM_SAP
CLog::Log(LOGNOTICE, "stop sap announcement listener");
g_sapsessions.StopThread();
#endif
#ifdef HAS_ZEROCONF
if(CZeroconfBrowser::IsInstantiated())
{
CLog::Log(LOGNOTICE, "stop zeroconf browser");
CZeroconfBrowser::GetInstance()->Stop();
CZeroconfBrowser::ReleaseInstance();
}
#endif
CLog::Log(LOGNOTICE, "clean cached files!");
#ifdef HAS_FILESYSTEM_RAR
g_RarManager.ClearCache(true);
#endif
#ifdef HAS_FILESYSTEM_SFTP
CSFTPSessionManager::DisconnectAllSessions();
#endif
CLog::Log(LOGNOTICE, "unload skin");
UnloadSkin();
#if defined(TARGET_DARWIN_OSX)
if (XBMCHelper::GetInstance().IsAlwaysOn() == false)
XBMCHelper::GetInstance().Stop();
#endif
#if defined(HAVE_LIBCRYSTALHD)
CCrystalHD::RemoveInstance();
#endif
g_mediaManager.Stop();
// Stop services before unloading Python
CAddonMgr::Get().StopServices(false);
/* Python resource freeing must be done after skin has been unloaded, not before
some windows still need it when deinitializing during skin unloading. */
#ifdef HAS_PYTHON
CLog::Log(LOGNOTICE, "stop python");
g_pythonParser.FreeResources();
#endif
#ifdef HAS_LCD
if (g_lcd)
{
g_lcd->Stop();
delete g_lcd;
g_lcd=NULL;
}
#endif
g_Windowing.DestroyRenderSystem();
g_Windowing.DestroyWindow();
g_Windowing.DestroyWindowSystem();
// shutdown the AudioEngine
CAEFactory::Shutdown();
CLog::Log(LOGNOTICE, "stopped");
}
catch (...)
{
CLog::Log(LOGERROR, "Exception in CApplication::Stop()");
}
// we may not get to finish the run cycle but exit immediately after a call to g_application.Stop()
// so we may never get to Destroy() in CXBApplicationEx::Run(), we call it here.
Destroy();
//
Sleep(200);
}
bool CApplication::PlayMedia(const CFileItem& item, int iPlaylist)
{
//If item is a plugin, expand out now and run ourselves again
if (item.IsPlugin())
{
CFileItem item_new(item);
if (XFILE::CPluginDirectory::GetPluginResult(item.GetPath(), item_new))
return PlayMedia(item_new, iPlaylist);
return false;
}
if (item.IsLastFM())
{
g_partyModeManager.Disable();
return CLastFmManager::GetInstance()->ChangeStation(item.GetAsUrl());
}
if (item.IsSmartPlayList())
{
CFileItemList items;
CUtil::GetRecursiveListing(item.GetPath(), items, "");
if (items.Size())
{
CSmartPlaylist smartpl;
//get name and type of smartplaylist, this will always succeed as GetDirectory also did this.
smartpl.OpenAndReadName(item.GetPath());
CPlayList playlist;
playlist.Add(items);
return ProcessAndStartPlaylist(smartpl.GetName(), playlist, (smartpl.GetType() == "songs" || smartpl.GetType() == "albums") ? PLAYLIST_MUSIC:PLAYLIST_VIDEO);
}
}
else if (item.IsPlayList() || item.IsInternetStream())
{
CGUIDialogCache* dlgCache = new CGUIDialogCache(5000, g_localizeStrings.Get(10214), item.GetLabel());
//is or could be a playlist
auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(item));
bool gotPlayList = (pPlayList.get() && pPlayList->Load(item.GetPath()));
if (dlgCache)
{
dlgCache->Close();
if (dlgCache->IsCanceled())
return true;
}
if (gotPlayList)
{
if (iPlaylist != PLAYLIST_NONE)
{
int track=0;
if (item.HasProperty("playlist_starting_track"))
track = (int)item.GetProperty("playlist_starting_track").asInteger();
return ProcessAndStartPlaylist(item.GetPath(), *pPlayList, iPlaylist, track);
}
else
{
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());
if(pPlayList->size())
return PlayFile(*(*pPlayList)[0], false);
}
}
}
//nothing special just play
return PlayFile(item, false);
}
// PlayStack()
// For playing a multi-file video. Particularly inefficient
// on startup, as we are required to calculate the length
// of each video, so we open + close each one in turn.
// A faster calculation of video time would improve this
// substantially.
bool CApplication::PlayStack(const CFileItem& item, bool bRestart)
{
if (!item.IsStack())
return false;
CVideoDatabase dbs;
// case 1: stacked ISOs
if (CFileItem(CStackDirectory::GetFirstStackedFile(item.GetPath()),false).IsDVDImage())
{
CStackDirectory dir;
CFileItemList movieList;
dir.GetDirectory(item.GetPath(), movieList);
int selectedFile = 1; // if playing from beginning, play file 1.
long startoffset = item.m_lStartOffset;
// We instructed the stack to resume.
if (startoffset == STARTOFFSET_RESUME) // selected file is not specified, pick the 'last' resume point
startoffset = CGUIWindowVideoBase::GetResumeItemOffset(&item);
if (startoffset & 0xF0000000) /* selected part is specified as a flag */
{
selectedFile = (startoffset>>28);
startoffset = startoffset & ~0xF0000000;
// set startoffset in movieitem. The remaining startoffset is either 0 (just play part from beginning) or positive (then we use STARTOFFSET_RESUME).
if (selectedFile > 0 && selectedFile <= (int)movieList.Size())
movieList[selectedFile - 1]->m_lStartOffset = startoffset > 0 ? STARTOFFSET_RESUME : 0;
}
// finally play selected item
if (selectedFile > 0 && selectedFile <= (int)movieList.Size())
return PlayFile(*(movieList[selectedFile - 1]));
}
// case 2: all other stacks
else
{
// see if we have the info in the database
// TODO: If user changes the time speed (FPS via framerate conversion stuff)
// then these times will be wrong.
// Also, this is really just a hack for the slow load up times we have
// A much better solution is a fast reader of FPS and fileLength
// that we can use on a file to get it's time.
vector<int> times;
bool haveTimes(false);
CVideoDatabase dbs;
if (dbs.Open())
{
dbs.GetVideoSettings(item.GetPath(), g_settings.m_currentVideoSettings);
haveTimes = dbs.GetStackTimes(item.GetPath(), times);
dbs.Close();
}
// calculate the total time of the stack
CStackDirectory dir;
dir.GetDirectory(item.GetPath(), *m_currentStack);
long totalTime = 0;
for (int i = 0; i < m_currentStack->Size(); i++)
{
if (haveTimes)
(*m_currentStack)[i]->m_lEndOffset = times[i];
else
{
int duration;
if (!CDVDFileInfo::GetFileDuration((*m_currentStack)[i]->GetPath(), duration))
{
m_currentStack->Clear();
return false;
}
totalTime += duration / 1000;
(*m_currentStack)[i]->m_lEndOffset = totalTime;
times.push_back(totalTime);
}
}
double seconds = item.m_lStartOffset / 75.0;
if (!haveTimes || item.m_lStartOffset == STARTOFFSET_RESUME )
{ // have our times now, so update the dB
if (dbs.Open())
{
if( !haveTimes )
dbs.SetStackTimes(item.GetPath(), times);
if( item.m_lStartOffset == STARTOFFSET_RESUME )
{
// can only resume seek here, not dvdstate
CBookmark bookmark;
if( dbs.GetResumeBookMark(item.GetPath(), bookmark) )
seconds = bookmark.timeInSeconds;
else
seconds = 0.0f;
}
dbs.Close();
}
}
*m_itemCurrentFile = item;
m_currentStackPosition = 0;
m_eCurrentPlayer = EPC_NONE; // must be reset on initial play otherwise last player will be used
if (seconds > 0)
{
// work out where to seek to
for (int i = 0; i < m_currentStack->Size(); i++)
{
if (seconds < (*m_currentStack)[i]->m_lEndOffset)
{
CFileItem item(*(*m_currentStack)[i]);
long start = (i > 0) ? (*m_currentStack)[i-1]->m_lEndOffset : 0;
item.m_lStartOffset = (long)(seconds - start) * 75;
m_currentStackPosition = i;
return PlayFile(item, true);
}
}
}
return PlayFile(*(*m_currentStack)[0], true);
}
return false;
}
bool CApplication::PlayFile(const CFileItem& item, bool bRestart)
{
if (!bRestart)
{
SaveCurrentFileSettings();
OutputDebugString("new file set audiostream:0\n");
// Switch to default options
g_settings.m_currentVideoSettings = g_settings.m_defaultVideoSettings;
// see if we have saved options in the database
m_iPlaySpeed = 1;
*m_itemCurrentFile = item;
m_nextPlaylistItem = -1;
m_currentStackPosition = 0;
m_currentStack->Clear();
if (item.IsVideo())
CUtil::ClearSubtitles();
}
if (item.IsDiscStub())
{
#ifdef HAS_DVD_DRIVE
// Display the Play Eject dialog
if (CGUIDialogPlayEject::ShowAndGetInput(item))
// PlayDiscAskResume takes path to disc. No parameter means default DVD drive.
// Can't do better as CGUIDialogPlayEject calls CMediaManager::IsDiscInDrive, which assumes default DVD drive anyway
return MEDIA_DETECT::CAutorun::PlayDiscAskResume();
#endif
return true;
}
if (item.IsPlayList())
return false;
if (item.IsPlugin())
{ // we modify the item so that it becomes a real URL
CFileItem item_new(item);
if (XFILE::CPluginDirectory::GetPluginResult(item.GetPath(), item_new))
return PlayFile(item_new, false);
return false;
}
if (URIUtils::IsUPnP(item.GetPath()))
{
CFileItem item_new(item);
if (XFILE::CUPnPDirectory::GetResource(item.GetPath(), item_new))
return PlayFile(item_new, false);
return false;
}
// if we have a stacked set of files, we need to setup our stack routines for
// "seamless" seeking and total time of the movie etc.
// will recall with restart set to true
if (item.IsStack())
return PlayStack(item, bRestart);
//Is TuxBox, this should probably be moved to CTuxBoxFile
if(item.IsTuxBox())
{
CLog::Log(LOGDEBUG, "%s - TuxBox URL Detected %s",__FUNCTION__, item.GetPath().c_str());
if(g_tuxboxService.IsRunning())
g_tuxboxService.Stop();
CFileItem item_new;
if(g_tuxbox.CreateNewItem(item, item_new))
{
// Make sure it doesn't have a player
// so we actually select one normally
m_eCurrentPlayer = EPC_NONE;
// keep the tuxbox:// url as playing url
// and give the new url to the player
if(PlayFile(item_new, true))
{
if(!g_tuxboxService.IsRunning())
g_tuxboxService.Start();
return true;
}
}
return false;
}
CPlayerOptions options;
if( item.HasProperty("StartPercent") )
{
double fallback = 0.0f;
if(item.GetProperty("StartPercent").isString())
fallback = (double)atof(item.GetProperty("StartPercent").asString().c_str());
options.startpercent = item.GetProperty("StartPercent").asDouble(fallback);
}
PLAYERCOREID eNewCore = EPC_NONE;
if( bRestart )
{
// have to be set here due to playstack using this for starting the file
options.starttime = item.m_lStartOffset / 75.0;
if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0 && m_itemCurrentFile->m_lStartOffset != 0)
m_itemCurrentFile->m_lStartOffset = STARTOFFSET_RESUME; // to force fullscreen switching
if( m_eForcedNextPlayer != EPC_NONE )
eNewCore = m_eForcedNextPlayer;
else if( m_eCurrentPlayer == EPC_NONE )
eNewCore = CPlayerCoreFactory::GetDefaultPlayer(item);
else
eNewCore = m_eCurrentPlayer;
}
else
{
options.starttime = item.m_lStartOffset / 75.0;
if (item.IsVideo())
{
// open the d/b and retrieve the bookmarks for the current movie
CVideoDatabase dbs;
dbs.Open();
dbs.GetVideoSettings(item.GetPath(), g_settings.m_currentVideoSettings);
if( item.m_lStartOffset == STARTOFFSET_RESUME )
{
options.starttime = 0.0f;
CBookmark bookmark;
CStdString path = item.GetPath();
if (item.HasVideoInfoTag() && item.GetVideoInfoTag()->m_strFileNameAndPath.Find("removable://") == 0)
path = item.GetVideoInfoTag()->m_strFileNameAndPath;
else if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
path = item.GetProperty("original_listitem_url").asString();
if(dbs.GetResumeBookMark(path, bookmark))
{
options.starttime = bookmark.timeInSeconds;
options.state = bookmark.playerState;
}
}
else if (item.HasVideoInfoTag())
{
const CVideoInfoTag *tag = item.GetVideoInfoTag();
if (tag->m_iBookmarkId != -1 && tag->m_iBookmarkId != 0)
{
CBookmark bookmark;
dbs.GetBookMarkForEpisode(*tag, bookmark);
options.starttime = bookmark.timeInSeconds;
options.state = bookmark.playerState;
}
}
dbs.Close();
}
if (m_eForcedNextPlayer != EPC_NONE)
eNewCore = m_eForcedNextPlayer;
else
eNewCore = CPlayerCoreFactory::GetDefaultPlayer(item);
}
// this really aught to be inside !bRestart, but since PlayStack
// uses that to init playback, we have to keep it outside
int playlist = g_playlistPlayer.GetCurrentPlaylist();
if (item.IsVideo() && g_playlistPlayer.GetPlaylist(playlist).size() > 1)
{ // playing from a playlist by the looks
// don't switch to fullscreen if we are not playing the first item...
options.fullscreen = !g_playlistPlayer.HasPlayedFirstFile() && g_advancedSettings.m_fullScreenOnMovieStart && !g_settings.m_bStartVideoWindowed;
}
else if(m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
{
// TODO - this will fail if user seeks back to first file in stack
if(m_currentStackPosition == 0 || m_itemCurrentFile->m_lStartOffset == STARTOFFSET_RESUME)
options.fullscreen = g_advancedSettings.m_fullScreenOnMovieStart && !g_settings.m_bStartVideoWindowed;
else
options.fullscreen = false;
// reset this so we don't think we are resuming on seek
m_itemCurrentFile->m_lStartOffset = 0;
}
else
options.fullscreen = g_advancedSettings.m_fullScreenOnMovieStart && !g_settings.m_bStartVideoWindowed;
// reset m_bStartVideoWindowed as it's a temp setting
g_settings.m_bStartVideoWindowed = false;
// reset any forced player
m_eForcedNextPlayer = EPC_NONE;
#ifdef HAS_KARAOKE
//We have to stop parsing a cdg before mplayer is deallocated
// WHY do we have to do this????
if (m_pKaraokeMgr)
m_pKaraokeMgr->Stop();
#endif
// tell system we are starting a file
m_bPlaybackStarting = true;
// We should restart the player, unless the previous and next tracks are using
// one of the players that allows gapless playback (paplayer, dvdplayer)
if (m_pPlayer)
{
if ( !(m_eCurrentPlayer == eNewCore && (m_eCurrentPlayer == EPC_DVDPLAYER || m_eCurrentPlayer == EPC_PAPLAYER)) )
{
delete m_pPlayer;
m_pPlayer = NULL;
}
}
if (!m_pPlayer)
{
m_eCurrentPlayer = eNewCore;
m_pPlayer = CPlayerCoreFactory::CreatePlayer(eNewCore, *this);
}
bool bResult;
if (m_pPlayer)
{
// don't hold graphicscontext here since player
// may wait on another thread, that requires gfx
CSingleExit ex(g_graphicsContext);
bResult = m_pPlayer->OpenFile(item, options);
}
else
{
CLog::Log(LOGERROR, "Error creating player for item %s (File doesn't exist?)", item.GetPath().c_str());
bResult = false;
}
if(bResult)
{
if (m_iPlaySpeed != 1)
{
int iSpeed = m_iPlaySpeed;
m_iPlaySpeed = 1;
SetPlaySpeed(iSpeed);
}
if( IsPlayingAudio() )
{
if (g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
}
#ifdef HAS_VIDEO_PLAYBACK
if( IsPlayingVideo() )
{
if (g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION)
g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
// if player didn't manange to switch to fullscreen by itself do it here
if( options.fullscreen && g_renderManager.IsStarted()
&& g_windowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO )
SwitchToFullScreen();
if (!item.IsDVDImage() && !item.IsDVDFile())
{
CVideoInfoTag *details = m_itemCurrentFile->GetVideoInfoTag();
// Save information about the stream if we currently have no data
if (!details->HasStreamDetails() ||
details->m_streamDetails.GetVideoDuration() <= 0)
{
if (m_pPlayer->GetStreamDetails(details->m_streamDetails) && details->HasStreamDetails())
{
CVideoDatabase dbs;
dbs.Open();
dbs.SetStreamDetailsForFileId(details->m_streamDetails, details->m_iFileId);
dbs.Close();
CUtil::DeleteVideoDatabaseDirectoryCache();
}
}
}
}
#endif
#if !defined(TARGET_DARWIN) && !defined(_LINUX)
g_audioManager.Enable(false);
#endif
}
m_bPlaybackStarting = false;
if (bResult)
{
// we must have started, otherwise player might send this later
if(IsPlaying())
OnPlayBackStarted();
else
OnPlayBackEnded();
}