with r_mode 1, tabbing out of the game will restore display settings on the desktop

fixed window restore after minimizing when clicking the task bar or using alt-tab
fixed r_mode 1 on secondary monitors
fixed in_mouse 2 input on secondary monitors
fixed the cursor sometimes staying visible and unclipped when restoring the window
This commit is contained in:
myT 2017-06-01 20:48:21 +02:00
parent d9bacec921
commit c3ee3f2a4d
6 changed files with 158 additions and 83 deletions

View File

@ -38,7 +38,8 @@ typedef struct
HGLRC hGLRC;
HINSTANCE hinstOpenGL;
int desktopBPP;
qbool cdsFullscreen;
qbool cdsDevModeValid;
DEVMODE cdsDevMode; // Custom device mode for full-screen with r_mode 1.
qbool pixelFormatSet;
int nPendingPF;
} glwstate_t;

View File

@ -471,7 +471,7 @@ static qbool GLW_CreateWindow( int width, int height, int colorbits )
const int w = r.right - r.left;
const int h = r.bottom - r.top;
const RECT monRect = g_wv.monitorRects[g_wv.monitor];
const RECT& monRect = g_wv.monitorRects[g_wv.monitor];
int dx = 0;
int dy = 0;
@ -517,19 +517,72 @@ static qbool GLW_CreateWindow( int width, int height, int colorbits )
}
static qbool GLW_Fullscreen( DEVMODE& dm )
static const char* GLW_GetCurrentDisplayDeviceName()
{
int cds = ChangeDisplaySettings( &dm, CDS_FULLSCREEN );
static char deviceName[CCHDEVICENAME + 1];
if (cds == DISP_CHANGE_SUCCESSFUL)
const HMONITOR hMonitor = g_wv.hMonitors[g_wv.monitor];
if ( hMonitor == NULL )
return NULL;
MONITORINFOEXA info;
ZeroMemory( &info, sizeof(info) );
info.cbSize = sizeof(info);
if ( GetMonitorInfoA(hMonitor, &info) == 0 )
return NULL;
Q_strncpyz( deviceName, info.szDevice, sizeof(deviceName) );
return deviceName;
}
static void GLW_UpdateMonitorRect( const char* deviceName )
{
if ( deviceName == NULL )
return;
DEVMODEA dm;
ZeroMemory( &dm, sizeof(dm) );
dm.dmSize = sizeof(dm);
if ( EnumDisplaySettingsExA(deviceName, ENUM_CURRENT_SETTINGS, &dm, 0) == 0 )
return;
if ( dm.dmPelsWidth == 0 || dm.dmPelsHeight == 0 )
return;
// Normally, we should check dm.dmFields for the following flags:
// DM_POSITION DM_PELSWIDTH DM_PELSHEIGHT
// EnumDisplaySettingsExA doesn't always set up the flags properly.
RECT& rect = g_wv.monitorRects[g_wv.monitor];
rect.left = dm.dmPosition.x;
rect.top = dm.dmPosition.y;
rect.right = dm.dmPosition.x + dm.dmPelsWidth;
rect.bottom = dm.dmPosition.y + dm.dmPelsHeight;
}
static qbool GLW_SetDisplaySettings( DEVMODE& dm )
{
const char* deviceName = GLW_GetCurrentDisplayDeviceName();
const int ec = ChangeDisplaySettingsExA( deviceName, &dm, NULL, CDS_FULLSCREEN, NULL );
if ( ec == DISP_CHANGE_SUCCESSFUL )
{
glw_state.cdsDevMode = dm;
glw_state.cdsDevModeValid = qtrue;
GLW_UpdateMonitorRect( deviceName );
return qtrue;
}
ri.Printf( PRINT_ALL, "...CDS: %ix%i (C%i) failed: ", dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel );
glw_state.cdsDevModeValid = qfalse;
ri.Printf( PRINT_ALL, "...CDS: %ix%i (C%i) failed: ", (int)dm.dmPelsWidth, (int)dm.dmPelsHeight, (int)dm.dmBitsPerPel );
#define CDS_ERROR(x) case x: ri.Printf( PRINT_ALL, #x##"\n" ); break;
switch (cds) {
switch (ec) {
default:
ri.Printf( PRINT_ALL, "unknown error %d\n", cds );
ri.Printf( PRINT_ALL, "unknown error %d\n", ec );
break;
CDS_ERROR( DISP_CHANGE_RESTART );
CDS_ERROR( DISP_CHANGE_BADPARAM );
@ -544,6 +597,31 @@ static qbool GLW_Fullscreen( DEVMODE& dm )
}
static void GLW_ResetDisplaySettings( qbool invalidate )
{
const char* deviceName = GLW_GetCurrentDisplayDeviceName();
ChangeDisplaySettingsEx( deviceName, NULL, NULL, 0, NULL );
GLW_UpdateMonitorRect( deviceName );
if ( invalidate )
glw_state.cdsDevModeValid = qfalse;
}
void WIN_SetGameDisplaySettings()
{
if ( glw_state.cdsDevModeValid )
GLW_SetDisplaySettings( glw_state.cdsDevMode );
}
void WIN_SetDesktopDisplaySettings()
{
// We don't invalidate glw_state.cdsDevModeValid so we can
// return to the previous mode later.
GLW_ResetDisplaySettings( qfalse );
}
static qbool GLW_SetMode( qbool cdsFullscreen )
{
HDC hDC = GetDC( GetDesktopWindow() );
@ -553,7 +631,7 @@ static qbool GLW_SetMode( qbool cdsFullscreen )
glInfo.isFullscreen = cdsFullscreen;
WIN_UpdateMonitorIndexFromCvar();
if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect ) ) {
const RECT monRect = g_wv.monitorRects[g_wv.monitor];
const RECT& monRect = g_wv.monitorRects[g_wv.monitor];
glConfig.vidWidth = monRect.right - monRect.left;
glConfig.vidHeight = monRect.bottom - monRect.top;
glConfig.windowAspect = (float)glConfig.vidWidth / glConfig.vidHeight;
@ -562,10 +640,10 @@ static qbool GLW_SetMode( qbool cdsFullscreen )
//ri.Printf( PRINT_DEVELOPER, "...setting mode %dx%d %s\n", glConfig.vidWidth, glConfig.vidHeight, cdsFullscreen ? "FS" : "W" );
DEVMODE dm;
memset( &dm, 0, sizeof( dm ) );
ZeroMemory( &dm, sizeof( dm ) );
dm.dmSize = sizeof( dm );
if (cdsFullscreen != glw_state.cdsFullscreen) {
if (cdsFullscreen != glw_state.cdsDevModeValid) {
if (cdsFullscreen) {
dm.dmPelsWidth = glConfig.vidWidth;
dm.dmPelsHeight = glConfig.vidHeight;
@ -581,25 +659,23 @@ static qbool GLW_SetMode( qbool cdsFullscreen )
dm.dmFields |= DM_BITSPERPEL;
}
glInfo.isFullscreen = qtrue;
glw_state.cdsFullscreen = qtrue;
const RECT& monRect = g_wv.monitorRects[g_wv.monitor];
dm.dmPosition.x = monRect.left;
dm.dmPosition.y = monRect.top;
dm.dmFields |= DM_POSITION;
if (!GLW_Fullscreen( dm )) {
glInfo.isFullscreen = qfalse;
glw_state.cdsFullscreen = qfalse;
}
glInfo.isFullscreen = GLW_SetDisplaySettings( dm );
}
else
{
ChangeDisplaySettings( 0, 0 );
glw_state.cdsFullscreen = qfalse;
GLW_ResetDisplaySettings( qtrue );
}
}
if (!GLW_CreateWindow( glConfig.vidWidth, glConfig.vidHeight, glConfig.colorBits ))
return qfalse;
if (EnumDisplaySettings( NULL, ENUM_CURRENT_SETTINGS, &dm ))
if (EnumDisplaySettingsA( GLW_GetCurrentDisplayDeviceName(), ENUM_CURRENT_SETTINGS, &dm ))
glInfo.displayFrequency = dm.dmDisplayFrequency;
return qtrue;
@ -668,7 +744,7 @@ static qbool GLW_LoadOpenGL()
// load the driver and bind our function pointers to it
if ( QGL_Init( OPENGL_DRIVER_NAME ) ) {
// create the window and set up the context
if ( GLW_SetMode( (qbool)r_fullscreen->integer ) ) {
if ( GLW_SetMode( (qbool)!!r_fullscreen->integer ) ) {
return qtrue;
}
}
@ -783,11 +859,10 @@ void GLimp_Shutdown()
}
// reset display settings
if ( glw_state.cdsFullscreen )
if ( glw_state.cdsDevModeValid )
{
ri.Printf( PRINT_DEVELOPER, "...resetting display\n" );
ChangeDisplaySettings( 0, 0 );
glw_state.cdsFullscreen = qfalse;
GLW_ResetDisplaySettings( qtrue );
}
// shutdown QGL subsystem
@ -895,10 +970,10 @@ void GLimp_WakeRenderer( void *data ) {
WaitForSingleObject( renderActiveEvent, INFINITE );
}
void WIN_UpdateResolution( int width, int height )
{
glConfig.vidWidth = width;
glConfig.vidHeight = height;
}

View File

@ -27,7 +27,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
struct Mouse {
virtual qbool Init() { return qtrue; }
virtual qbool Activate( qbool active );
virtual void OnWindowMoved() {}
virtual void Shutdown() {}
virtual qbool ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ) { return qfalse; } // returns true if the event was handled
@ -91,17 +90,14 @@ qbool rawmouse_t::Init()
qbool rawmouse_t::Activate( qbool active )
{
// RIDEV_NOLEGACY means we only get WM_INPUT and not WM_LBUTTONDOWN etc
RAWINPUTDEVICE rid;
rid.usUsagePage = 1;
rid.usUsage = 2;
rid.dwFlags = active ? RIDEV_NOLEGACY : RIDEV_REMOVE;
rid.hwndTarget = NULL;
rid.usUsagePage = 0x01;
rid.usUsage = 0x02; // page 1 item 2 = mouse, gg constants you asswipes >:(
if (active)
rid.dwFlags = RIDEV_NOLEGACY;
else
rid.dwFlags = RIDEV_REMOVE;
rid.hwndTarget = 0;
return RegisterRawInputDevices( &rid, 1, sizeof(rid) );
return !!RegisterRawInputDevices( &rid, 1, sizeof(rid) );
}
@ -162,7 +158,6 @@ qbool rawmouse_t::ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam )
struct winmouse_t : public Mouse {
virtual qbool Activate( qbool active );
virtual void OnWindowMoved();
virtual qbool ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam );
void UpdateWindowCenter();
@ -176,14 +171,9 @@ static winmouse_t winmouse;
void winmouse_t::UpdateWindowCenter()
{
const int sw = GetSystemMetrics( SM_CXSCREEN );
const int sh = GetSystemMetrics( SM_CYSCREEN );
RECT rc;
GetWindowRect( g_wv.hWnd, &rc );
window_center_x = ( max(rc.left, 0) + min(rc.right, sw) ) / 2;
window_center_y = ( max(rc.top, 0) + min(rc.bottom, sh) ) / 2;
const RECT& rect = g_wv.monitorRects[g_wv.monitor];
window_center_x = (int)( rect.left + rect.right ) / 2;
window_center_y = (int)( rect.top + rect.bottom ) / 2;
}
@ -201,17 +191,13 @@ qbool winmouse_t::Activate( qbool _active )
}
void winmouse_t::OnWindowMoved()
{
UpdateWindowCenter();
}
qbool winmouse_t::ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam )
{
if ( !active )
return qfalse;
UpdateWindowCenter();
#define QUEUE_WM_BUTTON( qbutton, mask ) \
Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qbutton, (wParam & mask), 0, NULL );
@ -352,14 +338,8 @@ void IN_Shutdown()
}
// called when the window gains or loses focus or changes in some way
// the window may have been destroyed and recreated between a deactivate and an activate
void IN_Activate( qbool active )
void IN_SetCursorSettings( qbool active )
{
if ( !mouse || !mouse->Mouse::Activate( active ) )
return;
if (active) {
while (ShowCursor(FALSE) >= 0)
;
@ -373,17 +353,20 @@ void IN_Activate( qbool active )
ClipCursor( NULL );
ReleaseCapture();
}
mouse->Activate( active );
}
void IN_WindowMoved()
// called when the window gains or loses focus or changes in some way
// the window may have been destroyed and recreated between a deactivate and an activate
void IN_Activate( qbool active )
{
if (!mouse)
if ( !mouse || !mouse->Mouse::Activate( active ) )
return;
mouse->OnWindowMoved();
IN_SetCursorSettings( active );
mouse->Activate( active );
}
@ -403,12 +386,7 @@ void IN_Frame()
if (!mouse)
return;
if (!IN_ShouldBeActive()) {
IN_Activate( qfalse );
return;
}
IN_Activate( qtrue );
IN_Activate( IN_ShouldBeActive() );
}

