//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
# if defined( USE_SDL )
# undef PROTECTED_THINGS_ENABLE
# include "SDL.h"
# include "SDL_syswm.h"
# if defined( OSX )
# define DONT_DEFINE_BOOL
# include <objc/message.h>
# endif
# endif
# if defined( WIN32 ) && !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
# include "winlite.h"
# include "xbox/xboxstubs.h"
# endif
# if defined( IS_WINDOWS_PC ) && !defined( USE_SDL )
# include <winsock.h>
# elif defined(_X360)
// nothing to include for 360
# elif defined(OSX)
# elif defined(LINUX) || defined(PLATFORM_BSD)
# include "tier0/dynfunction.h"
# elif defined(_WIN32)
# include "tier0/dynfunction.h"
# else
# error
# endif
# include "appframework/ilaunchermgr.h"
# include "igame.h"
# include "cl_main.h"
# include "host.h"
# include "quakedef.h"
# include "tier0/vcrmode.h"
# include "tier0/icommandline.h"
# include "ivideomode.h"
# include "gl_matsysiface.h"
# include "cdll_engine_int.h"
# include "vgui_baseui_interface.h"
# include "iengine.h"
# include "keys.h"
# include "VGuiMatSurface/IMatSystemSurface.h"
# include "tier3/tier3.h"
# include "sound.h"
# include "vgui_controls/Controls.h"
# include "vgui_controls/MessageDialog.h"
# include "sys_dll.h"
# include "inputsystem/iinputsystem.h"
# include "inputsystem/ButtonCode.h"
# ifdef WIN32
# undef WIN32_LEAN_AND_MEAN
# include "unicode/unicode.h"
# endif
# include "GameUI/IGameUI.h"
# include "matchmaking.h"
# include "sv_main.h"
# include "video/ivideoservices.h"
# include "sys.h"
# include "materialsystem/imaterial.h"
# if defined( _X360 )
# include "xbox/xbox_win32stubs.h"
# include "hl2orange.spa.h"
# endif
# if defined( LINUX )
# include "snd_dev_sdl.h"
# endif
# ifdef DBGFLAG_ASSERT
# define AssertExit( _exp ) Assert( _exp )
# define AssertExitF( _exp ) Assert( _exp )
# else
# define AssertExit( _exp ) if ( !( _exp ) ) return;
# define AssertExitF( _exp ) if ( !( _exp ) ) return false;
# endif
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
void S_BlockSound ( void ) ;
void S_UnblockSound ( void ) ;
void ClearIOStates ( void ) ;
//-----------------------------------------------------------------------------
// Game input events
//-----------------------------------------------------------------------------
enum GameInputEventType_t
{
IE_Close = IE_FirstAppEvent ,
IE_WindowMove ,
IE_AppActivated ,
} ;
# ifdef WIN32
static IUnicodeWindows * unicode = NULL ;
# endif
//-----------------------------------------------------------------------------
// Purpose: Main game interface, including message pump and window creation
//-----------------------------------------------------------------------------
class CGame : public IGame
{
public :
CGame ( void ) ;
virtual ~ CGame ( void ) ;
bool Init ( void * pvInstance ) ;
bool Shutdown ( void ) ;
bool CreateGameWindow ( void ) ;
void DestroyGameWindow ( ) ;
void SetGameWindow ( void * hWnd ) ;
// This is used in edit mode to override the default wnd proc associated w/
bool InputAttachToGameWindow ( ) ;
void InputDetachFromGameWindow ( ) ;
void PlayStartupVideos ( void ) ;
// This is the SDL_Window* under SDL, HWND otherwise.
void * GetMainWindow ( void ) ;
// This will be the HWND under D3D + Windows (both with and without SDL), SDL_Window* everywhere else.
void * GetMainDeviceWindow ( void ) ;
// This will be the HWND under Windows, the WindowRef under Mac, and (for now) NULL on Linux
void * GetMainWindowPlatformSpecificHandle ( void ) ;
void * * GetMainWindowAddress ( void ) ;
void GetDesktopInfo ( int & width , int & height , int & refreshrate ) ;
void SetWindowXY ( int x , int y ) ;
void SetWindowSize ( int w , int h ) ;
void GetWindowRect ( int * x , int * y , int * w , int * h ) ;
bool IsActiveApp ( void ) ;
void SetCanPostActivateEvents ( bool bEnable ) ;
bool CanPostActivateEvents ( ) ;
public :
# ifdef USE_SDL
void SetMainWindow ( SDL_Window * window ) ;
# else
# ifdef WIN32
LRESULT WindowProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam ) ;
# endif
void SetMainWindow ( HWND window ) ;
# endif
void SetActiveApp ( bool active ) ;
bool LoadUnicode ( ) ;
void UnloadUnicode ( ) ;
// Message handlers.
public :
void HandleMsg_WindowMove ( const InputEvent_t & event ) ;
void HandleMsg_ActivateApp ( const InputEvent_t & event ) ;
void HandleMsg_Close ( const InputEvent_t & event ) ;
// Call the appropriate HandleMsg_ function.
void DispatchInputEvent ( const InputEvent_t & event ) ;
// Dispatch all the queued up messages.
virtual void DispatchAllStoredGameMessages ( ) ;
private :
void AppActivate ( bool fActive ) ;
void PlayVideoAndWait ( const char * filename , bool bNeedHealthWarning = false ) ; // plays a video file and waits till it's done to return. Can be interrupted by user.
private :
void AttachToWindow ( ) ;
void DetachFromWindow ( ) ;
# ifndef _X360
static const wchar_t CLASSNAME [ ] ;
# else
static const char CLASSNAME [ ] ;
# endif
bool m_bExternallySuppliedWindow ;
# if defined( WIN32 )
HWND m_hWindow ;
# if !defined( USE_SDL )
HINSTANCE m_hInstance ;
// Stores a wndproc to chain message calls to
WNDPROC m_ChainedWindowProc ;
RECT m_rcLastRestoredClientRect ;
# endif
# endif
# if defined( USE_SDL )
SDL_Window * m_pSDLWindow ;
# endif
int m_x ;
int m_y ;
int m_width ;
int m_height ;
bool m_bActiveApp ;
CSysModule * m_hUnicodeModule ;
bool m_bCanPostActivateEvents ;
int m_iDesktopWidth , m_iDesktopHeight , m_iDesktopRefreshRate ;
void UpdateDesktopInformation ( ) ;
# ifdef WIN32
void UpdateDesktopInformation ( WPARAM wParam , LPARAM lParam ) ;
# endif
} ;
static CGame g_Game ;
IGame * game = ( IGame * ) & g_Game ;
# if !defined( _X360 )
const wchar_t CGame : : CLASSNAME [ ] = L " Valve001 " ;
# else
const char CGame : : CLASSNAME [ ] = " Valve001 " ;
# endif
// In VCR playback mode, it sleeps this amount each frame.
int g_iVCRPlaybackSleepInterval = 0 ;
// During VCR playback, if this is true, then it'll pause at the end of each frame.
bool g_bVCRSingleStep = false ;
bool g_bWaitingForStepKeyUp = false ; // Used to prevent it from running frames while you hold the S key down.
bool g_bShowVCRPlaybackDisplay = true ;
// These are all the windows messages that can change game state.
// See CGame::WindowProc for a description of how they work.
struct GameMessageHandler_t
{
int m_nEventType ;
void ( CGame : : * pFn ) ( const InputEvent_t & event ) ;
} ;
GameMessageHandler_t g_GameMessageHandlers [ ] =
{
{ IE_AppActivated , & CGame : : HandleMsg_ActivateApp } ,
{ IE_WindowMove , & CGame : : HandleMsg_WindowMove } ,
{ IE_Close , & CGame : : HandleMsg_Close } ,
{ IE_Quit , & CGame : : HandleMsg_Close } ,
} ;
void CGame : : AppActivate ( bool fActive )
{
// If text mode, force it to be active.
if ( g_bTextMode )
{
fActive = true ;
}
// Don't bother if we're already in the correct state
if ( IsActiveApp ( ) = = fActive )
return ;
// Don't let video modes changes queue up another activate event
SetCanPostActivateEvents ( false ) ;
# ifndef SWDS
if ( videomode )
{
if ( fActive )
{
videomode - > RestoreVideo ( ) ;
}
else
{
videomode - > ReleaseVideo ( ) ;
}
}
if ( host_initialized )
{
if ( fActive )
{
// Clear keyboard states (should be cleared already but...)
// VGui_ActivateMouse will reactivate the mouse soon.
ClearIOStates ( ) ;
UpdateMaterialSystemConfig ( ) ;
}
else
{
// Clear keyboard input and deactivate the mouse while we're away.
ClearIOStates ( ) ;
if ( g_ClientDLL )
{
g_ClientDLL - > IN_DeactivateMouse ( ) ;
}
}
}
# endif // SWDS
SetActiveApp ( fActive ) ;
# ifdef _XBOX
if ( host_initialized )
{
ClearIOStates ( ) ;
if ( fActive )
{
UpdateMaterialSystemConfig ( ) ;
}
}
SetActiveApp ( fActive ) ;
# endif
// Allow queueing of activation events
SetCanPostActivateEvents ( true ) ;
}
void CGame : : HandleMsg_WindowMove ( const InputEvent_t & event )
{
game - > SetWindowXY ( event . m_nData , event . m_nData2 ) ;
# ifndef SWDS
videomode - > UpdateWindowPosition ( ) ;
# endif
}
void CGame : : HandleMsg_ActivateApp ( const InputEvent_t & event )
{
AppActivate ( event . m_nData ? true : false ) ;
}
void CGame : : HandleMsg_Close ( const InputEvent_t & event )
{
if ( eng - > GetState ( ) = = IEngine : : DLL_ACTIVE )
{
eng - > SetQuitting ( IEngine : : QUIT_TODESKTOP ) ;
}
}
void CGame : : DispatchInputEvent ( const InputEvent_t & event )
{
switch ( event . m_nType )
{
// Handle button events specially,
// since we have all manner of crazy filtering going on when dealing with them
case IE_ButtonPressed :
case IE_ButtonDoubleClicked :
case IE_ButtonReleased :
Key_Event ( event ) ;
break ;
case IE_FingerDown :
case IE_FingerUp :
case IE_FingerMotion :
if ( g_ClientDLL )
g_ClientDLL - > IN_TouchEvent ( event . m_nType , event . m_nData , event . m_nData2 , event . m_nData3 ) ;
default :
// Let vgui have the first whack at events
if ( g_pMatSystemSurface & & g_pMatSystemSurface - > HandleInputEvent ( event ) )
break ;
for ( int i = 0 ; i < ARRAYSIZE ( g_GameMessageHandlers ) ; i + + )
{
if ( g_GameMessageHandlers [ i ] . m_nEventType = = event . m_nType )
{
( this - > * g_GameMessageHandlers [ i ] . pFn ) ( event ) ;
break ;
}
}
break ;
}
}
void CGame : : DispatchAllStoredGameMessages ( )
{
# if !defined( NO_VCR )
if ( VCRGetMode ( ) = = VCR_Playback )
{
InputEvent_t event ;
while ( VCRHook_PlaybackGameMsg ( & event ) )
{
event . m_nTick = g_pInputSystem - > GetPollTick ( ) ;
DispatchInputEvent ( event ) ;
}
}
else
{
int nEventCount = g_pInputSystem - > GetEventCount ( ) ;
const InputEvent_t * pEvents = g_pInputSystem - > GetEventData ( ) ;
for ( int i = 0 ; i < nEventCount ; + + i )
{
VCRHook_RecordGameMsg ( pEvents [ i ] ) ;
DispatchInputEvent ( pEvents [ i ] ) ;
}
VCRHook_RecordEndGameMsg ( ) ;
}
# else
int nEventCount = g_pInputSystem - > GetEventCount ( ) ;
const InputEvent_t * pEvents = g_pInputSystem - > GetEventData ( ) ;
for ( int i = 0 ; i < nEventCount ; + + i )
{
DispatchInputEvent ( pEvents [ i ] ) ;
}
# endif
}
void VCR_EnterPausedState ( )
{
// Turn this off in case they're in single-step mode.
g_bVCRSingleStep = false ;
# ifdef WIN32
// This is cheesy, but GetAsyncKeyState is blocked (in protected_things.h)
// from being accidentally used, so we get it through it by getting its pointer directly.
static HINSTANCE hInst = LoadLibrary ( " user32.dll " ) ;
if ( ! hInst )
return ;
typedef SHORT ( WINAPI * GetAsyncKeyStateFn ) ( int vKey ) ;
static GetAsyncKeyStateFn pfn = ( GetAsyncKeyStateFn ) GetProcAddress ( hInst , " GetAsyncKeyState " ) ;
if ( ! pfn )
return ;
// In this mode, we enter a wait state where we only pay attention to R and Q.
while ( 1 )
{
if ( pfn ( ' R ' ) & 0x8000 )
break ;
if ( pfn ( ' Q ' ) & 0x8000 )
TerminateProcess ( GetCurrentProcess ( ) , 1 ) ;
if ( pfn ( ' S ' ) & 0x8000 )
{
if ( ! g_bWaitingForStepKeyUp )
{
// Do a single step.
g_bVCRSingleStep = true ;
g_bWaitingForStepKeyUp = true ; // Don't do another single step until they release the S key.
break ;
}
}
else
{
// Ok, they released the S key, so we'll process it next time the key goes down.
g_bWaitingForStepKeyUp = false ;
}
Sleep ( 2 ) ;
}
# else
Assert ( ! " Impl me " ) ;
# endif
}
# ifdef WIN32
void VCR_HandlePlaybackMessages (
HWND hWnd ,
UINT uMsg ,
WPARAM wParam ,
LPARAM lParam
)
{
if ( uMsg = = WM_KEYDOWN )
{
if ( wParam = = VK_SUBTRACT | | wParam = = 0xbd )
{
g_iVCRPlaybackSleepInterval + = 5 ;
}
else if ( wParam = = VK_ADD | | wParam = = 0xbb )
{
g_iVCRPlaybackSleepInterval - = 5 ;
}
else if ( toupper ( wParam ) = = ' Q ' )
{
TerminateProcess ( GetCurrentProcess ( ) , 1 ) ;
}
else if ( toupper ( wParam ) = = ' P ' )
{
VCR_EnterPausedState ( ) ;
}
else if ( toupper ( wParam ) = = ' S ' & & ! g_bVCRSingleStep )
{
g_bWaitingForStepKeyUp = true ;
VCR_EnterPausedState ( ) ;
}
else if ( toupper ( wParam ) = = ' D ' )
{
g_bShowVCRPlaybackDisplay = ! g_bShowVCRPlaybackDisplay ;
}
g_iVCRPlaybackSleepInterval = clamp ( g_iVCRPlaybackSleepInterval , 0 , 500 ) ;
}
}
//-----------------------------------------------------------------------------
// Calls the default window procedure
// FIXME: It would be nice to remove the need for this, which we can do
// if we can make unicode work when running inside hammer.
//-----------------------------------------------------------------------------
static LRESULT WINAPI CallDefaultWindowProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
if ( unicode )
return unicode - > DefWindowProcW ( hWnd , uMsg , wParam , lParam ) ;
return DefWindowProc ( hWnd , uMsg , wParam , lParam ) ;
}
# endif
//-----------------------------------------------------------------------------
// Purpose: The user has accepted an invitation to a game, we need to detect if
// it's TF2 and restart properly if it is
//-----------------------------------------------------------------------------
void XBX_HandleInvite ( DWORD nUserId )
{
# ifdef _X360
// Grab our invite info
XINVITE_INFO inviteInfo ;
DWORD dwError = XInviteGetAcceptedInfo ( nUserId , & inviteInfo ) ;
if ( dwError ! = ERROR_SUCCESS )
return ;
// We only care if we're asked to join an Orange Box session
if ( inviteInfo . dwTitleID ! = TITLEID_THE_ORANGE_BOX )
{
// Do the normal "we've been invited to a game" behavior
return ;
}
// Otherwise, launch depending on our current MOD
if ( ! Q_stricmp ( GetCurrentMod ( ) , " tf " ) )
{
// We're already running TF2, so just join the session
if ( nUserId ! = XBX_GetPrimaryUserId ( ) )
{
// Switch users, the other had the invite
XBX_SetPrimaryUserId ( nUserId ) ;
}
// Kick off our join
g_pMatchmaking - > JoinInviteSession ( & ( inviteInfo . hostInfo ) ) ;
}
else
{
// Save off our session ID for later retrieval
// NOTE: We may need to actually save off the inviter's XID and search for them later on if we took too long or the
// session they were a part of went away
XBX_SetInviteSessionId ( inviteInfo . hostInfo . sessionID ) ;
XBX_SetInvitedUserId ( nUserId ) ;
// Quit via the menu path "QuitNoConfirm"
EngineVGui ( ) - > SystemNotification ( SYSTEMNOTIFY_INVITE_SHUTDOWN ) ;
}
# endif //_X360
}
# if defined( WIN32 ) && !defined( USE_SDL )
//-----------------------------------------------------------------------------
// Main windows procedure
//-----------------------------------------------------------------------------
LRESULT CGame : : WindowProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
LRESULT lRet = 0 ;
HDC hdc ;
PAINTSTRUCT ps ;
//
// NOTE: the way this function works is to handle all messages that just call through to
// Windows or provide data to it.
//
// Any messages that change the engine's internal state (like key events) are stored in a list
// and processed at the end of the frame. This is necessary for VCR mode to work correctly because
// Windows likes to pump messages during some of its API calls like SetWindowPos, and unless we add
// custom code around every Windows API call so VCR mode can trap the wndproc calls, VCR mode can't
// reproduce the calls to the wndproc.
//
if ( eng - > GetQuitting ( ) ! = IEngine : : QUIT_NOTQUITTING )
return CallWindowProc ( m_ChainedWindowProc , hWnd , uMsg , wParam , lParam ) ;
// If we're playing back, listen to a couple input things used to drive VCR mode
if ( VCRGetMode ( ) = = VCR_Playback )
{
VCR_HandlePlaybackMessages ( hWnd , uMsg , wParam , lParam ) ;
}
//
// Note: NO engine state should be changed in here while in VCR record or playback.
// We can send whatever we want to Windows, but if we change its state in here instead of
// in DispatchAllStoredGameMessages, the playback may not work because Windows messages
// are not deterministic, so you might get different messages during playback than you did during record.
//
InputEvent_t event ;
memset ( & event , 0 , sizeof ( event ) ) ;
event . m_nTick = g_pInputSystem - > GetPollTick ( ) ;
switch ( uMsg )
{
case WM_CREATE :
: : SetForegroundWindow ( hWnd ) ;
break ;
case WM_ACTIVATEAPP :
{
if ( CanPostActivateEvents ( ) )
{
bool bActivated = ( wParam = = 1 ) ;
event . m_nType = IE_AppActivated ;
event . m_nData = bActivated ;
g_pInputSystem - > PostUserEvent ( event ) ;
}
}
break ;
case WM_POWERBROADCAST :
// Don't go into Sleep mode when running engine, we crash on resume for some reason (as
// do half of the apps I have running usually anyway...)
if ( wParam = = PBT_APMQUERYSUSPEND )
{
Msg ( " OS requested hibernation, ignoring request. \n " ) ;
return BROADCAST_QUERY_DENY ;
}
lRet = CallWindowProc ( m_ChainedWindowProc , hWnd , uMsg , wParam , lParam ) ;
break ;
case WM_SYSCOMMAND :
if ( ( wParam = = SC_MONITORPOWER ) | | ( wParam = = SC_KEYMENU ) | | ( wParam = = SC_SCREENSAVE ) )
return lRet ;
if ( wParam = = SC_CLOSE )
{
# if !defined( NO_VCR )
// handle the close message, but make sure
// it's not because we accidently hit ALT-F4
if ( HIBYTE ( VCRHook_GetKeyState ( VK_LMENU ) ) | | HIBYTE ( VCRHook_GetKeyState ( VK_RMENU ) ) )
return lRet ;
# endif
Cbuf_Clear ( ) ;
Cbuf_AddText ( " quit \n " ) ;
}
# ifndef SWDS
if ( VCRGetMode ( ) = = VCR_Disabled )
{
S_BlockSound ( ) ;
S_ClearBuffer ( ) ;
}
# endif
lRet = CallWindowProc ( m_ChainedWindowProc , hWnd , uMsg , wParam , lParam ) ;
# ifndef SWDS
if ( VCRGetMode ( ) = = VCR_Disabled )
{
S_UnblockSound ( ) ;
}
# endif
break ;
case WM_CLOSE :
// Handle close messages
event . m_nType = IE_Close ;
g_pInputSystem - > PostUserEvent ( event ) ;
return 0 ;
case WM_MOVE :
event . m_nType = IE_WindowMove ;
event . m_nData = ( short ) LOWORD ( lParam ) ;
event . m_nData2 = ( short ) HIWORD ( lParam ) ;
g_pInputSystem - > PostUserEvent ( event ) ;
break ;
case WM_SIZE :
if ( wParam ! = SIZE_MINIMIZED )
{
// Update restored client rect
: : GetClientRect ( hWnd , & m_rcLastRestoredClientRect ) ;
}
else
{
# ifndef _X360
// Fix the window rect to have same client area as it used to have
// before it got minimized
RECT rcWindow ;
: : GetWindowRect ( hWnd , & rcWindow ) ;
rcWindow . right = rcWindow . left + m_rcLastRestoredClientRect . right ;
rcWindow . bottom = rcWindow . top + m_rcLastRestoredClientRect . bottom ;
: : AdjustWindowRect ( & rcWindow , : : GetWindowLong ( hWnd , GWL_STYLE ) , FALSE ) ;
: : MoveWindow ( hWnd , rcWindow . left , rcWindow . top ,
rcWindow . right - rcWindow . left , rcWindow . bottom - rcWindow . top , FALSE ) ;
# endif
}
break ;
case WM_SYSCHAR :
// keep Alt-Space from happening
break ;
case WM_COPYDATA :
// Hammer -> engine remote console command.
// Return true to indicate that the message was handled.
Cbuf_AddText ( ( const char * ) ( ( ( COPYDATASTRUCT * ) lParam ) - > lpData ) ) ;
Cbuf_AddText ( " \n " ) ;
lRet = 1 ;
break ;
# if defined( _X360 )
case WM_XREMOTECOMMAND :
Cbuf_AddText ( ( const char * ) lParam ) ;
Cbuf_AddText ( " \n " ) ;
break ;
case WM_SYS_STORAGEDEVICESCHANGED :
if ( ! EngineVGui ( ) - > IsGameUIVisible ( ) )
{
EngineVGui ( ) - > ActivateGameUI ( ) ;
}
EngineVGui ( ) - > SystemNotification ( SYSTEMNOTIFY_STORAGEDEVICES_CHANGED ) ;
break ;
case WM_XMP_PLAYBACKCONTROLLERCHANGED :
S_EnableMusic ( lParam ! = 0 ) ;
break ;
case WM_LIVE_INVITE_ACCEPTED :
XBX_HandleInvite ( LOWORD ( lParam ) ) ;
break ;
case WM_SYS_SIGNINCHANGED :
if ( XUserGetSigninState ( XBX_GetPrimaryUserId ( ) ) = = eXUserSigninState_NotSignedIn )
{
// X360TBD: User signed out - pause the game?
}
EngineVGui ( ) - > SystemNotification ( lParam ? SYSTEMNOTIFY_USER_SIGNEDIN : SYSTEMNOTIFY_USER_SIGNEDOUT ) ;
break ;
case WM_SYS_UI :
if ( lParam )
{
// Don't activate it if it's already active (a sub window may be active)
// Multiplayer doesn't want the UI to appear, since it can't pause anyway
if ( ! EngineVGui ( ) - > IsGameUIVisible ( ) & & g_ServerGlobalVariables . maxClients = = 1 )
{
Cbuf_AddText ( " gameui_activate " ) ;
}
}
EngineVGui ( ) - > SystemNotification ( lParam ? SYSTEMNOTIFY_XUIOPENING : SYSTEMNOTIFY_XUICLOSED ) ;
break ;
case WM_SYS_MUTELISTCHANGED :
g_pMatchmaking - > UpdateMuteList ( ) ;
break ;
case WM_SYS_INPUTDEVICESCHANGED :
{
XINPUT_CAPABILITIES caps ;
if ( XInputGetCapabilities ( XBX_GetPrimaryUserId ( ) , XINPUT_FLAG_GAMEPAD , & caps ) = = ERROR_DEVICE_NOT_CONNECTED )
{
if ( EngineVGui ( ) - > IsGameUIVisible ( ) = = false )
{
EngineVGui ( ) - > ActivateGameUI ( ) ;
}
}
}
break ;
# endif
case WM_PAINT :
hdc = BeginPaint ( hWnd , & ps ) ;
RECT rcClient ;
GetClientRect ( hWnd , & rcClient ) ;
# ifndef SWDS
// Only renders stuff if running -noshaderapi
if ( videomode )
{
videomode - > DrawNullBackground ( hdc , rcClient . right , rcClient . bottom ) ;
}
# endif
EndPaint ( hWnd , & ps ) ;
break ;
# ifndef _X360
case WM_DISPLAYCHANGE :
if ( ! m_iDesktopHeight | | ! m_iDesktopWidth )
{
UpdateDesktopInformation ( wParam , lParam ) ;
}
break ;
# endif
case WM_IME_NOTIFY :
switch ( wParam )
{
default :
break ;
# ifndef SWDS
case 14 :
if ( ! videomode - > IsWindowedMode ( ) )
return 0 ;
break ;
# endif
}
return CallWindowProc ( m_ChainedWindowProc , hWnd , uMsg , wParam , lParam ) ;
default :
lRet = CallWindowProc ( m_ChainedWindowProc , hWnd , uMsg , wParam , lParam ) ;
break ;
}
// return 0 if handled message, 1 if not
return lRet ;
}
# elif defined(OSX) || defined(LINUX) || defined(_WIN32) || defined(PLATFORM_BSD)
# else
# error
# endif
# if defined( WIN32 ) && !defined( USE_SDL )
//-----------------------------------------------------------------------------
// Creates the game window
//-----------------------------------------------------------------------------
static LRESULT WINAPI HLEngineWindowProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
return g_Game . WindowProc ( hWnd , uMsg , wParam , lParam ) ;
}
# define DEFAULT_EXE_ICON 101
static void DoSomeSocketStuffInOrderToGetZoneAlarmToNoticeUs ( void )
{
# ifdef IS_WINDOWS_PC
WSAData wsaData ;
if ( ! WSAStartup ( 0x0101 , & wsaData ) )
{
SOCKET tmpSocket = socket ( AF_INET , SOCK_DGRAM , 0 ) ;
if ( tmpSocket ! = INVALID_SOCKET )
{
char Options [ ] = { 1 } ;
setsockopt ( tmpSocket , SOL_SOCKET , SO_BROADCAST , Options , sizeof ( Options ) ) ;
char pszHostName [ 256 ] ;
gethostname ( pszHostName , sizeof ( pszHostName ) ) ;
hostent * hInfo = gethostbyname ( pszHostName ) ;
if ( hInfo )
{
sockaddr_in myIpAddress ;
memset ( & myIpAddress , 0 , sizeof ( myIpAddress ) ) ;
myIpAddress . sin_family = AF_INET ;
myIpAddress . sin_port = htons ( 27015 ) ; // our normal server port
myIpAddress . sin_addr . S_un . S_un_b . s_b1 = hInfo - > h_addr_list [ 0 ] [ 0 ] ;
myIpAddress . sin_addr . S_un . S_un_b . s_b2 = hInfo - > h_addr_list [ 0 ] [ 1 ] ;
myIpAddress . sin_addr . S_un . S_un_b . s_b3 = hInfo - > h_addr_list [ 0 ] [ 2 ] ;
myIpAddress . sin_addr . S_un . S_un_b . s_b4 = hInfo - > h_addr_list [ 0 ] [ 3 ] ;
if ( bind ( tmpSocket , ( sockaddr * ) & myIpAddress , sizeof ( myIpAddress ) ) ! = - 1 )
{
if ( sendto ( tmpSocket , pszHostName , 1 , 0 , ( sockaddr * ) & myIpAddress , sizeof ( myIpAddress ) ) = = - 1 )
{
// error?
}
}
}
closesocket ( tmpSocket ) ;
}
WSACleanup ( ) ;
}
# endif
}
# endif
bool CGame : : CreateGameWindow ( void )
{
// get the window name
char windowName [ 256 ] ;
windowName [ 0 ] = 0 ;
KeyValues * modinfo = new KeyValues ( " ModInfo " ) ;
if ( modinfo - > LoadFromFile ( g_pFileSystem , " gameinfo.txt " ) )
{
Q_strncpy ( windowName , modinfo - > GetString ( " game " ) , sizeof ( windowName ) ) ;
}
if ( ! windowName [ 0 ] )
{
Q_strncpy ( windowName , " HALF-LIFE 2 " , sizeof ( windowName ) ) ;
}
if ( IsOpenGL ( ) )
{
# ifdef TOGLES
V_strcat ( windowName , " - OpenGLES " , sizeof ( windowName ) ) ;
# else
V_strcat ( windowName , " - OpenGL " , sizeof ( windowName ) ) ;
# endif
}
# if PIX_ENABLE || defined( PIX_INSTRUMENTATION )
// PIX_ENABLE/PIX_INSTRUMENTATION is a big slowdown (that should never be checked in, but sometimes is by accident), so add this to the Window title too.
V_strcat ( windowName , " - PIX_ENABLE " , sizeof ( windowName ) ) ;
# endif
const char * p = CommandLine ( ) - > ParmValue ( " -window_name_suffix " , " " ) ;
if ( p & & V_strlen ( p ) )
{
V_strcat ( windowName , " - " , sizeof ( windowName ) ) ;
V_strcat ( windowName , p , sizeof ( windowName ) ) ;
}
# if defined( WIN32 ) && !defined( USE_SDL )
# ifndef SWDS
if ( IsPC ( ) )
{
if ( ! LoadUnicode ( ) )
{
return false ;
}
}
# if !defined( _X360 )
WNDCLASSW wc ;
# else
WNDCLASS wc ;
# endif
memset ( & wc , 0 , sizeof ( wc ) ) ;
wc . style = CS_OWNDC | CS_DBLCLKS ;
wc . lpfnWndProc = static_cast < WNDPROC > ( CallDefaultWindowProc ) ;
wc . hInstance = m_hInstance ;
wc . lpszClassName = CLASSNAME ;
// find the icon file in the filesystem
if ( IsPC ( ) )
{
char localPath [ MAX_PATH ] ;
if ( g_pFileSystem - > GetLocalPath ( " resource/game.ico " , localPath , sizeof ( localPath ) ) )
{
g_pFileSystem - > GetLocalCopy ( localPath ) ;
wc . hIcon = ( HICON ) : : LoadImage ( NULL , localPath , IMAGE_ICON , 0 , 0 , LR_LOADFROMFILE | LR_DEFAULTSIZE ) ;
}
else
{
wc . hIcon = ( HICON ) LoadIcon ( GetModuleHandle ( 0 ) , MAKEINTRESOURCE ( DEFAULT_EXE_ICON ) ) ;
}
}
# ifndef SWDS
char const * pszGameType = modinfo - > GetString ( " type " ) ;
if ( pszGameType & & Q_stristr ( pszGameType , " multiplayer " ) )
DoSomeSocketStuffInOrderToGetZoneAlarmToNoticeUs ( ) ;
# endif
wchar_t uc [ 512 ] ;
if ( IsPC ( ) )
{
: : MultiByteToWideChar ( CP_UTF8 , 0 , windowName , - 1 , uc , sizeof ( uc ) / sizeof ( wchar_t ) ) ;
}
modinfo - > deleteThis ( ) ;
modinfo = NULL ;
// Oops, we didn't clean up the class registration from last cycle which
// might mean that the wndproc pointer is bogus
# ifndef _X360
unicode - > UnregisterClassW ( CLASSNAME , m_hInstance ) ;
// Register it again
unicode - > RegisterClassW ( & wc ) ;
# else
RegisterClass ( & wc ) ;
# endif
// Note, it's hidden
DWORD style = WS_POPUP | WS_CLIPSIBLINGS ;
// Give it a frame if we want a border
if ( videomode - > IsWindowedMode ( ) )
{
if ( ! CommandLine ( ) - > FindParm ( " -noborder " ) )
{
style | = WS_OVERLAPPEDWINDOW ;
style & = ~ WS_THICKFRAME ;
}
}
// Never a max box
style & = ~ WS_MAXIMIZEBOX ;
int w , h ;
// Create a full screen size window by default, it'll get resized later anyway
w = GetSystemMetrics ( SM_CXSCREEN ) ;
h = GetSystemMetrics ( SM_CYSCREEN ) ;
// Create the window
DWORD exFlags = 0 ;
if ( g_bTextMode )
{
style & = ~ WS_VISIBLE ;
exFlags | = WS_EX_TOOLWINDOW ; // So it doesn't show up in the taskbar.
}
# if !defined( _X360 )
HWND hwnd = unicode - > CreateWindowExW ( exFlags , CLASSNAME , uc , style ,
0 , 0 , w , h , NULL , NULL , m_hInstance , NULL ) ;
// NOTE: On some cards, CreateWindowExW slams the FPU control word
SetupFPUControlWord ( ) ;
# else
HWND hwnd = CreateWindowEx ( exFlags , CLASSNAME , windowName , style ,
0 , 0 , w , h , NULL , NULL , m_hInstance , NULL ) ;
# endif
if ( ! hwnd )
{
Error ( " Fatal Error: Unable to create game window! " ) ;
return false ;
}
SetMainWindow ( hwnd ) ;
AttachToWindow ( ) ;
return true ;
# else
return true ;
# endif
# elif defined( USE_SDL )
bool windowed = videomode - > IsWindowedMode ( ) ;
modinfo - > deleteThis ( ) ;
modinfo = NULL ;
if ( ! g_pLauncherMgr - > CreateGameWindow ( windowName , windowed , 0 , 0 ) )
{
Error ( " Fatal Error: Unable to create game window! " ) ;
return false ;
}
char localPath [ MAX_PATH ] ;
if ( g_pFileSystem - > GetLocalPath ( " resource/game-icon.bmp " , localPath , sizeof ( localPath ) ) )
{
g_pFileSystem - > GetLocalCopy ( localPath ) ;
g_pLauncherMgr - > SetApplicationIcon ( localPath ) ;
}
SetMainWindow ( ( SDL_Window * ) g_pLauncherMgr - > GetWindowRef ( ) ) ;
AttachToWindow ( ) ;
return true ;
# else
# error
# endif
}
//-----------------------------------------------------------------------------
// Destroys the game window
//-----------------------------------------------------------------------------
void CGame : : DestroyGameWindow ( )
{
# if defined( USE_SDL )
g_pLauncherMgr - > DestroyGameWindow ( ) ;
# else
# ifndef DEDICATED
// Destroy all things created when the window was created
if ( ! m_bExternallySuppliedWindow )
{
DetachFromWindow ( ) ;
if ( m_hWindow )
{
DestroyWindow ( m_hWindow ) ;
m_hWindow = ( HWND ) 0 ;
}
# if !defined( _X360 )
unicode - > UnregisterClassW ( CLASSNAME , m_hInstance ) ;
UnloadUnicode ( ) ;
# else
UnregisterClass ( CLASSNAME , m_hInstance ) ;
# endif
}
else
{
m_hWindow = ( HWND ) 0 ;
m_bExternallySuppliedWindow = false ;
}
# endif // !defined( SWDS )
# endif
}
//-----------------------------------------------------------------------------
// This is used in edit mode to specify a particular game window (created by hammer)
//-----------------------------------------------------------------------------
void CGame : : SetGameWindow ( void * hWnd )
{
m_bExternallySuppliedWindow = true ;
# if defined( USE_SDL )
SDL_RaiseWindow ( ( SDL_Window * ) hWnd ) ;
# else
SetMainWindow ( ( HWND ) hWnd ) ;
# endif
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CGame : : AttachToWindow ( )
{
# if defined( WIN32 )
if ( ! m_hWindow )
return ;
# if !defined( USE_SDL )
m_ChainedWindowProc = ( WNDPROC ) GetWindowLongPtrW ( m_hWindow , GWLP_WNDPROC ) ;
SetWindowLongPtrW ( m_hWindow , GWLP_WNDPROC , ( LONG_PTR ) HLEngineWindowProc ) ;
# endif
# endif // WIN32
if ( g_pInputSystem )
{
// Attach the input system window proc
# if defined( WIN32 )
g_pInputSystem - > AttachToWindow ( ( void * ) m_hWindow ) ;
# else
g_pInputSystem - > AttachToWindow ( ( void * ) m_pSDLWindow ) ;
# endif
g_pInputSystem - > EnableInput ( true ) ;
g_pInputSystem - > EnableMessagePump ( false ) ;
}
if ( g_pMatSystemSurface )
{
// Attach the vgui matsurface window proc
# if defined( WIN32 )
g_pMatSystemSurface - > AttachToWindow ( ( void * ) m_hWindow , true ) ;
# else
g_pMatSystemSurface - > AttachToWindow ( ( void * ) m_pSDLWindow , true ) ;
# endif
g_pMatSystemSurface - > EnableWindowsMessages ( true ) ;
}
}
void CGame : : DetachFromWindow ( )
{
# if defined( WIN32 ) && !defined( USE_SDL )
if ( ! m_hWindow | | ! m_ChainedWindowProc )
{
m_ChainedWindowProc = NULL ;
return ;
}
# endif
if ( g_pMatSystemSurface )
{
// Detach the vgui matsurface window proc
g_pMatSystemSurface - > AttachToWindow ( NULL ) ;
}
if ( g_pInputSystem )
{
// Detach the input system window proc
g_pInputSystem - > EnableInput ( false ) ;
g_pInputSystem - > DetachFromWindow ( ) ;
}
# if defined( WIN32 ) && !defined( USE_SDL )
Assert ( ( WNDPROC ) GetWindowLongPtrW ( m_hWindow , GWLP_WNDPROC ) = = HLEngineWindowProc ) ;
SetWindowLongPtrW ( m_hWindow , GWLP_WNDPROC , ( LONG_PTR ) m_ChainedWindowProc ) ;
# endif
}
//-----------------------------------------------------------------------------
// This is used in edit mode to override the default wnd proc associated w/
// the game window specified in SetGameWindow.
//-----------------------------------------------------------------------------
bool CGame : : InputAttachToGameWindow ( )
{
// We can't use this feature unless we didn't control the creation of the window
if ( ! m_bExternallySuppliedWindow )
return true ;
AttachToWindow ( ) ;
# ifndef DEDICATED
vgui : : surface ( ) - > OnScreenSizeChanged ( videomode - > GetModeStereoWidth ( ) , videomode - > GetModeStereoHeight ( ) ) ;
# endif
// We don't get WM_ACTIVATEAPP messages in this case; simulate one.
AppActivate ( true ) ;
# if defined( WIN32 ) && !defined( USE_SDL )
// Capture + hide the mouse
SetCapture ( m_hWindow ) ;
# elif defined( USE_SDL )
Assert ( ! " Impl me " ) ;
return false ;
# else
# error
# endif
return true ;
}
void CGame : : InputDetachFromGameWindow ( )
{
// We can't use this feature unless we didn't control the creation of the window
if ( ! m_bExternallySuppliedWindow )
return ;
# if defined( WIN32 ) && !defined( USE_SDL )
if ( ! m_ChainedWindowProc )
return ;
// Release + show the mouse
ReleaseCapture ( ) ;
# elif defined( USE_SDL )
Assert ( ! " Impl me " ) ;
# else
# error "have no idea what OS we are building for"
# endif
// We don't get WM_ACTIVATEAPP messages in this case; simulate one.
AppActivate ( false ) ;
DetachFromWindow ( ) ;
}
void CGame : : PlayStartupVideos ( void )
{
if ( IsX360 ( ) | | Plat_IsInBenchmarkMode ( ) )
return ;
# ifndef SWDS
// Wait for the mode to change and stabilized
// FIXME: There's really no way to know when this is completed, so we have to guess a time that will mostly be correct
if ( videomode - > IsWindowedMode ( ) = = false )
{
Sys_Sleep ( 1000 ) ;
}
bool bEndGame = CommandLine ( ) - > CheckParm ( " -endgamevid " ) ;
bool bRecap = CommandLine ( ) - > CheckParm ( " -recapvid " ) ; // FIXME: This is a temp addition until the movie playback is centralized -- jdw
bool bNeedHealthWarning = false ;
const char * HealthFile = " media/HealthWarning.txt " ;
FileHandle_t hFile ;
COM_OpenFile ( HealthFile , & hFile ) ;
//There is no access to steam at this point so we are checking for the presence of an empty file that will only exist in the chinese depot
if ( hFile ! = FILESYSTEM_INVALID_HANDLE )
{
bNeedHealthWarning = true ;
COM_CloseFile ( hFile ) ;
}
if ( ! bNeedHealthWarning & & ! bEndGame & & ! bRecap & & ( CommandLine ( ) - > CheckParm ( " -dev " ) | | CommandLine ( ) - > CheckParm ( " -novid " ) | | CommandLine ( ) - > CheckParm ( " -allowdebug " ) ) )
return ;
const char * pszFile = " media/StartupVids.txt " ;
if ( bEndGame )
{
// Don't go back into the map that triggered this.
CommandLine ( ) - > RemoveParm ( " +map " ) ;
CommandLine ( ) - > RemoveParm ( " +load " ) ;
pszFile = " media/EndGameVids.txt " ;
}
else if ( bRecap )
{
pszFile = " media/RecapVids.txt " ;
}
int vidFileLength ;
// have to use the malloc memory allocation option in COM_LoadFile since the memory system isn't set up at this point.
const char * buffer = ( char * ) COM_LoadFile ( pszFile , 5 , & vidFileLength ) ;
if ( ( buffer = = NULL ) | | ( vidFileLength = = 0 ) )
{
return ;
}
// hide cursor while playing videos
# if defined( USE_SDL )
g_pLauncherMgr - > SetMouseVisible ( false ) ;
# elif defined( WIN32 )
: : ShowCursor ( FALSE ) ;
# endif
# if defined( LINUX )
extern void VAudioInit ( ) ;
VAudioInit ( ) ;
Audio_CreateSDLAudioDevice ( ) ;
# endif
const char * start = buffer ;
while ( true )
{
start = COM_Parse ( start ) ;
if ( Q_strlen ( com_token ) < = 0 )
{
break ;
}
// get the path to the media file and play it.
char localPath [ MAX_PATH ] ;
g_pFileSystem - > GetLocalPath ( com_token , localPath , sizeof ( localPath ) ) ;
PlayVideoAndWait ( localPath , bNeedHealthWarning ) ;
localPath [ 0 ] = 0 ; // just to make sure we don't play the same avi file twice in the case that one movie is there but another isn't.
}
// show cursor again
# if defined( USE_SDL )
g_pLauncherMgr - > SetMouseVisible ( true ) ;
# elif defined( WIN32 )
: : ShowCursor ( TRUE ) ;
# endif
// call free on the buffer since the buffer was malloc'd in COM_LoadFile
free ( ( void * ) buffer ) ;
# endif // SWDS
}
//-----------------------------------------------------------------------------
// Purpose: Plays a video until the video completes or ESC is pressed
// Input : *filename - Name of the file (relative to the filesystem)
//-----------------------------------------------------------------------------
void CGame : : PlayVideoAndWait ( const char * filename , bool bNeedHealthWarning )
{
// do we have a filename and a video system, and not on a console?
if ( ! filename | | ! filename [ 0 ] | | g_pVideo = = NULL )
return ;
// is it the valve logo file?
bool bIsValveLogo = ( Q_strstr ( filename , " valve. " ) ! = NULL ) ;
//Chinese health messages appears for 11 seconds, so we force a minimum delay time for those
float forcedMinTime = ( bIsValveLogo & & bNeedHealthWarning ) ? 11.0f : - 1.0f ;
# if defined( WIN32 ) && !defined ( _X360 ) && !defined( USE_SDL )
// Black out the back of the screen once at the beginning of each video (since we're not scaling to fit)
HDC dc = : : GetDC ( m_hWindow ) ;
RECT rect ;
rect . top = 0 ;
rect . bottom = m_height ;
rect . left = 0 ;
rect . right = m_width ;
HBRUSH hBlackBrush = ( HBRUSH ) : : GetStockObject ( BLACK_BRUSH ) ;
: : SetViewportOrgEx ( dc , 0 , 0 , NULL ) ;
: : FillRect ( dc , & rect , hBlackBrush ) ;
: : ReleaseDC ( ( HWND ) GetMainWindow ( ) , dc ) ;
# else
// need OS specific way to clear screen
# endif
VideoResult_t status = g_pVideo - > PlayVideoFileFullScreen ( filename , " GAME " , GetMainWindowPlatformSpecificHandle ( ) ,
m_width , m_height , m_iDesktopWidth , m_iDesktopHeight , videomode - > IsWindowedMode ( ) ,
forcedMinTime , VideoPlaybackFlags : : DEFAULT_FULLSCREEN_OPTIONS | VideoPlaybackFlags : : FILL_WINDOW ) ;
// Everything ok?
if ( status = = VideoResult : : SUCCESS )
{
return ;
}
// We don't worry if it could not find something to could play
if ( status = = VideoResult : : VIDEO_FILE_NOT_FOUND )
{
return ;
}
// Debug Builds, we want an error looked at by a developer, Release builds just send a message to the spew
# ifdef _DEBUG
Error ( " Error %d occurred attempting to play video file %s \n " , ( int ) status , filename ) ;
# else
Msg ( " Error %d occurred attempting to play video file %s \n " , ( int ) status , filename ) ;
# endif
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CGame : : CGame ( )
{
# if defined( USE_SDL )
m_pSDLWindow = 0 ;
# endif
# if defined( WIN32 )
# if !defined( USE_SDL )
unicode = NULL ;
m_hUnicodeModule = NULL ;
m_hInstance = 0 ;
m_ChainedWindowProc = NULL ;
# endif
m_hWindow = 0 ;
# endif
m_x = m_y = 0 ;
m_width = m_height = 0 ;
m_bActiveApp = false ;
m_bCanPostActivateEvents = true ;
m_iDesktopWidth = 0 ;
m_iDesktopHeight = 0 ;
m_iDesktopRefreshRate = 0 ;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CGame : : ~ CGame ( )
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CGame : : Init ( void * pvInstance )
{
m_bExternallySuppliedWindow = false ;
# if defined( WIN32 ) && !defined( USE_SDL )
OSVERSIONINFO vinfo ;
vinfo . dwOSVersionInfoSize = sizeof ( vinfo ) ;
if ( ! GetVersionEx ( & vinfo ) )
{
return false ;
}
if ( vinfo . dwPlatformId = = VER_PLATFORM_WIN32s )
{
return false ;
}
m_hInstance = ( HINSTANCE ) pvInstance ;
# endif
return true ;
}
bool CGame : : Shutdown ( void )
{
# if defined( WIN32 ) && !defined( USE_SDL )
m_hInstance = 0 ;
# endif
return true ;
}
bool CGame : : LoadUnicode ( void )
{
# ifdef WIN32
m_hUnicodeModule = Sys_LoadModule ( " unicode " ) ;
if ( ! m_hUnicodeModule )
{
Error ( " Unable to load unicode.dll " ) ;
return false ;
}
CreateInterfaceFn factory = Sys_GetFactory ( m_hUnicodeModule ) ;
if ( ! factory )
{
Error ( " Unable to get factory from unicode.dll " ) ;
return false ;
}
unicode = ( IUnicodeWindows * ) factory ( VENGINE_UNICODEINTERFACE_VERSION , NULL ) ;
if ( ! unicode )
{
Error ( " Unable to load interface '%s' from unicode.dll " , VENGINE_UNICODEINTERFACE_VERSION ) ;
return false ;
}
# endif
return true ;
}
void CGame : : UnloadUnicode ( )
{
# ifdef WIN32
unicode = NULL ;
if ( m_hUnicodeModule )
{
Sys_UnloadModule ( m_hUnicodeModule ) ;
m_hUnicodeModule = NULL ;
}
# endif
}
void * CGame : : GetMainWindow ( void )
{
# ifdef USE_SDL
return ( void * ) m_pSDLWindow ;
# else
return GetMainWindowPlatformSpecificHandle ( ) ;
# endif
}
void * CGame : : GetMainDeviceWindow ( void )
{
# if defined( DX_TO_GL_ABSTRACTION ) && defined( USE_SDL )
return ( void * ) m_pSDLWindow ;
# else
return ( void * ) m_hWindow ;
# endif
}
void * CGame : : GetMainWindowPlatformSpecificHandle ( void )
{
# ifdef WIN32
return ( void * ) m_hWindow ;
# else
SDL_SysWMinfo pInfo ;
SDL_VERSION ( & pInfo . version ) ;
if ( ! SDL_GetWindowWMInfo ( ( SDL_Window * ) m_pSDLWindow , & pInfo ) )
{
Error ( " Fatal Error: Unable to get window info from SDL. " ) ;
return NULL ;
}
# ifdef OSX
id nsWindow = ( id ) pInfo . info . cocoa . window ;
SEL selector = sel_registerName ( " windowRef " ) ;
id windowRef = ( ( id ( * ) ( id , SEL ) ) objc_msgSend ) ( nsWindow , selector ) ;
return windowRef ;
# else
// Not used on Linux.
return NULL ;
# endif
# endif // !WIN32
}
void * * CGame : : GetMainWindowAddress ( void )
{
# ifdef WIN32
return ( void * * ) & m_hWindow ;
# else
return NULL ;
# endif
}
void CGame : : GetDesktopInfo ( int & width , int & height , int & refreshrate )
{
# if defined( USE_SDL )
width = 640 ;
height = 480 ;
refreshrate = 0 ;
// Go through all the displays and return the size of the largest.
for ( int i = 0 ; i < SDL_GetNumVideoDisplays ( ) ; i + + )
{
SDL_Rect rect ;
if ( ! SDL_GetDisplayBounds ( i , & rect ) )
{
if ( ( rect . w > width ) | | ( ( rect . w = = width ) & & ( rect . h > height ) ) )
{
width = rect . w ;
height = rect . h ;
}
}
}
# else
// order of initialization means that this might get called early. In that case go ahead and grab the current
// screen window and setup based on that.
// we need to do this when initializing the base list of video modes, for example
if ( m_iDesktopWidth = = 0 )
{
HDC dc = : : GetDC ( NULL ) ;
width = : : GetDeviceCaps ( dc , HORZRES ) ;
height = : : GetDeviceCaps ( dc , VERTRES ) ;
refreshrate = : : GetDeviceCaps ( dc , VREFRESH ) ;
: : ReleaseDC ( NULL , dc ) ;
return ;
}
width = m_iDesktopWidth ;
height = m_iDesktopHeight ;
refreshrate = m_iDesktopRefreshRate ;
# endif
}
void CGame : : UpdateDesktopInformation ( )
{
# if defined( USE_SDL )
// Get the size of the display we will be displayed fullscreen on.
static ConVarRef sdl_displayindex ( " sdl_displayindex " ) ;
int displayIndex = sdl_displayindex . IsValid ( ) ? sdl_displayindex . GetInt ( ) : 0 ;
SDL_DisplayMode mode ;
SDL_GetDesktopDisplayMode ( displayIndex , & mode ) ;
m_iDesktopWidth = mode . w ;
m_iDesktopHeight = mode . h ;
m_iDesktopRefreshRate = mode . refresh_rate ;
# else
HDC dc = : : GetDC ( m_hWindow ) ;
m_iDesktopWidth = : : GetDeviceCaps ( dc , HORZRES ) ;
m_iDesktopHeight = : : GetDeviceCaps ( dc , VERTRES ) ;
m_iDesktopRefreshRate = : : GetDeviceCaps ( dc , VREFRESH ) ;
: : ReleaseDC ( m_hWindow , dc ) ;
# endif
}
# ifdef WIN32
void CGame : : UpdateDesktopInformation ( WPARAM wParam , LPARAM lParam )
{
m_iDesktopWidth = LOWORD ( lParam ) ;
m_iDesktopHeight = HIWORD ( lParam ) ;
}
# endif
# ifndef USE_SDL
void CGame : : SetMainWindow ( HWND window )
{
m_hWindow = window ;
// update our desktop info (since the results will change if we are going to fullscreen mode)
if ( ! m_iDesktopWidth | | ! m_iDesktopHeight )
{
UpdateDesktopInformation ( ) ;
}
}
# else
void CGame : : SetMainWindow ( SDL_Window * window )
{
# if defined( WIN32 )
// For D3D, we need to access the underlying HWND of the SDL_Window.
// We also can't do this in GetMainDeviceWindow and just use that, because for some reason
// people use GetMainWindowAddress and store that pointer to our member.
SDL_SysWMinfo pInfo ;
SDL_VERSION ( & pInfo . version ) ;
if ( ! SDL_GetWindowWMInfo ( ( SDL_Window * ) g_pLauncherMgr - > GetWindowRef ( ) , & pInfo ) )
{
Error ( " Fatal Error: Unable to get window info from SDL. " ) ;
return ;
}
m_hWindow = pInfo . info . win . window ;
# endif
m_pSDLWindow = window ;
// update our desktop info (since the results will change if we are going to fullscreen mode)
if ( ! m_iDesktopWidth | | ! m_iDesktopHeight )
{
UpdateDesktopInformation ( ) ;
}
}
# endif
void CGame : : SetWindowXY ( int x , int y )
{
m_x = x ;
m_y = y ;
}
void CGame : : SetWindowSize ( int w , int h )
{
m_width = w ;
m_height = h ;
}
void CGame : : GetWindowRect ( int * x , int * y , int * w , int * h )
{
if ( x )
{
* x = m_x ;
}
if ( y )
{
* y = m_y ;
}
if ( w )
{
* w = m_width ;
}
if ( h )
{
* h = m_height ;
}
}
bool CGame : : IsActiveApp ( void )
{
return m_bActiveApp ;
}
void CGame : : SetCanPostActivateEvents ( bool bEnabled )
{
m_bCanPostActivateEvents = bEnabled ;
}
bool CGame : : CanPostActivateEvents ( )
{
return m_bCanPostActivateEvents ;
}
void CGame : : SetActiveApp ( bool active )
{
m_bActiveApp = active ;
}