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; HGLRC hGLRC;
HINSTANCE hinstOpenGL; HINSTANCE hinstOpenGL;
int desktopBPP; int desktopBPP;
qbool cdsFullscreen; qbool cdsDevModeValid;
DEVMODE cdsDevMode; // Custom device mode for full-screen with r_mode 1.
qbool pixelFormatSet; qbool pixelFormatSet;
int nPendingPF; int nPendingPF;
} glwstate_t; } 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 w = r.right - r.left;
const int h = r.bottom - r.top; 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 dx = 0;
int dy = 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; 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; #define CDS_ERROR(x) case x: ri.Printf( PRINT_ALL, #x##"\n" ); break;
switch (cds) { switch (ec) {
default: default:
ri.Printf( PRINT_ALL, "unknown error %d\n", cds ); ri.Printf( PRINT_ALL, "unknown error %d\n", ec );
break; break;
CDS_ERROR( DISP_CHANGE_RESTART ); CDS_ERROR( DISP_CHANGE_RESTART );
CDS_ERROR( DISP_CHANGE_BADPARAM ); 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 ) static qbool GLW_SetMode( qbool cdsFullscreen )
{ {
HDC hDC = GetDC( GetDesktopWindow() ); HDC hDC = GetDC( GetDesktopWindow() );
@ -553,7 +631,7 @@ static qbool GLW_SetMode( qbool cdsFullscreen )
glInfo.isFullscreen = cdsFullscreen; glInfo.isFullscreen = cdsFullscreen;
WIN_UpdateMonitorIndexFromCvar(); WIN_UpdateMonitorIndexFromCvar();
if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect ) ) { 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.vidWidth = monRect.right - monRect.left;
glConfig.vidHeight = monRect.bottom - monRect.top; glConfig.vidHeight = monRect.bottom - monRect.top;
glConfig.windowAspect = (float)glConfig.vidWidth / glConfig.vidHeight; 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" ); //ri.Printf( PRINT_DEVELOPER, "...setting mode %dx%d %s\n", glConfig.vidWidth, glConfig.vidHeight, cdsFullscreen ? "FS" : "W" );
DEVMODE dm; DEVMODE dm;
memset( &dm, 0, sizeof( dm ) ); ZeroMemory( &dm, sizeof( dm ) );
dm.dmSize = sizeof( dm ); dm.dmSize = sizeof( dm );
if (cdsFullscreen != glw_state.cdsFullscreen) { if (cdsFullscreen != glw_state.cdsDevModeValid) {
if (cdsFullscreen) { if (cdsFullscreen) {
dm.dmPelsWidth = glConfig.vidWidth; dm.dmPelsWidth = glConfig.vidWidth;
dm.dmPelsHeight = glConfig.vidHeight; dm.dmPelsHeight = glConfig.vidHeight;
@ -581,25 +659,23 @@ static qbool GLW_SetMode( qbool cdsFullscreen )
dm.dmFields |= DM_BITSPERPEL; dm.dmFields |= DM_BITSPERPEL;
} }
glInfo.isFullscreen = qtrue; const RECT& monRect = g_wv.monitorRects[g_wv.monitor];
glw_state.cdsFullscreen = qtrue; dm.dmPosition.x = monRect.left;
dm.dmPosition.y = monRect.top;
dm.dmFields |= DM_POSITION;
if (!GLW_Fullscreen( dm )) { glInfo.isFullscreen = GLW_SetDisplaySettings( dm );
glInfo.isFullscreen = qfalse;
glw_state.cdsFullscreen = qfalse;
}
} }
else else
{ {
ChangeDisplaySettings( 0, 0 ); GLW_ResetDisplaySettings( qtrue );
glw_state.cdsFullscreen = qfalse;
} }
} }
if (!GLW_CreateWindow( glConfig.vidWidth, glConfig.vidHeight, glConfig.colorBits )) if (!GLW_CreateWindow( glConfig.vidWidth, glConfig.vidHeight, glConfig.colorBits ))
return qfalse; return qfalse;
if (EnumDisplaySettings( NULL, ENUM_CURRENT_SETTINGS, &dm )) if (EnumDisplaySettingsA( GLW_GetCurrentDisplayDeviceName(), ENUM_CURRENT_SETTINGS, &dm ))
glInfo.displayFrequency = dm.dmDisplayFrequency; glInfo.displayFrequency = dm.dmDisplayFrequency;
return qtrue; return qtrue;
@ -668,7 +744,7 @@ static qbool GLW_LoadOpenGL()
// load the driver and bind our function pointers to it // load the driver and bind our function pointers to it
if ( QGL_Init( OPENGL_DRIVER_NAME ) ) { if ( QGL_Init( OPENGL_DRIVER_NAME ) ) {
// create the window and set up the context // create the window and set up the context
if ( GLW_SetMode( (qbool)r_fullscreen->integer ) ) { if ( GLW_SetMode( (qbool)!!r_fullscreen->integer ) ) {
return qtrue; return qtrue;
} }
} }
@ -783,11 +859,10 @@ void GLimp_Shutdown()
} }
// reset display settings // reset display settings
if ( glw_state.cdsFullscreen ) if ( glw_state.cdsDevModeValid )
{ {
ri.Printf( PRINT_DEVELOPER, "...resetting display\n" ); ri.Printf( PRINT_DEVELOPER, "...resetting display\n" );
ChangeDisplaySettings( 0, 0 ); GLW_ResetDisplaySettings( qtrue );
glw_state.cdsFullscreen = qfalse;
} }
// shutdown QGL subsystem // shutdown QGL subsystem
@ -895,10 +970,10 @@ void GLimp_WakeRenderer( void *data ) {
WaitForSingleObject( renderActiveEvent, INFINITE ); WaitForSingleObject( renderActiveEvent, INFINITE );
} }
void WIN_UpdateResolution( int width, int height ) void WIN_UpdateResolution( int width, int height )
{ {
glConfig.vidWidth = width; glConfig.vidWidth = width;
glConfig.vidHeight = height; glConfig.vidHeight = height;
} }

