mirror of
https://github.com/Team-Resurgent/XBMC4Xbox.git
synced 2026-08-15 11:18:13 -07:00
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
5848 lines
189 KiB
C++
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);
|
|
}
|