#include "pch.hpp"
//===========================================================================//
// File:	 Windows.cpp													 //
// Project:  GameOS					                                         //
// Contents: Window-related routines										 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 11/04/97  SCP    Created													 //
//---------------------------------------------------------------------------//
// Copyright (C) 1999 Microsoft Corp.						                 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//
#include "Windows.hpp"
#include "WinProc.hpp"
#include "Globals.hpp"
#include "ErrorHandler.hpp"
#include "ControlManager.hpp"

HWND		hWindow = NULL;
HINSTANCE	hInstance = NULL;
char*		CommandLine="";
WNDCLASS	wndClass;
MSG			msg;
HDC			DesktopDC=NULL;
DWORD		ForceReStart=0;

Status status = BeforeInit;

extern bool RunFullScreen;
extern bool WindowsPause;
extern bool gDumpMachineInfo;
extern int LoseFocusBehavior;
extern bool gNoDialogs;
extern DWORD gLanguageDLL;
bool bScreenSaver=0;
bool StoredScreenSaverSetting=0;

extern void InitializeIME(HWND hWindow);
bool IgnoreImeHotKey(MSG* pmsg);
//
// Functions only in Win98/2000
//
T_SetThreadExecutionState _SetThreadExecutionState;
T_GetFileAttributesEx _GetFileAttributesEx;
T_GetDiskFreeSpaceEx _GetDiskFreeSpaceEx;



POINT clientToScreen = {0,0};
int widthX = 640;
int heightY = 480;

int WindowStartX=CW_USEDEFAULT,WindowStartY=CW_USEDEFAULT;

DWORD DesktopBpp;
DWORD DesktopRes;

HANDLE hMappedFile;

// jcem - begin
#include "ctcl_params.h"
//#define _ECTCL_Console              1 // CTCL_IsConsole()
//#define _ECTCL_Game                 2
//#define _ECTCL_CameraShip           3
//#define _ECTCL_None                 4
extern int (_stdcall* g_pfnCTCL_GetType)();
// jcem - end
//
// Is game already running, if so switch to it (and restore it if minimized)
//
bool AlreadyRunning()
{
	HWND tempHWND=FindWindow(Environment.applicationName,Environment.applicationName);

	if(tempHWND)									// Is game window already present?
	{
		WINDOWPLACEMENT wp;
		wp.length=sizeof(wp);
		GetWindowPlacement(tempHWND,&wp);
		SetForegroundWindow(tempHWND);				// If so, activate it.
		if(wp.showCmd==SW_SHOWMINIMIZED)
		{
			ShowWindow(tempHWND,SW_RESTORE);		// If minimized, restore it
		}
		return(1);									// Exit Game
	}

	hMappedFile=CreateFileMapping((HANDLE)0xffffffff,				// -1 hFile flag
							NULL,									// no sharing allowed
							PAGE_READONLY|SEC_RESERVE,				// no writing or physical space allocated
							0,										// high-byte size
							4,										// low byte size
							ApplicationName);						// use class string as file name

	if (hMappedFile!=NULL && GetLastError()==ERROR_ALREADY_EXISTS)	// Only a single file mapping can exist
	{
		CloseHandle(hMappedFile);
		hMappedFile=NULL;
		return(1);
	}
	return(0);
}












char*	IconName=0;
//
// Used to find the first ICON
//
BOOL CALLBACK EnumIcons( HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam )
{
	IconName=lpszName;
	return false;
}







//
//
//
// Create the main application window
//
//
//
void InitializeWindows()
{
	SPEW(( GROUP_GAMEOS, "InitializeWindows()" ));
//
// Always init cursor resource
//
	ArrowCursor=LoadCursor(NULL, IDC_ARROW);
//
// Check for running on an 8 Bit desktop
//
	DesktopBpp=GetDeviceCaps(DesktopDC,BITSPIXEL);
	DesktopRes=GetDeviceCaps(DesktopDC,HORZRES) + (GetDeviceCaps(DesktopDC,VERTRES)<<16);
//
// Check for functions only found in Win98 / 2000
//
	_SetThreadExecutionState=0;
	_SetThreadExecutionState = (T_SetThreadExecutionState)GetProcAddress( GetModuleHandle("kernel32.dll"), "SetThreadExecutionState" );
	_GetFileAttributesEx = (T_GetFileAttributesEx)GetProcAddress( GetModuleHandle("kernel32.dll"), "GetFileAttributesExA" );
	_GetDiskFreeSpaceEx = (T_GetDiskFreeSpaceEx)GetProcAddress( GetModuleHandle("kernel32.dll"), "GetDiskFreeSpaceExA" );
//
// Disable power management function of windows (Win98 / 2000 only)
//
	if( _SetThreadExecutionState )
	{
		_SetThreadExecutionState( ES_SYSTEM_REQUIRED|ES_DISPLAY_REQUIRED|ES_CONTINUOUS );
	}
//
// Disable screen savers
//
	SystemParametersInfo( SPI_GETSCREENSAVEACTIVE, 0, &bScreenSaver, 0 ); 
	SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, FALSE, 0, SPIF_SENDWININICHANGE ); 
	StoredScreenSaverSetting=1;