View file

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

View file

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

View file

@ -605,7 +605,7 @@ void WIN_UpdateMonitorIndexFromCvar()
return; 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 "../client/client.h"
#include "win_local.h" #include "win_local.h"
#include "glw_win.h"
// Console variables that we need to access from this module // 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) const qbool active = fActive && !fMinimized;
SetWindowPos( g_wv.hWnd, fActive ? HWND_TOPMOST : HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
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 ); Com_DPrintf("VID_AppActivate: %i\n", fActive );
Key_ClearStates(); // FIXME!!! Key_ClearStates(); // FIXME!!!
// we don't want to act like we're active if we're minimized // 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() ); IN_Activate( IN_ShouldBeActive() );
} }
@ -268,7 +269,7 @@ LRESULT CALLBACK MainWndProc (
break; break;
case WM_ACTIVATE: case WM_ACTIVATE:
VID_AppActivate( (LOWORD(wParam) != WA_INACTIVE), (BOOL)HIWORD(wParam) ); WIN_AppActivate( (LOWORD(wParam) != WA_INACTIVE), !!(BOOL)HIWORD(wParam) );
SNDDMA_Activate(); SNDDMA_Activate();
break; break;
@ -285,17 +286,13 @@ LRESULT CALLBACK MainWndProc (
r.bottom = 1; r.bottom = 1;
AdjustWindowRect( &r, GetWindowLong( hWnd, GWL_STYLE ), FALSE ); 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 x = LOWORD( lParam );
const int y = HIWORD( lParam ); const int y = HIWORD( lParam );
Cvar_SetValue( "vid_xpos", x + r.left - monRect.left ); Cvar_SetValue( "vid_xpos", x + r.left - monRect.left );
Cvar_SetValue( "vid_ypos", y + r.top - monRect.top ); Cvar_SetValue( "vid_ypos", y + r.top - monRect.top );
vid_xpos->modified = qfalse; vid_xpos->modified = qfalse;
vid_ypos->modified = qfalse; vid_ypos->modified = qfalse;
if ( g_wv.activeApp )
{
IN_WindowMoved();
}
} }
} }
break; break;
@ -353,6 +350,29 @@ LRESULT CALLBACK MainWndProc (
} }
break; 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: default:
// this is complicated because Win32 seems to pack multiple mouse events into // 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 // one update sometimes, so we always check all states and look for events