2014-01-04 12:33:02 +01:00
// Copyright (c) 2012- PPSSPP Project.
2013-07-29 05:23:27 -04:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2012-11-01 16:19:01 +01:00
// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003.
2013-07-29 05:23:27 -04:00
// It's improving slowly, though. :)
2012-11-01 16:19:01 +01:00
2013-07-28 21:01:49 -07:00
# include "Common/CommonWindows.h"
2014-06-04 19:15:41 +03:00
# include "Common/KeyMap.h"
2015-09-06 19:10:08 +02:00
# include <Windowsx.h>
2013-03-29 18:50:08 +01:00
2013-07-06 21:49:28 +02:00
# include <map>
2013-09-01 14:06:24 -07:00
# include <string>
2013-07-06 21:49:28 +02:00
2013-03-29 18:50:08 +01:00
# include "base/NativeApp.h"
2013-03-11 22:55:29 +01:00
# include "Globals.h"
2012-11-01 16:19:01 +01:00
# include "shellapi.h"
# include "commctrl.h"
2015-09-19 14:43:50 +02:00
# include "base/timeutil.h"
2013-08-26 19:00:16 +02:00
# include "i18n/i18n.h"
2013-03-29 18:50:08 +01:00
# include "input/input_state.h"
2013-07-08 12:35:08 +02:00
# include "input/keycodes.h"
2014-06-29 12:53:03 +02:00
# include "thread/threadutil.h"
2013-08-26 19:00:16 +02:00
# include "util/text/utf8.h"
2015-09-19 14:43:50 +02:00
# include "Core/Config.h"
2013-03-11 22:55:29 +01:00
# include "Core/Debugger/SymbolMap.h"
2014-01-01 16:45:37 -08:00
# include "Windows/InputBox.h"
2013-03-11 22:55:29 +01:00
# include "Windows/OpenGLBase.h"
# include "Windows/Debugger/Debugger_Disasm.h"
# include "Windows/Debugger/Debugger_MemoryDlg.h"
2013-09-22 11:03:29 -07:00
# include "Windows/GEDebugger/GEDebugger.h"
2015-09-19 14:43:50 +02:00
# include "Core/MIPS/JitCommon/NativeJit.h"
# include "Core/MIPS/JitCommon/JitBlockCache.h"
2012-11-01 16:19:01 +01:00
# include "main.h"
2013-03-11 22:55:29 +01:00
# include "Core/Core.h"
# include "Windows/EmuThread.h"
2012-11-01 16:19:01 +01:00
# include "resource.h"
2015-09-19 13:14:05 +02:00
# include "Windows/MainWindow.h"
2013-07-06 19:08:59 +02:00
# include "Windows/WindowsHost.h"
2013-03-11 22:55:29 +01:00
# include "Common/LogManager.h"
# include "Common/ConsoleListener.h"
# include "Windows/W32Util/DialogManager.h"
# include "Windows/W32Util/ShellUtil.h"
# include "Windows/W32Util/Misc.h"
2014-01-19 11:59:11 -08:00
# include "Windows/RawInput.h"
2014-01-19 22:54:49 +01:00
# include "Windows/TouchInputHandler.h"
2013-03-11 22:55:29 +01:00
# include "GPU/GPUInterface.h"
2013-05-22 18:00:06 +02:00
# include "UI/OnScreenDisplay.h"
2015-09-19 13:11:06 +02:00
# include "Windows/MainWindowMenu.h"
2013-11-27 21:57:17 +08:00
2012-11-01 16:19:01 +01:00
# ifdef THEMES
# include "XPTheme.h"
# endif
2014-02-24 13:28:20 +01:00
# define MOUSEEVENTF_FROMTOUCH_NOPEN 0xFF515780 //http://msdn.microsoft.com/en-us/library/windows/desktop/ms703320(v=vs.85).aspx
# define MOUSEEVENTF_MASK_PLUS_PENTOUCH 0xFFFFFF80
2014-01-23 18:05:42 +01:00
2013-11-30 18:21:47 -08:00
int verysleepy__useSendMessage = 1 ;
const UINT WM_VERYSLEEPY_MSG = WM_APP + 0x3117 ;
// Respond TRUE to a message with this param value to indicate support.
const WPARAM VERYSLEEPY_WPARAM_SUPPORTED = 0 ;
// Respond TRUE to a message wit this param value after filling in the addr name.
const WPARAM VERYSLEEPY_WPARAM_GETADDRINFO = 1 ;
2015-09-19 13:11:06 +02:00
struct VerySleepy_AddrInfo {
2013-11-30 18:21:47 -08:00
// Always zero for now.
int flags ;
// This is the pointer (always passed as 64 bits.)
unsigned long long addr ;
// Write the name here.
wchar_t name [ 256 ] ;
} ;
2013-03-29 21:21:27 +01:00
static RECT g_normalRC = { 0 } ;
2013-09-13 15:17:55 -04:00
static std : : wstring windowTitle ;
2013-03-29 18:50:08 +01:00
extern InputState input_state ;
2013-07-07 10:42:39 +02:00
2013-05-04 23:21:06 +02:00
# define TIMER_CURSORUPDATE 1
2013-06-12 02:14:53 +08:00
# define TIMER_CURSORMOVEUPDATE 2
2013-10-16 17:20:32 +02:00
# define CURSORUPDATE_INTERVAL_MS 1000
2013-06-12 02:14:53 +08:00
# define CURSORUPDATE_MOVE_TIMESPAN_MS 500
2013-04-18 17:13:00 +08:00
2014-06-29 22:13:53 +02:00
namespace MainWindow
{
2012-11-01 16:19:01 +01:00
HWND hwndMain ;
2014-06-29 22:13:53 +02:00
HWND hwndDisplay ;
HWND hwndGameList ;
2014-01-19 22:54:49 +01:00
TouchInputHandler touchHandler ;
2013-03-29 21:21:27 +01:00
static HMENU menu ;
2012-11-01 16:19:01 +01:00
2015-09-19 13:11:06 +02:00
HINSTANCE hInst ;
2013-05-26 14:55:23 -07:00
static int cursorCounter = 0 ;
2013-06-12 02:14:53 +08:00
static int prevCursorX = - 1 ;
static int prevCursorY = - 1 ;
static bool mouseButtonDown = false ;
static bool hideCursor = false ;
2014-06-29 21:03:24 +02:00
static bool g_inModeSwitch ; // when true, don't react to WM_SIZE
2014-07-29 18:18:57 -04:00
static int g_WindowState ;
2014-06-29 21:03:24 +02:00
2015-09-19 13:11:06 +02:00
// gross hack
bool noFocusPause = false ; // TOGGLE_PAUSE state to override pause on lost focus
2012-11-01 16:19:01 +01:00
# define MAX_LOADSTRING 100
2013-03-29 21:21:27 +01:00
const TCHAR * szTitle = TEXT ( " PPSSPP " ) ;
const TCHAR * szWindowClass = TEXT ( " PPSSPPWnd " ) ;
const TCHAR * szDisplayClass = TEXT ( " PPSSPPDisplay " ) ;
2012-11-01 16:19:01 +01:00
2013-03-17 14:46:39 +01:00
// Forward declarations of functions included in this code module:
2012-11-01 16:19:01 +01:00
LRESULT CALLBACK WndProc ( HWND , UINT , WPARAM , LPARAM ) ;
2014-06-29 22:13:53 +02:00
LRESULT CALLBACK DisplayProc ( HWND , UINT , WPARAM , LPARAM ) ;
2012-11-01 16:19:01 +01:00
2013-07-06 19:12:06 -07:00
HWND GetHWND ( ) {
2012-11-01 16:19:01 +01:00
return hwndMain ;
}
2014-06-29 22:13:53 +02:00
HWND GetDisplayHWND ( ) {
return hwndDisplay ;
}
2013-07-06 19:12:06 -07:00
void Init ( HINSTANCE hInstance ) {
2013-02-19 01:28:13 +01:00
# ifdef THEMES
WTL : : CTheme : : IsThemingSupported ( ) ;
2012-11-01 16:19:01 +01:00
# endif
//Register classes
WNDCLASSEX wcex ;
wcex . cbSize = sizeof ( WNDCLASSEX ) ;
2014-06-23 20:04:31 +02:00
wcex . style = CS_PARENTDC ;
2012-11-01 16:19:01 +01:00
wcex . lpfnWndProc = ( WNDPROC ) WndProc ;
wcex . cbClsExtra = 0 ;
wcex . cbWndExtra = 0 ;
wcex . hInstance = hInstance ;
wcex . hIcon = LoadIcon ( hInstance , ( LPCTSTR ) IDI_PPSSPP ) ;
wcex . hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
2012-12-05 14:31:41 +08:00
wcex . hbrBackground = ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ;
2013-08-26 19:00:16 +02:00
wcex . lpszMenuName = ( LPCWSTR ) IDR_MENU1 ;
2012-11-01 16:19:01 +01:00
wcex . lpszClassName = szWindowClass ;
2014-06-23 20:04:31 +02:00
wcex . hIconSm = ( HICON ) LoadImage ( hInstance , ( LPCTSTR ) IDI_PPSSPP , IMAGE_ICON , 16 , 16 , LR_SHARED ) ;
2012-11-01 16:19:01 +01:00
RegisterClassEx ( & wcex ) ;
2014-06-29 22:13:53 +02:00
wcex . style = CS_HREDRAW | CS_VREDRAW ;
wcex . lpfnWndProc = ( WNDPROC ) DisplayProc ;
wcex . hIcon = 0 ;
wcex . hbrBackground = ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ;
wcex . lpszMenuName = 0 ;
wcex . lpszClassName = szDisplayClass ;
wcex . hIconSm = 0 ;
RegisterClassEx ( & wcex ) ;
2012-11-01 16:19:01 +01:00
}
2013-03-30 17:49:02 +01:00
void SavePosition ( ) {
2014-06-23 20:04:31 +02:00
if ( g_Config . bFullScreen )
return ;
2013-09-13 11:39:40 -04:00
2013-03-30 17:49:02 +01:00
WINDOWPLACEMENT placement ;
GetWindowPlacement ( hwndMain , & placement ) ;
if ( placement . showCmd = = SW_SHOWNORMAL ) {
RECT rc ;
GetWindowRect ( hwndMain , & rc ) ;
g_Config . iWindowX = rc . left ;
g_Config . iWindowY = rc . top ;
2013-09-11 00:19:34 +02:00
g_Config . iWindowWidth = rc . right - rc . left ;
g_Config . iWindowHeight = rc . bottom - rc . top ;
2013-03-30 17:49:02 +01:00
}
}
2014-02-12 10:36:40 +01:00
static void GetWindowRectAtResolution ( int xres , int yres , RECT & rcInner , RECT & rcOuter ) {
2013-09-11 00:19:34 +02:00
rcInner . left = 0 ;
rcInner . top = 0 ;
rcInner . right = xres ;
rcInner . bottom = yres ;
rcOuter = rcInner ;
AdjustWindowRect ( & rcOuter , WS_OVERLAPPEDWINDOW , TRUE ) ;
rcOuter . right + = g_Config . iWindowX - rcOuter . left ;
rcOuter . bottom + = g_Config . iWindowY - rcOuter . top ;
rcOuter . left = g_Config . iWindowX ;
rcOuter . top = g_Config . iWindowY ;
}
2014-02-12 10:36:40 +01:00
static void ShowScreenResolution ( ) {
2015-07-01 23:50:16 +02:00
I18NCategory * gr = GetI18NCategory ( " Graphics " ) ;
2014-07-10 03:19:00 -04:00
std : : ostringstream messageStream ;
2015-07-01 23:50:16 +02:00
messageStream < < gr - > T ( " Internal Resolution " ) < < " : " ;
2014-07-10 03:19:00 -04:00
messageStream < < PSP_CoreParameter ( ) . renderWidth < < " x " < < PSP_CoreParameter ( ) . renderHeight < < " " ;
2015-07-01 23:50:16 +02:00
messageStream < < gr - > T ( " Window Size " ) < < " : " ;
2014-07-10 03:19:00 -04:00
messageStream < < PSP_CoreParameter ( ) . pixelWidth < < " x " < < PSP_CoreParameter ( ) . pixelHeight ;
osm . Show ( messageStream . str ( ) , 2.0f ) ;
2014-02-12 10:36:40 +01:00
}
2014-02-12 11:34:29 +01:00
static void UpdateRenderResolution ( ) {
2013-01-26 23:46:02 +01:00
RECT rc ;
GetClientRect ( hwndMain , & rc ) ;
2015-05-15 18:04:05 +02:00
// Actually, auto mode should be more granular...
2013-07-29 04:46:40 -04:00
// Round up to a zoom factor for the render size.
2013-09-11 00:19:34 +02:00
int zoom = g_Config . iInternalResolution ;
2015-05-15 18:04:05 +02:00
if ( zoom = = 0 ) { // auto mode
// Use the longest dimension
if ( g_Config . IsPortrait ( ) ) {
zoom = ( rc . bottom - rc . top + 479 ) / 480 ;
} else {
zoom = ( rc . right - rc . left + 479 ) / 480 ;
}
}
2014-06-24 22:32:38 +02:00
if ( zoom < = 1 )
zoom = 1 ;
2014-01-27 11:46:09 +05:00
2015-05-15 18:04:05 +02:00
if ( g_Config . IsPortrait ( ) ) {
PSP_CoreParameter ( ) . renderWidth = 272 * zoom ;
PSP_CoreParameter ( ) . renderHeight = 480 * zoom ;
2015-05-22 18:15:49 +02:00
} else {
PSP_CoreParameter ( ) . renderWidth = 480 * zoom ;
PSP_CoreParameter ( ) . renderHeight = 272 * zoom ;
2015-05-15 18:04:05 +02:00
}
}
static bool IsWindowSmall ( ) {
2015-09-07 22:35:45 +02:00
// Can't take this from config as it will not be set if windows is maximized.
RECT rc ;
GetWindowRect ( hwndMain , & rc ) ;
int width = rc . right - rc . left ;
int height = rc . bottom - rc . top ;
return g_Config . IsPortrait ( ) ? ( height < 480 + 80 ) : ( width < 480 + 80 ) ;
2015-09-19 13:11:06 +02:00
}
2014-02-12 11:34:29 +01:00
static void ResizeDisplay ( bool noWindowMovement = false ) {
2014-06-29 12:53:03 +02:00
AssertCurrentThreadName ( " Main " ) ;
2014-02-12 11:34:29 +01:00
int width = 0 , height = 0 ;
RECT rc ;
GetClientRect ( hwndMain , & rc ) ;
if ( ! noWindowMovement ) {
width = rc . right - rc . left ;
height = rc . bottom - rc . top ;
2015-05-15 18:04:05 +02:00
// Moves the internal window, not the frame. TODO: Get rid of the internal window. Tried before but Intel drivers screw up when minimizing, or something?
2014-06-29 22:13:53 +02:00
MoveWindow ( hwndDisplay , 0 , 0 , width , height , TRUE ) ;
2014-02-12 11:34:29 +01:00
// This is taken care of anyway later, but makes sure that ShowScreenResolution gets the right numbers.
// Need to clean all of this up...
PSP_CoreParameter ( ) . pixelWidth = width ;
PSP_CoreParameter ( ) . pixelHeight = height ;
}
UpdateRenderResolution ( ) ;
2013-09-26 17:46:11 -04:00
2014-02-10 16:22:16 +01:00
if ( ! noWindowMovement ) {
2015-05-15 18:04:05 +02:00
if ( UpdateScreenScale ( width , height , IsWindowSmall ( ) ) ) {
2014-12-28 13:19:19 -08:00
NativeMessageReceived ( " gpu resized " , " " ) ;
}
2014-02-10 16:22:16 +01:00
}
2013-09-11 00:19:34 +02:00
}
void SetWindowSize ( int zoom ) {
2014-06-29 13:11:06 +02:00
AssertCurrentThreadName ( " Main " ) ;
2012-11-17 17:46:05 +01:00
RECT rc , rcOuter ;
2015-05-15 18:04:05 +02:00
// Actually, auto mode should be more granular...
if ( g_Config . IsPortrait ( ) ) {
GetWindowRectAtResolution ( 272 * ( int ) zoom , 480 * ( int ) zoom , rc , rcOuter ) ;
} else {
GetWindowRectAtResolution ( 480 * ( int ) zoom , 272 * ( int ) zoom , rc , rcOuter ) ;
}
2012-11-17 17:46:05 +01:00
MoveWindow ( hwndMain , rcOuter . left , rcOuter . top , rcOuter . right - rcOuter . left , rcOuter . bottom - rcOuter . top , TRUE ) ;
2014-02-12 11:34:29 +01:00
ResizeDisplay ( false ) ;
2014-02-12 10:36:40 +01:00
ShowScreenResolution ( ) ;
2012-11-01 16:19:01 +01:00
}
2015-09-19 13:11:06 +02:00
void SetInternalResolution ( int res ) {
2013-09-19 21:18:26 -04:00
if ( res > = 0 & & res < = RESOLUTION_MAX )
2013-09-19 14:32:56 -04:00
g_Config . iInternalResolution = res ;
else {
2013-09-19 21:18:26 -04:00
if ( + + g_Config . iInternalResolution > RESOLUTION_MAX )
2013-09-19 14:32:56 -04:00
g_Config . iInternalResolution = 0 ;
}
2013-10-11 11:49:45 +05:00
2014-01-26 18:59:40 +05:00
// Taking auto-texture scaling into account
2013-10-11 11:49:45 +05:00
if ( g_Config . iTexScalingLevel = = TEXSCALING_AUTO )
setTexScalingMultiplier ( 0 ) ;
2013-09-19 14:32:56 -04:00
2014-02-13 16:23:16 -05:00
if ( gpu )
gpu - > Resized ( ) ;
2014-02-12 11:34:29 +01:00
UpdateRenderResolution ( ) ;
2014-02-12 10:36:40 +01:00
ShowScreenResolution ( ) ;
2013-09-11 00:19:34 +02:00
}
2013-05-26 14:55:23 -07:00
void CorrectCursor ( ) {
2014-06-22 09:38:46 +02:00
bool autoHide = g_Config . bFullScreen & & ! mouseButtonDown & & GetUIState ( ) = = UISTATE_INGAME ;
2013-06-12 02:14:53 +08:00
if ( autoHide & & hideCursor ) {
2013-05-26 14:55:23 -07:00
while ( cursorCounter > = 0 ) {
cursorCounter = ShowCursor ( FALSE ) ;
}
} else {
2013-06-12 02:14:53 +08:00
hideCursor = ! autoHide ;
2013-05-26 14:55:23 -07:00
if ( cursorCounter < 0 ) {
cursorCounter = ShowCursor ( TRUE ) ;
SetCursor ( LoadCursor ( NULL , IDC_ARROW ) ) ;
}
}
}
2015-02-15 23:07:24 +01:00
void ToggleFullscreen ( HWND hWnd , bool goingFullscreen ) {
2014-06-29 21:03:24 +02:00
// Make sure no rendering is happening during the switch.
Core_NotifyWindowHidden ( true ) ;
g_inModeSwitch = true ; // Make sure WM_SIZE doesn't call Core_NotifyWindowHidden(false)...
2014-07-16 23:50:46 -04:00
DWORD dwOldStyle ;
DWORD dwNewStyle ;
2013-09-11 00:19:34 +02:00
2014-07-16 23:50:46 -04:00
if ( ! goingFullscreen ) {
// Put caption and border styles back.
dwOldStyle = : : GetWindowLong ( hWnd , GWL_STYLE ) ;
2014-07-20 17:28:25 +02:00
dwOldStyle & = ~ WS_POPUP ;
2014-07-16 23:50:46 -04:00
dwNewStyle = dwOldStyle | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU ;
// Put back the menu bar.
: : SetMenu ( hWnd , menu ) ;
} else {
2014-07-29 18:18:57 -04:00
// If the window was maximized before going fullscreen, make sure to restore first
// in order not to have the taskbar show up on top of PPSSPP.
if ( g_WindowState = = SIZE_MAXIMIZED ) {
ShowWindow ( hwndMain , SW_RESTORE ) ;
}
2014-07-16 23:50:46 -04:00
// Remember the normal window rectangle.
: : GetWindowRect ( hWnd , & g_normalRC ) ;
2013-09-27 15:34:13 -04:00
2014-07-16 23:50:46 -04:00
// Remove caption and border styles.
dwOldStyle = : : GetWindowLong ( hWnd , GWL_STYLE ) ;
dwNewStyle = dwOldStyle & ~ ( WS_CAPTION | WS_THICKFRAME | WS_SYSMENU ) ;
2014-07-20 17:28:25 +02:00
// Add WS_POPUP
dwNewStyle | = WS_POPUP ;
2014-02-12 10:36:40 +01:00
}
2014-06-29 21:03:24 +02:00
2013-09-11 00:19:34 +02:00
: : SetWindowLong ( hWnd , GWL_STYLE , dwNewStyle ) ;
// Remove the menu bar.
2014-07-17 00:03:41 -04:00
: : SetMenu ( hWnd , goingFullscreen ? NULL : menu ) ;
2013-09-11 00:19:34 +02:00
2014-07-17 00:06:52 -04:00
// Resize to the appropriate view.
2014-07-29 18:18:57 -04:00
// If we're returning to window mode, re-apply the appropriate size setting.
if ( goingFullscreen ) {
ShowWindow ( hwndMain , SW_MAXIMIZE ) ;
} else {
ShowWindow ( hwndMain , g_WindowState = = SIZE_MAXIMIZED ? SW_MAXIMIZE : SW_RESTORE ) ;
}
2013-09-11 00:19:34 +02:00
2014-07-16 23:50:46 -04:00
g_Config . bFullScreen = goingFullscreen ;
2013-09-11 00:19:34 +02:00
CorrectCursor ( ) ;
2013-09-27 15:34:13 -04:00
bool showOSM = ( g_Config . iInternalResolution = = RESOLUTION_AUTO ) ;
2014-06-29 21:03:24 +02:00
ResizeDisplay ( false ) ;
2014-02-12 10:36:40 +01:00
if ( showOSM ) {
ShowScreenResolution ( ) ;
}
2014-07-17 00:03:41 -04:00
ShowOwnedPopups ( hwndMain , goingFullscreen ? FALSE : TRUE ) ;
2014-07-16 23:50:46 -04:00
W32Util : : MakeTopMost ( hwndMain , g_Config . bTopMost ) ;
2014-06-29 21:03:24 +02:00
g_inModeSwitch = false ;
Core_NotifyWindowHidden ( false ) ;
2015-02-15 23:07:24 +01:00
WindowsRawInput : : NotifyMenu ( ) ;
2013-09-11 00:19:34 +02:00
}
2013-10-15 13:10:14 +02:00
RECT DetermineWindowRectangle ( ) {
RECT rc ;
const int screenWidth = GetSystemMetrics ( SM_CXVIRTUALSCREEN ) ;
const int screenHeight = GetSystemMetrics ( SM_CYVIRTUALSCREEN ) ;
const int screenX = GetSystemMetrics ( SM_XVIRTUALSCREEN ) ;
const int screenY = GetSystemMetrics ( SM_YVIRTUALSCREEN ) ;
if ( ! g_Config . bFullScreen ) {
bool visibleHorizontally = ( ( g_Config . iWindowX + g_Config . iWindowWidth ) > = screenX ) & &
( ( g_Config . iWindowX + g_Config . iWindowWidth ) < ( screenWidth + g_Config . iWindowWidth ) ) ;
bool visibleVertically = ( ( g_Config . iWindowY + g_Config . iWindowHeight ) > = screenY ) & &
( ( g_Config . iWindowY + g_Config . iWindowHeight ) < ( screenHeight + g_Config . iWindowHeight ) ) ;
if ( ! visibleHorizontally )
g_Config . iWindowX = - 1 ;
if ( ! visibleVertically )
g_Config . iWindowY = - 1 ;
}
rc . left = g_Config . iWindowX ;
rc . top = g_Config . iWindowY ;
// First, get the w/h right.
if ( g_Config . iWindowWidth < = 0 | | g_Config . iWindowHeight < = 0 ) {
RECT rcInner = rc , rcOuter ;
2015-05-15 18:04:05 +02:00
bool portrait = g_Config . IsPortrait ( ) ;
GetWindowRectAtResolution ( 2 * ( portrait ? 272 : 480 ) , 2 * ( portrait ? 480 : 272 ) , rcInner , rcOuter ) ;
2013-10-15 13:10:14 +02:00
rc . right = rc . left + ( rcOuter . right - rcOuter . left ) ;
rc . bottom = rc . top + ( rcOuter . bottom - rcOuter . top ) ;
g_Config . iWindowWidth = rc . right - rc . left ;
g_Config . iWindowHeight = rc . bottom - rc . top ;
} else {
rc . right = rc . left + g_Config . iWindowWidth ;
rc . bottom = rc . top + g_Config . iWindowHeight ;
}
// Then center if necessary.
if ( g_Config . iWindowX = = - 1 & & g_Config . iWindowY = = - 1 ) {
// Center the window.
2013-10-15 22:02:14 -07:00
const int primaryScreenWidth = GetSystemMetrics ( SM_CXSCREEN ) ;
const int primaryScreenHeight = GetSystemMetrics ( SM_CYSCREEN ) ;
g_Config . iWindowX = ( primaryScreenWidth - g_Config . iWindowWidth ) / 2 ;
g_Config . iWindowY = ( primaryScreenHeight - g_Config . iWindowHeight ) / 2 ;
2013-10-15 13:10:14 +02:00
rc . left = g_Config . iWindowX ;
rc . top = g_Config . iWindowY ;
rc . right = rc . left + g_Config . iWindowWidth ;
rc . bottom = rc . top + g_Config . iWindowHeight ;
}
return rc ;
}
2013-09-13 15:17:55 -04:00
void UpdateWindowTitle ( ) {
2013-09-13 16:38:28 -04:00
// Seems to be fine to call now since we use a UNICODE build...
SetWindowText ( hwndMain , windowTitle . c_str ( ) ) ;
2013-09-13 15:17:55 -04:00
}
void SetWindowTitle ( const wchar_t * title ) {
windowTitle = title ;
}
2014-07-17 00:06:52 -04:00
BOOL Show ( HINSTANCE hInstance ) {
2013-09-22 14:44:35 -04:00
hInst = hInstance ; // Store instance handle in our global variable.
RECT rc = DetermineWindowRectangle ( ) ;
2013-03-29 21:21:27 +01:00
u32 style = WS_OVERLAPPEDWINDOW ;
2012-11-01 16:19:01 +01:00
2013-08-26 19:00:16 +02:00
hwndMain = CreateWindowEx ( 0 , szWindowClass , L " " , style ,
2013-06-08 08:32:07 +08:00
rc . left , rc . top , rc . right - rc . left , rc . bottom - rc . top , NULL , NULL , hInstance , NULL ) ;
2012-11-01 16:19:01 +01:00
if ( ! hwndMain )
return FALSE ;
2013-09-11 00:19:34 +02:00
RECT rcClient ;
GetClientRect ( hwndMain , & rcClient ) ;
2014-06-29 22:13:53 +02:00
hwndDisplay = CreateWindowEx ( 0 , szDisplayClass , L " " , WS_CHILD | WS_VISIBLE ,
0 , 0 , rcClient . right - rcClient . left , rcClient . bottom - rcClient . top , hwndMain , 0 , hInstance , 0 ) ;
if ( ! hwndDisplay )
return FALSE ;
2012-11-01 16:19:01 +01:00
menu = GetMenu ( hwndMain ) ;
2013-08-29 18:27:11 -04:00
2012-11-01 16:19:01 +01:00
# ifdef FINAL
RemoveMenu ( menu , 2 , MF_BYPOSITION ) ;
RemoveMenu ( menu , 2 , MF_BYPOSITION ) ;
# endif
MENUINFO info ;
ZeroMemory ( & info , sizeof ( MENUINFO ) ) ;
info . cbSize = sizeof ( MENUINFO ) ;
info . cyMax = 0 ;
info . dwStyle = MNS_CHECKORBMP ;
info . fMask = MIM_STYLE ;
2013-07-29 15:34:30 -04:00
for ( int i = 0 ; i < GetMenuItemCount ( menu ) ; i + + ) {
2015-09-19 13:11:06 +02:00
SetMenuInfo ( GetSubMenu ( menu , i ) , & info ) ;
2012-11-01 16:19:01 +01:00
}
2013-06-08 08:32:07 +08:00
UpdateMenus ( ) ;
2012-11-01 16:19:01 +01:00
2013-07-29 04:46:40 -04:00
// Accept dragged files.
2012-11-01 16:19:01 +01:00
DragAcceptFiles ( hwndMain , TRUE ) ;
2013-06-12 02:14:53 +08:00
hideCursor = true ;
2013-06-08 08:32:07 +08:00
SetTimer ( hwndMain , TIMER_CURSORUPDATE , CURSORUPDATE_INTERVAL_MS , 0 ) ;
2014-06-29 16:24:20 -04:00
2014-07-16 23:50:46 -04:00
ToggleFullscreen ( hwndMain , g_Config . bFullScreen ) ;
2013-06-08 08:32:07 +08:00
2013-07-06 13:47:37 -04:00
W32Util : : MakeTopMost ( hwndMain , g_Config . bTopMost ) ;
2014-06-29 22:13:53 +02:00
touchHandler . registerTouchWindow ( hwndDisplay ) ;
2013-04-16 21:12:55 +02:00
2014-01-19 11:59:11 -08:00
WindowsRawInput : : Init ( ) ;
2013-07-07 10:42:39 +02:00
2013-10-16 17:20:32 +02:00
SetFocus ( hwndMain ) ;
2014-03-24 20:13:35 -04:00
2012-11-01 16:19:01 +01:00
return TRUE ;
}
2013-08-26 14:19:46 +02:00
void CreateDebugWindows ( ) {
disasmWindow [ 0 ] = new CDisasm ( MainWindow : : GetHInstance ( ) , MainWindow : : GetHWND ( ) , currentDebugMIPS ) ;
DialogManager : : AddDlg ( disasmWindow [ 0 ] ) ;
disasmWindow [ 0 ] - > Show ( g_Config . bShowDebuggerOnLoad ) ;
2013-09-22 10:27:09 -07:00
geDebuggerWindow = new CGEDebugger ( MainWindow : : GetHInstance ( ) , MainWindow : : GetHWND ( ) ) ;
DialogManager : : AddDlg ( geDebuggerWindow ) ;
2013-08-26 14:19:46 +02:00
memoryWindow [ 0 ] = new CMemoryDlg ( MainWindow : : GetHInstance ( ) , MainWindow : : GetHWND ( ) , currentDebugMIPS ) ;
DialogManager : : AddDlg ( memoryWindow [ 0 ] ) ;
}
2014-02-14 21:17:36 -08:00
void DestroyDebugWindows ( ) {
DialogManager : : RemoveDlg ( disasmWindow [ 0 ] ) ;
if ( disasmWindow [ 0 ] )
delete disasmWindow [ 0 ] ;
disasmWindow [ 0 ] = 0 ;
DialogManager : : RemoveDlg ( geDebuggerWindow ) ;
if ( geDebuggerWindow )
delete geDebuggerWindow ;
geDebuggerWindow = 0 ;
DialogManager : : RemoveDlg ( memoryWindow [ 0 ] ) ;
if ( memoryWindow [ 0 ] )
delete memoryWindow [ 0 ] ;
memoryWindow [ 0 ] = 0 ;
}
2014-06-29 22:13:53 +02:00
LRESULT CALLBACK DisplayProc ( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam ) {
2013-09-23 23:56:32 -04:00
// Only apply a factor > 1 in windowed mode.
2015-05-15 18:04:05 +02:00
int factor = ! IsZoomed ( GetHWND ( ) ) & & ! g_Config . bFullScreen & & IsWindowSmall ( ) ? 2 : 1 ;
2014-06-23 20:04:31 +02:00
static bool firstErase = true ;
2013-09-23 23:56:32 -04:00
2013-07-29 15:34:30 -04:00
switch ( message ) {
2014-06-29 22:13:53 +02:00
case WM_ACTIVATE :
if ( wParam = = WA_ACTIVE | | wParam = = WA_CLICKACTIVE ) {
g_activeWindow = WINDOW_MAINWINDOW ;
2014-06-29 13:11:06 +02:00
}
2012-11-01 16:19:01 +01:00
break ;
2013-03-29 19:32:20 +01:00
2015-09-19 13:11:06 +02:00
case WM_SIZE :
ILOG ( " WM_SIZE inner (%d) " , ( int ) wParam ) ;
break ;
2014-06-29 22:13:53 +02:00
case WM_SETFOCUS :
break ;
2014-06-23 20:23:11 +02:00
2012-11-01 16:19:01 +01:00
case WM_ERASEBKGND :
2014-06-23 20:04:31 +02:00
if ( firstErase ) {
firstErase = false ;
// Paint black on first erase while OpenGL stuff is loading
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
}
// Then never erase, let the OpenGL drawing take care of everything.
return 1 ;
2013-03-29 19:32:20 +01:00
2013-06-01 23:34:50 +02:00
// Poor man's touch - mouse input. We send the data both as an input_state pointer,
// and as asynchronous touch events for minimal latency.
2012-11-01 16:19:01 +01:00
case WM_LBUTTONDOWN :
2014-02-24 13:28:20 +01:00
if ( ! touchHandler . hasTouch ( ) | |
( GetMessageExtraInfo ( ) & MOUSEEVENTF_MASK_PLUS_PENTOUCH ) ! = MOUSEEVENTF_FROMTOUCH_NOPEN )
2014-01-23 18:05:42 +01:00
{
2013-07-09 22:51:02 +02:00
// Hack: Take the opportunity to show the cursor.
mouseButtonDown = true ;
{
lock_guard guard ( input_state . lock ) ;
input_state . mouse_valid = true ;
input_state . pointer_down [ 0 ] = true ;
2013-03-31 19:15:59 -07:00
2013-09-23 23:56:32 -04:00
input_state . pointer_x [ 0 ] = GET_X_LPARAM ( lParam ) * factor ;
input_state . pointer_y [ 0 ] = GET_Y_LPARAM ( lParam ) * factor ;
2013-07-09 22:51:02 +02:00
}
2013-06-01 23:34:50 +02:00
TouchInput touch ;
touch . id = 0 ;
touch . flags = TOUCH_DOWN ;
2013-07-09 14:46:15 +02:00
touch . x = input_state . pointer_x [ 0 ] ;
touch . y = input_state . pointer_y [ 0 ] ;
2013-06-01 23:34:50 +02:00
NativeTouch ( touch ) ;
2013-07-09 22:51:02 +02:00
SetCapture ( hWnd ) ;
2014-02-24 13:28:20 +01:00
2015-09-07 21:21:17 +02:00
// Simulate doubleclick, doesn't work with RawInput enabled
static double lastMouseDown ;
double now = real_time_now ( ) ;
2015-09-07 21:22:58 +02:00
if ( ( now - lastMouseDown ) < 0.001 * GetDoubleClickTime ( ) ) {
2015-09-07 21:21:17 +02:00
if ( ! g_Config . bShowTouchControls & & GetUIState ( ) = = UISTATE_INGAME ) {
PostMessage ( hwndMain , WM_USER_TOGGLE_FULLSCREEN , 0 , 0 ) ;
}
2015-09-07 22:25:38 +02:00
lastMouseDown = 0.0 ;
} else {
lastMouseDown = real_time_now ( ) ;
2015-09-07 21:21:17 +02:00
}
2013-03-29 18:50:08 +01:00
}
2013-07-29 15:34:30 -04:00
break ;
2013-03-29 18:50:08 +01:00
case WM_MOUSEMOVE :
2014-02-24 13:28:20 +01:00
if ( ! touchHandler . hasTouch ( ) | |
( GetMessageExtraInfo ( ) & MOUSEEVENTF_MASK_PLUS_PENTOUCH ) ! = MOUSEEVENTF_FROMTOUCH_NOPEN )
2013-03-29 18:50:08 +01:00
{
2013-06-12 02:14:53 +08:00
// Hack: Take the opportunity to show the cursor.
mouseButtonDown = ( wParam & MK_LBUTTON ) ! = 0 ;
int cursorX = GET_X_LPARAM ( lParam ) ;
int cursorY = GET_Y_LPARAM ( lParam ) ;
if ( abs ( cursorX - prevCursorX ) > 1 | | abs ( cursorY - prevCursorY ) > 1 ) {
hideCursor = false ;
SetTimer ( hwndMain , TIMER_CURSORMOVEUPDATE , CURSORUPDATE_MOVE_TIMESPAN_MS , 0 ) ;
}
prevCursorX = cursorX ;
prevCursorY = cursorY ;
2013-07-09 22:51:02 +02:00
{
lock_guard guard ( input_state . lock ) ;
2013-09-23 23:56:32 -04:00
input_state . pointer_x [ 0 ] = GET_X_LPARAM ( lParam ) * factor ;
input_state . pointer_y [ 0 ] = GET_Y_LPARAM ( lParam ) * factor ;
2013-07-09 22:51:02 +02:00
}
2013-06-01 23:34:50 +02:00
if ( wParam & MK_LBUTTON ) {
TouchInput touch ;
touch . id = 0 ;
touch . flags = TOUCH_MOVE ;
2013-07-09 14:46:15 +02:00
touch . x = input_state . pointer_x [ 0 ] ;
touch . y = input_state . pointer_y [ 0 ] ;
2013-06-01 23:34:50 +02:00
NativeTouch ( touch ) ;
2013-03-31 19:15:59 -07:00
}
2013-03-29 18:50:08 +01:00
}
2012-11-01 16:19:01 +01:00
break ;
2013-03-29 18:50:08 +01:00
case WM_LBUTTONUP :
2014-02-24 13:28:20 +01:00
if ( ! touchHandler . hasTouch ( ) | |
( GetMessageExtraInfo ( ) & MOUSEEVENTF_MASK_PLUS_PENTOUCH ) ! = MOUSEEVENTF_FROMTOUCH_NOPEN )
2013-03-29 18:50:08 +01:00
{
2013-07-09 22:51:02 +02:00
// Hack: Take the opportunity to hide the cursor.
mouseButtonDown = false ;
{
lock_guard guard ( input_state . lock ) ;
input_state . pointer_down [ 0 ] = false ;
2013-09-23 23:56:32 -04:00
input_state . pointer_x [ 0 ] = GET_X_LPARAM ( lParam ) * factor ;
input_state . pointer_y [ 0 ] = GET_Y_LPARAM ( lParam ) * factor ;
2013-07-09 22:51:02 +02:00
}
2013-06-01 23:34:50 +02:00
TouchInput touch ;
touch . id = 0 ;
touch . flags = TOUCH_UP ;
2013-07-09 14:46:15 +02:00
touch . x = input_state . pointer_x [ 0 ] ;
touch . y = input_state . pointer_y [ 0 ] ;
2013-06-01 23:34:50 +02:00
NativeTouch ( touch ) ;
2013-07-09 22:51:02 +02:00
ReleaseCapture ( ) ;
2013-03-29 18:50:08 +01:00
}
2013-07-29 15:34:30 -04:00
break ;
2013-03-29 18:50:08 +01:00
2013-04-16 21:12:55 +02:00
case WM_TOUCH :
{
2014-01-19 22:54:49 +01:00
touchHandler . handleTouchEvent ( hWnd , message , wParam , lParam ) ;
2014-02-24 12:11:40 +01:00
return 0 ;
2013-04-16 21:12:55 +02:00
}
2014-06-29 22:13:53 +02:00
default :
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
}
return 0 ;
}
LRESULT CALLBACK WndProc ( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam ) {
switch ( message ) {
case WM_CREATE :
break ;
case WM_GETMINMAXINFO :
{
MINMAXINFO * minmax = reinterpret_cast < MINMAXINFO * > ( lParam ) ;
RECT rc = { 0 } ;
2015-05-15 18:04:05 +02:00
bool portrait = g_Config . IsPortrait ( ) ;
rc . right = portrait ? 272 : 480 ;
rc . bottom = portrait ? 480 : 272 ;
2014-06-29 22:13:53 +02:00
AdjustWindowRect ( & rc , WS_OVERLAPPEDWINDOW , TRUE ) ;
minmax - > ptMinTrackSize . x = rc . right - rc . left ;
minmax - > ptMinTrackSize . y = rc . bottom - rc . top ;
}
return 0 ;
2013-09-28 14:34:08 +02:00
case WM_ACTIVATE :
2013-10-11 14:53:25 +03:00
{
bool pause = true ;
if ( wParam = = WA_ACTIVE | | wParam = = WA_CLICKACTIVE ) {
2015-02-28 16:01:41 -08:00
WindowsRawInput : : GainFocus ( ) ;
2015-02-28 14:02:03 -08:00
InputDevice : : GainFocus ( ) ;
2013-10-11 14:53:25 +03:00
g_activeWindow = WINDOW_MAINWINDOW ;
pause = false ;
}
2014-06-22 09:38:46 +02:00
if ( ! noFocusPause & & g_Config . bPauseOnLostFocus & & GetUIState ( ) = = UISTATE_INGAME ) {
2013-10-11 14:53:25 +03:00
if ( pause ! = Core_IsStepping ( ) ) { // != is xor for bools
if ( disasmWindow [ 0 ] )
SendMessage ( disasmWindow [ 0 ] - > GetDlgHandle ( ) , WM_COMMAND , IDC_STOPGO , 0 ) ;
else
Core_EnableStepping ( pause ) ;
}
}
2013-10-31 00:34:09 +01:00
2015-05-21 10:49:47 +02:00
if ( wParam = = WA_ACTIVE ) {
NativeMessageReceived ( " got_focus " , " " ) ;
}
2013-10-31 00:34:09 +01:00
if ( wParam = = WA_INACTIVE ) {
2015-05-21 10:49:47 +02:00
NativeMessageReceived ( " lost_focus " , " " ) ;
2014-01-19 11:59:11 -08:00
WindowsRawInput : : LoseFocus ( ) ;
2015-02-28 14:02:03 -08:00
InputDevice : : LoseFocus ( ) ;
2013-10-31 00:34:09 +01:00
}
2013-09-28 14:34:08 +02:00
}
break ;
2012-11-01 16:19:01 +01:00
2014-06-29 22:13:53 +02:00
case WM_ERASEBKGND :
// This window is always covered by DisplayWindow. No reason to erase.
return 1 ;
2012-11-01 16:19:01 +01:00
case WM_MOVE :
2013-03-30 17:49:02 +01:00
SavePosition ( ) ;
2013-01-27 00:15:39 +01:00
break ;
2014-06-29 22:13:53 +02:00
case WM_SIZE :
if ( ! g_inModeSwitch ) {
2015-09-19 13:11:06 +02:00
ILOG ( " WM_SIZE (%d) " , ( int ) wParam ) ;
2014-06-29 22:13:53 +02:00
switch ( wParam ) {
case SIZE_MAXIMIZED :
case SIZE_RESTORED :
Core_NotifyWindowHidden ( false ) ;
2014-06-29 18:06:47 -04:00
if ( ! g_Config . bPauseWhenMinimized ) {
NativeMessageReceived ( " window minimized " , " false " ) ;
}
2014-06-29 22:13:53 +02:00
SavePosition ( ) ;
ResizeDisplay ( ) ;
2014-07-29 18:18:57 -04:00
g_WindowState = wParam ;
2014-06-29 22:13:53 +02:00
break ;
case SIZE_MINIMIZED :
2014-06-30 13:04:44 -04:00
Core_NotifyWindowHidden ( true ) ;
2014-06-29 18:06:47 -04:00
if ( ! g_Config . bPauseWhenMinimized ) {
NativeMessageReceived ( " window minimized " , " true " ) ;
}
2014-06-29 22:13:53 +02:00
break ;
default :
break ;
}
2015-09-19 13:11:06 +02:00
} else {
ILOG ( " WM_SIZE (%d) (ignored) " , ( int ) wParam ) ;
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
2014-06-29 22:13:53 +02:00
}
2015-01-17 19:49:58 -08:00
break ;
2014-06-29 22:13:53 +02:00
case WM_TIMER :
2013-05-04 23:21:06 +02:00
// Hack: Take the opportunity to also show/hide the mouse cursor in fullscreen mode.
2013-07-29 04:46:40 -04:00
switch ( wParam ) {
2013-06-12 02:14:53 +08:00
case TIMER_CURSORUPDATE :
CorrectCursor ( ) ;
return 0 ;
2013-07-29 15:34:30 -04:00
2013-06-12 02:14:53 +08:00
case TIMER_CURSORMOVEUPDATE :
hideCursor = true ;
KillTimer ( hWnd , TIMER_CURSORMOVEUPDATE ) ;
return 0 ;
}
break ;
2013-05-04 23:21:06 +02:00
2013-07-08 12:35:08 +02:00
// For some reason, need to catch this here rather than in DisplayProc.
case WM_MOUSEWHEEL :
{
int wheelDelta = ( short ) ( wParam > > 16 ) ;
KeyInput key ;
key . deviceId = DEVICE_ID_MOUSE ;
if ( wheelDelta < 0 ) {
2013-08-05 03:31:40 +10:00
key . keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN ;
2013-07-08 12:35:08 +02:00
wheelDelta = - wheelDelta ;
} else {
2013-08-05 03:31:40 +10:00
key . keyCode = NKCODE_EXT_MOUSEWHEEL_UP ;
2013-07-08 12:35:08 +02:00
}
// There's no separate keyup event for mousewheel events, let's pass them both together.
// This also means it really won't work great for key mapping :( Need to build a 1 frame delay or something.
key . flags = KEY_DOWN | KEY_UP | KEY_HASWHEELDELTA | ( wheelDelta < < 16 ) ;
NativeKey ( key ) ;
}
2013-07-29 15:34:30 -04:00
break ;
2013-07-08 12:35:08 +02:00
2012-11-01 16:19:01 +01:00
case WM_COMMAND :
2013-06-03 20:30:12 +08:00
{
2013-07-29 04:46:40 -04:00
if ( ! EmuThread_Ready ( ) )
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
2014-01-07 16:08:11 -05:00
2015-09-19 13:11:06 +02:00
MainWindowMenu_Process ( hWnd , wParam ) ;
2013-06-03 20:30:12 +08:00
}
2012-11-01 16:19:01 +01:00
break ;
2013-07-06 19:08:59 +02:00
2015-02-15 23:07:24 +01:00
case WM_USER_TOGGLE_FULLSCREEN :
ToggleFullscreen ( hwndMain , ! g_Config . bFullScreen ) ;
break ;
2013-07-07 10:42:39 +02:00
case WM_INPUT :
2014-01-19 12:11:08 -08:00
return WindowsRawInput : : Process ( hWnd , wParam , lParam ) ;
// TODO: Could do something useful with WM_INPUT_DEVICE_CHANGE?
2013-05-13 17:13:49 +08:00
2014-06-29 23:29:49 +02:00
// Not sure why we are actually getting WM_CHAR even though we use RawInput, but alright..
case WM_CHAR :
return WindowsRawInput : : ProcessChar ( hWnd , wParam , lParam ) ;
2013-11-30 18:21:47 -08:00
case WM_VERYSLEEPY_MSG :
switch ( wParam ) {
case VERYSLEEPY_WPARAM_SUPPORTED :
return TRUE ;
case VERYSLEEPY_WPARAM_GETADDRINFO :
{
VerySleepy_AddrInfo * info = ( VerySleepy_AddrInfo * ) lParam ;
const u8 * ptr = ( const u8 * ) info - > addr ;
2013-12-18 23:57:39 -08:00
std : : string name ;
2013-11-30 18:21:47 -08:00
2013-12-18 23:57:39 -08:00
if ( MIPSComp : : jit & & MIPSComp : : jit - > DescribeCodePtr ( ptr , name ) ) {
swprintf_s ( info - > name , L " Jit::%S " , name . c_str ( ) ) ;
return TRUE ;
2013-11-30 18:21:47 -08:00
}
2013-12-18 23:57:39 -08:00
if ( gpu & & gpu - > DescribeCodePtr ( ptr , name ) ) {
swprintf_s ( info - > name , L " GPU::%S " , name . c_str ( ) ) ;
return TRUE ;
2013-11-30 18:39:16 -08:00
}
2013-11-30 18:21:47 -08:00
}
return FALSE ;
default :
return FALSE ;
}
break ;
2012-11-01 16:19:01 +01:00
case WM_DROPFILES :
{
2013-06-08 08:32:07 +08:00
if ( ! EmuThread_Ready ( ) )
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
2012-11-01 16:19:01 +01:00
HDROP hdrop = ( HDROP ) wParam ;
int count = DragQueryFile ( hdrop , 0xFFFFFFFF , 0 , 0 ) ;
2013-07-29 04:46:40 -04:00
if ( count ! = 1 ) {
2013-08-26 19:00:16 +02:00
MessageBox ( hwndMain , L " You can only load one file at a time " , L " Error " , MB_ICONINFORMATION ) ;
2012-11-01 16:19:01 +01:00
}
else
{
TCHAR filename [ 512 ] ;
DragQueryFile ( hdrop , 0 , filename , 512 ) ;
TCHAR * type = filename + _tcslen ( filename ) - 3 ;
2013-08-26 19:00:16 +02:00
NativeMessageReceived ( " boot " , ConvertWStringToUTF8 ( filename ) . c_str ( ) ) ;
2013-10-16 01:19:15 -07:00
Core_EnableStepping ( false ) ;
2012-11-01 16:19:01 +01:00
}
}
break ;
case WM_CLOSE :
EmuThread_Stop ( ) ;
2014-03-23 22:18:54 -07:00
InputDevice : : StopPolling ( ) ;
2014-01-19 12:11:08 -08:00
WindowsRawInput : : Shutdown ( ) ;
2012-11-01 16:19:01 +01:00
2013-01-02 22:57:57 +01:00
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
2013-01-05 19:57:06 +01:00
2012-11-01 16:19:01 +01:00
case WM_DESTROY :
2013-06-12 02:14:53 +08:00
KillTimer ( hWnd , TIMER_CURSORUPDATE ) ;
KillTimer ( hWnd , TIMER_CURSORMOVEUPDATE ) ;
2012-11-01 16:19:01 +01:00
PostQuitMessage ( 0 ) ;
break ;
2013-09-23 23:01:26 -04:00
case WM_USER + 1 :
2014-02-14 21:17:36 -08:00
if ( disasmWindow [ 0 ] )
disasmWindow [ 0 ] - > NotifyMapLoaded ( ) ;
if ( memoryWindow [ 0 ] )
memoryWindow [ 0 ] - > NotifyMapLoaded ( ) ;
2013-08-26 14:19:46 +02:00
2014-02-14 21:17:36 -08:00
if ( disasmWindow [ 0 ] )
disasmWindow [ 0 ] - > UpdateDialog ( ) ;
2012-12-22 09:21:23 -08:00
2013-03-31 18:28:13 -07:00
SetForegroundWindow ( hwndMain ) ;
2012-11-01 16:19:01 +01:00
break ;
2013-03-29 19:52:32 +01:00
2013-07-21 02:21:50 -07:00
case WM_USER_SAVESTATE_FINISH :
SetCursor ( LoadCursor ( 0 , IDC_ARROW ) ) ;
break ;
2013-03-29 19:52:32 +01:00
2013-09-01 14:06:24 -07:00
case WM_USER_UPDATE_UI :
2015-09-19 13:11:06 +02:00
TranslateMenus ( hwndMain , menu ) ;
2013-09-01 14:06:24 -07:00
break ;
2013-09-08 00:22:38 -04:00
case WM_USER_UPDATE_SCREEN :
2014-02-12 10:36:40 +01:00
ResizeDisplay ( true ) ;
ShowScreenResolution ( ) ;
2013-09-08 00:22:38 -04:00
break ;
2013-09-13 15:17:55 -04:00
case WM_USER_WINDOW_TITLE_CHANGED :
UpdateWindowTitle ( ) ;
break ;
2014-01-19 18:44:41 -08:00
case WM_USER_BROWSE_BOOT_DONE :
BrowseAndBootDone ( ) ;
break ;
2013-03-29 19:32:20 +01:00
case WM_MENUSELECT :
2013-05-13 16:08:10 +08:00
// Unfortunately, accelerate keys (hotkeys) shares the same enabled/disabled states
// with corresponding menu items.
2013-03-29 19:32:20 +01:00
UpdateMenus ( ) ;
2014-01-20 00:57:20 -08:00
WindowsRawInput : : NotifyMenu ( ) ;
2013-03-29 19:32:20 +01:00
break ;
2012-11-01 16:19:01 +01:00
2013-05-02 20:58:10 +02:00
// Turn off the screensaver.
// Note that if there's a screensaver password, this simple method
// doesn't work on Vista or higher.
case WM_SYSCOMMAND :
{
2013-07-29 04:46:40 -04:00
switch ( wParam ) {
2013-05-02 20:58:10 +02:00
case SC_SCREENSAVE :
return 0 ;
case SC_MONITORPOWER :
return 0 ;
}
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
}
2012-11-01 16:19:01 +01:00
default :
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
}
return 0 ;
}
2013-08-30 20:15:13 +02:00
2013-07-29 04:46:40 -04:00
void Redraw ( ) {
2014-06-29 22:13:53 +02:00
InvalidateRect ( hwndDisplay , 0 , 0 ) ;
2012-11-01 16:19:01 +01:00
}
2013-03-29 21:21:27 +01:00
2013-07-29 04:46:40 -04:00
HINSTANCE GetHInstance ( ) {
2012-11-01 16:19:01 +01:00
return hInst ;
}
2013-10-13 14:14:28 -04:00
2013-10-13 14:25:59 -04:00
void ToggleDebugConsoleVisibility ( ) {
2013-10-13 14:14:28 -04:00
if ( ! g_Config . bEnableLogging ) {
LogManager : : GetInstance ( ) - > GetConsoleListener ( ) - > Show ( false ) ;
EnableMenuItem ( menu , ID_DEBUG_LOG , MF_GRAYED ) ;
}
else {
LogManager : : GetInstance ( ) - > GetConsoleListener ( ) - > Show ( true ) ;
EnableMenuItem ( menu , ID_DEBUG_LOG , MF_ENABLED ) ;
}
}
2015-09-19 13:11:06 +02:00
} // namespace