//
// Check for Windows 2000 RTM being present
//
	OSVERSIONINFO osinfo;
	osinfo.dwOSVersionInfoSize=sizeof(osinfo);
	GetVersionEx( &osinfo );

	if( osinfo.dwPlatformId==VER_PLATFORM_WIN32_NT )
	{
		if( osinfo.dwMajorVersion==5 )
		{
			if( osinfo.dwBuildNumber<2195 )
				PAUSE(( "Please upgrade to Windows 2000 RTM (Build 2195)" ));
		}
	}
//
// Check desktop is in a valid pixel format, create a game window
//
	if( Platform==Platform_Game )
	{
		if( DesktopBpp==1 || (!RunFullScreen && DesktopBpp!=16 && DesktopBpp!=32) )
		{
			char Buffer[256];
			char ColorMode[256];
			if( DesktopBpp==8 )
				strcpy(ColorMode, gos_GetResourceString( gLanguageDLL, GOS_STR_NO_HW_ACCEL_8BPP ) );
			else if( DesktopBpp==24 )
				strcpy(ColorMode, gos_GetResourceString( gLanguageDLL, GOS_STR_NO_HW_ACCEL_24BPP ) );
			else
			{
				MessageBox( NULL, gos_GetResourceString( gLanguageDLL, GOS_STR_UNSUPPORTED_COLOR_DEPTH ), ApplicationName, MB_OK | MB_ICONEXCLAMATION );
				status=AfterExit;
				exit(1);
			}

			void* pArg[1];
			pArg[0] = ColorMode;
			FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
				gos_GetResourceString(gLanguageDLL, GOS_STR_COLOR_DEPTH_NO_HW_ACCEL),
				0, 0, Buffer, sizeof(Buffer), (va_list*)pArg);
			ErrorMessageTitle=Buffer;
			if( 0==gNoDialogs )
			{
				DoColorDialog();
				if( ErrorReturn==-1 )
					ExitGameOS();
				if( ErrorReturn==1 )
					RunFullScreen=1;
			}
		}
//
// Create application window
//
		widthX = Environment.screenWidth;
		heightY = Environment.screenHeight;

		wndClass.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
		if (Environment.allowDoubleClicks)
			wndClass.style |= CS_DBLCLKS;

		wndClass.lpfnWndProc = (WNDPROC)GameOSWinProc;
		wndClass.cbClsExtra = 0;
		wndClass.cbWndExtra = 0;
		wndClass.hInstance = hInstance;
//
// Try and find first icon defined in file
//
		EnumResourceNames( hInstance, RT_GROUP_ICON, EnumIcons, 0 );
		if( IconName )
			wndClass.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(IconName) );
		else
			wndClass.hIcon = NULL;
		wndClass.hCursor = NULL;
		wndClass.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
		wndClass.lpszMenuName = Environment.applicationName;
		wndClass.lpszClassName = Environment.applicationName;

		if( RegisterClass(&wndClass) )
		{
			int WindowSizeX,WindowSizeY;
			RECT WindowRect;

			WindowRect.left=0;
			WindowRect.top=0;
			WindowRect.right=widthX;
			WindowRect.bottom=heightY;
			AdjustWindowRect(&WindowRect,WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MAXIMIZEBOX|WS_MINIMIZEBOX,0);
			WindowSizeX=WindowRect.right-WindowRect.left;
			WindowSizeY=WindowRect.bottom-WindowRect.top;
#ifdef _DEBUG
			hWindow = CreateWindow( Environment.applicationName, Environment.applicationName,
									WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MAXIMIZEBOX|WS_MINIMIZEBOX,
									WindowStartX, WindowStartY,
									WindowSizeX, WindowSizeY,
									NULL, NULL, hInstance, NULL);
#else // !_DEBUG
            DWORD dwEXStyle;
            if (g_pfnCTCL_GetType && (((*g_pfnCTCL_GetType)() == _ECTCL_Console) || ((*g_pfnCTCL_GetType)() == _ECTCL_None))) {
                dwEXStyle = WS_EX_APPWINDOW;
            } else {
                dwEXStyle = WS_EX_APPWINDOW|WS_EX_TOPMOST;
            }
			hWindow = CreateWindowEx(dwEXStyle,
                                    Environment.applicationName, Environment.applicationName,
									WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MAXIMIZEBOX|WS_MINIMIZEBOX,
									WindowStartX, WindowStartY,
									WindowSizeX, WindowSizeY,
									NULL, NULL, hInstance, NULL);
#endif // _DEBUG
			if( hWindow )
			{
                if( !gDumpMachineInfo ) {
					ShowWindow( hWindow, SW_SHOWDEFAULT );
                    SetFocus(hWindow);
                }
				InitializeIME(hWindow);
				gos_EnableIME(false);	// disable IME by default.
//#if !defined(_DEBUG)
//                SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
//                SetForegroundWindow(hWindow);
//#endif // !defined(_DEBUG)
				return;
			}
		}
		STOP(( "Cannot initialize windows" ));
	}
}


