forked from dolphin-emu/dolphin
		
	
		
			
				
	
	
		
			273 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			273 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2013 Dolphin Emulator Project
 | |
| // Licensed under GPLv2
 | |
| // Refer to the license.txt file included.
 | |
| 
 | |
| #include <windows.h>
 | |
| 
 | |
| #include "VideoConfig.h"
 | |
| #include "EmuWindow.h"
 | |
| #include "Fifo.h"
 | |
| #include "VertexShaderManager.h"
 | |
| #include "VideoBackendBase.h"
 | |
| #include "Core.h"
 | |
| #include "Host.h"
 | |
| #include "ConfigManager.h"
 | |
| 
 | |
| namespace EmuWindow
 | |
| {
 | |
| HWND m_hWnd = NULL;
 | |
| HWND m_hParent = NULL;
 | |
| HINSTANCE m_hInstance = NULL;
 | |
| WNDCLASSEX wndClass;
 | |
| const TCHAR m_szClassName[] = _T("DolphinEmuWnd");
 | |
| int g_winstyle;
 | |
| static volatile bool s_sizing;
 | |
| static const int TITLE_TEXT_BUF_SIZE = 1024;
 | |
| TCHAR m_titleTextBuffer[TITLE_TEXT_BUF_SIZE];
 | |
| static const int WM_SETTEXT_CUSTOM = WM_USER + WM_SETTEXT;
 | |
| 
 | |
| bool IsSizing()
 | |
| {
 | |
| 	return s_sizing;
 | |
| }
 | |
| 
 | |
| HWND GetWnd()
 | |
| {
 | |
| 	return m_hWnd;
 | |
| }
 | |
| 
 | |
| HWND GetParentWnd()
 | |
| {
 | |
| 	return m_hParent;
 | |
| }
 | |
| 
 | |
| void FreeLookInput( UINT iMsg, WPARAM wParam )
 | |
| {
 | |
| 	static bool mouseLookEnabled = false;
 | |
| 	static bool mouseMoveEnabled = false;
 | |
| 	static float lastMouse[2];
 | |
| 	POINT point;
 | |
| 
 | |
| 	switch(iMsg)
 | |
| 	{
 | |
| 	case WM_MOUSEMOVE:
 | |
| 		if (mouseLookEnabled)
 | |
| 		{
 | |
| 			GetCursorPos(&point);
 | |
| 			VertexShaderManager::RotateView((point.x - lastMouse[0]) / 200.0f, (point.y - lastMouse[1]) / 200.0f);
 | |
| 			lastMouse[0] = (float)point.x;
 | |
| 			lastMouse[1] = (float)point.y;
 | |
| 		}
 | |
| 
 | |
| 		if (mouseMoveEnabled)
 | |
| 		{
 | |
| 			GetCursorPos(&point);
 | |
| 			VertexShaderManager::TranslateView((point.x - lastMouse[0]) / 50.0f, (point.y - lastMouse[1]) / 50.0f);
 | |
| 			lastMouse[0] = (float)point.x;
 | |
| 			lastMouse[1] = (float)point.y;
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case WM_RBUTTONDOWN:
 | |
| 		GetCursorPos(&point);
 | |
| 		lastMouse[0] = (float)point.x;
 | |
| 		lastMouse[1] = (float)point.y;
 | |
| 		mouseLookEnabled= true;
 | |
| 		break;
 | |
| 	case WM_MBUTTONDOWN:
 | |
| 		GetCursorPos(&point);
 | |
| 		lastMouse[0] = (float)point.x;
 | |
| 		lastMouse[1] = (float)point.y;
 | |
| 		mouseMoveEnabled= true;
 | |
| 		break;
 | |
| 	case WM_RBUTTONUP:
 | |
| 		mouseLookEnabled = false;
 | |
| 		break;
 | |
| 	case WM_MBUTTONUP:
 | |
| 		mouseMoveEnabled = false;
 | |
| 		break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
 | |
| {
 | |
| 	if (g_ActiveConfig.bFreeLook)
 | |
| 		FreeLookInput( iMsg, wParam );
 | |
| 
 | |
| 	switch( iMsg )
 | |
| 	{
 | |
| 	case WM_PAINT:
 | |
| 		{
 | |
| 			HDC hdc;
 | |
| 			PAINTSTRUCT ps;
 | |
| 			hdc = BeginPaint(hWnd, &ps);
 | |
| 			EndPaint(hWnd, &ps);
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case WM_ENTERSIZEMOVE:
 | |
| 		s_sizing = true;
 | |
| 		break;
 | |
| 
 | |
| 	case WM_EXITSIZEMOVE:
 | |
| 		s_sizing = false;
 | |
| 		break;
 | |
| 
 | |
| 	/* Post the mouse events to the main window, it's necessary, because the difference between the
 | |
| 	   keyboard inputs is that these events only appear here, not in the parent window or any other WndProc()*/
 | |
| 	case WM_LBUTTONDOWN:
 | |
| 		if(g_ActiveConfig.backend_info.bSupports3DVision && g_ActiveConfig.b3DVision)
 | |
| 		{
 | |
| 			// This basically throws away the left button down input when b3DVision is activated so WX
 | |
| 			// can't get access to it, stopping focus pulling on mouse click.
 | |
| 			// (Input plugins use a different system so it doesn't cause too much weirdness)
 | |
| 			break;
 | |
| 		}
 | |
| 	case WM_LBUTTONUP:
 | |
| 	case WM_LBUTTONDBLCLK:
 | |
| 		PostMessage(GetParentWnd(), iMsg, wParam, lParam);
 | |
| 		break;
 | |
| 
 | |
| 	// This is called when we close the window when we render to a separate window
 | |
| 	case WM_CLOSE:
 | |
| 		// When the user closes the window, we post an event to the main window to call Stop()
 | |
| 		// Which then handles all the necessary steps to Shutdown the core
 | |
| 		if (m_hParent == NULL)
 | |
| 		{
 | |
| 			// Stop the game
 | |
| 			//PostMessage(m_hParent, WM_USER, WM_USER_STOP, 0);
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case WM_USER:
 | |
| 		break;
 | |
| 
 | |
| 	// Called when a screensaver wants to show up while this window is active
 | |
| 	case WM_SYSCOMMAND:
 | |
| 	
 | |
| 		switch (wParam) 
 | |
| 		{
 | |
| 		case SC_SCREENSAVE:
 | |
| 		case SC_MONITORPOWER:
 | |
| 		if (SConfig::GetInstance().m_LocalCoreStartupParameter.bDisableScreenSaver)
 | |
| 			break;
 | |
| 		default:
 | |
| 			return DefWindowProc(hWnd, iMsg, wParam, lParam);
 | |
| 		}
 | |
| 		break;
 | |
| 	case WM_SETCURSOR:
 | |
| 		PostMessage(m_hParent, WM_USER, WM_USER_SETCURSOR, 0);
 | |
| 		return true;
 | |
| 
 | |
| 	case WM_SETTEXT_CUSTOM:
 | |
| 		SendMessage(hWnd, WM_SETTEXT, wParam, lParam);
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		return DefWindowProc(hWnd, iMsg, wParam, lParam);
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| HWND OpenWindow(HWND parent, HINSTANCE hInstance, int width, int height, const TCHAR *title)
 | |
| {
 | |
| 	wndClass.cbSize = sizeof( wndClass );
 | |
| 	wndClass.style  = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
 | |
| 	wndClass.lpfnWndProc = WndProc;
 | |
| 	wndClass.cbClsExtra = 0;
 | |
| 	wndClass.cbWndExtra = 0;
 | |
| 	wndClass.hInstance = hInstance;
 | |
| 	wndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
 | |
| 	wndClass.hCursor = NULL;
 | |
| 	wndClass.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
 | |
| 	wndClass.lpszMenuName = NULL;
 | |
| 	wndClass.lpszClassName = m_szClassName;
 | |
| 	wndClass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
 | |
| 
 | |
| 	m_hInstance = hInstance;
 | |
| 	RegisterClassEx( &wndClass );
 | |
| 
 | |
| 	m_hParent = parent;
 | |
| 
 | |
| 	m_hWnd = CreateWindow(m_szClassName, title, (g_ActiveConfig.backend_info.bSupports3DVision && g_ActiveConfig.b3DVision) ? WS_EX_TOPMOST | WS_POPUP : WS_CHILD,
 | |
| 		0, 0, width, height, m_hParent, NULL, hInstance, NULL);
 | |
| 
 | |
| 	return m_hWnd;
 | |
| }
 | |
| 
 | |
| void Show()
 | |
| {
 | |
| 	ShowWindow(m_hWnd, SW_SHOW);
 | |
| 	BringWindowToTop(m_hWnd);
 | |
| 	UpdateWindow(m_hWnd);
 | |
| 	SetFocus(m_hParent);
 | |
| }
 | |
| 
 | |
| HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title)
 | |
| {
 | |
| 	// TODO:
 | |
| 	// 1. Remove redundant window manipulation,
 | |
| 	// 2. Make DX9 in fullscreen can be overlapped by other dialogs
 | |
| 	// 3. Request window sizes which actually make the client area map to a common resolution
 | |
| 	HWND Ret;
 | |
| 	int x=0, y=0, width=640, height=480;
 | |
| 	Host_GetRenderWindowSize(x, y, width, height);
 | |
| 
 | |
| 	 // TODO: Don't show if fullscreen
 | |
| 	Ret = OpenWindow(hParent, hInstance, width, height, title);
 | |
| 
 | |
| 	if (Ret)
 | |
| 	{
 | |
| 		Show();
 | |
| 	}
 | |
| 	return Ret;
 | |
| }
 | |
| 
 | |
| void Close()
 | |
| {
 | |
| 	DestroyWindow(m_hWnd);
 | |
| 	UnregisterClass(m_szClassName, m_hInstance);
 | |
| }
 | |
| 
 | |
| void SetSize(int width, int height)
 | |
| {
 | |
| 	RECT rc = {0, 0, width, height};
 | |
| 	DWORD style = GetWindowLong(m_hWnd, GWL_STYLE);
 | |
| 	AdjustWindowRect(&rc, style, false);
 | |
| 
 | |
| 	int w = rc.right - rc.left;
 | |
| 	int h = rc.bottom - rc.top;
 | |
| 
 | |
| 	rc.left = (1280 - w)/2;
 | |
| 	rc.right = rc.left + w;
 | |
| 	rc.top = (1024 - h)/2;
 | |
| 	rc.bottom = rc.top + h;
 | |
| 	MoveWindow(m_hWnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE);
 | |
| }
 | |
| 
 | |
| void SetWindowText(const TCHAR* text)
 | |
| {
 | |
| 	// the simple way.
 | |
| 	// we don't do this because it's a blocking call and the GUI thread might be waiting for us.
 | |
| 	//::SetWindowText(m_hWnd, text);
 | |
| 
 | |
| 	// copy to m_titleTextBuffer in such a way that
 | |
| 	// it remains null-terminated and without garbage data at every point in time,
 | |
| 	// in case another thread reads it while we're doing this.
 | |
| 	for (int i = 0; i < TITLE_TEXT_BUF_SIZE-1; ++i)
 | |
| 	{
 | |
| 		m_titleTextBuffer[i+1] = 0;
 | |
| 		TCHAR c = text[i];
 | |
| 		m_titleTextBuffer[i] = c;
 | |
| 		if (!c)
 | |
| 			break;
 | |
| 	}
 | |
| 
 | |
| 	// the OS doesn't allow posting WM_SETTEXT,
 | |
| 	// so we post our own message and convert it to that in WndProc
 | |
| 	PostMessage(m_hWnd, WM_SETTEXT_CUSTOM, 0, (LPARAM)m_titleTextBuffer);
 | |
| }
 | |
| 
 | |
| }
 |