Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

5749 lines (5015 sloc) 178.113 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.Initialize();
#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 ;
}
if (!skin->HasSkinFile("Home.xml"))
{
// failed to find home.xml
// fallback to default skin
if (strcmpi(skin->ID().c_str(), DEFAULT_SKIN) != 0)
{
CLog::Log(LOGERROR, "home.xml doesn't exist in skin: %s, fallback to \"%s\" skin", skin->ID().c_str(), DEFAULT_SKIN);
g_guiSettings.SetString("lookandfeel.skin", DEFAULT_SKIN);
LoadSkin(DEFAULT_SKIN);
CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(24102), g_localizeStrings.Get(24103));
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...");
// 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;
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;
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 (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