From 3bf9df6b2785fa6d951086978a3e66f49427166a Mon Sep 17 00:00:00 2001 From: FluorescentCIAAfricanAmerican <0934gj3049fk@protonmail.com> Date: Wed, 22 Apr 2020 12:56:21 -0400 Subject: 1 --- engine/sys_mainwind.cpp | 1742 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1742 insertions(+) create mode 100644 engine/sys_mainwind.cpp (limited to 'engine/sys_mainwind.cpp') diff --git a/engine/sys_mainwind.cpp b/engine/sys_mainwind.cpp new file mode 100644 index 0000000..8d9e08e --- /dev/null +++ b/engine/sys_mainwind.cpp @@ -0,0 +1,1742 @@ +//========= 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 +#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 +#elif defined(_X360) + // nothing to include for 360 +#elif defined(OSX) +#elif defined(LINUX) + #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 + int 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; + + 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 LONG 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 +//----------------------------------------------------------------------------- +int CGame::WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + +{ + LONG 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) + +#elif defined(LINUX) + +#elif defined(_WIN32) + +#else +#error +#endif + + +#if defined( WIN32 ) && !defined( USE_SDL ) +//----------------------------------------------------------------------------- +// Creates the game window +//----------------------------------------------------------------------------- +static LONG 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() ) + { + V_strcat( windowName, " - OpenGL", sizeof( windowName ) ); + } + +#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 = 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 = 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; +} + -- cgit v1.2.3