Files
XBMC4Xbox/xbmc/Application.cpp
Rocky5 921f9fe9f8 Clean Copy
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
2024-01-08 19:01:29 +00:00

5848 lines
189 KiB
C++

/*
* Copyright (C) 2005-2013 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, see
* <http://www.gnu.org/licenses/>.
*
*/
#include "system.h"
#include "utils/log.h"
#include "Application.h"
#include "interfaces/Builtins.h"
#include "Splash.h"
#include "input/KeyboardLayoutConfiguration.h"
#include "LangInfo.h"
#ifdef HAS_XBOX_HARDWARE
#include "xbox/XKEEPROM.h"
#include "utils/LCD.h"
#include "xbox/IoSupport.h"
#include "xbox/XKHDD.h"
#endif
#include "xbox/xbeheader.h"
#include "Util.h"
#include "utils/URIUtils.h"
#include "TextureManager.h"
#include "cores/dvdplayer/DVDFileInfo.h"
#include "PlayListPlayer.h"
#include "Autorun.h"
#ifdef HAS_LCD
#include "utils/LCDFactory.h"
#endif
#ifdef HAS_XBOX_HARDWARE
#include "utils/MemoryUnitManager.h"
#include "utils/FanController.h"
#include "utils/LED.h"
#endif
#include "XBVideoConfig.h"
#include "utils/LangCodeExpander.h"
#include "GUIInfoManager.h"
#include "playlists/PlayListFactory.h"
#include "GUIFontManager.h"
#include "GUIColorManager.h"
#include "GUITextLayout.h"
#include "SkinInfo.h"
#include "lib/libPython/XBPython.h"
#include "input/ButtonTranslator.h"
#include "GUIAudioManager.h"
#include "lib/libscrobbler/lastfmscrobbler.h"
#include "lib/libscrobbler/librefmscrobbler.h"
#include "GUIPassword.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
#include "FileSystem/HTSPDirectory.h"
#include "utils/TuxBoxUtil.h"
#include "utils/SystemInfo.h"
#include "utils/TimeUtils.h"
#include "ApplicationRenderer.h"
#include "GUILargeTextureManager.h"
#include "music/LastFmManager.h"
#include "SmartPlaylist.h"
#include "FileSystem/RarManager.h"
#include "playlists/PlayList.h"
#include "utils/DownloadQueueManager.h"
#include "settings/AdvancedSettings.h"
#include "LocalizeStrings.h"
#include "utils/CharsetConverter.h"
#ifdef HAS_FILESYSTEM
#include "FileSystem/DAAPFile.h"
#endif
#ifdef HAS_UPNP
#include "network/UPnP.h"
#include "FileSystem/UPnPDirectory.h"
#endif
#include "PartyModeManager.h"
#ifdef HAS_VIDEO_PLAYBACK
#include "cores/VideoRenderers/RenderManager.h"
#endif
#ifdef HAS_KARAOKE
#include "CdgParser.h"
#endif
#include "AudioContext.h"
#include "GUIFontTTF.h"
#include "xbox/network.h"
#include "utils/Win32Exception.h"
#include "lib/libGoAhead/XBMChttp.h"
#include "lib/libGoAhead/WebServer.h"
#ifdef HAS_FTP_SERVER
#include "lib/libfilezilla/xbfilezilla.h"
#endif
#ifdef HAS_TIME_SERVER
#include "utils/Sntp.h"
#endif
#ifdef HAS_XFONT
#include <xfont.h> // for textout functions
#endif
#ifdef HAS_EVENT_SERVER
#include "utils/EventServer.h"
#endif
// Windows includes
#include "GUIWindowManager.h"
#include "windows/GUIWindowHome.h"
#include "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/GUIWindowVideoFiles.h"
#include "video/windows/GUIWindowVideoNav.h"
#include "settings/GUIWindowSettingsProfile.h"
#include "settings/GUIWindowSettingsScreenCalibration.h"
#include "programs/GUIWindowPrograms.h"
#include "pictures/GUIWindowPictures.h"
#include "GUIWindowScripts.h"
#include "windows/GUIWindowWeather.h"
#include "GUIWindowGameSaves.h"
#include "windows/GUIWindowLoginScreen.h"
#include "music/windows/GUIWindowVisualisation.h"
#include "windows/GUIWindowSystemInfo.h"
#include "windows/GUIWindowScreensaver.h"
#include "pictures/GUIWindowSlideShow.h"
#include "windows/GUIWindowStartup.h"
#include "video/windows/GUIWindowFullScreen.h"
#include "GUIWindowOSD.h"
#include "GUIWindowMusicOverlay.h"
#include "GUIWindowVideoOverlay.h"
// Dialog includes
#include "music/dialogs/GUIDialogMusicOSD.h"
#include "dialogs/GUIDialogVisualisationSettings.h"
#include "music/dialogs/GUIDialogVisualisationPresetList.h"
#include "dialogs/GUIDialogTrainerSettings.h"
#include "GUIWindowScriptsInfo.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/GUIDialogTextViewer.h"
#include "dialogs/GUIDialogKeyboard.h"
#include "dialogs/GUIDialogYesNo.h"
#include "dialogs/GUIDialogOK.h"
#include "dialogs/GUIDialogProgress.h"
#include "dialogs/GUIDialogSelect.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 "dialogs/GUIDialogPluginSettings.h"
#include "video/dialogs/GUIDialogFullScreenInfo.h"
#include "dialogs/GUIDialogSlider.h"
#include "cores/dlgcache.h"
#include "guilib/GUIControlFactory.h"
#ifdef _LINUX
#include "XHandle.h"
#endif
using namespace std;
using namespace XFILE;
using namespace MEDIA_DETECT;
using namespace PLAYLIST;
using namespace VIDEO;
using namespace MUSIC_INFO;
#ifdef HAS_EVENT_SERVER
using namespace EVENTSERVER;
#endif
// 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
#ifdef HAS_LCD
#pragma comment (lib,"xbmc/lib/libXenium/XeniumSPIg.lib")
#endif
#if defined(_DEBUG) && !defined(USE_RELEASE_LIBS)
#ifdef HAS_FILESYSTEM
#pragma comment (lib,"xbmc/lib/libXBMS/libXBMSd.lib") // SECTIONNAME=LIBXBMS
#pragma comment (lib,"xbmc/lib/libsmb/libsmbd.lib") // SECTIONNAME=LIBSMB
#pragma comment (lib,"xbmc/lib/libxdaap/libxdaapd.lib") // SECTIONNAME=LIBXDAAP
#pragma comment (lib,"xbmc/lib/libRTV/libRTVd.lib") // SECTIONNAME=LIBRTV
#endif
#ifdef _XBOX
#pragma comment (lib,"xbmc/lib/libGoAhead/goaheadd.lib") // SECTIONNAME=LIBHTTP
#pragma comment (lib,"xbmc/lib/sqLite/libSQLite3d.lib")
#pragma comment (lib,"xbmc/lib/libshout/libshoutd.lib" )
#pragma comment (lib,"xbmc/lib/libcdio/libcdiod.lib" )
#pragma comment (lib,"xbmc/lib/libiconv/libiconvd.lib")
#pragma comment (lib,"xbmc/lib/libfribidi/libfribidid.lib")
#pragma comment (lib,"xbmc/lib/libpcre/libpcred.lib")
#else
#pragma comment (lib,"../../xbmc/lib/libGoAhead/goahead_win32d.lib") // SECTIONNAME=LIBHTTP
#pragma comment (lib,"../../xbmc/lib/sqLite/libSQLite3_win32d.lib")
#pragma comment (lib,"../../xbmc/lib/libcdio/libcdio_win32d.lib" )
#pragma comment (lib,"../../xbmc/lib/libiconv/libiconvd.lib")
#pragma comment (lib,"../../xbmc/lib/libfribidi/libfribidid.lib")
#pragma comment (lib,"../../xbmc/lib/libpcre/libpcred.lib")
#endif
#ifdef HAS_MIKMOD
#pragma comment (lib,"xbmc/lib/mikxbox/mikxboxd.lib") // SECTIONNAME=MOD_RW,MOD_RX
#endif
#else
#ifdef HAS_FILESYSTEM
#pragma comment (lib,"xbmc/lib/libXBMS/libXBMS.lib")
#pragma comment (lib,"xbmc/lib/libsmb/libsmb.lib")
#pragma comment (lib,"xbmc/lib/libxdaap/libxdaap.lib") // SECTIONNAME=LIBXDAAP
#pragma comment (lib,"xbmc/lib/libRTV/libRTV.lib")
#endif
#ifdef _XBOX
#pragma comment (lib,"xbmc/lib/libGoAhead/goahead.lib")
#pragma comment (lib,"xbmc/lib/sqLite/libSQLite3.lib")
#pragma comment (lib,"xbmc/lib/libcdio/libcdio.lib")
#pragma comment (lib,"xbmc/lib/libshout/libshout.lib")
#pragma comment (lib,"xbmc/lib/libiconv/libiconv.lib")
#pragma comment (lib,"xbmc/lib/libfribidi/libfribidi.lib")
#pragma comment (lib,"xbmc/lib/libpcre/libpcre.lib")
#else
#pragma comment (lib,"../../xbmc/lib/libGoAhead/goahead_win32.lib")
#pragma comment (lib,"../../xbmc/lib/sqLite/libSQLite3_win32.lib")
#pragma comment (lib,"../../xbmc/lib/libshout/libshout_win32.lib" )
#pragma comment (lib,"../../xbmc/lib/libcdio/libcdio_win32.lib" )
#pragma comment (lib,"../../xbmc/lib/libiconv/libiconv.lib")
#pragma comment (lib,"../../xbmc/lib/libfribidi/libfribidi.lib")
#pragma comment (lib,"../../xbmc/lib/libpcre/libpcre.lib")
#endif
#ifdef HAS_MIKMOD
#pragma comment (lib,"xbmc/lib/mikxbox/mikxbox.lib")
#endif
#endif
#define MAX_FFWD_SPEED 5
CStdString g_LoadErrorStr;
#ifdef HAS_XBOX_D3D
static void WaitCallback(DWORD flags)
{
#ifndef PROFILE
/* if cpu is far ahead of gpu, sleep instead of yield */
if( flags & D3DWAIT_PRESENT )
while(D3DDevice::GetPushDistance(D3DDISTANCE_FENCES_TOWAIT) > 0)
Sleep(1);
else if( flags & (D3DWAIT_OBJECTLOCK | D3DWAIT_BLOCKONFENCE | D3DWAIT_BLOCKUNTILIDLE) )
while(D3DDevice::GetPushDistance(D3DDISTANCE_FENCES_TOWAIT) > 1)
Sleep(1);
#endif
}
#endif
//extern IDirectSoundRenderer* m_pAudioDecoder;
CApplication::CApplication(void) : m_ctrDpad(220, 220), m_itemCurrentFile(new CFileItem), m_progressTrackingItem(new CFileItem)
{
m_iPlaySpeed = 1;
m_bSpinDown = false;
m_bNetworkSpinDown = false;
m_dwSpinDownTime = timeGetTime();
m_pWebServer = NULL;
m_pXbmcHttp = NULL;
m_prevMedia="";
m_pFileZilla = NULL;
m_pPlayer = NULL;
#ifdef HAS_XBOX_HARDWARE
XSetProcessQuantumLength(5); //default=20msec
XSetFileCacheSize (256*1024); //default=64kb
#endif
m_bScreenSave = false; // CB: SCREENSAVER PATCH
m_iScreenSaveLock = 0;
m_skinReloadTime = 0;
m_bInitializing = true;
m_eForcedNextPlayer = EPC_NONE;
m_strPlayListFile = "";
m_nextPlaylistItem = -1;
m_bPlaybackStarting = false;
//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_pCdgParser = new CCdgParser();
#endif
m_currentStack = new CFileItemList;
}
CApplication::~CApplication(void)
{
delete m_currentStack;
}
// text out routine for below
#ifdef HAS_XFONT
static void __cdecl FEH_TextOut(XFONT* pFont, int iLine, const wchar_t* fmt, ...)
{
wchar_t buf[100];
va_list args;
va_start(args, fmt);
_vsnwprintf(buf, 100, fmt, args);
va_end(args);
if (!(iLine & 0x8000))
CLog::Log(LOGFATAL, "%S", buf);
bool Center = (iLine & 0x10000) > 0;
pFont->SetTextAlignment(Center ? XFONT_TOP | XFONT_CENTER : XFONT_TOP | XFONT_LEFT);
iLine &= 0x7fff;
for (int i = 0; i < 2; i++)
{
D3DRECT rc = { 0, 50 + 25 * iLine, 720, 50 + 25 * (iLine + 1) };
D3DDevice::Clear(1, &rc, D3DCLEAR_TARGET, 0, 0, 0);
pFont->TextOut(g_application.m_pBackBuffer, buf, -1, Center ? 360 : 80, 50 + 25*iLine);
D3DDevice::Present(0, 0, 0, 0);
}
}
#else
static void __cdecl FEH_TextOut(void* pFont, int iLine, const wchar_t* fmt, ...) {}
#endif
HWND g_hWnd = NULL;
void CApplication::InitBasicD3D()
{
bool bPal = g_videoConfig.HasPAL();
CLog::Log(LOGINFO, "Init display in default mode: %s", bPal ? "PAL" : "NTSC");
// init D3D with defaults (NTSC or PAL standard res)
m_d3dpp.BackBufferWidth = 720;
m_d3dpp.BackBufferHeight = bPal ? 576 : 480;
m_d3dpp.BackBufferFormat = D3DFMT_LIN_X8R8G8B8;
m_d3dpp.BackBufferCount = 1;
m_d3dpp.EnableAutoDepthStencil = FALSE;
m_d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
#ifdef HAS_XBOX_D3D
m_d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
#else
m_d3dpp.FullScreen_PresentationInterval = 0;
m_d3dpp.Windowed = TRUE;
m_d3dpp.hDeviceWindow = g_hWnd;
#endif
if (!(m_pD3D = Direct3DCreate8(D3D_SDK_VERSION)))
{
CLog::Log(LOGFATAL, "FATAL ERROR: Unable to create Direct3D!");
Sleep(INFINITE); // die
}
// Check if we have the required modes available
g_videoConfig.GetModes(m_pD3D);
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 = g_videoConfig.GetSafeMode();
CLog::Log(LOGERROR, "Resetting to mode %s", g_settings.m_ResInfo[g_guiSettings.m_LookAndFeelResolution].strMode);
CLog::Log(LOGERROR, "Done reset");
}
// Transfer the resolution information to our graphics context
g_graphicsContext.SetD3DParameters(&m_d3dpp);
g_graphicsContext.SetVideoResolution(g_guiSettings.m_LookAndFeelResolution, TRUE);
// Create the device
#ifdef HAS_XBOX_D3D
// Xbox MUST use HAL / Hardware Vertex Processing!
if (m_pD3D->CreateDevice(0, D3DDEVTYPE_HAL, NULL, D3DCREATE_HARDWARE_VERTEXPROCESSING, &m_d3dpp, &m_pd3dDevice) != S_OK)
{
CLog::Log(LOGFATAL, "FATAL ERROR: Unable to create D3D Device!");
Sleep(INFINITE); // die
}
m_pd3dDevice->GetBackBuffer(0, 0, &m_pBackBuffer);
#else
if (m_pD3D->CreateDevice(0, D3DDEVTYPE_REF, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &m_d3dpp, &m_pd3dDevice) != S_OK)
{
CLog::Log(LOGFATAL, "FATAL ERROR: Unable to create D3D Device!");
Sleep(INFINITE); // die
}
#endif
if (m_splash)
{
m_splash->Stop();
}
m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0, 0, 0);
m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
// This function does not return!
void CApplication::FatalErrorHandler(bool InitD3D, bool MapDrives, bool InitNetwork)
{
// XBMC couldn't start for some reason...
// g_LoadErrorStr should contain the reason
CLog::Log(LOGWARNING, "Emergency recovery console starting...");
bool HaveGamepad = true; // should always have the gamepad when we get here
if (InitD3D)
InitBasicD3D();
if (m_splash)
{
m_splash->Stop();
}
m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0, 0, 0);
m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
// D3D is up, load default font
#ifdef HAS_XFONT
XFONT* pFont;
if (XFONT_OpenDefaultFont(&pFont) != S_OK)
{
CLog::Log(LOGFATAL, "FATAL ERROR: Unable to open default font!");
Sleep(INFINITE); // die
}
// defaults for text
pFont->SetBkMode(XFONT_OPAQUE);
pFont->SetBkColor(D3DCOLOR_XRGB(0, 0, 0));
pFont->SetTextColor(D3DCOLOR_XRGB(0xff, 0x20, 0x20));
#else
void *pFont = NULL;
#endif
int iLine = 0;
FEH_TextOut(pFont, iLine++, L"XBMC Fatal Error:");
char buf[500];
strncpy(buf, g_LoadErrorStr.c_str(), 500);
buf[499] = 0;
char* pNewline = strtok(buf, "\n");
while (pNewline)
{
FEH_TextOut(pFont, iLine++, L"%S", pNewline);
pNewline = strtok(NULL, "\n");
}
++iLine;
#ifdef HAS_XBOX_HARDWARE
if (MapDrives)
{
// map in default drives
CIoSupport::RemapDriveLetter('C',"Harddisk0\\Partition2");
CIoSupport::RemapDriveLetter('D',"Cdrom0");
CIoSupport::RemapDriveLetter('E',"Harddisk0\\Partition1");
//Add. also Drive F/G
if (CIoSupport::PartitionExists(6))
CIoSupport::RemapDriveLetter('F',"Harddisk0\\Partition6");
if (CIoSupport::PartitionExists(7))
CIoSupport::RemapDriveLetter('G',"Harddisk0\\Partition7");
}
#endif
bool Pal = g_graphicsContext.GetVideoResolution() == PAL_4x3;
if (HaveGamepad)
FEH_TextOut(pFont, (Pal ? 16 : 12) | 0x18000, L"Press any button to reboot");
bool NetworkUp = false;
// Boot up the network for FTP
if (InitNetwork)
{
std::vector<int> netorder;
if (m_bXboxMediacenterLoaded)
{
if (g_guiSettings.GetInt("network.assignment") == NETWORK_DHCP)
{
netorder.push_back(NETWORK_DHCP);
netorder.push_back(NETWORK_STATIC);
}
else if (g_guiSettings.GetInt("network.assignment") == NETWORK_STATIC)
{
netorder.push_back(NETWORK_STATIC);
netorder.push_back(NETWORK_DHCP);
}
else
{
netorder.push_back(NETWORK_DASH);
netorder.push_back(NETWORK_DHCP);
netorder.push_back(NETWORK_STATIC);
}
}
else
{
netorder.push_back(NETWORK_DASH);
netorder.push_back(NETWORK_DHCP);
netorder.push_back(NETWORK_STATIC);
}
while(1)
{
std::vector<int>::iterator it;
for( it = netorder.begin();it != netorder.end(); it++)
{
m_network.Deinitialize();
#ifdef HAS_XBOX_NETWORK
if (!m_network.IsEthernetConnected())
{
FEH_TextOut(pFont, iLine, L"Network cable unplugged");
break;
}
#endif
switch( (*it) )
{
case NETWORK_DASH:
FEH_TextOut(pFont, iLine, L"Init network using dash settings...");
m_network.Initialize(NETWORK_DASH, "","","","","");
break;
case NETWORK_DHCP:
FEH_TextOut(pFont, iLine, L"Init network using DHCP...");
m_network.Initialize(NETWORK_DHCP, "","","","","");
break;
default:
FEH_TextOut(pFont, iLine, L"Init network using static ip...");
if( m_bXboxMediacenterLoaded )
{
m_network.Initialize(NETWORK_STATIC,
g_guiSettings.GetString("network.ipaddress").c_str(),
g_guiSettings.GetString("network.subnet").c_str(),
g_guiSettings.GetString("network.gateway").c_str(),
g_guiSettings.GetString("network.dns").c_str(),
g_guiSettings.GetString("network.dns2").c_str() );
}
else
{
m_network.Initialize(NETWORK_STATIC,
"192.168.0.42",
"255.255.255.0",
"192.168.0.1",
"192.168.0.1",
"0.0.0.0" );
}
break;
}
#ifdef HAS_XBOX_NETWORK
DWORD dwState = XNET_GET_XNADDR_PENDING;
while (dwState == XNET_GET_XNADDR_PENDING)
{
dwState = m_network.UpdateState();
if (HaveGamepad && AnyButtonDown())
m_applicationMessenger.Restart();
Sleep(50);
}
if ((dwState & XNET_GET_XNADDR_DHCP || dwState & XNET_GET_XNADDR_STATIC) && !(dwState & XNET_GET_XNADDR_NONE || dwState & XNET_GET_XNADDR_TROUBLESHOOT))
{
/* yay, we got network */
NetworkUp = true;
break;
}
#endif
/* increment line before next attempt */
++iLine;
}
/* break out of the continous loop if we have network*/
if( NetworkUp )
break;
else
{
int n = 10;
while (n)
{
FEH_TextOut(pFont, (iLine + 1) | 0x8000, L"Unable to init network, retrying in %d seconds", n--);
for (int i = 0; i < 20; ++i)
{
Sleep(50);
if (HaveGamepad && AnyButtonDown())
m_applicationMessenger.Restart();
}
}
}
}
}
if( NetworkUp )
{
FEH_TextOut(pFont, iLine++, L"IP Address: %S", m_network.m_networkinfo.ip);
++iLine;
}
if (NetworkUp)
{
#ifdef HAS_FTP_SERVER
if (!m_pFileZilla)
{
// Start FTP with default settings
FEH_TextOut(pFont, iLine++, L"Starting FTP server...");
StartFtpEmergencyRecoveryMode();
}
FEH_TextOut(pFont, iLine++, L"FTP server running on port %d, login: xbox/xbox", m_pFileZilla->mSettings.GetServerPort());
#endif
++iLine;
}
if (HaveGamepad)
{
for (;;)
{
Sleep(50);
if (AnyButtonDown())
{
g_application.Stop();
Sleep(200);
#ifdef _XBOX
#ifndef _DEBUG // don't actually shut off if debug build, it hangs VS for a long time
XKUtils::XBOXPowerCycle();
#endif
#else
SendMessage(g_hWnd, WM_CLOSE, 0, 0);
#endif
}
}
}
else
{
#ifdef _XBOX
Sleep(INFINITE);
#else
SendMessage(g_hWnd, WM_CLOSE, 0, 0);
#endif
}
}
LONG WINAPI CApplication::UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
PCSTR pExceptionString = "Unknown exception code";
#define STRINGIFY_EXCEPTION(code) case code: pExceptionString = #code; break
switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
{
STRINGIFY_EXCEPTION(EXCEPTION_ACCESS_VIOLATION);
STRINGIFY_EXCEPTION(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
STRINGIFY_EXCEPTION(EXCEPTION_BREAKPOINT);
STRINGIFY_EXCEPTION(EXCEPTION_FLT_DENORMAL_OPERAND);
STRINGIFY_EXCEPTION(EXCEPTION_FLT_DIVIDE_BY_ZERO);
STRINGIFY_EXCEPTION(EXCEPTION_FLT_INEXACT_RESULT);
STRINGIFY_EXCEPTION(EXCEPTION_FLT_INVALID_OPERATION);
STRINGIFY_EXCEPTION(EXCEPTION_FLT_OVERFLOW);
STRINGIFY_EXCEPTION(EXCEPTION_FLT_STACK_CHECK);
STRINGIFY_EXCEPTION(EXCEPTION_ILLEGAL_INSTRUCTION);
STRINGIFY_EXCEPTION(EXCEPTION_INT_DIVIDE_BY_ZERO);
STRINGIFY_EXCEPTION(EXCEPTION_INT_OVERFLOW);
STRINGIFY_EXCEPTION(EXCEPTION_INVALID_DISPOSITION);
STRINGIFY_EXCEPTION(EXCEPTION_NONCONTINUABLE_EXCEPTION);
STRINGIFY_EXCEPTION(EXCEPTION_SINGLE_STEP);
}
#undef STRINGIFY_EXCEPTION
g_LoadErrorStr.Format("%s (0x%08x)\n at 0x%08x",
pExceptionString, ExceptionInfo->ExceptionRecord->ExceptionCode,
ExceptionInfo->ExceptionRecord->ExceptionAddress);
CLog::Log(LOGFATAL, "%s", g_LoadErrorStr.c_str());
return ExceptionInfo->ExceptionRecord->ExceptionCode;
}
#ifdef _XBOX
#include "xbox/Undocumented.h"
extern "C" HANDLE __stdcall KeGetCurrentThread(VOID);
#endif
extern "C" void __stdcall init_emu_environ();
extern "C" void __stdcall update_emu_environ();
HRESULT CApplication::Create(HWND hWnd)
{
#ifdef HAS_XBOX_HARDWARE
// better 128mb ram support
// set MTRRDefType memory type to write-back as done in other XBox apps - seems a bit of a hack as really the def type
// should be uncachable and the mtrr/mask for ram instead set up for 128MB with writeback as is done in cromwell.
m_128MBHack = false;
MEMORYSTATUS status;
GlobalMemoryStatus( &status );
// if we have more than 64MB free
if( status.dwTotalPhys > 67108864 )
{
__asm
{
mov ecx, 0x2ff
rdmsr
mov al, 0x06
wrmsr
}
m_128MBHack = true;
}
#endif
#ifdef _DEBUG
g_advancedSettings.m_logLevel = LOG_LEVEL_DEBUG;
g_advancedSettings.m_logLevelHint = LOG_LEVEL_DEBUG;
#else
g_advancedSettings.m_logLevel = LOG_LEVEL_NORMAL;
g_advancedSettings.m_logLevelHint = LOG_LEVEL_NORMAL;
#endif
CLog::SetLogLevel(g_advancedSettings.m_logLevel);
g_guiSettings.Initialize(); // Initialize default Settings
g_settings.Initialize(); //Initialize default AdvancedSettings
g_hWnd = hWnd;
HRESULT hr;
//grab a handle to our thread to be used later in identifying the render thread
m_threadID = GetCurrentThreadId();
//floating point precision to 24 bits (faster performance)
_controlfp(_PC_24, _MCW_PC);
init_emu_environ();
/* install win32 exception translator, win32 exceptions
* can now be caught using c++ try catch */
win32_exception::install_handler();
CStdString strExecutablePath;
char szDevicePath[MAX_PATH];
// map Q to home drive of xbe to load the config file
CUtil::GetHomePath(strExecutablePath);
CIoSupport::GetPartition(strExecutablePath.c_str()[0], szDevicePath);
strcat(szDevicePath, &strExecutablePath.c_str()[2]);
CIoSupport::RemapDriveLetter('Q', szDevicePath);
// Do all the special:// & driveletter mapping & setup profiles
InitDirectoriesXbox();
CLog::Log(LOGNOTICE, "-----------------------------------------------------------------------");
CLog::Log(LOGNOTICE, "Starting XBMC4Xbox %s (SVN:%s, compiler %i). Built on %s ", VERSION_STRING, SVN_REV, _MSC_VER, __DATE__);
CSpecialProtocol::LogPaths();
char szXBEFileName[1024];
CIoSupport::GetXbePath(szXBEFileName);
CLog::Log(LOGNOTICE, "The executable running is: %s", szXBEFileName);
CLog::Log(LOGNOTICE, "Log File is located: %sxbmc.log", g_settings.m_logFolder.c_str());
CLog::Log(LOGNOTICE, "-----------------------------------------------------------------------");
// 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/";
}
else
{
CStdString strMnt = _P(g_settings.GetUserDataFolder());
if (strMnt.Left(2).Equals("Q:"))
{
CUtil::GetHomePath(strMnt);
strMnt += _P(g_settings.GetUserDataFolder()).substr(2);
}
CIoSupport::GetPartition(strMnt.c_str()[0], szDevicePath);
strcat(szDevicePath, &strMnt.c_str()[2]);
CIoSupport::RemapDriveLetter('T', szDevicePath);
}
if (m_128MBHack)
CLog::Log(LOGNOTICE, "128MB hack enabled");
CLog::Log(LOGNOTICE, "Setup DirectX");
// Create the Direct3D object
if ( NULL == ( m_pD3D = Direct3DCreate8(D3D_SDK_VERSION) ) )
{
CLog::Log(LOGFATAL, "XBAppEx: Unable to create Direct3D!" );
return E_FAIL;
}
//list available videomodes
g_videoConfig.GetModes(m_pD3D);
//init the present parameters with values that are supported
RESOLUTION initialResolution = g_videoConfig.GetInitialMode(m_pD3D, &m_d3dpp);
// Transfer the resolution information to our graphics context
g_graphicsContext.SetD3DParameters(&m_d3dpp);
g_graphicsContext.SetVideoResolution(initialResolution, TRUE);
// 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.
#ifdef HAS_XBOX_HARDWARE
XInitDevices( m_dwNumInputDeviceTypes, m_InputDeviceTypes );
// Create the gamepad devices
if ( FAILED(hr = XBInput_CreateGamepads(&m_Gamepad)) )
{
CLog::Log(LOGERROR, "XBAppEx: Call to CreateGamepads() failed!" );
return hr;
}
if ( FAILED(hr = XBInput_CreateIR_Remotes()) )
{
CLog::Log(LOGERROR, "XBAppEx: Call to CreateIRRemotes() failed!" );
return hr;
}
#endif
// Create the Mouse and Keyboard devices
g_Mouse.Initialize(&hWnd);
g_Keyboard.Initialize(hWnd);
#ifdef HAS_XBOX_HARDWARE
// Wait for controller polling to finish. in an elegant way, instead of a Sleep(1000)
while (XGetDeviceEnumerationStatus() == XDEVICE_ENUMERATION_BUSY)
{
ReadInput();
}
Sleep(10); // needed or the readinput doesnt fetch anything
ReadInput();
#endif
#ifdef HAS_GAMEPAD
//Check for LTHUMBCLICK+RTHUMBCLICK and BLACK+WHITE, no LTRIGGER+RTRIGGER
if (((m_DefaultGamepad.wButtons & (XINPUT_GAMEPAD_LEFT_THUMB + XINPUT_GAMEPAD_RIGHT_THUMB)) && !(m_DefaultGamepad.wButtons & (KEY_BUTTON_LEFT_TRIGGER+KEY_BUTTON_RIGHT_TRIGGER))) ||
((m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_BLACK] && m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_WHITE]) && !(m_DefaultGamepad.wButtons & KEY_BUTTON_LEFT_TRIGGER+KEY_BUTTON_RIGHT_TRIGGER)))
{
CLog::Log(LOGINFO, "Key combination detected for userdata deletion (LTHUMB+RTHUMB or BLACK+WHITE)");
InitBasicD3D();
// D3D is up, load default font
XFONT* pFont;
if (XFONT_OpenDefaultFont(&pFont) != S_OK)
{
CLog::Log(LOGFATAL, "FATAL ERROR: Unable to open default font!");
Sleep(INFINITE); // die
}
// defaults for text
pFont->SetBkMode(XFONT_OPAQUE);
pFont->SetBkColor(D3DCOLOR_XRGB(0, 0, 0));
pFont->SetTextColor(D3DCOLOR_XRGB(0xff, 0x20, 0x20));
int iLine = 0;
FEH_TextOut(pFont, iLine++, L"Key combination for userdata deletion detected!");
FEH_TextOut(pFont, iLine++, L"Are you sure you want to proceed?");
iLine++;
FEH_TextOut(pFont, iLine++, L"A for yes, any other key for no");
bool bAnyAnalogKey = false;
while (m_DefaultGamepad.wPressedButtons != XBGAMEPAD_NONE) // wait for user to let go of lclick + rclick
{
ReadInput();
}
while (m_DefaultGamepad.wPressedButtons == XBGAMEPAD_NONE && !bAnyAnalogKey)
{
ReadInput();
bAnyAnalogKey = m_DefaultGamepad.bPressedAnalogButtons[0] || m_DefaultGamepad.bPressedAnalogButtons[1] || m_DefaultGamepad.bPressedAnalogButtons[2] || m_DefaultGamepad.bPressedAnalogButtons[3] || m_DefaultGamepad.bPressedAnalogButtons[4] || m_DefaultGamepad.bPressedAnalogButtons[5] || m_DefaultGamepad.bPressedAnalogButtons[6] || m_DefaultGamepad.bPressedAnalogButtons[7];
}
if (m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_A])
{
CUtil::DeleteGUISettings();
CUtil::WipeDir(URIUtils::AddFileToFolder(g_settings.GetUserDataFolder(),"database\\"));
CUtil::WipeDir(URIUtils::AddFileToFolder(g_settings.GetUserDataFolder(),"thumbnails\\"));
CUtil::WipeDir(URIUtils::AddFileToFolder(g_settings.GetUserDataFolder(),"playlists\\"));
CUtil::WipeDir(URIUtils::AddFileToFolder(g_settings.GetUserDataFolder(),"cache\\"));
CUtil::WipeDir(URIUtils::AddFileToFolder(g_settings.GetUserDataFolder(),"profiles\\"));
CUtil::WipeDir(URIUtils::AddFileToFolder(g_settings.GetUserDataFolder(),"visualisations\\"));
CFile::Delete(URIUtils::AddFileToFolder(g_settings.GetUserDataFolder(),"avpacksettings.xml"));
g_settings.DeleteAllProfiles();
g_settings.SaveProfiles(PROFILES_FILE);
char szXBEFileName[1024];
CIoSupport::GetXbePath(szXBEFileName);
CUtil::RunXBE(szXBEFileName);
}
m_pd3dDevice->Release();
}
#endif
CIoSupport::RemapDriveLetter('C', "Harddisk0\\Partition2");
CIoSupport::RemapDriveLetter('E', "Harddisk0\\Partition1");
CIoSupport::Dismount("Cdrom0");
CIoSupport::RemapDriveLetter('D', "Cdrom0");
// Attempt to read the LBA48 v3 patch partition table, if kernel supports the command and it exists.
CIoSupport::ReadPartitionTable();
if (CIoSupport::HasPartitionTable())
{
// Mount up to Partition15 if they are available.
for (int i=EXTEND_PARTITION_BEGIN; i <= (EXTEND_PARTITION_BEGIN+EXTEND_PARTITIONS_LIMIT-1); i++)
{
char szDevice[32];
if (CIoSupport::PartitionExists(i))
{
char cDriveLetter = 'A' + i - 1;
char extendDriveLetter = CIoSupport::GetExtendedPartitionDriveLetter(cDriveLetter-EXTEND_DRIVE_BEGIN);
CLog::Log(LOGNOTICE, " map extended drive %c:", extendDriveLetter);
sprintf(szDevice, "Harddisk0\\Partition%u", i);
CIoSupport::RemapDriveLetter(extendDriveLetter, szDevice);
}
}
}
else
{
if (CIoSupport::DriveExists('F'))
CIoSupport::RemapDriveLetter('F', "Harddisk0\\Partition6");
if (CIoSupport::DriveExists('G'))
CIoSupport::RemapDriveLetter('G', "Harddisk0\\Partition7");
}
CIoSupport::RemapDriveLetter('X',"Harddisk0\\Partition3");
CIoSupport::RemapDriveLetter('Y',"Harddisk0\\Partition4");
#ifdef HAS_XBOX_HARDWARE
CIoSupport::RemapDriveLetter('Z',"Harddisk0\\Partition5");
#endif
CLog::Log(LOGINFO, "Drives are mapped");
CLog::Log(LOGNOTICE, "load settings...");
g_LoadErrorStr = "Unable to load settings";
m_bAllSettingsLoaded = g_settings.Load(m_bXboxMediacenterLoaded, m_bSettingsLoaded);
if (!m_bAllSettingsLoaded)
FatalErrorHandler(true, true, true);
update_emu_environ();//apply the GUI settings
// Check for WHITE + Y for forced Error Handler (to recover if something screwy happens)
#ifdef HAS_GAMEPAD
if (m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_Y] && m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_WHITE])
{
g_LoadErrorStr = "Key code detected for Error Recovery mode";
FatalErrorHandler(true, true, true);
}
#endif
//Check for X+Y - if pressed, set debug log mode and mplayer debuging on
CheckForDebugButtonCombo();
#ifdef HAS_XBOX_HARDWARE
bool bNeedReboot = false;
char temp[1024];
CIoSupport::GetXbePath(temp);
char temp2[1024];
char temp3;
temp3 = temp[0];
CIoSupport::GetPartition(temp3,temp2);
CStdString strTemp(temp+2);
int iLastSlash = strTemp.rfind('\\');
strcat(temp2,strTemp.substr(0,iLastSlash).c_str());
F_VIDEO ForceVideo = VIDEO_NULL;
F_COUNTRY ForceCountry = COUNTRY_NULL;
if (CUtil::RemoveTrainer())
bNeedReboot = true;
// now check if we are switching video modes. if, are we in the wrong mode according to eeprom?
if (g_guiSettings.GetBool("myprograms.gameautoregion"))
{
bool fDoPatchTest = false;
// should use xkeeprom.h :/
EEPROMDATA EEPROM;
ZeroMemory(&EEPROM, sizeof(EEPROMDATA));
if( XKUtils::ReadEEPROMFromXBOX((LPBYTE)&EEPROM))
{
DWORD DWVideo = *(LPDWORD)(&EEPROM.VideoStandard[0]);
char temp[1024];
CIoSupport::GetXbePath(temp);
char temp2[1024];
char temp3;
temp3 = temp[0];
CIoSupport::GetPartition(temp3,temp2);
CStdString strTemp(temp+2);
int iLastSlash = strTemp.rfind('\\');
strcat(temp2,strTemp.substr(0,iLastSlash).c_str());
if ((DWVideo == XKEEPROM::VIDEO_STANDARD::NTSC_M) && ((XGetVideoStandard() == XC_VIDEO_STANDARD_PAL_I) || (XGetVideoStandard() == XC_VIDEO_STANDARD_NTSC_J) || initialResolution > 5))
{
CLog::Log(LOGINFO, "Rebooting to change resolution from %s back to NTSC_M", (XGetVideoStandard() == XC_VIDEO_STANDARD_PAL_I) ? "PAL" : "NTSC_J");
ForceVideo = VIDEO_NTSCM;
ForceCountry = COUNTRY_USA;
bNeedReboot = true;
fDoPatchTest = true;
}
else if ((DWVideo == XKEEPROM::VIDEO_STANDARD::PAL_I) && ((XGetVideoStandard() == XC_VIDEO_STANDARD_NTSC_M) || (XGetVideoStandard() == XC_VIDEO_STANDARD_NTSC_J) || initialResolution < 6))
{
CLog::Log(LOGINFO, "Rebooting to change resolution from %s back to PAL_I", (XGetVideoStandard() == XC_VIDEO_STANDARD_NTSC_M) ? "NTSC_M" : "NTSC_J");
ForceVideo = VIDEO_PAL50;
ForceCountry = COUNTRY_EUR;
bNeedReboot = true;
fDoPatchTest = true;
}
else if ((DWVideo == XKEEPROM::VIDEO_STANDARD::NTSC_J) && ((XGetVideoStandard() == XC_VIDEO_STANDARD_NTSC_M) || (XGetVideoStandard() == XC_VIDEO_STANDARD_PAL_I) || initialResolution > 5))
{
CLog::Log(LOGINFO, "Rebooting to change resolution from %s back to NTSC_J", (XGetVideoStandard() == XC_VIDEO_STANDARD_PAL_I) ? "PAL" : "NTSC_M");
ForceVideo = VIDEO_NTSCJ;
ForceCountry = COUNTRY_JAP;
bNeedReboot = true;
fDoPatchTest = true;
}
else
CUtil::RemoveKernelPatch(); // This removes the Resolution patch from the kernel if it is not needed (if actual resolution matches eeprom setting)
if (fDoPatchTest) // Is set if we have to test whether our patch is in the kernel & therefore responsible for the mismatch of resolution & eeprom setting
{
if (!CUtil::LookForKernelPatch()) // If our patch is not present we are not responsible for the mismatch of current resolution & eeprom setting
{
// We do a hard reset to come back to default resolution and avoid infinite reboots
CLog::Log(LOGINFO, "No infinite reboot loop...");
m_applicationMessenger.Reset();
}
}
}
}
if (bNeedReboot)
{
Destroy();
CUtil::LaunchXbe(temp2,("D:\\"+strTemp.substr(iLastSlash+1)).c_str(),NULL,ForceVideo,ForceCountry);
}
#endif
// 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]);
// Load the langinfo to have user charset <-> utf-8 conversion
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 strKeyboardLayoutConfigurationPath;
strKeyboardLayoutConfigurationPath.Format("Q:\\language\\%s\\keyboardmap.xml", g_guiSettings.GetString("locale.language"));
CLog::Log(LOGINFO, "load keyboard layout configuration info file: %s", strKeyboardLayoutConfigurationPath.c_str());
g_keyboardLayoutConfiguration.Load(strKeyboardLayoutConfigurationPath);
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(true, false, true);
CLog::Log(LOGINFO, "load keymapping");
if (!CButtonTranslator::GetInstance().Load())
FatalErrorHandler(true, false, true);
// check the skin file for testing purposes
CStdString strSkinBase = "special://xbmc/skin/";
CStdString strSkinPath = strSkinBase + g_guiSettings.GetString("lookandfeel.skin");
CLog::Log(LOGINFO, "Checking skin version of: %s", g_guiSettings.GetString("lookandfeel.skin").c_str());
if (!g_SkinInfo.Check(strSkinPath))
{
// reset to the default skin (DEFAULT_SKIN)
CLog::Log(LOGINFO, "The above skin isn't suitable - checking the version of the default: %s", DEFAULT_SKIN);
strSkinPath = strSkinBase + DEFAULT_SKIN;
if (!g_SkinInfo.Check(strSkinPath))
{
g_LoadErrorStr.Format("No suitable skin version found.\nWe require at least version %5.4f \n", g_SkinInfo.GetMinVersion());
FatalErrorHandler(true, false, true);
}
}
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 = initialResolution;
}
// Transfer the new resolution information to our graphics context
#ifndef HAS_XBOX_D3D
m_d3dpp.Windowed = TRUE;
m_d3dpp.hDeviceWindow = g_hWnd;
#else
#define D3DCREATE_MULTITHREADED 0
#endif
g_graphicsContext.SetD3DParameters(&m_d3dpp);
g_graphicsContext.SetVideoResolution(g_guiSettings.m_LookAndFeelResolution, TRUE);
if ( FAILED( hr = m_pD3D->CreateDevice(0, D3DDEVTYPE_HAL, NULL,
D3DCREATE_MULTITHREADED | D3DCREATE_HARDWARE_VERTEXPROCESSING,
&m_d3dpp, &m_pd3dDevice ) ) )
{
// try software vertex processing
if ( FAILED( hr = m_pD3D->CreateDevice(0, D3DDEVTYPE_HAL, NULL,
D3DCREATE_MULTITHREADED | D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&m_d3dpp, &m_pd3dDevice ) ) )
{
// and slow as arse reference processing
if ( FAILED( hr = m_pD3D->CreateDevice(0, D3DDEVTYPE_REF, NULL,
D3DCREATE_MULTITHREADED | D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&m_d3dpp, &m_pd3dDevice ) ) )
{
CLog::Log(LOGFATAL, "XBAppEx: Could not create D3D device!" );
CLog::Log(LOGFATAL, " width/height:(%ix%i)" , m_d3dpp.BackBufferWidth, m_d3dpp.BackBufferHeight);
CLog::Log(LOGFATAL, " refreshrate:%i" , m_d3dpp.FullScreen_RefreshRateInHz);
if (m_d3dpp.Flags & D3DPRESENTFLAG_WIDESCREEN)
CLog::Log(LOGFATAL, " 16:9 widescreen");
else
CLog::Log(LOGFATAL, " 4:3");
if (m_d3dpp.Flags & D3DPRESENTFLAG_INTERLACED)
CLog::Log(LOGFATAL, " interlaced");
if (m_d3dpp.Flags & D3DPRESENTFLAG_PROGRESSIVE)
CLog::Log(LOGFATAL, " progressive");
return hr;
}
}
}
g_graphicsContext.SetD3DDevice(m_pd3dDevice);
g_graphicsContext.CaptureStateBlock();
// set filters
g_graphicsContext.Get3DDevice()->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR /*g_settings.m_minFilter*/ );
g_graphicsContext.Get3DDevice()->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR /*g_settings.m_maxFilter*/ );
CUtil::InitGamma();
// set GUI res and force the clear of the screen
g_graphicsContext.SetVideoResolution(g_guiSettings.m_LookAndFeelResolution, TRUE, true);
m_splash = new CSplash("Q:\\media\\splash.png");
m_splash->Start();
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);
g_windowManager.Initialize();
// show recovery console on fatal error instead of freezing
CLog::Log(LOGINFO, "install unhandled exception filter");
SetUnhandledExceptionFilter(UnhandledExceptionFilter);
#ifdef HAS_XBOX_D3D
D3DDevice::SetWaitCallback(WaitCallback);
#endif
g_Mouse.SetEnabled(g_guiSettings.GetBool("lookandfeel.enablemouse"));
CUtil::InitRandomSeed();
return CXBApplicationEx::Create(hWnd);
}
HRESULT CApplication::Initialize()
{
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());
// UserData folder layout:
// UserData/
// Database/
// CDDb/
// Thumbnails/
// Music/
// temp/
// 0 .. F/
CDirectory::Create(g_settings.GetUserDataFolder());
CDirectory::Create(g_settings.GetProfileUserDataFolder());
g_settings.CreateProfileFolders();
CDirectory::Create(g_settings.GetProfilesThumbFolder());
CUtil::WipeDir("Z:\\");
CreateDirectory("Z:\\temp", NULL); // temp directory for python and dllGetTempPathA
CreateDirectory("Q:\\scripts", NULL);
CreateDirectory("Q:\\plugins", NULL);
CreateDirectory("Q:\\plugins\\music", NULL);
CreateDirectory("Q:\\plugins\\video", NULL);
CreateDirectory("Q:\\plugins\\pictures", NULL);
CreateDirectory("Q:\\plugins\\programs", NULL);
CreateDirectory("Q:\\language", NULL);
CreateDirectory("Q:\\visualisations", NULL);
CreateDirectory("Q:\\sounds", NULL);
CreateDirectory(g_settings.GetUserDataFolder()+"\\visualisations",NULL);
// initialize network
if (!m_bXboxMediacenterLoaded)
{
CLog::Log(LOGINFO, "using default network settings");
g_guiSettings.SetString("network.ipaddress", "192.168.0.100");
g_guiSettings.SetString("network.subnet", "255.255.255.0");
g_guiSettings.SetString("network.gateway", "192.168.0.1");
g_guiSettings.SetString("network.dns", "192.168.0.1");
g_guiSettings.SetString("network.dns2", "0.0.0.0");
g_guiSettings.SetBool("services.ftpserver", true);
g_guiSettings.SetBool("services.webserver", false);
g_guiSettings.SetBool("locale.timeserver", false);
}
/* setup network based on our settings */
/* network will start it's init procedure */
m_network.SetupNetwork();
StartServices();
g_windowManager.Add(new CGUIWindowHome); // window id = 0
CLog::Log(LOGNOTICE, "load default skin:[%s]", g_guiSettings.GetString("lookandfeel.skin").c_str());
LoadSkin(g_guiSettings.GetString("lookandfeel.skin"));
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 CGUIWindowVideoFiles); // window id = 6
g_windowManager.Add(new CGUIWindowSettings); // window id = 4
g_windowManager.Add(new CGUIWindowSystemInfo); // window id = 7
g_windowManager.Add(new CGUIWindowSettingsScreenCalibration); // window id = 11
g_windowManager.Add(new CGUIWindowSettingsCategory); // window id = 12 slideshow:window id 2007
g_windowManager.Add(new CGUIWindowScripts); // window id = 20
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 CGUIWindowGameSaves); // window id = 35
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(&m_guiDialogVolumeBar); // window id = 104
g_windowManager.Add(&m_guiDialogSeekBar); // window id = 115
g_windowManager.Add(new CGUIDialogSubMenu); // window id = 105
g_windowManager.Add(new CGUIDialogContextMenu); // window id = 106
g_windowManager.Add(&m_guiDialogKaiToast); // 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 CGUIDialogPlayerControls); // window id = 113
g_windowManager.Add(new CGUIDialogSlider); // window id = 145
g_windowManager.Add(new CGUIDialogMusicOSD); // window id = 120
g_windowManager.Add(new CGUIDialogVisualisationSettings); // window id = 121
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 CGUIDialogTrainerSettings); // window id = 127
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 CGUIDialogPluginSettings); // window id = 140
g_windowManager.Add(new CGUIDialogTextViewer); // window id = 147
g_windowManager.Add(new CGUIDialogLockSettings); // window id = 131
g_windowManager.Add(new CGUIDialogContentSettings); // window id = 132
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 CGUIWindowMusicInfo); // window id = 2001
g_windowManager.Add(new CGUIDialogOK); // window id = 2002
g_windowManager.Add(new CGUIWindowVideoInfo); // window id = 2003
g_windowManager.Add(new CGUIWindowScriptsInfo); // window id = 2004
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
g_windowManager.Add(new CGUIWindowOSD); // window id = 2901
g_windowManager.Add(new CGUIWindowMusicOverlay); // window id = 2903
g_windowManager.Add(new CGUIWindowVideoOverlay); // 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 */
g_DownloadManager.Initialize();
m_ctrDpad.SetDelays(100, 500); //g_settings.m_iMoveDelayController, g_settings.m_iRepeatDelayController);
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
{
g_windowManager.ActivateWindow(g_SkinInfo.GetFirstWindow());
}
g_pythonParser.bStartup = true;
//g_sysinfo.Refresh();
CLog::Log(LOGINFO, "removing tempfiles");
CUtil::RemoveTempFiles();
if (!m_bAllSettingsLoaded)
{
CLog::Log(LOGWARNING, "settings not correct, show dialog");
CStdString test;
CUtil::GetHomePath(test);
CGUIDialogOK *dialog = (CGUIDialogOK *)g_windowManager.GetWindow(WINDOW_DIALOG_OK);
if (dialog)
{
dialog->SetHeading(279);
dialog->SetLine(0, "Error while loading settings");
dialog->SetLine(1, test);
dialog->SetLine(2, "");;
dialog->DoModal();
}
}
// Show mute symbol
if (g_settings.m_nVolumeLevel == VOLUME_MINIMUM)
Mute();
// 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();
m_slowTimer.StartZero();
#ifdef __APPLE__
g_xbmcHelper.CaptureAllInput();
#endif
CLog::Log(LOGNOTICE, "initialize done");
m_bInitializing = false;
// final check for debugging combo
CheckForDebugButtonCombo();
// reset our screensaver (starts timers etc.)
ResetScreenSaver();
return S_OK;
}
void CApplication::PrintXBEToLCD(const char* xbePath)
{
#ifdef HAS_LCD
int pLine = 0;
CStdString strXBEName;
if (!CUtil::GetXBEDescription(xbePath, strXBEName))
{
CUtil::GetDirectoryName(xbePath, strXBEName);
CUtil::ShortenFileName(strXBEName);
CUtil::RemoveIllegalChars(strXBEName);
}
// crop to LCD screen size
if ((int)strXBEName.size() > g_advancedSettings.m_lcdColumns)
strXBEName = strXBEName.Left(g_advancedSettings.m_lcdColumns);
if (g_lcd)
{
g_infoManager.SetLaunchingXBEName(strXBEName);
g_lcd->Render(ILCD::LCD_MODE_XBE_LAUNCH);
}
#endif
}
void CApplication::StartIdleThread()
{
m_idleThread.Create(false, 0x100);
}
void CApplication::StopIdleThread()
{
m_idleThread.StopThread();
}
void CApplication::StartWebServer()
{
if (g_guiSettings.GetBool("services.webserver") && m_network.IsAvailable() )
{
CLog::Log(LOGNOTICE, "Webserver: Starting...");
CSectionLoader::Load("LIBHTTP");
m_pWebServer = new CWebServer();
m_pWebServer->Start(m_network.m_networkinfo.ip, atoi(g_guiSettings.GetString("services.webserverport")), "Q:\\web", false);
if (m_pWebServer)
{
m_pWebServer->SetUserName(g_guiSettings.GetString("services.webserverusername").c_str());
m_pWebServer->SetPassword(g_guiSettings.GetString("services.webserverpassword").c_str());
}
if (m_pWebServer && m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
m_applicationMessenger.HttpApi("broadcastlevel; StartUp;1");
}
}
void CApplication::StopWebServer()
{
if (m_pWebServer)
{
CLog::Log(LOGNOTICE, "Webserver: Stopping...");
m_pWebServer->Stop();
delete m_pWebServer;
m_pWebServer = NULL;
CSectionLoader::Unload("LIBHTTP");
CLog::Log(LOGNOTICE, "Webserver: Stopped...");
}
}
void CApplication::StartFtpServer()
{
#ifdef HAS_FTP_SERVER
if ( g_guiSettings.GetBool("services.ftpserver") && m_network.IsAvailable() )
{
CLog::Log(LOGNOTICE, "XBFileZilla: Starting...");
if (!m_pFileZilla)
{
CStdString xmlpath = "special://xbmc/system/";
// if user didn't upgrade properly,
// check whether UserData/FileZilla Server.xml exists
if (CFile::Exists(g_settings.GetUserDataItem("FileZilla Server.xml")))
xmlpath = g_settings.GetUserDataFolder();
// check file size and presence
CFile xml;
if (xml.Open(xmlpath+"FileZilla Server.xml") && xml.GetLength() > 0)
{
m_pFileZilla = new CXBFileZilla(_P(xmlpath));
m_pFileZilla->Start(false);
}
else
{
// 'FileZilla Server.xml' does not exist or is corrupt,
// falling back to ftp emergency recovery mode
CLog::Log(LOGNOTICE, "XBFileZilla: 'FileZilla Server.xml' is missing or is corrupt!");
CLog::Log(LOGNOTICE, "XBFileZilla: Starting ftp emergency recovery mode");
StartFtpEmergencyRecoveryMode();
}
xml.Close();
}
}
#endif
}
void CApplication::StopFtpServer()
{
#ifdef HAS_FTP_SERVER
if (m_pFileZilla)
{
CLog::Log(LOGINFO, "XBFileZilla: Stopping...");
/*
std::vector<SXFConnection> mConnections;
std::vector<SXFConnection>::iterator it;
m_pFileZilla->GetAllConnections(mConnections);
for(it = mConnections.begin();it != mConnections.end();it++)
{
CLog(LOGDEBUG, "%s - Closing FTP connection %i", it->mId);
m_pFileZilla->CloseConnection(it->mId);
}
*/
m_pFileZilla->Stop();
delete m_pFileZilla;
m_pFileZilla = NULL;
CLog::Log(LOGINFO, "XBFileZilla: Stopped");
}
#endif
}
void CApplication::StartTimeServer()
{
#ifdef HAS_TIME_SERVER
if (g_guiSettings.GetBool("locale.timeserver") && m_network.IsAvailable() )
{
if( !m_psntpClient )
{
CSectionLoader::Load("SNTP");
CLog::Log(LOGNOTICE, "start timeserver client");
m_psntpClient = new CSNTPClient();
m_psntpClient->Update();
}
}
#endif
}
void CApplication::StopTimeServer()
{
#ifdef HAS_TIME_SERVER
if( m_psntpClient )
{
CLog::Log(LOGNOTICE, "stop time server client");
SAFE_DELETE(m_psntpClient);
CSectionLoader::Unload("SNTP");
}
#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
}
void CApplication::StartEventServer()
{
#ifdef HAS_EVENT_SERVER
CEventServer* server = CEventServer::GetInstance();
if (!server)
{
CLog::Log(LOGERROR, "ES: Out of memory");
return;
}
if (g_guiSettings.GetBool("services.esenabled"))
{
CLog::Log(LOGNOTICE, "ES: Starting event server");
server->StartServer();
}
#endif
}
bool CApplication::StopEventServer(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");
}
else
{
CLog::Log(LOGNOTICE, "ES: Stopping event server");
}
CEventServer::GetInstance()->StopServer();
#endif
return true;
}
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::StartLEDControl(bool switchoff)
{
#ifdef HAS_XBOX_HARDWARE
if (switchoff && g_guiSettings.GetInt("system.ledcolour") != LED_COLOUR_NO_CHANGE)
{
if ( IsPlayingVideo() && (g_guiSettings.GetInt("system.leddisableonplayback") == LED_PLAYBACK_VIDEO))
ILED::CLEDControl(LED_COLOUR_OFF);
if ( IsPlayingAudio() && (g_guiSettings.GetInt("system.leddisableonplayback") == LED_PLAYBACK_MUSIC))
ILED::CLEDControl(LED_COLOUR_OFF);
if ( ((IsPlayingVideo() || IsPlayingAudio())) && (g_guiSettings.GetInt("system.leddisableonplayback") == LED_PLAYBACK_VIDEO_MUSIC))
ILED::CLEDControl(LED_COLOUR_OFF);
}
else if (!switchoff)
ILED::CLEDControl(g_guiSettings.GetInt("system.ledcolour"));
#endif
}
void CApplication::DimLCDOnPlayback(bool dim)
{
#ifdef HAS_LCD
if(g_lcd && dim && (g_guiSettings.GetInt("lcd.disableonplayback") != LED_PLAYBACK_OFF) && (g_guiSettings.GetInt("lcd.type") != LCD_TYPE_NONE))
{
if ( (IsPlayingVideo()) && g_guiSettings.GetInt("lcd.disableonplayback") == LED_PLAYBACK_VIDEO)
g_lcd->SetBackLight(0);
if ( (IsPlayingAudio()) && g_guiSettings.GetInt("lcd.disableonplayback") == LED_PLAYBACK_MUSIC)
g_lcd->SetBackLight(0);
if ( ((IsPlayingVideo() || IsPlayingAudio())) && g_guiSettings.GetInt("lcd.disableonplayback") == LED_PLAYBACK_VIDEO_MUSIC)
g_lcd->SetBackLight(0);
}
else if(!dim)
g_lcd->SetBackLight(g_guiSettings.GetInt("lcd.backlight"));
#endif
}
void CApplication::StartServices()
{
#ifdef HAS_XBOX_HARDWARE
if (g_advancedSettings.m_bPowerSave)
{
CLog::Log(LOGNOTICE, "Using idle thread with HLT (power saving)");
StartIdleThread();
}
else
CLog::Log(LOGNOTICE, "Not using idle thread with HLT (no power saving)");
#endif
CheckDate();
StartLEDControl(false);
// Start Thread for DVD Mediatype detection
CLog::Log(LOGNOTICE, "start dvd mediatype detection");
m_DetectDVDType.Create(false, THREAD_MINSTACKSIZE);
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
#ifdef HAS_XBOX_HARDWARE
if (g_guiSettings.GetBool("system.autotemperature"))
{
CLog::Log(LOGNOTICE, "start fancontroller");
CFanController::Instance()->Start(g_guiSettings.GetInt("system.targettemperature"), g_guiSettings.GetInt("system.minfanspeed"));
}
else if (g_guiSettings.GetBool("system.fanspeedcontrol"))
{
CLog::Log(LOGNOTICE, "setting fanspeed");
CFanController::Instance()->SetFanSpeed(g_guiSettings.GetInt("system.fanspeed"));
}
int setting_level = g_guiSettings.GetInt("harddisk.aamlevel");
if (setting_level == AAM_QUIET)
XKHDD::SetAAMLevel(0x80);
else if (setting_level == AAM_FAST)
XKHDD::SetAAMLevel(0xFE);
setting_level = g_guiSettings.GetInt("harddisk.apmlevel");
switch(setting_level)
{
case APM_LOPOWER:
XKHDD::SetAPMLevel(0x80);
break;
case APM_HIPOWER:
XKHDD::SetAPMLevel(0xFE);
break;
case APM_LOPOWER_STANDBY:
XKHDD::SetAPMLevel(0x01);
break;
case APM_HIPOWER_STANDBY:
XKHDD::SetAPMLevel(0x7F);
break;
}
#endif
}
void CApplication::CheckDate()
{
CLog::Log(LOGNOTICE, "Checking the Date!");
// Check the Date: Year, if it is above 2099 set to 2004!
SYSTEMTIME CurTime;
SYSTEMTIME NewTime;
GetLocalTime(&CurTime);
GetLocalTime(&NewTime);
CLog::Log(LOGINFO, "Current Date is: %i-%i-%i", CurTime.wDay, CurTime.wMonth, CurTime.wYear);
if ((CurTime.wYear > 2099) || (CurTime.wYear < 2001) ) // XBOX MS Dashboard also uses min/max DateYear 2001/2099 !!
{
CLog::Log(LOGNOTICE, "- The Date is Wrong: Setting New Date!");
NewTime.wYear = 2004; // 2004
NewTime.wMonth = 1; // January
NewTime.wDayOfWeek = 1; // Monday
NewTime.wDay = 5; // Monday 05.01.2004!!
NewTime.wHour = 12;
NewTime.wMinute = 0;
FILETIME stNewTime, stCurTime;
SystemTimeToFileTime(&NewTime, &stNewTime);
SystemTimeToFileTime(&CurTime, &stCurTime);
#ifdef HAS_XBOX_HARDWARE
NtSetSystemTime(&stNewTime, &stCurTime); // Set a Default Year 2004!
#endif
CLog::Log(LOGNOTICE, "- New Date is now: %i-%i-%i",NewTime.wDay, NewTime.wMonth, NewTime.wYear);
}
return ;
}
void CApplication::StopServices()
{
m_network.NetworkMessage(CNetwork::SERVICES_DOWN, 0);
CLog::Log(LOGNOTICE, "stop dvd detect media");
m_DetectDVDType.StopThread();
#ifdef HAS_XBOX_HARDWARE
CLog::Log(LOGNOTICE, "stop fancontroller");
CFanController::Instance()->Stop();
CFanController::RemoveInstance();
if (g_advancedSettings.m_bPowerSave)
StopIdleThread();
#endif
}
void CApplication::DelayLoadSkin()
{
m_skinReloadTime = CTimeUtils::GetFrameTime() + 2000;
return ;
}
void CApplication::CancelDelayLoadSkin()
{
m_skinReloadTime = 0;
}
void CApplication::ReloadSkin()
{
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);
}
}
void CApplication::LoadSkin(const CStdString& strSkin)
{
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
}
//stop the busy renderer if it's running before we lock the graphiccontext or we could deadlock.
g_ApplicationRenderer.Stop();
// close the music and video overlays (they're re-opened automatically later)
CSingleLock lock(g_graphicsContext);
m_skinReloadTime = 0;
CStdString strHomePath;
CStdString strSkinPath = "Q:\\skin\\" + strSkin;
CLog::Log(LOGINFO, " load skin from:%s", strSkinPath.c_str());
// save the current window details
int currentWindow = g_windowManager.GetActiveWindow();
vector<int> currentModelessWindows;
g_windowManager.GetActiveModelessWindows(currentModelessWindows);
CLog::Log(LOGINFO, " delete old skin...");
UnloadSkin();
// Load in the skin.xml file if it exists
g_SkinInfo.Load(strSkinPath);
CLog::Log(LOGINFO, " load fonts for skin...");
g_graphicsContext.SetMediaDir(strSkinPath);
g_directoryCache.ClearSubPaths(strSkinPath);
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(strSkinPath, "language", langPath);
URIUtils::AddSlashAtEnd(langPath);
g_localizeStrings.LoadSkinStrings(langPath, g_guiSettings.GetString("locale.language"));
LARGE_INTEGER start;
QueryPerformanceCounter(&start);
CLog::Log(LOGINFO, " load new skin...");
CGUIWindowHome *pHome = (CGUIWindowHome *)g_windowManager.GetWindow(WINDOW_HOME);
if (!g_SkinInfo.Check(strSkinPath) || !pHome || !pHome->Load("Home.xml"))
{
// failed to load home.xml
// fallback to default skin
if ( strcmpi(strSkin.c_str(), DEFAULT_SKIN) != 0)
{
CLog::Log(LOGERROR, "failed to load home.xml for skin:%s, fallback to \"%s\" skin", strSkin.c_str(), DEFAULT_SKIN);
g_guiSettings.SetString("lookandfeel.skin", DEFAULT_SKIN);
LoadSkin(g_guiSettings.GetString("lookandfeel.skin"));
return ;
}
}
// Load the user windows
LoadUserWindows();
LARGE_INTEGER end, freq;
QueryPerformanceCounter(&end);
QueryPerformanceFrequency(&freq);
CLog::Log(LOGDEBUG,"Load Skin XML: %.2fms", 1000.f * (end.QuadPart - start.QuadPart) / freq.QuadPart);
CLog::Log(LOGINFO, " initialize new skin...");
m_guiPointer.AllocResources(true);
m_guiDialogVolumeBar.AllocResources(true);
m_guiDialogSeekBar.AllocResources(true);
m_guiDialogKaiToast.AllocResources(true);
m_guiDialogMuteBug.AllocResources(true);
g_windowManager.AddMsgTarget(this);
g_windowManager.AddMsgTarget(&g_playlistPlayer);
g_windowManager.AddMsgTarget(&g_infoManager);
g_windowManager.SetCallback(*this);
g_windowManager.Initialize();
g_audioManager.Initialize(CAudioContext::DEFAULT_DEVICE);
g_audioManager.Load();
if (g_SkinInfo.HasSkinFile("DialogFullScreenInfo.xml"))
g_windowManager.Add(new CGUIDialogFullScreenInfo);
CLog::Log(LOGINFO, " skin loaded...");
// leave the graphics lock
lock.Leave();
g_ApplicationRenderer.Start();
// 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()
{
g_ApplicationRenderer.Stop();
g_audioManager.DeInitialize(CAudioContext::DEFAULT_DEVICE);
g_windowManager.DeInitialize();
//These windows are not handled by the windowmanager (why not?) so we should unload them manually
CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0);
m_guiPointer.OnMessage(msg);
m_guiPointer.ResetControlStates();
m_guiPointer.FreeResources(true);
m_guiDialogMuteBug.OnMessage(msg);
m_guiDialogMuteBug.ResetControlStates();
m_guiDialogMuteBug.FreeResources(true);
// remove the skin-dependent window
g_windowManager.Delete(WINDOW_DIALOG_FULLSCREEN_INFO);
g_TextureManager.Cleanup();
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)
{
CStdString strPath = URIUtils::AddFileToFolder(vecSkinPath[i], "custom*.xml");
CLog::Log(LOGINFO, "Loading user windows, path %s", vecSkinPath[i].c_str());
WIN32_FIND_DATA NextFindFileData;
HANDLE hFind = FindFirstFile(_P(strPath).c_str(), &NextFindFileData);
while (hFind != INVALID_HANDLE_VALUE)
{
WIN32_FIND_DATA FindFileData = NextFindFileData;
if (!FindNextFile(hFind, &NextFindFileData))
{
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
// skip "up" directories, which come in all queries
if (!strcmp(FindFileData.cFileName, ".") || !strcmp(FindFileData.cFileName, ".."))
continue;
CStdString strFileName = URIUtils::AddFileToFolder(vecSkinPath[i], FindFileData.cFileName);
CLog::Log(LOGINFO, "Loading skin file: %s", strFileName.c_str());
CStdString strLower(FindFileData.cFileName);
strLower.MakeLower();
strLower = URIUtils::AddFileToFolder(vecSkinPath[i], strLower);
TiXmlDocument xmlDoc;
if (!xmlDoc.LoadFile(strFileName) && !xmlDoc.LoadFile(strLower))
{
CLog::Log(LOGERROR, "unable to load:%s, Line %d\n%s", strFileName.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>", strFileName.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());
}
int visibleCondition = 0;
CGUIControlFactory::GetConditionalVisibility(pRootElement, visibleCondition);
if (strType.Equals("dialog"))
pWindow = new CGUIDialog(id + WINDOW_HOME, FindFileData.cFileName);
else if (strType.Equals("submenu"))
pWindow = new CGUIDialogSubMenu(id + WINDOW_HOME, FindFileData.cFileName);
else if (strType.Equals("buttonmenu"))
pWindow = new CGUIDialogButtonMenu(id + WINDOW_HOME, FindFileData.cFileName);
else
pWindow = new CGUIStandardWindow(id + WINDOW_HOME, FindFileData.cFileName);
// 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, false);
g_windowManager.AddCustomWindow(pWindow);
}
CloseHandle(hFind);
}
return true;
}
#ifdef HAS_XBOX_D3D // needed for screenshot
void CApplication::Render()
{
#else
void CApplication::RenderNoPresent()
{
#endif
// don't do anything that would require graphiccontext to be locked before here in fullscreen.
// that stuff should go into renderfullscreen instead as that is called from the renderin thread
#ifdef HAS_XBOX_HARDWARE // Win32 renders from the main thread, not from the player thread
// dont show GUI when playing full screen video
if (g_graphicsContext.IsFullScreenVideo() && IsPlaying() && !IsPaused())
{
Sleep(50);
ResetScreenSaver();
g_infoManager.ResetCache();
return;
}
#endif
g_ApplicationRenderer.Render();
}
void CApplication::DoRender()
{
if(!m_pd3dDevice)
return;
g_graphicsContext.Lock();
m_pd3dDevice->BeginScene();
g_windowManager.UpdateModelessVisibility();
//SWATHWIDTH of 4 improves fillrates (performance investigator)
#ifdef HAS_XBOX_D3D
m_pd3dDevice->SetRenderState(D3DRS_SWATHWIDTH, 4);
#endif
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;
}
}
// Now render any dialogs
g_windowManager.RenderDialogs();
// Render the mouse pointer
if (g_Mouse.IsActive())
{
m_guiPointer.Render();
}
{
// free memory if we got les then 10megs free ram
MEMORYSTATUS stat;
GlobalMemoryStatus(&stat);
DWORD dwMegFree = (DWORD)(stat.dwAvailPhys / (1024 * 1024));
if (dwMegFree <= 10)
{
g_TextureManager.Flush();
}
// reset image scaling and effect states
g_graphicsContext.SetRenderingResolution(g_graphicsContext.GetVideoResolution(), false);
// If we have the remote codes enabled, then show them
if (g_advancedSettings.m_displayRemoteCodes)
{
#ifdef HAS_IR_REMOTE
XBIR_REMOTE* pRemote = &m_DefaultIR_Remote;
static iRemoteCode = 0;
static iShowRemoteCode = 0;
if (pRemote->wButtons)
{
iRemoteCode = 255 - pRemote->wButtons; // remote OBC code is 255-wButtons
iShowRemoteCode = 50;
}
if (iShowRemoteCode > 0)
{
CStdStringW wszText;
wszText.Format(L"Remote Code: %i", iRemoteCode);
float x = 0.08f * g_graphicsContext.GetWidth();
float y = 0.12f * g_graphicsContext.GetHeight();
#ifndef _DEBUG
if (LOG_LEVEL_DEBUG_FREEMEM > g_advancedSettings.m_logLevel)
y = 0.08f * g_graphicsContext.GetHeight();
#endif
CGUITextLayout::DrawOutlineText(g_fontManager.GetFont("font13"), x, y, 0xffffffff, 0xff000000, 2, wszText);
iShowRemoteCode--;
}
#endif
}
RenderMemoryStatus();
}
m_pd3dDevice->EndScene();
#ifdef HAS_XBOX_D3D
m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
#endif
g_graphicsContext.Unlock();
// 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();
}
#ifndef HAS_XBOX_D3D
void CApplication::Render()
{
g_graphicsContext.Lock();
{ // frame rate limiter (really bad, but it does the trick :p)
const static unsigned int singleFrameTime = 10;
static unsigned int lastFrameTime = 0;
unsigned int currentTime = timeGetTime();
if (lastFrameTime + singleFrameTime > currentTime)
Sleep(lastFrameTime + singleFrameTime - currentTime);
lastFrameTime = timeGetTime();
}
RenderNoPresent();
// Present the backbuffer contents to the display
if (m_pd3dDevice) m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
CTimeUtils::UpdateFrameTime();
g_graphicsContext.Unlock();
}
#endif
void CApplication::RenderMemoryStatus()
{
g_infoManager.UpdateFPS();
#if !defined(_DEBUG) && !defined(PROFILE)
if (LOG_LEVEL_DEBUG_FREEMEM <= g_advancedSettings.m_logLevel)
#endif
{
// reset the window scaling and fade status
RESOLUTION res = g_graphicsContext.GetVideoResolution();
g_graphicsContext.SetRenderingResolution(res, false);
CStdStringW wszText;
MEMORYSTATUS stat;
GlobalMemoryStatus(&stat);
wszText.Format(L"FreeMem %d/%d KB, FPS %2.1f, CPU %2.0f%%", stat.dwAvailPhys/1024, stat.dwTotalPhys/1024, g_infoManager.GetFPS(), (1.0f - m_idleThread.GetRelativeUsage())*100);
float x = 0.04f * g_graphicsContext.GetWidth() + g_settings.m_ResInfo[res].Overscan.left;
float y = 0.04f * g_graphicsContext.GetHeight() + g_settings.m_ResInfo[res].Overscan.top;
CGUITextLayout::DrawOutlineText(g_fontManager.GetFont("font13"), x, y, 0xffffffff, 0xff000000, 2, wszText);
}
}
// 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(CKey& key)
{
// Turn the mouse off, as we've just got a keypress from controller or remote
g_Mouse.SetInactive();
// 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 the screensaver timer
// but not for the analog thumbsticks/triggers
if (!key.IsAnalogButton())
{
// reset harddisk spindown timer
m_bSpinDown = false;
m_bNetworkSpinDown = false;
// reset Idle Timer
m_idleTimer.StartZero();
ResetScreenSaver();
// allow some keys to be processed while the screensaver is active
if (ResetScreenSaverWindow())
{
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);
#ifdef HAS_SDL
g_Keyboard.Reset();
#endif
if (!key.IsAnalogButton())
CLog::Log(LOGDEBUG, "%s: %i pressed, trying fullscreen info action %s", __FUNCTION__, (int) key.GetButtonCode(), 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 (control->GetControlType() == CGUIControl::GUICONTROL_EDIT ||
(control->IsContainer() && g_Keyboard.GetShift()))
useKeyboard = true;
}
}
if (useKeyboard)
{
action = CAction(0); // reset our action
if (key.GetFromHttpApi())
action = CAction(key.GetButtonCode() != KEY_INVALID ? key.GetButtonCode() : 0, key.GetUnicode());
else
{ // see if we've got an ascii key
if (g_Keyboard.GetUnicode())
action = CAction(g_Keyboard.GetAscii() | KEY_ASCII, g_Keyboard.GetUnicode());
else
action = CAction(g_Keyboard.GetKey() | KEY_VKEY);
}
#ifdef HAS_SDL
g_Keyboard.Reset();
#endif
CLog::Log(LOGDEBUG, "%s: %i pressed, trying keyboard action %i", __FUNCTION__, (int) key.GetButtonCode(), action.GetID());
if (OnAction(action))
return true;
// failed to handle the keyboard action, drop down through to standard action
}
if (key.GetFromHttpApi())
{
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: %i pressed, action is %s", __FUNCTION__, (int) key.GetButtonCode(), action.GetName().c_str());
bool bResult = false;
// play sound before the action unless the button is held,
// where we execute after the action as held actions aren't fired every time.
if(action.GetHoldTime())
{
bResult = OnAction(action);
if(bResult)
g_audioManager.PlayActionSound(action);
}
else
{
g_audioManager.PlayActionSound(action);
bResult = OnAction(action);
}
return bResult;
}
bool CApplication::OnAction(CAction &action)
{
// Let's tell the outside world about this action
if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=2)
{
CStdString tmp;
tmp.Format("%i",action.GetID());
m_applicationMessenger.HttpApi("broadcastlevel; OnAction:"+tmp+";2");
}
// 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;
}
}
// 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;
}
// power down : turn off after 3 seconds of button down
static bool PowerButtonDown = false;
static DWORD PowerButtonCode;
static DWORD MarkTime;
if (action.GetID() == ACTION_POWERDOWN)
{
// Hold button for 3 secs to power down
if (!PowerButtonDown)
{
MarkTime = GetTickCount();
PowerButtonDown = true;
PowerButtonCode = action.GetButtonCode();
}
}
if (PowerButtonDown)
{
if (g_application.IsButtonDown(PowerButtonCode))
{
if (GetTickCount() >= MarkTime + 3000)
{
m_applicationMessenger.Shutdown();
return true;
}
}
else
PowerButtonDown = false;
}
// 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_pPlayer->Pause();
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)
{
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 (action.GetID() == ACTION_MUTE)
{
Mute();
return true;
}
if (action.GetID() == ACTION_TOGGLE_DIGITAL_ANALOG)
{
if(g_guiSettings.GetInt("audiooutput.mode")==AUDIO_DIGITAL)
g_guiSettings.SetInt("audiooutput.mode", AUDIO_ANALOG);
else
g_guiSettings.SetInt("audiooutput.mode", AUDIO_DIGITAL);
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))
{
// increase or decrease the volume
int volume = g_settings.m_nVolumeLevel + g_settings.m_dynamicRangeCompressionLevel;
// calculate speed so that a full press will equal 1 second from min to max
float speed = float(VOLUME_MAXIMUM - VOLUME_MINIMUM);
if( action.GetRepeat() )
speed *= action.GetRepeat();
else
speed /= 50; //50 fps
if (g_settings.m_bMute)
{
// only unmute if volume is to be increased, otherwise leave muted
if (action.GetID() == ACTION_VOLUME_DOWN)
return true;
if (g_settings.m_iPreMuteVolumeLevel == 0)
SetVolume(1);
else
// In muted, unmute
Mute();
return true;
}
if (action.GetID() == ACTION_VOLUME_UP)
{
volume += (int)((float)fabs(action.GetAmount()) * action.GetAmount() * speed);
}
else
{
volume -= (int)((float)fabs(action.GetAmount()) * action.GetAmount() * speed);
}
SetHardwareVolume(volume);
#ifndef HAS_SDL_AUDIO
g_audioManager.SetVolume(g_settings.m_nVolumeLevel);
#else
g_audioManager.SetVolume((int)(128.f * (g_settings.m_nVolumeLevel - VOLUME_MINIMUM) / (float)(VOLUME_MAXIMUM - VOLUME_MINIMUM)));
#endif
// show visual feedback of volume change...
m_guiDialogVolumeBar.Show();
m_guiDialogVolumeBar.OnAction(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;
m_guiDialogSeekBar.OnAction(action);
return true;
}
if (action.GetID() == ACTION_SHOW_PLAYLIST)
{
int iPlaylist = g_playlistPlayer.GetCurrentPlaylist();
if (iPlaylist == PLAYLIST_VIDEO && g_windowManager.GetActiveWindow() != WINDOW_VIDEO_PLAYLIST)
g_windowManager.ActivateWindow(WINDOW_VIDEO_PLAYLIST);
else if (iPlaylist == PLAYLIST_MUSIC && g_windowManager.GetActiveWindow() != WINDOW_MUSIC_PLAYLIST)
g_windowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST);
return true;
}
return false;
}
void CApplication::UpdateLCD()
{
#ifdef HAS_LCD
static lTickCount = 0;
if (!g_lcd || g_guiSettings.GetInt("lcd.type") == LCD_TYPE_NONE)
return ;
long lTimeOut = 1000;
if ( m_iPlaySpeed != 1)
lTimeOut = 0;
if ( ((long)GetTickCount() - 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 = GetTickCount();
}
#endif
}
void CApplication::FrameMove()
{
// 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;
g_graphicsContext.Lock();
// check if there are notifications to display
if (m_guiDialogKaiToast.DoWork())
{
if (!m_guiDialogKaiToast.IsDialogRunning())
{
m_guiDialogKaiToast.Show();
}
}
g_graphicsContext.Unlock();
UpdateLCD();
// read raw input from controller, remote control, mouse and keyboard
ReadInput();
// process input actions
ProcessMouse();
ProcessHTTPApiButtons();
ProcessKeyboard();
ProcessRemote(frameTime);
ProcessGamepad(frameTime);
ProcessEventServer(frameTime);
g_windowManager.FrameMove();
}
bool CApplication::ProcessGamepad(float frameTime)
{
#ifdef HAS_GAMEPAD
// Handle the gamepad button presses. We check for button down,
// then call OnKey() which handles the translation to actions, and sends the
// action to our window manager's OnAction() function, which filters the messages
// to where they're supposed to end up, returning true if the message is successfully
// processed. If OnKey() returns false, then the key press wasn't processed at all,
// and we can safely process the next key (or next check on the same key in the
// case of the analog sticks which can produce more than 1 key event.)
WORD wButtons = m_DefaultGamepad.wButtons;
WORD wDpad = wButtons & (XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_RIGHT);
BYTE bLeftTrigger = m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER];
BYTE bRightTrigger = m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER];
BYTE bButtonA = m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_A];
BYTE bButtonB = m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_B];
BYTE bButtonX = m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_X];
BYTE bButtonY = m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_Y];
// pass them through the delay
WORD wDir = m_ctrDpad.DpadInput(wDpad, 0 != bLeftTrigger, 0 != bRightTrigger);
// map all controller & remote actions to their keys
if (m_DefaultGamepad.fX1 || m_DefaultGamepad.fY1)
{
CKey key(KEY_BUTTON_LEFT_THUMB_STICK, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.fX2 || m_DefaultGamepad.fY2)
{
CKey key(KEY_BUTTON_RIGHT_THUMB_STICK, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
// direction specific keys (for defining different actions for each direction)
// We need to be able to know when it last had a direction, so that we can
// post the reset direction code the next time around (to reset scrolling,
// fastforwarding and other analog actions)
// For the sticks, once it is pushed in one direction (eg up) it will only
// detect movement in that direction of movement (eg up or down) - the other
// direction (eg left and right) will not be registered until the stick has
// been recentered for at least 2 frames.
// first the right stick
static lastRightStickKey = 0;
int newRightStickKey = 0;
if (lastRightStickKey == KEY_BUTTON_RIGHT_THUMB_STICK_UP || lastRightStickKey == KEY_BUTTON_RIGHT_THUMB_STICK_DOWN)
{
if (m_DefaultGamepad.fY2 > 0)
newRightStickKey = KEY_BUTTON_RIGHT_THUMB_STICK_UP;
else if (m_DefaultGamepad.fY2 < 0)
newRightStickKey = KEY_BUTTON_RIGHT_THUMB_STICK_DOWN;
else if (m_DefaultGamepad.fX2 != 0)
{
newRightStickKey = KEY_BUTTON_RIGHT_THUMB_STICK_UP;
//m_DefaultGamepad.fY2 = 0.00001f; // small amount of movement
}
}
else if (lastRightStickKey == KEY_BUTTON_RIGHT_THUMB_STICK_LEFT || lastRightStickKey == KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT)
{
if (m_DefaultGamepad.fX2 > 0)
newRightStickKey = KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT;
else if (m_DefaultGamepad.fX2 < 0)
newRightStickKey = KEY_BUTTON_RIGHT_THUMB_STICK_LEFT;
else if (m_DefaultGamepad.fY2 != 0)
{
newRightStickKey = KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT;
//m_DefaultGamepad.fX2 = 0.00001f; // small amount of movement
}
}
else
{
if (m_DefaultGamepad.fY2 > 0 && m_DefaultGamepad.fX2*2 < m_DefaultGamepad.fY2 && -m_DefaultGamepad.fX2*2 < m_DefaultGamepad.fY2)
newRightStickKey = KEY_BUTTON_RIGHT_THUMB_STICK_UP;
else if (m_DefaultGamepad.fY2 < 0 && m_DefaultGamepad.fX2*2 < -m_DefaultGamepad.fY2 && -m_DefaultGamepad.fX2*2 < -m_DefaultGamepad.fY2)
newRightStickKey = KEY_BUTTON_RIGHT_THUMB_STICK_DOWN;
else if (m_DefaultGamepad.fX2 > 0 && m_DefaultGamepad.fY2*2 < m_DefaultGamepad.fX2 && -m_DefaultGamepad.fY2*2 < m_DefaultGamepad.fX2)
newRightStickKey = KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT;
else if (m_DefaultGamepad.fX2 < 0 && m_DefaultGamepad.fY2*2 < -m_DefaultGamepad.fX2 && -m_DefaultGamepad.fY2*2 < -m_DefaultGamepad.fX2)
newRightStickKey = KEY_BUTTON_RIGHT_THUMB_STICK_LEFT;
}
if (lastRightStickKey && newRightStickKey != lastRightStickKey)
{ // was held down last time - and we have a new key now
// post old key reset message...
CKey key(lastRightStickKey, 0, 0, 0, 0, 0, 0);
lastRightStickKey = newRightStickKey;
if (OnKey(key)) return true;
}
lastRightStickKey = newRightStickKey;
// post the new key's message
if (newRightStickKey)
{
CKey key(newRightStickKey, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
// now the left stick
static lastLeftStickKey = 0;
int newLeftStickKey = 0;
if (lastLeftStickKey == KEY_BUTTON_LEFT_THUMB_STICK_UP || lastLeftStickKey == KEY_BUTTON_LEFT_THUMB_STICK_DOWN)
{
if (m_DefaultGamepad.fY1 > 0)
newLeftStickKey = KEY_BUTTON_LEFT_THUMB_STICK_UP;
else if (m_DefaultGamepad.fY1 < 0)
newLeftStickKey = KEY_BUTTON_LEFT_THUMB_STICK_DOWN;
}
else if (lastLeftStickKey == KEY_BUTTON_LEFT_THUMB_STICK_LEFT || lastLeftStickKey == KEY_BUTTON_LEFT_THUMB_STICK_RIGHT)
{
if (m_DefaultGamepad.fX1 > 0)
newLeftStickKey = KEY_BUTTON_LEFT_THUMB_STICK_RIGHT;
else if (m_DefaultGamepad.fX1 < 0)
newLeftStickKey = KEY_BUTTON_LEFT_THUMB_STICK_LEFT;
}
else
{ // check for a new control movement
if (m_DefaultGamepad.fY1 > 0 && m_DefaultGamepad.fX1 < m_DefaultGamepad.fY1 && -m_DefaultGamepad.fX1 < m_DefaultGamepad.fY1)
newLeftStickKey = KEY_BUTTON_LEFT_THUMB_STICK_UP;
else if (m_DefaultGamepad.fY1 < 0 && m_DefaultGamepad.fX1 < -m_DefaultGamepad.fY1 && -m_DefaultGamepad.fX1 < -m_DefaultGamepad.fY1)
newLeftStickKey = KEY_BUTTON_LEFT_THUMB_STICK_DOWN;
else if (m_DefaultGamepad.fX1 > 0 && m_DefaultGamepad.fY1 < m_DefaultGamepad.fX1 && -m_DefaultGamepad.fY1 < m_DefaultGamepad.fX1)
newLeftStickKey = KEY_BUTTON_LEFT_THUMB_STICK_RIGHT;
else if (m_DefaultGamepad.fX1 < 0 && m_DefaultGamepad.fY1 < -m_DefaultGamepad.fX1 && -m_DefaultGamepad.fY1 < -m_DefaultGamepad.fX1)
newLeftStickKey = KEY_BUTTON_LEFT_THUMB_STICK_LEFT;
}
if (lastLeftStickKey && newLeftStickKey != lastLeftStickKey)
{ // was held down last time - and we have a new key now
// post old key reset message...
CKey key(lastLeftStickKey, 0, 0, 0, 0, 0, 0);
lastLeftStickKey = newLeftStickKey;
if (OnKey(key)) return true;
}
lastLeftStickKey = newLeftStickKey;
// post the new key's message
if (newLeftStickKey)
{
CKey key(newLeftStickKey, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
// Trigger detection
static lastTriggerKey = 0;
int newTriggerKey = 0;
if (bLeftTrigger)
newTriggerKey = KEY_BUTTON_LEFT_ANALOG_TRIGGER;
else if (bRightTrigger)
newTriggerKey = KEY_BUTTON_RIGHT_ANALOG_TRIGGER;
if (lastTriggerKey && newTriggerKey != lastTriggerKey)
{ // was held down last time - and we have a new key now
// post old key reset message...
CKey key(lastTriggerKey, 0, 0, 0, 0, 0, 0);
lastTriggerKey = newTriggerKey;
if (OnKey(key)) return true;
}
lastTriggerKey = newTriggerKey;
// post the new key's message
if (newTriggerKey)
{
CKey key(newTriggerKey, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
// Now the digital buttons...
if ( wDir & DC_LEFTTRIGGER)
{
CKey key(KEY_BUTTON_LEFT_TRIGGER, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if ( wDir & DC_RIGHTTRIGGER)
{
CKey key(KEY_BUTTON_RIGHT_TRIGGER, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if ( wDir & DC_LEFT )
{
CKey key(KEY_BUTTON_DPAD_LEFT, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if ( wDir & DC_RIGHT)
{
CKey key(KEY_BUTTON_DPAD_RIGHT, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if ( wDir & DC_UP )
{
CKey key(KEY_BUTTON_DPAD_UP, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if ( wDir & DC_DOWN )
{
CKey key(KEY_BUTTON_DPAD_DOWN, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_BACK )
{
CKey key(KEY_BUTTON_BACK, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_START)
{
CKey key(KEY_BUTTON_START, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_LEFT_THUMB)
{
CKey key(KEY_BUTTON_LEFT_THUMB_BUTTON, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_RIGHT_THUMB)
{
CKey key(KEY_BUTTON_RIGHT_THUMB_BUTTON, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_A])
{
CKey key(KEY_BUTTON_A, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_B])
{
CKey key(KEY_BUTTON_B, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_X])
{
CKey key(KEY_BUTTON_X, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_Y])
{
CKey key(KEY_BUTTON_Y, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK])
{
CKey key(KEY_BUTTON_BLACK, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
if (m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_WHITE])
{
CKey key(KEY_BUTTON_WHITE, bLeftTrigger, bRightTrigger, m_DefaultGamepad.fX1, m_DefaultGamepad.fY1, m_DefaultGamepad.fX2, m_DefaultGamepad.fY2, frameTime);
if (OnKey(key)) return true;
}
#endif
return false;
}
bool CApplication::ProcessRemote(float frameTime)
{
#ifdef HAS_IR_REMOTE
if (m_DefaultIR_Remote.wButtons)
{
// time depends on whether the movement is repeated (held down) or not.
// If it is, we use the FPS timer to get a repeatable speed.
// If it isn't, we use 20 to get repeatable jumps.
float time = (m_DefaultIR_Remote.bHeldDown) ? frameTime : 0.020f;
CKey key(m_DefaultIR_Remote.wButtons, 0, 0, 0, 0, 0, 0, time);
return OnKey(key);
}
#endif
return false;
}
bool CApplication::ProcessMouse()
{
if (!g_Mouse.IsActive())
return false;
// Reset the screensaver and idle timers
m_idleTimer.StartZero();
ResetScreenSaver();
if (ResetScreenSaverWindow())
return true;
int actionID = ACTION_MOUSE_MOVE;
if (g_Mouse.bClick[MOUSE_LEFT_BUTTON])
actionID = ACTION_MOUSE_LEFT_CLICK;
else if (g_Mouse.bClick[MOUSE_RIGHT_BUTTON])
actionID = ACTION_MOUSE_RIGHT_CLICK;
else if (g_Mouse.bClick[MOUSE_MIDDLE_BUTTON])
actionID = ACTION_MOUSE_MIDDLE_CLICK;
else if (g_Mouse.bDoubleClick[MOUSE_LEFT_BUTTON])
actionID = ACTION_MOUSE_DOUBLE_CLICK;
else if (g_Mouse.bHold[MOUSE_LEFT_BUTTON])
actionID = ACTION_MOUSE_DRAG;
else if (g_Mouse.GetWheel() > 0)
actionID = ACTION_MOUSE_WHEEL_UP;
else if (g_Mouse.GetWheel() < 0)
actionID = ACTION_MOUSE_WHEEL_DOWN;
CAction action(actionID, (unsigned int)g_Mouse.bHold[MOUSE_LEFT_BUTTON], g_Mouse.GetLocation().x, g_Mouse.GetLocation().y, g_Mouse.GetLastMove().x, g_Mouse.GetLastMove().y);
return g_windowManager.OnAction(action);
}
void CApplication::CheckForTitleChange()
{
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)
{
m_applicationMessenger.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().IsEmpty())
msg+=m_pXbmcHttp->GetOpenTag()+"AudioArtist:"+tagVal->GetArtist()+m_pXbmcHttp->GetCloseTag();
if (m_prevMedia!=msg)
{
m_applicationMessenger.HttpApi("broadcastlevel; MediaChanged:"+msg+";1");
m_prevMedia=msg;
}
}
}
}
}
bool CApplication::ProcessHTTPApiButtons()
{
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
{
g_Mouse.SetLocation(CPoint(keyHttp.GetLeftThumbX(), keyHttp.GetLeftThumbY()));
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());
g_windowManager.OnAction(action);
}
else
OnKey(keyHttp);
return true;
}
}
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();
ResetScreenSaverWindow();
}
// now handle any buttons or axis
std::string joystickName;
bool isAxis = false;
float fAmount = 0.0;
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);
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())
{
g_Mouse.SetLocation(pos, true);
return g_windowManager.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*/)
{
#ifdef HAS_EVENT_SERVER
m_idleTimer.StartZero();
// Make sure to reset screen saver, mouse.
ResetScreenSaver();
if (ResetScreenSaverWindow())
return true;
#ifdef HAS_SDL_JOYSTICK
g_Joystick.Reset();
#endif
g_Mouse.SetInactive();
// Figure out what window we're taking the event for.
int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
if (g_windowManager.HasModalDialog())
iWin = g_windowManager.GetTopMostModalDialogID() & WINDOW_ID_MASK;
// This code is copied from the OnKey handler, it should be factored out.
if (iWin == WINDOW_FULLSCREEN_VIDEO &&
g_application.m_pPlayer &&
g_application.m_pPlayer->IsInMenu())
{
// If player is in some sort of menu, (ie DVDMENU) map buttons differently.
iWin = WINDOW_VIDEO_MENU;
}
int actionID;
CStdString actionName;
bool fullRange = false;
// Translate using regular joystick translator.
if (CButtonTranslator::GetInstance().TranslateJoystickString(iWin, joystickName.c_str(), wKeyID, isAxis, actionID, actionName, fullRange))
{
CAction action(actionID, fAmount, 0.0f, actionName, holdTime);
bool bResult = false;
// play sound before the action unless the button is held,
// where we execute after the action as held actions aren't fired every time.
if(action.GetHoldTime())
{
bResult = OnAction(action);
if(bResult)
g_audioManager.PlayActionSound(action);
}
else
{
g_audioManager.PlayActionSound(action);
bResult = OnAction(action);
}
return bResult;
}
else
{
CLog::Log(LOGDEBUG, "ERROR mapping joystick action");
}
#endif
return false;
}
bool CApplication::ProcessKeyboard()
{
// process the keyboard buttons etc.
BYTE vkey = g_Keyboard.GetKey();
WCHAR unicode = g_Keyboard.GetUnicode();
if (vkey || unicode)
{
// got a valid keypress - convert to a key code
int keyID;
if (vkey) // FIXME, every ascii has a vkey so vkey would always and ascii would never be processed, but fortunately OnKey uses wkeyID only to detect keyboard use and the real key is recalculated correctly.
keyID = vkey | KEY_VKEY;
else
keyID = KEY_UNICODE;
// CLog::Log(LOGDEBUG,"Keyboard: time=%i key=%i", CTimeUtils::GetFrameTime(), vkey);
CKey key(keyID);
key.SetHeld(g_Keyboard.KeyHeld());
return OnKey(key);
}
return false;
}
bool CApplication::IsButtonDown(DWORD code)
{
#ifdef HAS_GAMEPAD
if (code >= KEY_BUTTON_A && code <= KEY_BUTTON_RIGHT_TRIGGER)
{
// analogue
return (m_DefaultGamepad.bAnalogButtons[code - KEY_BUTTON_A + XINPUT_GAMEPAD_A] > XINPUT_GAMEPAD_MAX_CROSSTALK);
}
else if (code >= KEY_BUTTON_DPAD_UP && code <= KEY_BUTTON_RIGHT_THUMB_BUTTON)
{
// digital
return (m_DefaultGamepad.wButtons & (1 << (code - KEY_BUTTON_DPAD_UP))) != 0;
}
else
{
// remote
return m_DefaultIR_Remote.wButtons == code;
}
#endif
return false;
}
bool CApplication::AnyButtonDown()
{
ReadInput();
#ifdef HAS_GAMEPAD
if (m_DefaultGamepad.wPressedButtons || m_DefaultIR_Remote.wButtons)
return true;
for (int i = 0; i < 6; ++i)
{
if (m_DefaultGamepad.bPressedAnalogButtons[i])
return true;
}
#endif
return false;
}
HRESULT 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_MUSIC_INFO);
g_windowManager.Delete(WINDOW_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_MUSIC_INFO);
g_windowManager.Delete(WINDOW_VIDEO_INFO);
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_MUSIC_OSD);
g_windowManager.Delete(WINDOW_DIALOG_VIS_SETTINGS);
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_TRAINER_SETTINGS);
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_PLUGIN_SETTINGS);
g_windowManager.Delete(WINDOW_DIALOG_SLIDER);
g_windowManager.Delete(WINDOW_DIALOG_TEXT_VIEWER);
g_windowManager.Delete(WINDOW_STARTUP_ANIM);
g_windowManager.Delete(WINDOW_LOGIN_SCREEN);
g_windowManager.Delete(WINDOW_VISUALISATION);
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_SCREEN_CALIBRATION);
g_windowManager.Delete(WINDOW_SYSTEM_INFORMATION);
g_windowManager.Delete(WINDOW_SCREENSAVER);
g_windowManager.Delete(WINDOW_OSD);
g_windowManager.Delete(WINDOW_MUSIC_OVERLAY);
g_windowManager.Delete(WINDOW_VIDEO_OVERLAY);
g_windowManager.Delete(WINDOW_SCRIPTS_INFO);
g_windowManager.Delete(WINDOW_SLIDESHOW);
g_windowManager.Delete(WINDOW_HOME);
g_windowManager.Delete(WINDOW_PROGRAMS);
g_windowManager.Delete(WINDOW_PICTURES);
g_windowManager.Delete(WINDOW_SCRIPTS);
g_windowManager.Delete(WINDOW_GAMESAVES);
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_NETWORK);
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);
CLog::Log(LOGNOTICE, "unload sections");
CSectionLoader::UnloadAll();
// reset our d3d params before we destroy
g_graphicsContext.SetD3DDevice(NULL);
g_graphicsContext.SetD3DParameters(NULL);
#ifdef _DEBUG
// 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
g_infoManager.Clear();
DllLoaderContainer::Clear();
g_playlistPlayer.Clear();
g_settings.Clear();
g_guiSettings.Clear();
g_advancedSettings.Clear();
#endif
#ifdef _CRTDBG_MAP_ALLOC
_CrtDumpMemoryLeaks();
while(1); // execution ends
#endif
return S_OK;
}
catch (...)
{
CLog::Log(LOGERROR, "Exception in CApplication::Cleanup()");
return E_FAIL;
}
}
void CApplication::Stop(bool bLCDStop)
{
try
{
if (m_pXbmcHttp)
{
if(g_settings.m_HttpApiBroadcastLevel>=1)
m_applicationMessenger.HttpApi("broadcastlevel; ShutDown;1");
m_pXbmcHttp->shuttingDown=true;
//Sleep(100);
}
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;
CLog::Log(LOGNOTICE, "stop all");
// stop scanning before we kill the network and so on
CGUIDialogMusicScan *musicScan = (CGUIDialogMusicScan *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_SCAN);
if (musicScan)
musicScan->StopScanning();
CGUIDialogVideoScan *videoScan = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
if (videoScan)
videoScan->StopScanning();
StopServices();
//Sleep(5000);
#ifdef __APPLE__
g_xbmcHelper.ReleaseAllInput();
#endif
if (m_pPlayer)
{
CLog::Log(LOGNOTICE, "stop player");
delete m_pPlayer;
m_pPlayer = NULL;
}
#ifdef HAS_FILESYSTEM
CLog::Log(LOGNOTICE, "stop daap clients");
g_DaapClient.Release();
#endif
//g_lcd->StopThread();
m_applicationMessenger.Cleanup();
CLog::Log(LOGNOTICE, "clean cached files!");
g_RarManager.ClearCache(true);
CLog::Log(LOGNOTICE, "unload skin");
UnloadSkin();
CLog::Log(LOGNOTICE, "stop python");
g_pythonParser.FreeResources();
#ifdef HAS_LCD
if (g_lcd && bLCDStop)
{
g_lcd->Stop();
delete g_lcd;
g_lcd=NULL;
}
#endif
CLog::Log(LOGNOTICE, "stopped");
}
catch (...)
{
CLog::Log(LOGERROR, "Exception in CApplication::Stop()");
}
Destroy();
}
bool CApplication::PlayMedia(const CFileItem& item, int iPlaylist)
{
if (item.IsLastFM())
{
g_partyModeManager.Disable();
return CLastFmManager::GetInstance()->ChangeStation(item.GetAsUrl());
}
if (item.IsSmartPlayList())
{
CDirectory dir;
CFileItemList items;
if (dir.GetDirectory(item.GetPath(), items) && 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())
{
//is or could be a playlist
auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(item));
if (pPlayList.get() && pPlayList->Load(item.GetPath()))
{
if (iPlaylist != PLAYLIST_NONE)
{
int track=0;
if (item.HasProperty("playlist_starting_track"))
track = item.GetPropertyInt("playlist_starting_track");
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;
// 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);
}
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.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 CFileTuxBox
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") )
{
options.startpercent = item.GetPropertyDouble("StartPercent");
}
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;
if(dbs.GetResumeBookMark(item.GetPath(), 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 (playlist == PLAYLIST_VIDEO && g_playlistPlayer.GetPlaylist(playlist).size() > 1)
{ // playing from a playlist by the looks
// don't switch to fullscreen if we are not playing the first item...
options.fullscreen = !g_playlistPlayer.HasPlayedFirstFile() && g_advancedSettings.m_fullScreenOnMovieStart && !g_settings.m_bStartVideoWindowed;
}
else if(m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
{
// TODO - this will fail if user seeks back to first file in stack
if(m_currentStackPosition == 0 || m_itemCurrentFile->m_lStartOffset == STARTOFFSET_RESUME)
options.fullscreen = g_advancedSettings.m_fullScreenOnMovieStart && !g_settings.m_bStartVideoWindowed;
else
options.fullscreen = false;
// reset this so we don't think we are resuming on seek
m_itemCurrentFile->m_lStartOffset = 0;
}
else
options.fullscreen = g_advancedSettings.m_fullScreenOnMovieStart && !g_settings.m_bStartVideoWindowed;
// reset m_bStartVideoWindowed as it's a temp setting
g_settings.m_bStartVideoWindowed = false;
// reset any forced player
m_eForcedNextPlayer = EPC_NONE;
#ifdef HAS_KARAOKE
//We have to stop parsing a cdg before mplayer is deallocated
// WHY do we have to do this????
if(m_pCdgParser)
m_pCdgParser->Stop();
#endif
// tell system we are starting a file
m_bPlaybackStarting = true;
// We should restart the player, unless the previous and next tracks are using
// one of the players that allows gapless playback (paplayer, dvdplayer)
if (m_pPlayer)
{
if ( !(m_eCurrentPlayer == eNewCore && (m_eCurrentPlayer == EPC_DVDPLAYER || m_eCurrentPlayer == EPC_PAPLAYER)) )
{
delete m_pPlayer;
m_pPlayer = NULL;
}
}
if (!m_pPlayer)
{
m_eCurrentPlayer = eNewCore;
m_pPlayer = CPlayerCoreFactory::CreatePlayer(eNewCore, *this);
}
bool bResult;
if (m_pPlayer)
{
// don't hold graphicscontext here since player
// may wait on another thread, that requires gfx
CSingleExit ex(g_graphicsContext);
bResult = m_pPlayer->OpenFile(item, options);
}
else
{
CLog::Log(LOGERROR, "Error creating player for item %s (File doesn't exist?)", item.GetPath().c_str());
bResult = false;
}
if(bResult)
{
if (m_iPlaySpeed != 1)
{
int iSpeed = m_iPlaySpeed;
m_iPlaySpeed = 1;
SetPlaySpeed(iSpeed);
}
if( IsPlayingAudio() )
{
if (g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
}
#ifdef HAS_VIDEO_PLAYBACK
if( IsPlayingVideo() )
{
if (g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION)
g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
// if player didn't manange to switch to fullscreen by itself do it here
if( options.fullscreen && g_renderManager.IsStarted()
&& g_windowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO )
SwitchToFullScreen();
if (!item.IsDVDImage() && !item.IsDVDFile())
{
CVideoInfoTag *details = m_itemCurrentFile->GetVideoInfoTag();
// Save information about the stream if we currently have no data
if (!details->HasStreamDetails() ||
details->m_streamDetails.GetVideoDuration() <= 0)
{
if (m_pPlayer->GetStreamDetails(details->m_streamDetails) && details->HasStreamDetails())
{
CVideoDatabase dbs;
dbs.Open();
dbs.SetStreamDetailsForFileId(details->m_streamDetails, details->m_iFileId);
dbs.Close();
CUtil::DeleteVideoDatabaseDirectoryCache();
}
}
}
}
#endif
g_audioManager.Enable(false);
}
m_bPlaybackStarting = false;
if(bResult)
{
// we must have started, otherwise player might send this later
if(IsPlaying())
OnPlayBackStarted();
else
OnPlayBackEnded();
}
else
{
// we send this if it isn't playlistplayer that is doing this
int next = g_playlistPlayer.GetNextSong();
int size = g_playlistPlayer.GetPlaylist(g_playlistPlayer.GetCurrentPlaylist()).size();
if(next < 0
|| next >= size)
OnPlayBackStopped();
}
return bResult;
}
void CApplication::OnPlayBackEnded()
{
if(m_bPlaybackStarting)
return;
// informs python script currently running playback has ended
// (does nothing if python is not loaded)
g_pythonParser.OnPlayBackEnded();
// Let's tell the outside world as well
if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
m_applicationMessenger.HttpApi("broadcastlevel; OnPlayBackEnded;1");
if (IsPlayingAudio())
{
CLastfmScrobbler::GetInstance()->SubmitQueue();
CLibrefmScrobbler::GetInstance()->SubmitQueue();
}
CLog::Log(LOGDEBUG, "%s - Playback has finished", __FUNCTION__);
CGUIMessage msg(GUI_MSG_PLAYBACK_ENDED, 0, 0);
g_windowManager.SendThreadMessage(msg);
}
void CApplication::OnPlayBackStarted()
{
if(m_bPlaybackStarting)
return;
// informs python script currently running playback has started
// (does nothing if python is not loaded)
g_pythonParser.OnPlayBackStarted();
// Let's tell the outside world as well
if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
m_applicationMessenger.HttpApi("broadcastlevel; OnPlayBackStarted;1");
CLog::Log(LOGDEBUG, "%s - Playback has started", __FUNCTION__);
CGUIMessage msg(GUI_MSG_PLAYBACK_STARTED, 0, 0);
g_windowManager.SendThreadMessage(msg);
}
void CApplication::OnQueueNextItem()
{
// informs python script currently running that we are requesting the next track
// (does nothing if python is not loaded)
g_pythonParser.OnQueueNextItem(); // currently unimplemented
// Let's tell the outside world as well
if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
m_applicationMessenger.HttpApi("broadcastlevel; OnQueueNextItem;1");
CLog::Log(LOGDEBUG, "Player has asked for the next item");
if(IsPlayingAudio())
{
CLastfmScrobbler::GetInstance()->SubmitQueue();
CLibrefmScrobbler::GetInstance()->SubmitQueue();
}
CGUIMessage msg(GUI_MSG_QUEUE_NEXT_ITEM, 0, 0);
g_windowManager.SendThreadMessage(msg);
}
void CApplication::OnPlayBackStopped()
{
if(m_bPlaybackStarting)
return;
// informs python script currently running playback has ended
// (does nothing if python is not loaded)
g_pythonParser.OnPlayBackStopped();
// Let's tell the outside world as well
if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
m_applicationMessenger.HttpApi("broadcastlevel; OnPlayBackStopped;1");
if (IsPlayingAudio())
{
CLastfmScrobbler::GetInstance()->SubmitQueue();
CLibrefmScrobbler::GetInstance()->SubmitQueue();
}
CLog::Log(LOGDEBUG, "%s - Playback was stopped", __FUNCTION__);
CGUIMessage msg( GUI_MSG_PLAYBACK_STOPPED, 0, 0 );
g_windowManager.SendThreadMessage(msg);
}
void CApplication::OnPlayBackPaused()
{
g_pythonParser.OnPlayBackPaused();
// Let's tell the outside world as well
if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
m_applicationMessenger.HttpApi("broadcastlevel; OnPlayBackPaused;1");
CLog::Log(LOGDEBUG, "%s - Playback was paused", __FUNCTION__);
}
void CApplication::OnPlayBackResumed()
{
g_pythonParser.OnPlayBackResumed();
// Let's tell the outside world as well
if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
m_applicationMessenger.HttpApi("broadcastlevel; OnPlayBackResumed;1");
CLog::Log(LOGDEBUG, "%s - Playback was resumed", __FUNCTION__);
}
void CApplication::OnPlayBackSpeedChanged(int iSpeed)
{
g_pythonParser.OnPlayBackSpeedChanged(iSpeed);
// Let's tell the outside world as well
if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
{
CStdString tmp;
tmp.Format("broadcastlevel; OnPlayBackSpeedChanged:%i;1",iSpeed);
m_applicationMessenger.HttpApi(tmp);
}
CLog::Log(LOGDEBUG, "%s - Playback speed changed", __FUNCTION__);
}
void CApplication::OnPlayBackSeek(int iTime, int seekOffset)
{
g_pythonParser.OnPlayBackSeek(iTime, seekOffset);
// Let's tell the outside world as well
if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
{
CStdString tmp;
tmp.Format("broadcastlevel; OnPlayBackSeek:%i;1",iTime);
m_applicationMessenger.HttpApi(tmp);
}
CLog::Log(LOGDEBUG, "%s - Playback skip", __FUNCTION__);
// g_infoManager.SetDisplayAfterSeek(2500, seekOffset/1000);
}
void CApplication::OnPlayBackSeekChapter(int iChapter)
{
g_pythonParser.OnPlayBackSeekChapter(iChapter);
// Let's tell the outside world as well
if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
{
CStdString tmp;
tmp.Format("broadcastlevel; OnPlayBackSkeekChapter:%i;1",iChapter);
m_applicationMessenger.HttpApi(tmp);
}
CLog::Log(LOGDEBUG, "%s - Playback skip", __FUNCTION__);
}
bool CApplication::IsPlaying() const
{
if (!m_pPlayer)
return false;
if (!m_pPlayer->IsPlaying())
return false;
return true;
}
bool CApplication::IsPaused() const
{
if (!m_pPlayer)
return false;
if (!m_pPlayer->IsPlaying())
return false;
return m_pPlayer->IsPaused();
}
bool CApplication::IsPlayingAudio() const
{
if (!m_pPlayer)
return false;
if (!m_pPlayer->IsPlaying())
return false;
if (m_pPlayer->HasVideo())
return false;
if (m_pPlayer->HasAudio())
return true;
return false;
}
bool CApplication::IsPlayingVideo() const
{
if (!m_pPlayer)
return false;
if (!m_pPlayer->IsPlaying())
return false;
if (m_pPlayer->HasVideo())
return true;
return false;
}
bool CApplication::IsPlayingFullScreenVideo() const
{
return IsPlayingVideo() && g_graphicsContext.IsFullScreenVideo();
}
void CApplication::SaveFileState()
{
CStdString progressTrackingFile = m_progressTrackingItem->GetPath();
if (progressTrackingFile != "")
{
if (m_progressTrackingItem->IsVideo())
{
CLog::Log(LOGDEBUG, "%s - Saving file state for video item %s", __FUNCTION__, progressTrackingFile.c_str());
CVideoDatabase videodatabase;
if (videodatabase.Open())
{
bool updateListing = false;
// No resume & watched status for livetv
if (!m_progressTrackingItem->IsLiveTV())
{
if (m_progressTrackingPlayCountUpdate)
{
CLog::Log(LOGDEBUG, "%s - Marking video item %s as watched", __FUNCTION__, progressTrackingFile.c_str());
// consider this item as played
videodatabase.IncrementPlayCount(*m_progressTrackingItem);
m_progressTrackingItem->GetVideoInfoTag()->m_playCount++;
m_progressTrackingItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, true);
updateListing = true;
}
if (m_progressTrackingVideoResumeBookmark.timeInSeconds < 0.0f)
{
videodatabase.ClearBookMarksOfFile(progressTrackingFile, CBookmark::RESUME);
}
else if (m_progressTrackingVideoResumeBookmark.timeInSeconds > 0.0f)
{
videodatabase.AddBookMarkToFile(progressTrackingFile, m_progressTrackingVideoResumeBookmark, CBookmark::RESUME);
}
}
if (g_settings.m_currentVideoSettings != g_settings.m_defaultVideoSettings)
{
videodatabase.SetVideoSettings(progressTrackingFile, g_settings.m_currentVideoSettings);
}
if ((m_progressTrackingItem->IsDVDImage() ||
m_progressTrackingItem->IsDVDFile() ) &&
m_progressTrackingItem->HasVideoInfoTag() &&
m_progressTrackingItem->GetVideoInfoTag()->HasStreamDetails())
{
videodatabase.SetStreamDetailsForFile(m_progressTrackingItem->GetVideoInfoTag()->m_streamDetails,progressTrackingFile);
updateListing = true;
}
videodatabase.Close();
if (updateListing)
{
CUtil::DeleteVideoDatabaseDirectoryCache();
// CFileItemPtr msgItem(new CFileItem(*m_progressTrackingItem));
// if (m_progressTrackingItem->HasProperty("original_listitem_url"))
// msgItem->SetPath(m_progressTrackingItem->GetProperty("original_listitem_url"));
CGUIMessage message(GUI_MSG_NOTIFY_ALL, g_windowManager.GetActiveWindow(), 0, GUI_MSG_UPDATE, 0);
// CGUIMessage message(GUI_MSG_NOTIFY_ALL, g_windowManager.GetActiveWindow(), 0, GUI_MSG_UPDATE_ITEM, 1, msgItem); // 1 to update the listing as well
g_windowManager.SendThreadMessage(message);
}
}
}
if (m_progressTrackingItem->IsAudio())
{
CLog::Log(LOGDEBUG, "%s - Saving file state for audio item %s", __FUNCTION__, progressTrackingFile.c_str());
if (m_progressTrackingPlayCountUpdate)
{
// Can't write to the musicdatabase while scanning for music info
CGUIDialogMusicScan *dialog = (CGUIDialogMusicScan *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_SCAN);
if (dialog && !dialog->IsDialogRunning())
{
// consider this item as played
CLog::Log(LOGDEBUG, "%s - Marking audio item %s as listened", __FUNCTION__, progressTrackingFile.c_str());
CMusicDatabase musicdatabase;
if (musicdatabase.Open())
{
musicdatabase.IncrTop100CounterByFileName(progressTrackingFile);
musicdatabase.Close();
}
}
}
}
}
}
void CApplication::UpdateFileState()
{
// Did the file change?
if (m_progressTrackingItem->GetPath() != "" && m_progressTrackingItem->GetPath() != CurrentFile())
{
SaveFileState();
// Reset tracking item
m_progressTrackingItem->Reset();
}
else
{
if (IsPlayingVideo() || IsPlayingAudio())
{
if (m_progressTrackingItem->GetPath() == "")
{
// Init some stuff
*m_progressTrackingItem = CurrentFileItem();
m_progressTrackingPlayCountUpdate = false;
}
if ((m_progressTrackingItem->IsAudio() && g_advancedSettings.m_audioPlayCountMinimumPercent > 0 &&
GetPercentage() >= g_advancedSettings.m_audioPlayCountMinimumPercent) ||
(m_progressTrackingItem->IsVideo() && g_advancedSettings.m_videoPlayCountMinimumPercent > 0 &&
GetPercentage() >= g_advancedSettings.m_videoPlayCountMinimumPercent))
{
m_progressTrackingPlayCountUpdate = true;
}
if (m_progressTrackingItem->IsVideo())
{
if ((m_progressTrackingItem->IsDVDImage() ||
m_progressTrackingItem->IsDVDFile() ) &&
m_pPlayer->GetTotalTime() > 15*60)
{
m_progressTrackingItem->GetVideoInfoTag()->m_streamDetails.Reset();
m_pPlayer->GetStreamDetails(m_progressTrackingItem->GetVideoInfoTag()->m_streamDetails);
}
// Update bookmark for save
m_progressTrackingVideoResumeBookmark.player = CPlayerCoreFactory::GetPlayerName(m_eCurrentPlayer);
m_progressTrackingVideoResumeBookmark.playerState = m_pPlayer->GetPlayerState();
m_progressTrackingVideoResumeBookmark.thumbNailImage.Empty();
if (g_advancedSettings.m_videoIgnorePercentAtEnd > 0 &&
GetTotalTime() - GetTime() < 0.01f * g_advancedSettings.m_videoIgnorePercentAtEnd * GetTotalTime())
{
// Delete the bookmark
m_progressTrackingVideoResumeBookmark.timeInSeconds = -1.0f;
}
else
if (GetTime() > g_advancedSettings.m_videoIgnoreSecondsAtStart)
{
// Update the bookmark
m_progressTrackingVideoResumeBookmark.timeInSeconds = GetTime();
m_progressTrackingVideoResumeBookmark.totalTimeInSeconds = GetTotalTime();
}
else
{
// Do nothing
m_progressTrackingVideoResumeBookmark.timeInSeconds = 0.0f;
}
}
}
}
}
void CApplication::StopPlaying()
{
int iWin = g_windowManager.GetActiveWindow();
if ( IsPlaying() )
{
#ifdef HAS_KARAOKE
if( m_pCdgParser )
m_pCdgParser->Stop();
#endif
if (m_pPlayer)
m_pPlayer->CloseFile();
// turn off visualisation window when stopping
if (iWin == WINDOW_VISUALISATION
|| iWin == WINDOW_FULLSCREEN_VIDEO)
g_windowManager.PreviousWindow();
g_partyModeManager.Disable();
}
}
bool CApplication::NeedRenderFullScreen()
{
if (g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
{
g_windowManager.UpdateModelessVisibility();
if (g_windowManager.HasDialogOnScreen()) return true;
if (g_Mouse.IsActive()) return true;
CGUIWindowFullScreen *pFSWin = (CGUIWindowFullScreen *)g_windowManager.GetWindow(WINDOW_FULLSCREEN_VIDEO);
if (!pFSWin)
return false;
return pFSWin->NeedRenderFullScreen();
}
return false;
}
void CApplication::RenderFullScreen()
{
g_ApplicationRenderer.Render(true);
}
void CApplication::DoRenderFullScreen()
{
if (g_graphicsContext.IsFullScreenVideo())
{
// make sure our overlays are closed
CGUIDialog *overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_VIDEO_OVERLAY);
if (overlay) overlay->Close(true);
overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_MUSIC_OVERLAY);
if (overlay) overlay->Close(true);
CGUIWindowFullScreen *pFSWin = (CGUIWindowFullScreen *)g_windowManager.GetWindow(WINDOW_FULLSCREEN_VIDEO);
if (!pFSWin)
return ;
pFSWin->RenderFullScreen();
if (g_windowManager.HasDialogOnScreen())
g_windowManager.RenderDialogs();
// Render the mouse pointer, if visible...
if (g_Mouse.IsActive())
g_application.m_guiPointer.Render();
}
}
void CApplication::ResetScreenSaver()
{
// reset our timers
m_shutdownTimer.StartZero();
// screen saver timer is reset only if we're not already in screensaver mode
if (!m_bScreenSave && m_iScreenSaveLock == 0)
m_screenSaverTimer.StartZero();
}
bool CApplication::ResetScreenSaverWindow()
{
if (m_iScreenSaveLock == 2)
return false;
// if Screen saver is active
if (m_bScreenSave)
{
if (m_iScreenSaveLock == 0)
if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE &&
(g_settings.UsingLoginScreen() || g_guiSettings.GetBool("masterlock.startuplock")) &&
g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE &&
m_screenSaverMode != "Dim" && m_screenSaverMode != "Black" && m_screenSaverMode != "Visualisation")
{
m_iScreenSaveLock = 2;
CGUIMessage msg(GUI_MSG_CHECK_LOCK,0,0);
g_windowManager.GetWindow(WINDOW_SCREENSAVER)->OnMessage(msg);
}
if (m_iScreenSaveLock == -1)
{
m_iScreenSaveLock = 0;
return true;
}
// disable screensaver
m_bScreenSave = false;
m_iScreenSaveLock = 0;
m_screenSaverTimer.StartZero();
float fFadeLevel = 1.0f;
if (m_screenSaverMode == "Visualisation" || m_screenSaverMode == "Slideshow" || m_screenSaverMode == "Fanart Slideshow")
{
// we can just continue as usual from vis mode
return false;
}
else if (m_screenSaverMode == "Dim")
{
fFadeLevel = (float)g_guiSettings.GetInt("screensaver.dimlevel") / 100;
}
else if (m_screenSaverMode == "Black")
{
fFadeLevel = 0;
}
else if (m_screenSaverMode != "None")
{ // we're in screensaver window
if (g_windowManager.GetActiveWindow() == WINDOW_SCREENSAVER)
g_windowManager.PreviousWindow(); // show the previous window
return true;
}
// Fade to dim or black screensaver is active --> fade in
D3DGAMMARAMP Ramp;
for (float fade = fFadeLevel; fade <= 1; fade += 0.01f)
{
for (int i = 0;i < 256;i++)
{
Ramp.red[i] = (int)((float)m_OldRamp.red[i] * fade);
Ramp.green[i] = (int)((float)m_OldRamp.green[i] * fade);
Ramp.blue[i] = (int)((float)m_OldRamp.blue[i] * fade);
}
Sleep(5);
m_pd3dDevice->SetGammaRamp(GAMMA_RAMP_FLAG, &Ramp); // use immediate to get a smooth fade
}
m_pd3dDevice->SetGammaRamp(0, &m_OldRamp); // put the old gamma ramp back in place
return true;
}
else
return false;
}
void CApplication::CheckScreenSaver()
{
// if the screen saver window is active, then clearly we are already active
if (g_windowManager.IsWindowActive(WINDOW_SCREENSAVER))
{
m_bScreenSave = true;
return;
}
bool resetTimer = false;
if (IsPlayingVideo() && !m_pPlayer->IsPaused()) // are we playing video and it is not paused?
resetTimer = true;
if (IsPlayingAudio() && g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION) // are we playing some music in fullscreen vis?
resetTimer = true;
if (resetTimer)
{
m_screenSaverTimer.StartZero();
return;
}
if (m_bScreenSave) // already running the screensaver
return;
if ( m_screenSaverTimer.GetElapsedSeconds() > g_guiSettings.GetInt("screensaver.time") * 60 )
ActivateScreenSaver();
}
// activate the screensaver.
// if forceType is true, we ignore the various conditions that can alter
// the type of screensaver displayed
void CApplication::ActivateScreenSaver(bool forceType /*= false */)
{
D3DGAMMARAMP Ramp;
FLOAT fFadeLevel = 0;
m_bScreenSave = true;
// Get Screensaver Mode
m_screenSaverMode = g_guiSettings.GetString("screensaver.mode");
// disable screensaver lock from the login screen
m_iScreenSaveLock = g_windowManager.GetActiveWindow() == WINDOW_LOGIN_SCREEN ? 1 : 0;
if (!forceType)
{
// set to Dim in the case of a dialog on screen or playing video
if (g_windowManager.HasModalDialog() || (IsPlayingVideo() && g_guiSettings.GetBool("screensaver.usedimonpause")))
m_screenSaverMode = "Dim";
// Check if we are Playing Audio and Vis instead Screensaver!
else if (IsPlayingAudio() && g_guiSettings.GetBool("screensaver.usemusicvisinstead") && g_guiSettings.GetString("musicplayer.visualisation") != "None")
{ // activate the visualisation
m_screenSaverMode = "Visualisation";
g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
return;
}
}
// Picture slideshow
if (m_screenSaverMode == "SlideShow" || m_screenSaverMode == "Fanart Slideshow")
{
// reset our codec info - don't want that on screen
g_infoManager.SetShowCodec(false);
m_applicationMessenger.PictureSlideShow(g_guiSettings.GetString("screensaver.slideshowpath"), true);
return;
}
else if (m_screenSaverMode == "Dim")
{
fFadeLevel = (FLOAT) g_guiSettings.GetInt("screensaver.dimlevel") / 100; // 0.07f;
}
else if (m_screenSaverMode == "Black")
{
fFadeLevel = 0;
}
else if (m_screenSaverMode != "None")
{
g_windowManager.ActivateWindow(WINDOW_SCREENSAVER);
return ;
}
// Fade to fFadeLevel
m_pd3dDevice->GetGammaRamp(&m_OldRamp); // Store the old gamma ramp
for (float fade = 1.f; fade >= fFadeLevel; fade -= 0.01f)
{
for (int i = 0;i < 256;i++)
{
Ramp.red[i] = (int)((float)m_OldRamp.red[i] * fade);
Ramp.green[i] = (int)((float)m_OldRamp.green[i] * fade);
Ramp.blue[i] = (int)((float)m_OldRamp.blue[i] * fade);
}
Sleep(5);
m_pd3dDevice->SetGammaRamp(GAMMA_RAMP_FLAG, &Ramp); // use immediate to get a smooth fade
}
}
void CApplication::CheckShutdown()
{
#ifdef HAS_XBOX_HARDWARE
CGUIDialogMusicScan *pMusicScan = (CGUIDialogMusicScan *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_SCAN);
CGUIDialogVideoScan *pVideoScan = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
// first check if we should reset the timer
bool resetTimer = false;
if (IsPlaying()) // is something playing?
resetTimer = true;
#ifdef HAS_FTP_SERVER
if (m_pFileZilla && m_pFileZilla->GetNoConnections() != 0) // is FTP active ?
resetTimer = true;
#endif
if (pMusicScan && pMusicScan->IsScanning()) // music scanning?
resetTimer = true;
if (pVideoScan && pVideoScan->IsScanning()) // video scanning?
resetTimer = true;
if (g_windowManager.IsWindowActive(WINDOW_DIALOG_PROGRESS)) // progress dialog is onscreen
resetTimer = true;
if (resetTimer)
{
m_shutdownTimer.StartZero();
return;
}
if ( m_shutdownTimer.GetElapsedSeconds() > g_guiSettings.GetInt("system.shutdowntime") * 60 )
{
m_applicationMessenger.Shutdown(); // Turn off the box
}
#endif
}
//Check if hd spindown must be blocked
bool CApplication::MustBlockHDSpinDown(bool bCheckThisForNormalSpinDown)
{
#ifdef HAS_XBOX_HARDWARE
if (IsPlayingVideo())
{
//block immediate spindown when playing a video non-fullscreen (videocontrol is playing)
if ((!bCheckThisForNormalSpinDown) && (!g_graphicsContext.IsFullScreenVideo()))
{
return true;
}
//allow normal hd spindown always if the movie is paused
if ((bCheckThisForNormalSpinDown) && (m_pPlayer->IsPaused()))
{
return false;
}
//don't allow hd spindown when playing files with vobsub subtitles.
CStdString strSubTitelExtension;
if (m_pPlayer->GetSubtitleExtension(strSubTitelExtension))
{
return (strSubTitelExtension == ".idx");
}
}
#endif
return false;
}
void CApplication::CheckNetworkHDSpinDown(bool playbackStarted)
{
int iSpinDown = g_guiSettings.GetInt("harddisk.remoteplayspindown");
if (iSpinDown == SPIN_DOWN_NONE)
return ;
if (g_windowManager.HasModalDialog())
return ;
if (MustBlockHDSpinDown(false))
return ;
if ((!m_bNetworkSpinDown) || playbackStarted)
{
int iDuration = 0;
if (IsPlayingAudio())
{
//try to get duration from current tag because mplayer doesn't calculate vbr mp3 correctly
if (m_itemCurrentFile->HasMusicInfoTag())
iDuration = m_itemCurrentFile->GetMusicInfoTag()->GetDuration();
}
if (IsPlaying() && iDuration <= 0)
{
iDuration = (int)GetTotalTime();
}
//spin down harddisk when the current file being played is not on local harddrive and
//duration is more then spindown timeoutsetting or duration is unknown (streams)
if (
!m_itemCurrentFile->IsHD() &&
(
(iSpinDown == SPIN_DOWN_VIDEO && IsPlayingVideo()) ||
(iSpinDown == SPIN_DOWN_MUSIC && IsPlayingAudio()) ||
(iSpinDown == SPIN_DOWN_BOTH && (IsPlayingVideo() || IsPlayingAudio()))
) &&
(
(iDuration <= 0) ||
(iDuration > g_guiSettings.GetInt("harddisk.remoteplayspindownminduration")*60)
)
)
{
m_bNetworkSpinDown = true;
if (!playbackStarted)
{ //if we got here not because of a playback start check what screen we are in
// get the current active window
int iWin = g_windowManager.GetActiveWindow();
if (iWin == WINDOW_FULLSCREEN_VIDEO)
{
// check if OSD is visible, if so don't do immediate spindown
CGUIWindowOSD *pOSD = (CGUIWindowOSD *)g_windowManager.GetWindow(WINDOW_OSD);
if (pOSD)
m_bNetworkSpinDown = !pOSD->IsDialogRunning();
}
}
if (m_bNetworkSpinDown)
{
//do the spindown right now + delayseconds
m_dwSpinDownTime = timeGetTime();
}
}
}
if (m_bNetworkSpinDown)
{
// check the elapsed time
DWORD dwTimeSpan = timeGetTime() - m_dwSpinDownTime;
if ( (m_dwSpinDownTime != 0) && (dwTimeSpan >= ((DWORD)g_guiSettings.GetInt("harddisk.remoteplayspindowndelay")*1000UL)) )
{
// time has elapsed, spin it down
#ifdef HAS_XBOX_HARDWARE
XKHDD::SpindownHarddisk();
#endif
//stop checking until a key is pressed.
m_dwSpinDownTime = 0;
m_bNetworkSpinDown = true;
}
else if (m_dwSpinDownTime == 0 && IsPlaying())
{
// we are currently spun down - let's spin back up again if we are playing media
// and we're within 10 seconds (or 0.5*spindown time) of the end. This should
// make returning to the GUI a bit snappier + speed up stacked item changes.
int iMinSpinUp = 10;
if (iMinSpinUp > g_guiSettings.GetInt("harddisk.remoteplayspindowndelay")*0.5f)
iMinSpinUp = (int)(g_guiSettings.GetInt("harddisk.remoteplayspindowndelay")*0.5f);
if (g_infoManager.GetPlayTimeRemaining() == iMinSpinUp)
{ // spin back up
#ifdef HAS_XBOX_HARDWARE
XKHDD::SpindownHarddisk(false);
#endif
}
}
}
}
void CApplication::CheckHDSpindown()
{
if (!g_guiSettings.GetInt("harddisk.spindowntime"))
return ;
if (g_windowManager.HasModalDialog())
return ;
if (MustBlockHDSpinDown())
return ;
if (!m_bSpinDown &&
(
!IsPlaying() ||
(IsPlaying() && !m_itemCurrentFile->IsHD())
)
)
{
m_bSpinDown = true;
m_bNetworkSpinDown = false; // let networkspindown override normal spindown
m_dwSpinDownTime = timeGetTime();
}
//Can we do a spindown right now?
if (m_bSpinDown)
{
// yes, then check the elapsed time
DWORD dwTimeSpan = timeGetTime() - m_dwSpinDownTime;
if ( (m_dwSpinDownTime != 0) && (dwTimeSpan >= ((DWORD)g_guiSettings.GetInt("harddisk.spindowntime")*60UL*1000UL)) )
{
// time has elapsed, spin it down
#ifdef HAS_XBOX_HARDWARE
XKHDD::SpindownHarddisk();
#endif
//stop checking until a key is pressed.
m_dwSpinDownTime = 0;
m_bSpinDown = true;
}
}
}
bool CApplication::OnMessage(CGUIMessage& message)
{
switch ( message.GetMessage() )
{
case GUI_MSG_NOTIFY_ALL:
{
if (message.GetParam1()==GUI_MSG_REMOVED_MEDIA)
{
// Update general playlist: Remove DVD playlist items
int nRemoved = g_playlistPlayer.RemoveDVDItems();
if ( nRemoved > 0 )
{
CGUIMessage msg( GUI_MSG_PLAYLIST_CHANGED, 0, 0 );
g_windowManager.SendMessage( msg );
}
// stop the file if it's on dvd (will set the resume point etc)
if (m_itemCurrentFile->IsOnDVD())
StopPlaying();
}
}
break;
case GUI_MSG_PLAYBACK_STARTED:
{
// Update our infoManager with the new details etc.
if (m_nextPlaylistItem >= 0)
{ // we've started a previously queued item
CFileItemPtr item = g_playlistPlayer.GetPlaylist(g_playlistPlayer.GetCurrentPlaylist())[m_nextPlaylistItem];
// update the playlist manager
int currentSong = g_playlistPlayer.GetCurrentSong();
int param = ((currentSong & 0xffff) << 16) | (m_nextPlaylistItem & 0xffff);
CGUIMessage msg(GUI_MSG_PLAYLISTPLAYER_CHANGED, 0, 0, g_playlistPlayer.GetCurrentPlaylist(), param, item);
g_windowManager.SendThreadMessage(msg);
g_playlistPlayer.SetCurrentSong(m_nextPlaylistItem);
*m_itemCurrentFile = *item;
}
g_infoManager.SetCurrentItem(*m_itemCurrentFile);
CLastFmManager::GetInstance()->OnSongChange(*m_itemCurrentFile);
g_partyModeManager.OnSongChange(true);
CheckNetworkHDSpinDown(true);
StartLEDControl(true);
DimLCDOnPlayback(true);
if (IsPlayingAudio())
{
// Start our cdg parser as appropriate
#ifdef HAS_KARAOKE
if (m_pCdgParser && g_guiSettings.GetBool("karaoke.enabled") && !m_itemCurrentFile->IsInternetStream())
{
if (m_pCdgParser->IsRunning())
m_pCdgParser->Stop();
if (m_itemCurrentFile->IsMusicDb())
{
if (!m_itemCurrentFile->HasMusicInfoTag() || !m_itemCurrentFile->GetMusicInfoTag()->Loaded())
{
IMusicInfoTagLoader* tagloader = CMusicInfoTagLoaderFactory::CreateLoader(m_itemCurrentFile->GetPath());
tagloader->Load(m_itemCurrentFile->GetPath(),*m_itemCurrentFile->GetMusicInfoTag());
delete tagloader;
}
m_pCdgParser->Start(m_itemCurrentFile->GetMusicInfoTag()->GetURL());
}
else
m_pCdgParser->Start(m_itemCurrentFile->GetPath());
}
#endif
// Let scrobbler know about the track
const CMusicInfoTag* tag=g_infoManager.GetCurrentSongTag();
if (tag)
{
CLastfmScrobbler::GetInstance()->AddSong(*tag, CLastFmManager::GetInstance()->IsRadioEnabled());
CLibrefmScrobbler::GetInstance()->AddSong(*tag, CLastFmManager::GetInstance()->IsRadioEnabled());
}
}
return true;
}
break;
case GUI_MSG_QUEUE_NEXT_ITEM:
{
// Check to see if our playlist player has a new item for us,
// and if so, we check whether our current player wants the file
int iNext = g_playlistPlayer.GetNextSong();
CPlayList& playlist = g_playlistPlayer.GetPlaylist(g_playlistPlayer.GetCurrentPlaylist());
if (iNext < 0 || iNext >= playlist.size())
{
if (m_pPlayer) m_pPlayer->OnNothingToQueueNotify();
return true; // nothing to do
}
// ok, grab the next song
CFileItemPtr item = playlist[iNext];
// ok - send the file to the player if it wants it
if (m_pPlayer && m_pPlayer->QueueNextFile(*item))
{ // player wants the next file
m_nextPlaylistItem = iNext;
}
return true;
}
break;
case GUI_MSG_PLAYBACK_STOPPED:
case GUI_MSG_PLAYBACK_ENDED:
case GUI_MSG_PLAYLISTPLAYER_STOPPED:
{
// first check if we still have items in the stack to play
if (message.GetMessage() == GUI_MSG_PLAYBACK_ENDED)
{
if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0 && m_currentStackPosition < m_currentStack->Size() - 1)
{ // just play the next item in the stack
PlayFile(*(*m_currentStack)[++m_currentStackPosition], true);
return true;
}
}
// In case playback ended due to user eg. skipping over the end, clear
// our resume bookmark here
if (message.GetMessage() == GUI_MSG_PLAYBACK_ENDED && m_progressTrackingPlayCountUpdate && g_advancedSettings.m_videoIgnorePercentAtEnd > 0)
{
// Delete the bookmark
m_progressTrackingVideoResumeBookmark.timeInSeconds = -1.0f;
}
// reset our spindown
m_bNetworkSpinDown = false;
m_bSpinDown = false;
// reset the current playing file
m_itemCurrentFile->Reset();
g_infoManager.ResetCurrentItem();
m_currentStack->Clear();
// stop lastfm
if (CLastFmManager::GetInstance()->IsRadioEnabled())
CLastFmManager::GetInstance()->StopRadio();
if (message.GetMessage() == GUI_MSG_PLAYBACK_ENDED)
{
// sending true to PlayNext() effectively passes bRestart to PlayFile()
// which is not generally what we want (except for stacks, which are
// handled above)
g_playlistPlayer.PlayNext();
}
else
{
delete m_pPlayer;
m_pPlayer = 0;
}
if (!IsPlaying())
{
g_audioManager.Enable(true);
StartLEDControl(false);
DimLCDOnPlayback(false);
#ifdef HAS_KARAOKE
if(m_pCdgParser)
m_pCdgParser->Free();
#endif
}
if (!IsPlayingVideo() && g_windowManager.GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO)
{
g_windowManager.PreviousWindow();
}
if (!IsPlayingAudio() && g_playlistPlayer.GetCurrentPlaylist() == PLAYLIST_NONE && g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION)
{
g_settings.Save(); // save vis settings
ResetScreenSaverWindow();
g_windowManager.PreviousWindow();
}
// DVD ejected while playing in vis ?
if (!IsPlayingAudio() && (m_itemCurrentFile->IsCDDA() || m_itemCurrentFile->IsOnDVD()) && !CDetectDVDMedia::IsDiscInDrive() && g_windowManager.GetActiveWindow() == WINDOW_VISUALISATION)
{
// yes, disable vis
g_settings.Save(); // save vis settings
ResetScreenSaverWindow();
g_windowManager.PreviousWindow();
}
return true;
}
break;
case GUI_MSG_PLAYLISTPLAYER_STARTED:
case GUI_MSG_PLAYLISTPLAYER_CHANGED:
{
return true;
}
break;
case GUI_MSG_FULLSCREEN:
{ // Switch to fullscreen, if we can
SwitchToFullScreen();
return true;
}
break;
case GUI_MSG_EXECUTE:
if (message.GetStringParam().length() > 0)
return ExecuteXBMCAction(message.GetStringParam());
break;
}
return false;
}
bool CApplication::ExecuteXBMCAction(std::string actionStr)
{
// see if it is a user set string
CLog::Log(LOGDEBUG,"%s : Translating %s", __FUNCTION__, actionStr.c_str());
CGUIInfoLabel info(actionStr, "");
actionStr = info.GetLabel(0);
CLog::Log(LOGDEBUG,"%s : To %s", __FUNCTION__, actionStr.c_str());
// user has asked for something to be executed
if (CBuiltins::HasCommand(actionStr))
CBuiltins::Execute(actionStr);
else
{
// try translating the action from our ButtonTranslator
int actionID;
if (CButtonTranslator::TranslateActionString(actionStr.c_str(), actionID))
{
OnAction(CAction(actionID));
return true;
}
CFileItem item(actionStr, false);
if (item.IsPythonScript())
{ // a python script
unsigned int argc = 1;
char ** argv = new char*[argc];
argv[0] = (char*)item.GetPath().c_str();
g_pythonParser.evalFile(argv[0], argc, (const char**)argv);
delete [] argv;
}
else if (item.IsXBE())
{ // an XBE
int iRegion;
if (g_guiSettings.GetBool("myprograms.gameautoregion"))
{
CXBE xbe;
iRegion = xbe.ExtractGameRegion(item.GetPath());
if (iRegion < 1 || iRegion > 7)
iRegion = 0;
iRegion = xbe.FilterRegion(iRegion);
}
else
iRegion = 0;
CUtil::RunXBE(item.GetPath().c_str(),NULL,F_VIDEO(iRegion));
}
else if (item.IsAudio() || item.IsVideo())
{ // an audio or video file
PlayFile(item);
}
else
return false;
}
return true;
}
void CApplication::Process()
{
// check if we need to load a new skin
if (m_skinReloadTime && CTimeUtils::GetFrameTime() >= m_skinReloadTime)
{
ReloadSkin();
}
// dispatch the messages generated by python or other threads to the current window
g_windowManager.DispatchThreadMessages();
// process messages which have to be send to the gui
// (this can only be done after g_windowManager.Render())
m_applicationMessenger.ProcessWindowMessages();
// process any Python scripts
g_pythonParser.Process();
// process messages, even if a movie is playing
m_applicationMessenger.ProcessMessages();
// check for memory unit changes
#ifdef HAS_XBOX_HARDWARE
if (g_memoryUnitManager.Update())
{ // changes have occured - update our shares
CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_REMOVED_MEDIA);
g_windowManager.SendThreadMessage(msg);
}
#endif
// check if we can free unused memory
g_audioManager.FreeUnused();
// check how far we are through playing the current item
// and do anything that needs doing (lastfm submission, playcount updates etc)
CheckPlayingProgress();
// update sound
if (m_pPlayer)
m_pPlayer->DoAudioWork();
// process karaoke
#ifdef HAS_KARAOKE
if (m_pCdgParser)
m_pCdgParser->ProcessVoice();
#endif
// do any processing that isn't needed on each run
if( m_slowTimer.GetElapsedMilliseconds() > 500 )
{
m_slowTimer.Reset();
ProcessSlow();
}
}
// We get called every 500ms
void CApplication::ProcessSlow()
{
// check our network state every 15 seconds or when net status changes
m_network.CheckNetwork(30);
// check if we need 2 spin down the harddisk
CheckNetworkHDSpinDown();
if (!m_bNetworkSpinDown)
CheckHDSpindown();
// Store our file state for use on close()
UpdateFileState();
if (IsPlayingAudio())
{
CLastfmScrobbler::GetInstance()->UpdateStatus();
CLibrefmScrobbler::GetInstance()->UpdateStatus();
}
// Check if we need to activate the screensaver (if enabled).
if (g_guiSettings.GetString("screensaver.mode") != "None")
CheckScreenSaver();
// check if we need to shutdown (if enabled)
if (g_guiSettings.GetInt("system.shutdowntime"))
CheckShutdown();
// check if we should restart the player
CheckDelayedPlayerRestart();
// check if we can unload any unreferenced dlls or sections
if (!IsPlayingVideo())
CSectionLoader::UnloadDelayed();
// Xbox Autodetection - Send in X sec PingTime Interval
if (g_windowManager.GetActiveWindow() != WINDOW_LOGIN_SCREEN) // sorry jm ;D
CUtil::AutoDetection();
// check for any idle curl connections
g_curlInterface.CheckIdle();
// check for any idle myth sessions
CMythSession::CheckIdle();
#ifdef HAS_FILESYSTEM
// check for any idle htsp sessions
HTSP::CHTSPDirectorySession::CheckIdle();
#endif
#ifdef HAS_TIME_SERVER
// check for any needed sntp update
if(m_psntpClient && m_psntpClient->UpdateNeeded())
m_psntpClient->Update();
#endif
// LED - LCD SwitchOn On Paused! m_bIsPaused=TRUE -> LED/LCD is ON!
if(IsPaused() != m_bIsPaused)
{
if(g_guiSettings.GetBool("system.ledenableonpaused"))
StartLEDControl(m_bIsPaused);
if(g_guiSettings.GetBool("lcd.enableonpaused"))
DimLCDOnPlayback(m_bIsPaused);
m_bIsPaused = IsPaused();
}
if (!IsPlayingVideo())
g_largeTextureManager.CleanupUnusedImages();
// checks whats in the DVD drive and tries to autostart the content (xbox games, dvd, cdda, avi files...)
if (!IsPlayingVideo())
m_Autorun.HandleAutorun();
// update upnp server/renderer states
if(CUPnP::IsInstantiated())
CUPnP::GetInstance()->UpdateState();
//Check to see if current playing Title has changed and whether we should broadcast the fact
CheckForTitleChange();
}
// Global Idle Time in Seconds
// idle time will be resetet if on any OnKey()
// int return: system Idle time in seconds! 0 is no idle!
int CApplication::GlobalIdleTime()
{
if(!m_idleTimer.IsRunning())
{
m_idleTimer.Stop();
m_idleTimer.StartZero();
}
return (int)m_idleTimer.GetElapsedSeconds();
}
float CApplication::NavigationIdleTime()
{
if (!m_navigationTimer.IsRunning())
{
m_navigationTimer.Stop();
m_navigationTimer.StartZero();
}
return m_navigationTimer.GetElapsedSeconds();
}
void CApplication::DelayedPlayerRestart()
{
m_restartPlayerTimer.StartZero();
}
void CApplication::CheckDelayedPlayerRestart()
{
if (m_restartPlayerTimer.GetElapsedSeconds() > 3)
{
m_restartPlayerTimer.Stop();
m_restartPlayerTimer.Reset();
Restart(true);
}
}
void CApplication::Restart(bool bSamePosition)
{
// this function gets called when the user changes a setting (like noninterleaved)
// and which means we gotta close & reopen the current playing file
// first check if we're playing a file
if ( !IsPlayingVideo() && !IsPlayingAudio())
return ;
if( !m_pPlayer )
return ;
SaveFileState();
// do we want to return to the current position in the file
if (false == bSamePosition)
{
// no, then just reopen the file and start at the beginning
PlayFile(*m_itemCurrentFile, true);
return ;
}
// else get current position
double time = GetTime();
// get player state, needed for dvd's
CStdString state = m_pPlayer->GetPlayerState();
// set the requested starttime
m_itemCurrentFile->m_lStartOffset = (long)(time * 75.0);
// reopen the file
if ( PlayFile(*m_itemCurrentFile, true) && m_pPlayer )
m_pPlayer->SetPlayerState(state);
}
const CStdString& CApplication::CurrentFile()
{
return m_itemCurrentFile->GetPath();
}
CFileItem& CApplication::CurrentFileItem()
{
return *m_itemCurrentFile;
}
void CApplication::Mute(void)
{
if (g_settings.m_bMute)
{ // muted - unmute.
// In case our premutevolume is 0, return to 100% volume
if( g_settings.m_iPreMuteVolumeLevel == 0 )
{
SetVolume(100);
}
else
{
SetVolume(g_settings.m_iPreMuteVolumeLevel);
g_settings.m_iPreMuteVolumeLevel = 0;
}
m_guiDialogVolumeBar.Show();
}
else
{ // mute
g_settings.m_iPreMuteVolumeLevel = GetVolume();
SetVolume(0);
}
}
void CApplication::SetVolume(int iPercent)
{
// convert the percentage to a mB (milliBell) value (*100 for dB)
long hardwareVolume = (long)((float)iPercent * 0.01f * (VOLUME_MAXIMUM - VOLUME_MINIMUM) + VOLUME_MINIMUM);
SetHardwareVolume(hardwareVolume);
g_audioManager.SetVolume(g_settings.m_nVolumeLevel);
}
void CApplication::SetHardwareVolume(long hardwareVolume)
{
// TODO DRC
if (hardwareVolume >= VOLUME_MAXIMUM) // + VOLUME_DRC_MAXIMUM
hardwareVolume = VOLUME_MAXIMUM;// + VOLUME_DRC_MAXIMUM;
if (hardwareVolume <= VOLUME_MINIMUM)
{
hardwareVolume = VOLUME_MINIMUM;
}
// update our settings
if (hardwareVolume > VOLUME_MAXIMUM)
{
g_settings.m_dynamicRangeCompressionLevel = hardwareVolume - VOLUME_MAXIMUM;
g_settings.m_nVolumeLevel = VOLUME_MAXIMUM;
}
else
{
g_settings.m_dynamicRangeCompressionLevel = 0;
g_settings.m_nVolumeLevel = hardwareVolume;
}
// update mute state
if(!g_settings.m_bMute && hardwareVolume <= VOLUME_MINIMUM)
{
g_settings.m_bMute = true;
if (!m_guiDialogMuteBug.IsDialogRunning())
m_guiDialogMuteBug.Show();
}
else if(g_settings.m_bMute && hardwareVolume > VOLUME_MINIMUM)
{
g_settings.m_bMute = false;
if (m_guiDialogMuteBug.IsDialogRunning())
m_guiDialogMuteBug.Close();
}
// and tell our player to update the volume
if (m_pPlayer)
{
m_pPlayer->SetVolume(g_settings.m_nVolumeLevel);
// TODO DRC
// m_pPlayer->SetDynamicRangeCompression(g_settings.m_dynamicRangeCompressionLevel);
}
}
int CApplication::GetVolume() const
{
// converts the hardware volume (in mB) to a percentage
return int(((float)(g_settings.m_nVolumeLevel + g_settings.m_dynamicRangeCompressionLevel - VOLUME_MINIMUM)) / (VOLUME_MAXIMUM - VOLUME_MINIMUM)*100.0f + 0.5f);
}
int CApplication::GetSubtitleDelay() const
{
// converts subtitle delay to a percentage
return int(((float)(g_settings.m_currentVideoSettings.m_SubtitleDelay + g_advancedSettings.m_videoSubsDelayRange)) / (2 * g_advancedSettings.m_videoSubsDelayRange)*100.0f + 0.5f);
}
int CApplication::GetAudioDelay() const
{
// converts subtitle delay to a percentage
return int(((float)(g_settings.m_currentVideoSettings.m_AudioDelay + g_advancedSettings.m_videoAudioDelayRange)) / (2 * g_advancedSettings.m_videoAudioDelayRange)*100.0f + 0.5f);
}
void CApplication::SetPlaySpeed(int iSpeed)
{
if (!IsPlayingAudio() && !IsPlayingVideo())
return ;
if (m_iPlaySpeed == iSpeed)
return ;
if (!m_pPlayer->CanSeek())
return;
if (m_pPlayer->IsPaused())
{
if (
((m_iPlaySpeed > 1) && (iSpeed > m_iPlaySpeed)) ||
((m_iPlaySpeed < -1) && (iSpeed < m_iPlaySpeed))
)
{
iSpeed = m_iPlaySpeed; // from pause to ff/rw, do previous ff/rw speed
}
m_pPlayer->Pause();
}
m_iPlaySpeed = iSpeed;
m_pPlayer->ToFFRW(m_iPlaySpeed);
if (m_iPlaySpeed == 1)
{ // restore volume
m_pPlayer->SetVolume(g_settings.m_nVolumeLevel);
}
else
{ // mute volume
m_pPlayer->SetVolume(VOLUME_MINIMUM);
}
}
int CApplication::GetPlaySpeed() const
{
return m_iPlaySpeed;
}
// Returns the total time in seconds of the current media. Fractional
// portions of a second are possible - but not necessarily supported by the
// player class. This returns a double to be consistent with GetTime() and
// SeekTime().
double CApplication::GetTotalTime() const
{
double rc = 0.0;
if (IsPlaying() && m_pPlayer)
{
if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
rc = (*m_currentStack)[m_currentStack->Size() - 1]->m_lEndOffset;
else
rc = m_pPlayer->GetTotalTime();
}
return rc;
}
void CApplication::ResetPlayTime()
{
if (IsPlaying() && m_pPlayer)
m_pPlayer->ResetTime();
}
// Returns the current time in seconds of the currently playing media.
// Fractional portions of a second are possible. This returns a double to
// be consistent with GetTotalTime() and SeekTime().
double CApplication::GetTime() const
{
double rc = 0.0;
if (IsPlaying() && m_pPlayer)
{
if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
{
long startOfCurrentFile = (m_currentStackPosition > 0) ? (*m_currentStack)[m_currentStackPosition-1]->m_lEndOffset : 0;
rc = (double)startOfCurrentFile + m_pPlayer->GetTime() * 0.001;
}
else
rc = static_cast<double>(m_pPlayer->GetTime() * 0.001f);
}
return rc;
}
// Sets the current position of the currently playing media to the specified
// time in seconds. Fractional portions of a second are valid. The passed
// time is the time offset from the beginning of the file as opposed to a
// delta from the current position. This method accepts a double to be
// consistent with GetTime() and GetTotalTime().
void CApplication::SeekTime( double dTime )
{
if (IsPlaying() && m_pPlayer && (dTime >= 0.0))
{
if (!m_pPlayer->CanSeek()) return;
if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
{
// find the item in the stack we are seeking to, and load the new
// file if necessary, and calculate the correct seek within the new
// file. Otherwise, just fall through to the usual routine if the
// time is higher than our total time.
for (int i = 0; i < m_currentStack->Size(); i++)
{
if ((*m_currentStack)[i]->m_lEndOffset > dTime)
{
long startOfNewFile = (i > 0) ? (*m_currentStack)[i-1]->m_lEndOffset : 0;
if (m_currentStackPosition == i)
m_pPlayer->SeekTime((__int64)((dTime - startOfNewFile) * 1000.0));
else
{ // seeking to a new file
m_currentStackPosition = i;
CFileItem item(*(*m_currentStack)[i]);
item.m_lStartOffset = (long)((dTime - startOfNewFile) * 75.0);
// don't just call "PlayFile" here, as we are quite likely called from the
// player thread, so we won't be able to delete ourselves.
m_applicationMessenger.PlayFile(item, true);
}
return;
}
}
}
// convert to milliseconds and perform seek
m_pPlayer->SeekTime( static_cast<__int64>( dTime * 1000.0 ) );
}
}
float CApplication::GetPercentage() const
{
if (IsPlaying() && m_pPlayer)
{
if (IsPlayingAudio() && m_itemCurrentFile->HasMusicInfoTag())
{
const CMusicInfoTag& tag = *m_itemCurrentFile->GetMusicInfoTag();
if (tag.GetDuration() > 0)
return (float)(GetTime() / tag.GetDuration() * 100);
}
if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
return (float)(GetTime() / GetTotalTime() * 100);
else
return m_pPlayer->GetPercentage();
}
return 0.0f;
}
float CApplication::GetCachePercentage() const
{
if (IsPlaying() && m_pPlayer)
{
// Note that the player returns a relative cache percentage and we want an absolute percentage
// We also need to take into account the stack's total time vs. currently playing file's total time
float stackedTotalTime = (float) GetTotalTime();
if (stackedTotalTime > 0.0f)
return min( 100.0f, GetPercentage() + (m_pPlayer->GetCachePercentage() * m_pPlayer->GetTotalTime() / stackedTotalTime ) );
}
return 0.0f;
}
void CApplication::SeekPercentage(float percent)
{
if (IsPlaying() && m_pPlayer && (percent >= 0.0))
{
if (!m_pPlayer->CanSeek()) return;
if (m_itemCurrentFile->IsStack() && m_currentStack->Size() > 0)
SeekTime(percent * 0.01 * GetTotalTime());
else
m_pPlayer->SeekPercentage(percent);
}
}
// SwitchToFullScreen() returns true if a switch is made, else returns false
bool CApplication::SwitchToFullScreen()
{
// if playing from the video info window, close it first!
if (g_windowManager.HasModalDialog() && g_windowManager.GetTopMostModalDialogID() == WINDOW_VIDEO_INFO)
{
CGUIWindowVideoInfo* pDialog = (CGUIWindowVideoInfo*)g_windowManager.GetWindow(WINDOW_VIDEO_INFO);
if (pDialog) pDialog->Close(true);
}
// don't switch if there is a dialog on screen or the slideshow is active
if (g_windowManager.HasModalDialog() || g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW)
return false;
// See if we're playing a video, and are in GUI mode
if ( IsPlayingVideo() && g_windowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO)
{
// then switch to fullscreen mode
g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO);
g_TextureManager.Flush();
return true;
}
// special case for switching between GUI & visualisation mode. (only if we're playing an audio song)
if (IsPlayingAudio() && g_windowManager.GetActiveWindow() != WINDOW_VISUALISATION)
{ // then switch to visualisation
g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
g_TextureManager.Flush();
return true;
}
return false;
}
PLAYERCOREID CApplication::GetCurrentPlayer()
{
return m_eCurrentPlayer;
}
// when a scan is initiated, save current settings
// and enable tag reading and remote thums
void CApplication::SaveMusicScanSettings()
{
CLog::Log(LOGINFO,"Music scan has started... Enabling tag reading, and remote thumbs");
g_settings.m_bMyMusicIsScanning = true;
g_settings.Save();
}
void CApplication::RestoreMusicScanSettings()
{
g_settings.m_bMyMusicIsScanning = false;
g_settings.Save();
}
void CApplication::UpdateLibraries()
{
if (g_guiSettings.GetBool("videolibrary.updateonstartup"))
{
CLog::Log(LOGNOTICE, "%s - Starting video library startup scan", __FUNCTION__);
CGUIDialogVideoScan *scanner = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
SScraperInfo info;
VIDEO::SScanSettings settings;
if (scanner && !scanner->IsScanning())
scanner->StartScanning("",info,settings,false);
}
if (g_guiSettings.GetBool("musiclibrary.updateonstartup"))
{
CLog::Log(LOGNOTICE, "%s - Starting music library startup scan", __FUNCTION__);
CGUIDialogMusicScan *scanner = (CGUIDialogMusicScan *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_SCAN);
if (scanner && !scanner->IsScanning())
scanner->StartScanning("");
}
}
void CApplication::CheckPlayingProgress()
{
// check if we haven't rewound past the start of the file
if (IsPlaying())
{
int iSpeed = g_application.GetPlaySpeed();
if (iSpeed < 1)
{
iSpeed *= -1;
int iPower = 0;
while (iSpeed != 1)
{
iSpeed >>= 1;
iPower++;
}
if (g_infoManager.GetPlayTime() / 1000 < iPower)
{
g_application.SetPlaySpeed(1);
g_application.SeekTime(0);
}
}
}
}
bool CApplication::ProcessAndStartPlaylist(const CStdString& strPlayList, CPlayList& playlist, int iPlaylist, int track)
{
CLog::Log(LOGDEBUG,"CApplication::ProcessAndStartPlaylist(%s, %i)",strPlayList.c_str(), iPlaylist);
// initial exit conditions
// no songs in playlist just return
if (playlist.size() == 0)
return false;
// illegal playlist
if (iPlaylist < PLAYLIST_MUSIC || iPlaylist > PLAYLIST_VIDEO)
return false;
// setup correct playlist
g_playlistPlayer.ClearPlaylist(iPlaylist);
// if the playlist contains an internet stream, this file will be used
// to generate a thumbnail for musicplayer.cover
g_application.m_strPlayListFile = strPlayList;
// add the items to the playlist player
g_playlistPlayer.Add(iPlaylist, playlist);
// if we have a playlist
if (g_playlistPlayer.GetPlaylist(iPlaylist).size())
{
// start playing it
g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
g_playlistPlayer.Reset();
g_playlistPlayer.Play(track);
return true;
}
return false;
}
void CApplication::CheckForDebugButtonCombo()
{
#ifdef HAS_GAMEPAD
ReadInput();
if (m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_X] && m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_Y])
{
g_advancedSettings.m_logLevel = LOG_LEVEL_DEBUG_FREEMEM;
CLog::SetLogLevel(g_advancedSettings.m_logLevel);
CLog::Log(LOGINFO, "Key combination detected for full debug logging (X+Y)");
}
#ifdef _DEBUG
g_advancedSettings.m_logLevel = LOG_LEVEL_DEBUG_FREEMEM;
#endif
#endif
}
void CApplication::StartFtpEmergencyRecoveryMode()
{
#ifdef HAS_FTP_SERVER
m_pFileZilla = new CXBFileZilla(NULL);
m_pFileZilla->Start();
// Default settings
m_pFileZilla->mSettings.SetMaxUsers(0);
m_pFileZilla->mSettings.SetWelcomeMessage("XBMC emergency recovery console FTP.");
// default user
CXFUser* pUser;
m_pFileZilla->AddUser("xbox", pUser);
pUser->SetPassword("xbox");
pUser->SetShortcutsEnabled(false);
pUser->SetUseRelativePaths(false);
pUser->SetBypassUserLimit(false);
pUser->SetUserLimit(0);
pUser->SetIPLimit(0);
pUser->AddDirectory("/", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS | XBDIR_HOME);
pUser->AddDirectory("C:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
pUser->AddDirectory("D:\\", XBFILE_READ | XBDIR_LIST | XBDIR_SUBDIRS);
pUser->AddDirectory("E:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
pUser->AddDirectory("Q:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
//Add existing extended partitions
if (CIoSupport::DriveExists('F')){
pUser->AddDirectory("F:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
}
if (CIoSupport::DriveExists('G')){
pUser->AddDirectory("G:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
}
if (CIoSupport::DriveExists('R')){
pUser->AddDirectory("R:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
}
if (CIoSupport::DriveExists('S')){
pUser->AddDirectory("S:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
}
if (CIoSupport::DriveExists('V')){
pUser->AddDirectory("V:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
}
if (CIoSupport::DriveExists('W')){
pUser->AddDirectory("W:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
}
if (CIoSupport::DriveExists('A')){
pUser->AddDirectory("A:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
}
if (CIoSupport::DriveExists('B')){
pUser->AddDirectory("B:\\", XBFILE_READ | XBFILE_WRITE | XBFILE_DELETE | XBFILE_APPEND | XBDIR_DELETE | XBDIR_CREATE | XBDIR_LIST | XBDIR_SUBDIRS);
}
pUser->CommitChanges();
#endif
}
void CApplication::SaveCurrentFileSettings()
{
if (m_itemCurrentFile->IsVideo())
{
// save video settings
if (g_settings.m_currentVideoSettings != g_settings.m_defaultVideoSettings)
{
CVideoDatabase dbs;
dbs.Open();
dbs.SetVideoSettings(m_itemCurrentFile->GetPath(), g_settings.m_currentVideoSettings);
dbs.Close();
}
}
}
CApplicationMessenger& CApplication::getApplicationMessenger()
{
return m_applicationMessenger;
}
CNetwork& CApplication::getNetwork()
{
return m_network;
}
bool CApplication::IsCurrentThread() const
{
return CThread::IsCurrentThread(m_threadID);
}
void CApplication::InitDirectoriesXbox()
{
// Set installation path. Use Q as ie. F doesn't exist yet!!!
CStdString install_path = "Q:\\";
// check logpath
CStdString strLogFile, strLogFileOld;
g_settings.m_logFolder = install_path;
URIUtils::AddSlashAtEnd(g_settings.m_logFolder);
strLogFile.Format("%sxbmc.log", g_settings.m_logFolder);
strLogFileOld.Format("%sxbmc.old.log", g_settings.m_logFolder);
// Rotate the log (xbmc.log -> xbmc.old.log)
::DeleteFile(strLogFileOld.c_str());
::MoveFile(strLogFile.c_str(), strLogFileOld.c_str());
// map our special drives to the correct drive letter
CSpecialProtocol::SetXBMCPath(install_path);
CSpecialProtocol::SetHomePath(install_path);
CSpecialProtocol::SetTempPath("Z:\\");
// First profile is always the Master Profile
CSpecialProtocol::SetMasterProfilePath("Q:\\UserData");
g_settings.LoadProfiles(PROFILES_FILE);
}