//
// Close down windows
//
void DestroyWindows()
{
	if( _SetThreadExecutionState )
	{
		_SetThreadExecutionState( ES_CONTINUOUS );				// Re-enable powersavings
	}
	if( StoredScreenSaverSetting )
	{
		SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, bScreenSaver, 0, SPIF_SENDWININICHANGE ); 
		StoredScreenSaverSetting=0;
	}
	if( wndClass.hIcon )
	{
		DestroyIcon( wndClass.hIcon );
	}

	if( hMappedFile )
	{
		CloseHandle(hMappedFile);
		hMappedFile=0;
	}
}


//
//
// This the the windows 'message loop' - all messages are delt with before continuing the game
//
//
void Update()
{
	LOG_BLOCK("Gos::Update ( windows messages )");

//
// If stopped because of a windows menu, freeze game
//
	if( WindowsPause )
	{
		LOG_BLOCK("Windows::WaitMessage");
		WaitMessage();
	}
//
// Empty all the windows messages
//
	while( PeekMessage(&msg,NULL,0,0,PM_REMOVE) )
	{
		if( msg.message==WM_QUIT ) 
			break;
//
// In MFC applications; Translate only if it is not the main app window.  (e.g. it is a child of the main app window)
//
		if( Platform == Platform_MFC )
		{
			HWND hwndForeground = GetForegroundWindow();
			if( (hwndForeground!=hWindow) && IsDialogMessage(hwndForeground, &msg) )
				continue;
		}
//
// Otherwise translate and process message
//
		if (!IgnoreImeHotKey(&msg))
		{
		{
			LOG_BLOCK("Windows::TranslateMessage");
			TranslateMessage( &msg );
		}
		{
			LOG_BLOCK("Windows::DispatchMessage");
			DispatchMessage( &msg );
		}
		}
	}
//
// Was scroll lock pressed and replay required?
//
	if( ForceReStart )
	{
		ForceReStart=0;
		RestartGameOS();
	}
//
// Was one a quit message?
//
	if( msg.message==WM_QUIT )
		WindowClosed = 1;
//
// If not active, or got keyboard focus, give back time to system - When multiple apps allowed, dont slow down
//
	if( !gActive || !gGotFocus )
	{
		switch( LoseFocusBehavior )
		{
			case 0:
				if( !GosEventLog::Logging() )
					Sleep(20);
				break;
			case 1:
				WaitMessage(); 
			case 2:
				break;
		}
	}
	else
	{
		if (LoseFocusBehavior == 3)
		{
			static double timeLastTime = 0.0;
			const double minTimePerFrame = 1 / 60.0;
			double thisTime = gos_GetHiResTime();

			double timeToWait = minTimePerFrame - (thisTime - timeLastTime);
			if (timeToWait > 0)
			{
				Sleep((int)(timeToWait * 1000));
			}

			timeLastTime = thisTime;
		}
	}
}






//
// Fills the passed buffer with any text in the clipboard and returns string length (truncated to buffer size)
//
DWORD __stdcall gos_GetClipboardText( char* Buffer, DWORD BufferSize )
{
	*Buffer=0;

	if( !IsClipboardFormatAvailable(CF_TEXT) )
		return 0;

	if( !OpenClipboard(hWindow) )
		return 0;  

	HGLOBAL hglb = GetClipboardData(CF_TEXT);
	
	if( hglb )
	{ 
		char* lptstr = (char*)GlobalLock(hglb);
		if( lptstr != NULL )
		{
			strncpy( Buffer, lptstr, BufferSize ); 
			Buffer[BufferSize-1]=0;
			GlobalUnlock(hglb);
		}
		CloseClipboard(); 
		return strlen(Buffer);
	} 

	CloseClipboard(); 
	return 0;
}


//
// Sets the windows clipboard to the current text string
//
void __stdcall gos_SetClipboardText( char* Text )
{
	if( !OpenClipboard(hWindow) )
		return;
	EmptyClipboard(); 

	if( *Text==0 )
		return;

	HGLOBAL hglbCopy = GlobalAlloc(GMEM_DDESHARE, strlen(Text)+1);
	if( !hglbCopy)
	{ 
		CloseClipboard();
		return;
	} 

	char* lptstrCopy = (char*)GlobalLock(hglbCopy); 

	memcpy(lptstrCopy, Text, strlen(Text)+1 );

	GlobalUnlock(hglbCopy);

	SetClipboardData(CF_TEXT, hglbCopy);

	CloseClipboard(); 
}






