Ejemplo n.º 1
0
void IF_ReleaseMouseCapture(CP_HINTERFACE hInterface)
{
	CPs_InterfaceWindowState* pState;
	
	// Init
	pState = (CPs_InterfaceWindowState*)hInterface;
	CP_CHECKOBJECT(pState);
	
	pState->m_bMouseCaptured = FALSE;
	ReleaseCapture();
}
Ejemplo n.º 2
0
void IF_PostAppMessage(CP_HINTERFACE hInterface, const UINT uiMessage, const WPARAM wParam, const LPARAM lParam)
{
	CPs_InterfaceWindowState* pState;
	
	// Init
	pState = (CPs_InterfaceWindowState*)hInterface;
	CP_CHECKOBJECT(pState);
	CP_ASSERT(uiMessage >= WM_APP);
	
	PostMessage(pState->m_hWnd, uiMessage, wParam, lParam);
}
Ejemplo n.º 3
0
BOOL CPSLOCAL_Read(CPs_InStream* pStream, void* pDestBuffer, const size_t iBytesToRead, size_t* piBytesRead)
{
	DWORD bytes;
	BOOL reply;
	
	CPs_InStream_File* pContext = (CPs_InStream_File*)pStream->m_pModuleCookie;
	CP_CHECKOBJECT(pContext);
	
	reply = ReadFile(pContext->m_hFile, pDestBuffer, (DWORD)iBytesToRead, &bytes, 0);
	*piBytesRead = bytes;
	return reply;
}
Ejemplo n.º 4
0
void CPP_OMFL_Flush(CPs_OutputModule* pModule)
{
#ifdef _DEBUG
	CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
	
	CP_CHECKOBJECT(pContext);
	
	// Stop any pending playing
	
	CP_ASSERT(CPP_OMFL_IsOutputComplete(pModule));
#endif
}
Ejemplo n.º 5
0
void IF_SetMouseCapture(CP_HINTERFACE hInterface, wp_IF_onMouseMessage pfn_onMouseMove, wp_IF_onMouseMessage pfn_onMouseButton_LUp)
{
	CPs_InterfaceWindowState* pState;
	
	// Init
	pState = (CPs_InterfaceWindowState*)hInterface;
	CP_CHECKOBJECT(pState);
	
	pState->m_bMouseCaptured = TRUE;
	pState->m_hndlr_onMouseMove = pfn_onMouseMove;
	pState->m_hndlr_onMouseButton_LUp = pfn_onMouseButton_LUp;
	SetCapture(pState->m_hWnd);
}
Ejemplo n.º 6
0
void IF_SetVisible(CP_HINTERFACE hInterface, const BOOL bVisible)
{
	CPs_InterfaceWindowState* pState;
	
	// Init
	pState = (CPs_InterfaceWindowState*)hInterface;
	CP_CHECKOBJECT(pState);
	
	if (bVisible)
		if (IsIconic(pState->m_hWnd))
			ShowWindow(pState->m_hWnd, SW_RESTORE);

	ShowWindow(pState->m_hWnd, bVisible ? SW_SHOW : SW_HIDE);

}
Ejemplo n.º 7
0
const CPs_SubFile* CP_FindFile(CP_COMPOSITEFILE hComposite, const char* pcFilename)
{
	CPs_CompositeContext* pContext = (CPs_CompositeContext*)hComposite;
	const CPs_SubFile* pSubFile_Cursor;
	CP_CHECKOBJECT(pContext);
	
	// Search for subfile
	
	for (pSubFile_Cursor = pContext->m_pFirstSubFile; pSubFile_Cursor; pSubFile_Cursor = (const CPs_SubFile*)pSubFile_Cursor->m_pNext)
	{
		if (stricmp(pSubFile_Cursor->m_pcName, pcFilename) == 0)
			return pSubFile_Cursor;
	}
	
	return NULL;
}
Ejemplo n.º 8
0
void CPSINET_Uninitialise(CPs_InStream* pStream)
{
	CPs_InStream_Internet* pContext = (CPs_InStream_Internet*)pStream->m_pModuleCookie;
	CP_CHECKOBJECT(pContext);
	
	// Clear the thread
	pContext->m_pBufferFillContext->m_bTerminate = TRUE;
	WaitForSingleObject(pContext->m_hFillerThread, INFINITE);
	CloseHandle(pContext->m_hFillerThread);
	free(pContext->m_pBufferFillContext->m_pcFlexiURL);
	free(pContext->m_pBufferFillContext);
	
	// Free this context
	pContext->m_pCircleBuffer->Uninitialise(pContext->m_pCircleBuffer);
	free(pContext);
	free(pStream);
}
Ejemplo n.º 9
0
void CPP_OMFL_SetPause(CPs_OutputModule* pModule, const BOOL bPause)
{
	CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
	CP_CHECKOBJECT(pContext);
	
	if (!pContext->m_hFile)
		return;
		
	// Toggle pause state
	if (bPause == TRUE)
		pContext->m_bPaused = TRUE;
	else
	{
		pContext->m_bPaused = FALSE;
		SetEvent(pModule->m_evtBlockFree);
	}
}
Ejemplo n.º 10
0
void CPP_OMFL_SetInternalVolume(CPs_OutputModule* pModule, const int iNewVolume)
{
	CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
	int iNewVolume_DWORD;
	CP_CHECKOBJECT(pContext);
	
	if (!pContext->m_hFile)
		return;
		
	// Clip volume to word
	iNewVolume_DWORD = iNewVolume * 656;
	
	if (iNewVolume_DWORD > 0xFFFF)
		iNewVolume_DWORD = 0xFFFF;
		
	iNewVolume_DWORD |= (iNewVolume_DWORD << 16);
	
}
Ejemplo n.º 11
0
unsigned int CircleGetFreeSpace(CPs_CircleBuffer* pCBuffer)
{
	unsigned int iNumBytesFree;
	
	CP_CHECKOBJECT(pCBuffer);
	EnterCriticalSection(&pCBuffer->m_csCircleBuffer);
	
	if (pCBuffer->m_iWriteCursor < pCBuffer->m_iReadCursor)
		iNumBytesFree = (pCBuffer->m_iReadCursor - 1) - pCBuffer->m_iWriteCursor;
	else if (pCBuffer->m_iWriteCursor == pCBuffer->m_iReadCursor)
		iNumBytesFree = pCBuffer->m_iBufferSize;
	else
		iNumBytesFree = (pCBuffer->m_iReadCursor - 1) + (pCBuffer->m_iBufferSize - pCBuffer->m_iWriteCursor);
		
	LeaveCriticalSection(&pCBuffer->m_csCircleBuffer);
	
	return iNumBytesFree;
}
Ejemplo n.º 12
0
void IF_RemoveAllSubparts(CP_HINTERFACE hInterface)
{
	CPs_InterfaceWindowState* pState;
	CPs_InterfacePart* pSubPart_Cursor;
	CPs_InterfacePart* pSubPart_Next;
	
	// Init
	pState = (CPs_InterfaceWindowState*)hInterface;
	CP_CHECKOBJECT(pState);
	
	// Walk through list destroying subparts
	
	for (pSubPart_Cursor = pState->m_pFirstSubPart; pSubPart_Cursor; pSubPart_Cursor = pSubPart_Next)
	{
		pSubPart_Next = (CPs_InterfacePart*)pSubPart_Cursor->m_hNext;
		IP_Destroy(pSubPart_Cursor);
	}
	
	pState->m_pFirstSubPart = NULL;
}
Ejemplo n.º 13
0
void CPP_OMFL_Uninitialise(CPs_OutputModule* pModule)
{
	CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
	CP_CHECKOBJECT(pContext);
	CP_TRACE0("Wave out shutting down");
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
	
	// If there is a File handle
	
	if (pContext->m_hFile)
	{
		// Stop any pending playing
		fclose(pContext->m_hFile);
		pContext->m_hFile = NULL;
		// Clean up
		CloseHandle(pModule->m_evtBlockFree);
	}
	
	free(pContext);
	
	pModule->m_pModuleCookie = NULL;
}
Ejemplo n.º 14
0
void IF_AddSubPart_Indicator(CP_HINTERFACE hInterface,
							 const char* pcName,
							 const DWORD dwAlign,
							 const RECT* prPosition)
{
	CPs_InterfaceWindowState* pState;
	CPs_InterfacePart* pSubPart_Next;
	
	// Init
	pState = (CPs_InterfaceWindowState*)hInterface;
	CP_CHECKOBJECT(pState);
	
	// Add new head to list
	pSubPart_Next = pState->m_pFirstSubPart;
	
	// Setup new part
	pState->m_pFirstSubPart = IP_Create_Indicator(pcName);
	pState->m_pFirstSubPart->m_hNext = pSubPart_Next;
	pState->m_pFirstSubPart->m_hOwner = hInterface;
	pState->m_pFirstSubPart->m_dwAlign = dwAlign;
	pState->m_pFirstSubPart->m_bRectAlignMode = TRUE;
	pState->m_pFirstSubPart->m_rPosition = *prPosition;
}
Ejemplo n.º 15
0
BOOL CircleBufferRead(CPs_CircleBuffer* pCBuffer, void* pDestBuffer, const unsigned int _iBytesToRead, unsigned int* pbBytesRead)
{
	unsigned int iBytesToRead = _iBytesToRead;
	unsigned int iBytesRead = 0;
	DWORD dwWaitResult;
	BOOL bComplete = FALSE;
	CP_CHECKOBJECT(pCBuffer);
	
	while (iBytesToRead > 0 && bComplete == FALSE)
	{
		dwWaitResult = WaitForSingleObject(pCBuffer->m_evtDataAvailable, CIC_WAITTIMEOUT);
		
		if (dwWaitResult == WAIT_TIMEOUT)
		{
			CP_TRACE0("Circle buffer - did not fill in time!");
			*pbBytesRead = iBytesRead;
			return FALSE;
		}
		
		EnterCriticalSection(&pCBuffer->m_csCircleBuffer);
		
		// Take what we can from the CBuffer
		
		if (pCBuffer->m_iReadCursor > pCBuffer->m_iWriteCursor)
		{
			unsigned int iChunkSize = pCBuffer->m_iBufferSize - pCBuffer->m_iReadCursor;
			
			if (iChunkSize > iBytesToRead)
				iChunkSize = iBytesToRead;
				
			// Perform the read
			memcpy((BYTE*)pDestBuffer + iBytesRead,
				   pCBuffer->m_pBuffer + pCBuffer->m_iReadCursor,
				   iChunkSize);
			       
			iBytesRead += iChunkSize;
			iBytesToRead -= iChunkSize;
			
			pCBuffer->m_iReadCursor += iChunkSize;
			
			if (pCBuffer->m_iReadCursor >= pCBuffer->m_iBufferSize)
				pCBuffer->m_iReadCursor -= pCBuffer->m_iBufferSize;
		}
		
		if (iBytesToRead && pCBuffer->m_iReadCursor < pCBuffer->m_iWriteCursor)
		{
			unsigned int iChunkSize = pCBuffer->m_iWriteCursor - pCBuffer->m_iReadCursor;
			
			if (iChunkSize > iBytesToRead)
				iChunkSize = iBytesToRead;
				
			// Perform the read
			memcpy((BYTE*)pDestBuffer + iBytesRead,
				   pCBuffer->m_pBuffer + pCBuffer->m_iReadCursor,
				   iChunkSize);
			       
			iBytesRead += iChunkSize;
			iBytesToRead -= iChunkSize;
			pCBuffer->m_iReadCursor += iChunkSize;
		}
		
		// Is there any more data to read
		
		if (pCBuffer->m_iReadCursor == pCBuffer->m_iWriteCursor)
		{
			if (pCBuffer->m_bComplete)
				bComplete = TRUE;
		}
		
		else
			SetEvent(pCBuffer->m_evtDataAvailable);
			
		LeaveCriticalSection(&pCBuffer->m_csCircleBuffer);
	}
	
	*pbBytesRead = iBytesRead;
	
	return bComplete ? FALSE : TRUE;
}
Ejemplo n.º 16
0
void CPP_OMFL_RefillBuffers(CPs_OutputModule* pModule)
{
	BOOL bMoreData;
	DWORD dwBufferLength = CPC_OUTPUTBLOCKSIZE;
	BYTE lpData[CPC_OUTPUTBLOCKSIZE];
	
	CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
	CP_CHECKOBJECT(pContext);
	
	
	// Open a file out
	
	if (!pContext->m_hFile)
	{
		CPs_FileInfo pFileInfo;
		CP_HPLAYLISTITEM hCurrent = CPL_GetActiveItem(globals.m_hPlaylist);
		const char *pathname = CPLI_GetPath(hCurrent);
		char newpath[MAX_PATH];
		int rec_rate;
		int rec_bits;
		UINT temp;
		WAVEFORMATEX wfs;
		char *dot;
		
		pModule->m_pCoDec->GetFileInfo(pModule->m_pCoDec, &pFileInfo);
		rec_rate = pFileInfo.m_iFreq_Hz;
		rec_bits = pFileInfo.m_b16bit == TRUE ? 16 : 8;
		
		// saving internet stream
		
		if (_strnicmp(pathname, CIC_HTTPHEADER, strlen(CIC_HTTPHEADER)) == 0)
		{
			strcpy(newpath, "Stream.wav");
			pFileInfo.m_iFileLength_Secs = 0xffffffff;
		}
		
		else
		{
			// replace the extension with .wav
			strcpy(newpath, pathname);
			dot = strrchr(newpath, '.');
			
			if (dot)
				*dot = '\0';
			
			strcat(newpath, ".wav");
		}
		
		// Trap error
		
		while (!pContext->m_hFile)
		{
			OPENFILENAME fn;
			char filefilter[] =
				"WAV files (*.wav)\0*.wav\0"
				"All Files (*.*)\0*.*\0";
			BOOL    returnval;
			fn.lStructSize = sizeof(OPENFILENAME);
			fn.hwndOwner = (HWND) GetWindowLong(windows.wnd_main, DWLP_USER);
			fn.hInstance = NULL;
			fn.lpstrFilter = filefilter;
			fn.lpstrCustomFilter = NULL;
			fn.nMaxCustFilter = 0;
			fn.nFilterIndex = 0;
			fn.lpstrFile = newpath;
			fn.nMaxFile = MAX_PATH * 200;
			fn.lpstrFileTitle = NULL;
			fn.nMaxFileTitle = 0;
			fn.lpstrInitialDir = options.last_used_directory;
			fn.lpstrTitle = NULL;
			fn.Flags = OFN_ENABLESIZING |
					   OFN_HIDEREADONLY | OFN_EXPLORER;
			fn.nFileOffset = 0;
			fn.nFileExtension = 0;
			fn.lpstrDefExt = NULL;
			fn.lCustData = 0;
			fn.lpfnHook = NULL;
			fn.lpTemplateName = NULL;
			returnval = GetSaveFileName(&fn);
			
			if (!returnval)
				return;
			
			pContext->m_hFile = fopen(fn.lpstrFile, "wb");
			
			if (pContext->m_hFile)
				break;
		}
		
		// Wave header stuff
		
		// prep wave format header
		wfs.wFormatTag = WAVE_FORMAT_PCM;
		wfs.nChannels = pFileInfo.m_bStereo == TRUE ? 2 : 1;
		wfs.nSamplesPerSec = rec_rate;
		wfs.nBlockAlign = (short)(rec_bits / 8 * wfs.nChannels);
		wfs.nAvgBytesPerSec = rec_rate * wfs.nBlockAlign;
		wfs.wBitsPerSample = rec_bits;
		wfs.cbSize = 0;
		
		// RIFF header block
		fwrite("RIFF", 4, 1, pContext->m_hFile);
		temp =  sizeof(wfs) + 20 + (pFileInfo.m_iFileLength_Secs * wfs.nAvgBytesPerSec);
		fwrite(&temp, 4, 1, pContext->m_hFile);
		fwrite("WAVE", 4, 1, pContext->m_hFile);
		
		// 'fmt ' block
		fwrite("fmt ", 4, 1, pContext->m_hFile);
		temp = sizeof(wfs);
		fwrite(&temp, 4, 1, pContext->m_hFile);
		fwrite(&wfs, sizeof(wfs), 1, pContext->m_hFile);
		
		// 'data' block
		fwrite("data", 4, 1, pContext->m_hFile);
		temp = pFileInfo.m_iFileLength_Secs * wfs.nAvgBytesPerSec;
		fwrite(&temp, 4, 1, pContext->m_hFile);
	}
	
	
	
	// Scan ring buffer and fill any empty blocks - any blocks that become free
	// while this loop is running will retrigger the event - the worse that can
	// happen is that we enter this loop with no blocks free
	
	// Get block from CoDec and then just send it to the device (how easy is this!)
	bMoreData = pModule->m_pCoDec->GetPCMBlock(pModule->m_pCoDec, lpData, &dwBufferLength);
	
	
	// If there is EQ then apply it
	{
		// Note that the EQ module is initailised and uninitialsed by the engine
		CPs_EqualiserModule* pEQModule = (CPs_EqualiserModule*)pModule->m_pEqualiser;
		pEQModule->ApplyEQToBlock_Inplace(pEQModule, lpData, dwBufferLength);
	}
	
	if (dwBufferLength > 0)
		fwrite(lpData, dwBufferLength, 1, pContext->m_hFile);
		
	// Nothing to send
	if (bMoreData == FALSE)
	{
		pModule->m_pCoDec->CloseFile(pModule->m_pCoDec);
		pModule->m_pCoDec = NULL;
		
		if (pContext->m_hFile) 
			fclose(pContext->m_hFile);
		
		pContext->m_hFile = NULL;
	}
	
	if (!pContext->m_bPaused)
		SetEvent(pModule->m_evtBlockFree);
}
Ejemplo n.º 17
0
void IF_UpdateSubPartLayout(CP_HINTERFACE hInterface)
{
	CPs_InterfaceWindowState* pState;
	CPs_InterfacePart* pSubPart_Cursor;
	
	// Init
	pState = (CPs_InterfaceWindowState*)hInterface;
	CP_CHECKOBJECT(pState);
	
	// Walk through list setting position
	
	for (pSubPart_Cursor = pState->m_pFirstSubPart; pSubPart_Cursor; pSubPart_Cursor = (CPs_InterfacePart*)pSubPart_Cursor->m_hNext)
	{
		if (pSubPart_Cursor->m_bRectAlignMode == TRUE)
		{
			// Set position
			// - left
			if (pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_LEFT)
				pSubPart_Cursor->m_rLocation.left = pSubPart_Cursor->m_rPosition.left;
			else
			{
				CP_ASSERT(pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_RIGHT);
				pSubPart_Cursor->m_rLocation.left = pState->m_szWindowSize.cx - pSubPart_Cursor->m_rPosition.right - pSubPart_Cursor->m_rPosition.left;
			}
			
			// - right
			
			if (pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_RIGHT)
				pSubPart_Cursor->m_rLocation.right = pState->m_szWindowSize.cx - pSubPart_Cursor->m_rPosition.right;
			else
			{
				CP_ASSERT(pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_LEFT);
				pSubPart_Cursor->m_rLocation.right = pSubPart_Cursor->m_rLocation.left + pSubPart_Cursor->m_rPosition.right;
			}
			
			// - top
			
			if (pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_TOP)
				pSubPart_Cursor->m_rLocation.top = pSubPart_Cursor->m_rPosition.top;
			else
			{
				//  CP_ASSERT(pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_BOTTOM);
				pSubPart_Cursor->m_rLocation.top = pState->m_szWindowSize.cy - pSubPart_Cursor->m_rPosition.bottom - pSubPart_Cursor->m_rPosition.top;
			}
			
			// - bottom
			
			if (pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_BOTTOM)
				pSubPart_Cursor->m_rLocation.bottom = pState->m_szWindowSize.cy - pSubPart_Cursor->m_rPosition.bottom;
			else
			{
//                CP_ASSERT(pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_TOP);
				pSubPart_Cursor->m_rLocation.bottom = pSubPart_Cursor->m_rLocation.top + pSubPart_Cursor->m_rPosition.bottom;
			}
		}
		
		else
		{
			// Set position
			if (pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_LEFT)
				pSubPart_Cursor->m_rLocation.left = pSubPart_Cursor->m_ptOffset.x;
			else
			{
				CP_ASSERT(pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_RIGHT);
				pSubPart_Cursor->m_rLocation.left = pState->m_szWindowSize.cx - pSubPart_Cursor->m_szSize.cx - pSubPart_Cursor->m_ptOffset.x;
			}
			
			pSubPart_Cursor->m_rLocation.right = pSubPart_Cursor->m_rLocation.left + pSubPart_Cursor->m_szSize.cx;
			
			if (pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_TOP)
				pSubPart_Cursor->m_rLocation.top = pSubPart_Cursor->m_ptOffset.y;
			else
			{
				CP_ASSERT(pSubPart_Cursor->m_dwAlign & CPC_COMMANDTARGET_ALIGN_BOTTOM);
				pSubPart_Cursor->m_rLocation.top = pState->m_szWindowSize.cy - pSubPart_Cursor->m_szSize.cy - pSubPart_Cursor->m_ptOffset.y;
			}
			
			pSubPart_Cursor->m_rLocation.bottom = pSubPart_Cursor->m_rLocation.top + pSubPart_Cursor->m_szSize.cy;
		}
	}
}
Ejemplo n.º 18
0
DWORD WINAPI CPI_Player__EngineEP(void* pCookie)
{
	BOOL bTerminateThread = FALSE;
	HRESULT hr_ComState;
	CPs_PlayerContext playercontext;
	
	playercontext.m_pBaseEngineParams = (CPs_PlayEngine*)pCookie;
	playercontext.m_bOutputActive = FALSE;
	playercontext.m_iProportion_TrackLength = 0;
	playercontext.m_iLastSentTime_Secs = -1;
	playercontext.m_iLastSentTime_Proportion = -1;
	playercontext.m_iInternalVolume = 100;
	CP_CHECKOBJECT(playercontext.m_pBaseEngineParams);
	
	CP_TRACE0("Cooler Engine Startup");
	hr_ComState = CoInitialize(NULL);
		
	// Initialise CoDecs
	CP_InitialiseCodec_MPEG(&playercontext.m_CoDecs[CP_CODEC_MPEG]);
	CP_InitialiseCodec_WAV(&playercontext.m_CoDecs[CP_CODEC_WAV]);
	CP_InitialiseCodec_OGG(&playercontext.m_CoDecs[CP_CODEC_OGG]);
	CP_InitialiseCodec_WinAmpPlugin(&playercontext.m_CoDecs[CP_CODEC_WINAMPPLUGIN]);
	
	// Initialise output module
	
	if (options.decoder_output_mode > CP_OUTPUT_last)
		options.decoder_output_mode = CP_OUTPUT_last;
		
	playercontext.m_dwCurrentOutputModule = options.decoder_output_mode;
	
	CPI_Player_Output_Initialise_WaveMapper(&playercontext.m_OutputModules[CP_OUTPUT_WAVE]);
	CPI_Player_Output_Initialise_DirectSound(&playercontext.m_OutputModules[CP_OUTPUT_DIRECTSOUND]);
	CPI_Player_Output_Initialise_File(&playercontext.m_OutputModules[CP_OUTPUT_FILE]);
	
	playercontext.m_pCurrentOutputModule = &playercontext.m_OutputModules[playercontext.m_dwCurrentOutputModule];
	
	// Initialise EQ
	CPI_Player_Equaliser_Initialise_Basic(&playercontext.m_Equaliser);
	
	{
		CPs_PlayEngine* player = (CPs_PlayEngine*)pCookie;
		player->m_pContext = &playercontext;
	}
	
	// Initialise USER32.DLL for this thread
	{
		MSG msgDummy;
		PeekMessage(&msgDummy, 0, WM_USER, WM_USER, PM_NOREMOVE);
		
		// Signal this thread ready for input
		SetEvent(playercontext.m_pBaseEngineParams->m_hEvtThreadReady);
	}
	
	do
	{
		// Process any pending messages
		BOOL bForceRefill = FALSE;
		MSG msg;
		DWORD dwWaitResult;
		
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			// Decode engine message
			switch (msg.message)
			{
			
				case CPTM_QUIT:
					bTerminateThread = TRUE;
					break;
					
				case CPTM_OPENFILE:
				{
					char* pcFilename = (char*)msg.wParam;
					
					// If there is another pending openfile then ignore this one
					// This helps when this thread is non responsive (on an http connect for example)
					// and the user is hammering the hell out of the play button (as I always
					// do) - this will cause a number of open/closes to be placed into the
					// message queue which will tie up this thread for ages!!
					MSG msg2;
					
					if (PeekMessage(&msg2, NULL, CPTM_OPENFILE, CPTM_OPENFILE, PM_NOREMOVE) == FALSE)
					{
						CPs_CoDecModule* pNewCoDec;
						
						// If there is a CoDec playing then shut it down
						
						if (playercontext.m_pCurrentOutputModule->m_pCoDec)
						{
							playercontext.m_pCurrentOutputModule->m_pCoDec->CloseFile(playercontext.m_pCurrentOutputModule->m_pCoDec);
							playercontext.m_pCurrentOutputModule->m_pCoDec = NULL;
						}
						
						CP_TRACE1("Openfile \"%s\"", pcFilename);
						
						pNewCoDec = OpenCoDec(&playercontext, pcFilename);
						
						// If the open failed then request a new stream from the interface
						
						if (pNewCoDec == NULL)
						{
							PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsEndOfStream, 0);
						}
						
						// Check the file's format - if the sample rate, nChannels or sample size has changed
						// then clear the current output and shutdown output device (this will cause a gap
						// - but only when the format changes)
						
						else if (playercontext.m_bOutputActive == TRUE)
						{
							CPs_FileInfo FileInfo;
							pNewCoDec->GetFileInfo(pNewCoDec, &FileInfo);
							
							if (FileInfo.m_iFreq_Hz != playercontext.m_iOpenDevice_Freq_Hz
									|| FileInfo.m_bStereo != playercontext.m_bOpenDevice_Stereo
									|| FileInfo.m_b16bit != playercontext.m_bOpenDevice_16bit)
							{
								CP_TRACE0("Stream format changes - clearing stream");
								EmptyOutputStream(&playercontext);
								StartPlay(pNewCoDec, &playercontext);
								bForceRefill = TRUE;
							}
						}
						
						playercontext.m_pCurrentOutputModule->m_pCoDec = pNewCoDec;
					}
					
					#ifdef _DEBUG
					else
					{
						CP_TRACE1("Openfile of \"%s\" ignored due to other opens in the queue", pcFilename);
					}
					#endif
					
					// Cleanup
					free(pcFilename);
				}
				
				break;
				
				case CPTM_SEEK:
				
					if (playercontext.m_bOutputActive == TRUE)
					{
						// Ignore message if there is another on it's way!
						MSG msg2;
						
						if (PeekMessage(&msg2, NULL, CPTM_SEEK, CPTM_SEEK, PM_NOREMOVE) == FALSE)
						{
							if (playercontext.m_pCurrentOutputModule->m_pCoDec)
								playercontext.m_pCurrentOutputModule->m_pCoDec->Seek(playercontext.m_pCurrentOutputModule->m_pCoDec, (int)msg.wParam, (int)msg.lParam);
								
							playercontext.m_pCurrentOutputModule->Flush(playercontext.m_pCurrentOutputModule);
							
							bForceRefill = TRUE;
						}
					}
					// FALLTHROUGH - to let coolplayer know playing has resumed (bugfix from seeking when paused)  */
					
				case CPTM_PLAY:
					if (playercontext.m_pCurrentOutputModule->m_pCoDec)
					{
						// If we don't have an output stage - initialise one now
						if (playercontext.m_bOutputActive == FALSE)
						{
							StartPlay(playercontext.m_pCurrentOutputModule->m_pCoDec, &playercontext);
							bForceRefill = TRUE;
						}
						
						playercontext.m_pCurrentOutputModule->SetPause(playercontext.m_pCurrentOutputModule, FALSE);
						
						PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsPlaying, 0);
						playercontext.m_iLastSentTime_Secs = -1;
						playercontext.m_iLastSentTime_Proportion = -1;
						UpdateProgress(&playercontext);
					}
					
					break;
					
				case CPTM_STOP:
				
					if (playercontext.m_pCurrentOutputModule->m_pCoDec)
					{
						playercontext.m_pCurrentOutputModule->m_pCoDec->CloseFile(playercontext.m_pCurrentOutputModule->m_pCoDec);
						playercontext.m_pCurrentOutputModule->m_pCoDec = NULL;
					}
					
					if (playercontext.m_bOutputActive == TRUE)
					{
						playercontext.m_bOutputActive = FALSE;
						playercontext.m_pCurrentOutputModule->Uninitialise(playercontext.m_pCurrentOutputModule);
					}
					
					PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsStopped, 0);
					
					break;
					
				case CPTM_PAUSE:
					CP_TRACE0("Pause");
					
					if (playercontext.m_bOutputActive == TRUE)
						playercontext.m_pCurrentOutputModule->SetPause(playercontext.m_pCurrentOutputModule, TRUE);
						
					PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsPaused, 0);
					
					break;
					
				case CPTM_SETPROGRESSTRACKLENGTH:
					playercontext.m_iProportion_TrackLength = (int)msg.wParam;
					
					break;
					
				case CPTM_SENDSYNCCOOKIE:
					PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_SYNCCOOKIE, msg.wParam, 0);
					
					break;
					
				case CPTM_BLOCKMSGUNTILENDOFSTREAM:
					EmptyOutputStream(&playercontext);
					
					break;
					
				case CPTM_ENUMOUTPUTDEVICES:
					EnumOutputDevices(&playercontext);
					
					break;
					
				case CPTM_SETEQSETTINGS:
				{
					MSG msg2;
					CPs_EQSettings* pEQ = (CPs_EQSettings*)msg.wParam;
					
					// If there is another pending EQ message do no processing for this one (try to reduce noise)
					
					if (PeekMessage(&msg2, NULL, CPTM_SETEQSETTINGS, CPTM_OPENFILE, PM_NOREMOVE) == FALSE)
					{
						BOOL bEQEnableStateChanged;
						playercontext.m_Equaliser.ApplySettings(&playercontext.m_Equaliser, pEQ, &bEQEnableStateChanged);
						
						// Empty the buffers (this will cause a discontinuity in the music but at least
						// the EQ setting change will be immediate
						
						if (playercontext.m_bOutputActive == TRUE && playercontext.m_pCurrentOutputModule->OnEQChanged)
							playercontext.m_pCurrentOutputModule->OnEQChanged(playercontext.m_pCurrentOutputModule);
					}
					
					free(pEQ);
				}
				
				break;
				
				case CPTM_ONOUTPUTMODULECHANGE:
				{
					playercontext.m_dwCurrentOutputModule = options.decoder_output_mode;
					SetCurrentOutputModule(&playercontext, NULL, &bForceRefill);
				}
				
				break;
				
				case CPTM_ASSOCIATEFILEEXTENSIONS:
					AssociateFileExtensions(&playercontext);
					break;
					
				case CPTM_SETINTERNALVOLUME:
					playercontext.m_iInternalVolume = (int)msg.wParam;
					
					if (playercontext.m_bOutputActive == TRUE && playercontext.m_pCurrentOutputModule->SetInternalVolume)
						playercontext.m_pCurrentOutputModule->SetInternalVolume(playercontext.m_pCurrentOutputModule, playercontext.m_iInternalVolume);
						
					break;
			}
		}
		
		if (bTerminateThread)
			break;
			
		// Wait for either another message or a buffer expiry (if we have a player)
		if (playercontext.m_bOutputActive)
		{
			dwWaitResult = 0L;
			
			if (bForceRefill == FALSE)
			{
				if (playercontext.m_pCurrentOutputModule->m_evtBlockFree)
					dwWaitResult = MsgWaitForMultipleObjects(1, &playercontext.m_pCurrentOutputModule->m_evtBlockFree, FALSE, 1000, QS_POSTMESSAGE);
				else
					dwWaitResult = WAIT_OBJECT_0;
			}
			
			// If the buffer event is signaled then request a refill
			
			if (bForceRefill == TRUE || dwWaitResult == WAIT_OBJECT_0)
			{
				if (playercontext.m_pCurrentOutputModule->m_pCoDec)
				{
					playercontext.m_pCurrentOutputModule->RefillBuffers(playercontext.m_pCurrentOutputModule);
					
					if (playercontext.m_pCurrentOutputModule->m_pCoDec == NULL)
					{
						// Tell UI that we need another file to play
						PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsEndOfStream, 0);
					}
					
					else
						UpdateProgress(&playercontext);
				}
				
				// If output has finished everything that it was doing - close the engine
				
				else if (playercontext.m_pCurrentOutputModule->IsOutputComplete(playercontext.m_pCurrentOutputModule) == TRUE)
				{
					playercontext.m_bOutputActive = FALSE;
					playercontext.m_pCurrentOutputModule->Uninitialise(playercontext.m_pCurrentOutputModule);
					PostMessage(playercontext.m_pBaseEngineParams->m_hWndNotify, CPNM_PLAYERSTATE, (WPARAM)cppsStopped, 0);
				}
			}
		}
		
		else
		{
			WaitMessage();
		}
	}
	
	while (bTerminateThread == FALSE);
	
	// Clean up output (if it's still active)
	if (playercontext.m_pCurrentOutputModule->m_pCoDec)
	{
		playercontext.m_pCurrentOutputModule->m_pCoDec->CloseFile(playercontext.m_pCurrentOutputModule->m_pCoDec);
		playercontext.m_pCurrentOutputModule->m_pCoDec = NULL;
	}
	
	if (playercontext.m_bOutputActive == TRUE)
		playercontext.m_pCurrentOutputModule->Uninitialise(playercontext.m_pCurrentOutputModule);
		
	// Clean up modules
	playercontext.m_Equaliser.Uninitialise(&playercontext.m_Equaliser);
	
	CleanupCoDecs(&playercontext);
	
	if (hr_ComState == S_OK)
		CoUninitialize();
		
	CP_TRACE0("Cooler Engine terminating");
	
	return 0;
}
Ejemplo n.º 19
0
unsigned int _stdcall EP_FillerThread(void* _pContext)
{
	CPs_BufferFillerContext* pContext = (CPs_BufferFillerContext*)_pContext;
	HINTERNET hInternet;
	HINTERNET hURLStream;
	DWORD dwTimeout;
	BOOL bStreamComplete = FALSE;
	INTERNET_BUFFERS internetbuffer;
	BYTE bReadBuffer[CIC_READCHUNKSIZE];
	
	CP_CHECKOBJECT(pContext);
	
	PostMessage(pContext->m_hWndNotify, CPNM_SETSTREAMINGSTATE, (WPARAM)TRUE, (LPARAM)0);
	
	// Check that we can open this file
	hInternet = InternetOpen("CoolPlayer",
							 INTERNET_OPEN_TYPE_PRECONFIG,
							 NULL, NULL, 0L);
	                         
	if (hInternet == NULL)
	{
		pContext->m_pCircleBuffer->SetComplete(pContext->m_pCircleBuffer);
		CP_TRACE0("EP_FillerThread::NoInternetOpen");
		return 0;
	}
	
	dwTimeout = 2000;
	InternetSetOption(hInternet, INTERNET_OPTION_CONNECT_TIMEOUT, &dwTimeout, sizeof(dwTimeout));
	
	hURLStream = InternetOpenUrl(hInternet,
								 pContext->m_pcFlexiURL,
								 NULL,
								 0,
								 INTERNET_FLAG_NO_CACHE_WRITE
								 | INTERNET_FLAG_PRAGMA_NOCACHE,
								 0);
	                             
	if (hURLStream == NULL)
	{
		InternetCloseHandle(hInternet);
		pContext->m_pCircleBuffer->SetComplete(pContext->m_pCircleBuffer);
		CP_TRACE1("EP_FillerThread::NoOpenURL %s", pContext->m_pcFlexiURL);
		return 0;
	}
	
	// Setup the internet buffer
	internetbuffer.dwStructSize = sizeof(internetbuffer);
	internetbuffer.Next = NULL;
	internetbuffer.lpcszHeader = NULL;
	internetbuffer.lpvBuffer = bReadBuffer;
	internetbuffer.dwBufferLength = CIC_READCHUNKSIZE;
	
	// Perform reading
	while (pContext->m_bTerminate == FALSE && bStreamComplete == FALSE)
	{
		BOOL bReadResult;
		
		// Is our circle buffer full?
		
		if (pContext->m_pCircleBuffer->GetFreeSize(pContext->m_pCircleBuffer) < CIC_READCHUNKSIZE)
		{
			Sleep(20);
			continue;
		}
		
		// Read in another chunk - if we don't get any data that's ok - we would rather poll the
		// buffers than just hang on the socket (so the stream can be shutdown if needed)
		internetbuffer.dwBufferLength = CIC_READCHUNKSIZE;
		bReadResult = InternetReadFileEx(hURLStream, &internetbuffer, IRF_NO_WAIT, 0);
		
		if (bReadResult == FALSE)
			bStreamComplete = TRUE;
			
		if (internetbuffer.dwBufferLength)
		{
			pContext->m_pCircleBuffer->Write(pContext->m_pCircleBuffer,
											 internetbuffer.lpvBuffer,
											 internetbuffer.dwBufferLength);
			                                 
			PostMessage(pContext->m_hWndNotify,
						CPNM_SETSTREAMINGSTATE,
						(WPARAM)TRUE,
						(LPARAM)(pContext->m_pCircleBuffer->GetUsedSize(pContext->m_pCircleBuffer)*100) / CIC_STREAMBUFFERSIZE);
		}
		
		else
			Sleep(20);
	}
	
	InternetCloseHandle(hURLStream);
	
	InternetCloseHandle(hInternet);
	
	pContext->m_pCircleBuffer->SetComplete(pContext->m_pCircleBuffer);
	PostMessage(pContext->m_hWndNotify, CPNM_SETSTREAMINGSTATE, (WPARAM)FALSE, (LPARAM)0);
	CP_TRACE0("EP_FillerThread normal shutdown");
	return 0;
}
Ejemplo n.º 20
0
BOOL CF_GetSubFile(CP_COMPOSITEFILE hComposite, const char* pcSubfilename, void** ppSubFile_Uncompressed, unsigned int* piSubFile_Length)
{
	CPs_CompositeContext* pContext = (CPs_CompositeContext*)hComposite;
	const CPs_SubFile* pSubFile;
	DWORD dwCRC32;
	CP_CHECKOBJECT(pContext);
	
	pSubFile = CP_FindFile(hComposite, pcSubfilename);
	
	if (!pSubFile)
	{
		*ppSubFile_Uncompressed = NULL;
		*piSubFile_Length = 0;
		return FALSE;
	}
	
	// Create dest block
	*ppSubFile_Uncompressed = malloc(pSubFile->m_iUncompressedSize);
	
	*piSubFile_Length = pSubFile->m_iUncompressedSize;
	
	if (pSubFile->m_wMethod == CPC_PKFILE_METHOD_STORED)
	{
		memcpy(*ppSubFile_Uncompressed, pContext->m_pFileBase + pSubFile->m_iFileOffset, *piSubFile_Length);
	}
	
	else if (pSubFile->m_wMethod == CPC_PKFILE_METHOD_DEFLATED)
	{
		z_stream zStream;
		
		zStream.zalloc = Z_NULL;
		zStream.zfree = Z_NULL;
		zStream.opaque = Z_NULL;
		zStream.data_type = Z_BINARY;
		inflateInit2(&zStream, -15);  // 15bit window (32Kb window size) (-ve to use an undocumented zLib "no zLib headers" mode)
		
		// Decompress
		zStream.next_out = (BYTE*) * ppSubFile_Uncompressed;
		zStream.avail_out = *piSubFile_Length;
		zStream.next_in = pContext->m_pFileBase + pSubFile->m_iFileOffset;
		zStream.avail_in = pSubFile->m_iCompressedSize;
		inflate(&zStream, Z_FINISH);
		
		// Cleanup
		inflateEnd(&zStream);
	}
	
	// Check CRC32
	dwCRC32 = crc32(0, *ppSubFile_Uncompressed, *piSubFile_Length);
	
	if (dwCRC32 != pSubFile->m_dwCRC32)
	{
		// CRC32 does not match
		free(*ppSubFile_Uncompressed);
		*ppSubFile_Uncompressed = NULL;
		*piSubFile_Length = 0;
		return FALSE;
	}
	
	return TRUE;
}
Ejemplo n.º 21
0
LRESULT CALLBACK exp_InterfaceWindowProc(HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam)
{
	CPs_InterfaceWindowState* pState;
	
	// Get the window's data object
	
	if (uiMessage == WM_NCCREATE)
	{
		HMODULE hModApplication;
		pState = (CPs_InterfaceWindowState*)((CREATESTRUCT*)lParam)->lpCreateParams;
		pState->m_hWnd = hWnd;
		SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pState);
		
		// Setup icons
		hModApplication = GetModuleHandle(NULL);
		SendMessage(hWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)LoadIcon(hModApplication, MAKEINTRESOURCE(APP_ICON)));
		SendMessage(hWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)LoadIcon(hModApplication, MAKEINTRESOURCE(APP_ICON)));
	}
	
	else
		pState = (CPs_InterfaceWindowState*)GetWindowLong(hWnd, GWLP_USERDATA);
		
	// We get some messages before the window gets it's WM_NCCREATE!!! (just how bad is Windows eh???)
	if (!pState)
		return DefWindowProc(hWnd, uiMessage, wParam, lParam);
		
	CP_CHECKOBJECT(pState);
	
	// Message handlers
	switch (uiMessage)
	{
	
		case WM_MOUSEMOVE:
		{
			if (pState->m_bMouseCaptured)
			{
				if (pState->m_hndlr_onMouseMove)
					pState->m_hndlr_onMouseMove(pState, MAKEPOINTS(lParam), (SHORT)wParam);
			}
			
			else
			{
				CPs_InterfacePart* pHitSubPart;
				POINT ptMouse;
				ptMouse.x = (short)LOWORD(lParam);
				ptMouse.y = (short)HIWORD(lParam);
				
				pHitSubPart = IF_HitTestMouse(pState, &ptMouse);
				IF_SetFloatActiveSubPart(pState, pHitSubPart);
			}
			
			return 0;
		} // end WM_MOUSEMOVE

		case WM_LBUTTONDOWN:
		{
			CPs_InterfacePart* pHitSubPart;
			POINT ptMouse;
			ptMouse.x = (short)LOWORD(lParam);
			ptMouse.y = (short)HIWORD(lParam);
			
			pHitSubPart = IF_HitTestMouse(pState, &ptMouse);
			
			if (pHitSubPart && pHitSubPart->onMouseButton_LDown)
			{
				SetCapture(pState->m_hWnd);
				pState->m_pActiveSubpart = pHitSubPart;
				pHitSubPart->onMouseButton_LDown(pHitSubPart, MAKEPOINTS(lParam));
			}

			return 0;
		} // end WM_LBUTTONDOWN
				
		case WM_LBUTTONUP:
		{
			if (pState->m_bMouseCaptured)
			{
				if (pState->m_hndlr_onMouseButton_LUp)
					pState->m_hndlr_onMouseButton_LUp(pState, MAKEPOINTS(lParam), (SHORT)wParam);
			}
			
			else
			{
				if (pState->m_pActiveSubpart)
				{
					ReleaseCapture();
					
					if (pState->m_pActiveSubpart->onMouseButton_LUp)
						pState->m_pActiveSubpart->onMouseButton_LUp(pState->m_pActiveSubpart, MAKEPOINTS(lParam));
						
					pState->m_pActiveSubpart = NULL;
				}
			}
			
			return 0;
		} // end WM_LBUTTONUP


		case WM_NCDESTROY:
		{
			IF_CleanupState(pState);
			break;
		} // end WM_NCDESTROY
			
		case WM_CREATE:
		{
			const CREATESTRUCT* pCS = (const CREATESTRUCT*)lParam;
			
			// Update size/pos cache
			pState->m_ptWindowPos.x = pCS->x;
			pState->m_ptWindowPos.y = pCS->y;
			pState->m_szWindowSize.cx = pCS->cx;
			pState->m_szWindowSize.cy = pCS->cy;
			
			// Reposition any subitems
			IF_UpdateSubPartLayout(pState);
			
			// Callback
			
			if (pState->m_hndlr_onCreate)
			{
				RECT rInitialPos;
				
				rInitialPos.left = 0;
				rInitialPos.top = 0;
				rInitialPos.right = pCS->cx;
				rInitialPos.bottom = pCS->cy;
				pState->m_hndlr_onCreate(pState, &rInitialPos);
			}
			
			IF_RebuildRegion(pState);

			return 0;
		} // end WM_CREATE

		
		case WM_DESTROY:
		{
			if (pState->m_hndlr_onDestroy)
				pState->m_hndlr_onDestroy(pState);
				
			IF_RemoveAllSubparts(pState);
			
			break;
		} // end WM_DESTROY
		
			
		case WM_NCHITTEST:
		{
			CPs_InterfacePart* pSubPart_Cursor;
			POINT ptMouse;
			ptMouse.x = (short)LOWORD(lParam) - pState->m_ptWindowPos.x;
			ptMouse.y = (short)HIWORD(lParam) - pState->m_ptWindowPos.y;
			
			// First perform hit testing on subparts
			
			for (pSubPart_Cursor = pState->m_pFirstSubPart; pSubPart_Cursor; pSubPart_Cursor = (CPs_InterfacePart*)pSubPart_Cursor->m_hNext)
			{
				if (PtInRect(&pSubPart_Cursor->m_rLocation, ptMouse) == TRUE)
					return HTCLIENT;
			}
			
			// If the window is sizable - perform hit testing on edges
			
			if (pState->m_dwStyle & CPC_INTERFACE_STYLE_RESIZING)
			{
				// Is the mouse inside the size bands
				// - top band
				if (ptMouse.y < CPC_SIZEBORDER)
				{
					// Are we in a corner
					// - left
					if (ptMouse.x < CPC_SIZEBORDER)
						return HTTOPLEFT;
						
					// - right
					else if (ptMouse.x > (pState->m_szWindowSize.cx - CPC_SIZEBORDER))
						return HTTOPRIGHT;
					else
						return HTTOP;
				}
				
				// - bottom band
				
				else if (ptMouse.y > (pState->m_szWindowSize.cy - CPC_SIZEBORDER))
				{
					// Are we in a corner
					// - left
					if (ptMouse.x < CPC_SIZEBORDER)
						return HTBOTTOMLEFT;
						
					// - right
					else if (ptMouse.x > (pState->m_szWindowSize.cx - CPC_SIZEBORDER))
						return HTBOTTOMRIGHT;
					else
						return HTBOTTOM;
				}
				
				// - left band
				
				else if (ptMouse.x < CPC_SIZEBORDER)
					return HTLEFT;
					
				// - right band
				else if (ptMouse.x > (pState->m_szWindowSize.cx - CPC_SIZEBORDER))
					return HTRIGHT;
			}
			
			// - return the caption so that the window is dragged
			return HTCAPTION;
		} // end WM_NCHITTEST
		
		case WM_WINDOWPOSCHANGED:
		
		{
			const WINDOWPOS* pWP = (const WINDOWPOS*)lParam;
			RECT rNewPos;
			BOOL bSizeChanged;
			
			rNewPos.left = pWP->x;
			rNewPos.right = pWP->x + pWP->cx;
			rNewPos.top = pWP->y;
			rNewPos.bottom = pWP->y + pWP->cy;
			bSizeChanged = (pWP->flags & SWP_NOSIZE) ? FALSE : TRUE;
			
			pState->m_ptWindowPos.x = pWP->x;
			pState->m_ptWindowPos.y = pWP->y;
			pState->m_szWindowSize.cx = pWP->cx;
			pState->m_szWindowSize.cy = pWP->cy;
			
			if (bSizeChanged)
			{
				IF_UpdateSubPartLayout(pState);
				IF_RebuildRegion(pState);
			}
			
			// Perform callback
			
			if (pState->m_hndlr_onPosChange)
				pState->m_hndlr_onPosChange(pState, &rNewPos, bSizeChanged);

			return 0;
		} // end WM_WINDOWPOSCHANGED

		
		case WM_NCCALCSIZE:
		{
			// We do not wish to have any window area lost to captions etc (also prevent the system
			// from preserving our window contents during a resize
			return WVR_REDRAW;
		} // end WM_NCCALCSIZE
			
		case WM_NCACTIVATE:
			return TRUE;
			
		case WM_NCPAINT:
			return 0;
			
		case WM_NCMOUSEMOVE:
			IF_SetFloatActiveSubPart(pState, NULL);
			return 0;
			
		case WM_MOUSELEAVE:
			IF_SetFloatActiveSubPart(pState, NULL);
			pState->m_bMouseLeaveEventSet = FALSE;
			return 0;
			
		case WM_CLOSE:
		{
			if (pState->m_hndlr_onClose)
			{
				pState->m_hndlr_onClose(pState);
				return 0;
			}
			
			break;
		} // end WM_CLOSE
		
			
		case WM_PAINT:
		{
			PAINTSTRUCT ps;
			CPs_DrawContext drawcontext;
			
			// Prepare for draw
			drawcontext.m_dcDraw = BeginPaint(hWnd, &ps);
			drawcontext.m_ptOffset.x = 0;
			drawcontext.m_ptOffset.y = 0;
			GetClipBox(drawcontext.m_dcDraw, &drawcontext.m_rClip);
			
			IF_PaintWindow(pState, &drawcontext);
			
			// Cleanup
			EndPaint(hWnd, &ps);

			return 0;
		} // end WM_PAINT
		

		case WM_ACTIVATE:
		{
			if (LOWORD(wParam) == WA_ACTIVE)
				SetFocus(hWnd);
				
			return 0;
		} // end WM_ACTIVATE
		
			
		case WM_SYSKEYDOWN:
			// FALLTHROUGH
		case WM_KEYDOWN:
		{
			if (pState->m_hndlr_onKeyDown)
			{
				const BOOL bAltIsDown = (GetAsyncKeyState(VK_MENU)  & 0x8000) ? TRUE : FALSE;
				const BOOL bCtrlIsDown = (GetAsyncKeyState(VK_CONTROL)  & 0x8000) ? TRUE : FALSE;
				const BOOL bShiftIsDown = (GetAsyncKeyState(VK_SHIFT)  & 0x8000) ? TRUE : FALSE;
				pState->m_hndlr_onKeyDown(pState, (unsigned int)wParam, bAltIsDown, bCtrlIsDown, bShiftIsDown);
			}
			
			return 0;
		} // end WM_KEYDOWN
		
			
		case WM_DROPFILES:
		{
			if (pState->m_hndlr_onDropFiles)
				pState->m_hndlr_onDropFiles(pState, (HDROP)wParam);
				
			return 0;
		} // end WM_DROPFILES
		
			
		case WM_GETMINMAXINFO:
		{
			MINMAXINFO* pMinMaxInfo = (MINMAXINFO*)lParam;
			RECT rWorkArea;
			
			if (pfnGetMonitorInfo)
			{
				// Multimonitors are supported by this OS
				MONITORINFO mi;
				HMONITOR hmon = pfnMonitorFromWindow(pState->m_hWnd, MONITOR_DEFAULTTOPRIMARY);
				mi.cbSize = sizeof(mi);
				pfnGetMonitorInfo(hmon, &mi);
				
				// Get the work area of this monitor - as an offset from this monitors virtual space
				rWorkArea.left = mi.rcWork.left - mi.rcMonitor.left;
				rWorkArea.right = mi.rcWork.right - mi.rcMonitor.left;
				rWorkArea.top = mi.rcWork.top - mi.rcMonitor.top;
				rWorkArea.bottom = mi.rcWork.bottom - mi.rcMonitor.top;
			}
			
			else
			{
				// Single monitor only OS
				SystemParametersInfo(SPI_GETWORKAREA, 0, &rWorkArea, 0);
			}
			
			pMinMaxInfo->ptMinTrackSize.x = pState->m_szMinSize.cx;
			
			pMinMaxInfo->ptMinTrackSize.y = pState->m_szMinSize.cy;
			pMinMaxInfo->ptMaxPosition.x = rWorkArea.left;
			pMinMaxInfo->ptMaxPosition.y = rWorkArea.top;
			pMinMaxInfo->ptMaxSize.x = rWorkArea.right - rWorkArea.left;
			pMinMaxInfo->ptMaxSize.y = rWorkArea.bottom - rWorkArea.top;
			pMinMaxInfo->ptMaxTrackSize.x = pMinMaxInfo->ptMaxSize.x;
			pMinMaxInfo->ptMaxTrackSize.y = pMinMaxInfo->ptMaxSize.y;
		
			return 0;
		} // end WM_GETMINMAXINFO
		
		
		case WM_SETFOCUS:
		{
			if (pState->m_hndlr_onFocus)
				pState->m_hndlr_onFocus(pState, TRUE);
				
			return 0;
		} // end WM_SETFOCUS
			

		case WM_KILLFOCUS:
		{
			if (pState->m_hndlr_onFocus)
				pState->m_hndlr_onFocus(pState, FALSE);
				
			return 0;
		} // end WM_KILLFOCUS
			
		case WM_COMMAND:
		{
			if (pState->m_hndlr_onCommandMessage)
				pState->m_hndlr_onCommandMessage(pState, wParam, lParam);
				
			return 0;
		} // end WM_COMMAND
	}
	
	// Route message (to windows if it isn't handled)
	
	if (uiMessage >= WM_APP && pState->m_hndlr_onAppMessage)
		return pState->m_hndlr_onAppMessage(pState, uiMessage, wParam, lParam);
		
	return DefWindowProc(hWnd, uiMessage, wParam, lParam);
}