View File

@ -33,8 +33,8 @@ void Conbuf_AppendText( const char *msg );
void IN_Init();
void IN_SetCursorSettings( qbool active );
void IN_Activate( qbool active );
void IN_WindowMoved();
qbool IN_ShouldBeActive();
qbool IN_ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ); // returns true if the event was handled
void IN_Frame();
@ -45,6 +45,8 @@ void WIN_UpdateMonitorIndexFromMainWindow();
void WIN_UpdateResolution( int width, int height );
void WIN_RegisterLastValidHotKey();
void WIN_UnregisterHotKey();
void WIN_SetGameDisplaySettings();
void WIN_SetDesktopDisplaySettings();
void SNDDMA_Activate();
@ -62,7 +64,6 @@ typedef struct
HWND hWnd;
HINSTANCE hInstance;
qbool activeApp;
qbool isMinimized;
// when we get a windows message, we store the time off
// using Sys_Milliseconds

View File

@ -605,7 +605,7 @@ void WIN_UpdateMonitorIndexFromCvar()
return;
}
g_wv.monitor = monitor - 1;
g_wv.monitor = Com_ClampInt( 0, g_wv.monitorCount - 1, monitor - 1 );
}

View File

@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../client/client.h"
#include "win_local.h"
#include "glw_win.h"
// Console variables that we need to access from this module
@ -72,19 +73,19 @@ static void WIN_EnableAltTab()
}
static void VID_AppActivate( BOOL fActive, BOOL minimize )
static void WIN_AppActivate( BOOL fActive, BOOL fMinimized )
{
if (r_fullscreen->integer)
SetWindowPos( g_wv.hWnd, fActive ? HWND_TOPMOST : HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
const qbool active = fActive && !fMinimized;
g_wv.isMinimized = (minimize == TRUE);
if (r_fullscreen->integer)
SetWindowPos( g_wv.hWnd, active ? HWND_TOPMOST : HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
Com_DPrintf("VID_AppActivate: %i\n", fActive );
Key_ClearStates(); // FIXME!!!
// we don't want to act like we're active if we're minimized
g_wv.activeApp = (fActive && !g_wv.isMinimized);
g_wv.activeApp = active;
IN_Activate( IN_ShouldBeActive() );
}
@ -268,7 +269,7 @@ LRESULT CALLBACK MainWndProc (
break;
case WM_ACTIVATE:
VID_AppActivate( (LOWORD(wParam) != WA_INACTIVE), (BOOL)HIWORD(wParam) );
WIN_AppActivate( (LOWORD(wParam) != WA_INACTIVE), !!(BOOL)HIWORD(wParam) );
SNDDMA_Activate();
break;
@ -285,17 +286,13 @@ LRESULT CALLBACK MainWndProc (
r.bottom = 1;
AdjustWindowRect( &r, GetWindowLong( hWnd, GWL_STYLE ), FALSE );
const RECT monRect = g_wv.monitorRects[g_wv.monitor];
const RECT& monRect = g_wv.monitorRects[g_wv.monitor];
const int x = LOWORD( lParam );
const int y = HIWORD( lParam );
Cvar_SetValue( "vid_xpos", x + r.left - monRect.left );
Cvar_SetValue( "vid_ypos", y + r.top - monRect.top );
vid_xpos->modified = qfalse;
vid_ypos->modified = qfalse;
if ( g_wv.activeApp )
{
IN_WindowMoved();
}
}
}
break;
@ -353,6 +350,29 @@ LRESULT CALLBACK MainWndProc (
}
break;
case WM_SETFOCUS:
if ( glw_state.cdsDevModeValid ) // is there a valid mode to restore?
{
WIN_SetGameDisplaySettings();
if ( glw_state.cdsDevModeValid ) // was the mode successfully restored?
{
const RECT& rect = g_wv.monitorRects[g_wv.monitor];
const DEVMODE& dm = glw_state.cdsDevMode;
SetWindowPos( hWnd, NULL, (int)rect.left, (int)rect.top, (int)dm.dmPelsWidth, (int)dm.dmPelsHeight, SWP_NOZORDER );
}
}
g_wv.activeApp = (qbool)!IsIconic( hWnd );
IN_SetCursorSettings( IN_ShouldBeActive() );
break;
case WM_KILLFOCUS:
g_wv.activeApp = qfalse;
IN_SetCursorSettings( qfalse );
if ( glw_state.cdsDevModeValid )
WIN_SetDesktopDisplaySettings();
break;
default:
// this is complicated because Win32 seems to pack multiple mouse events into
// one update sometimes, so we always check all states and look for events