Merge remote-tracking branch 'DanielGibson/improve-window-handling'

This commit is contained in:
Robert Beckebans 2013-01-05 11:35:52 +01:00
commit 0881085589
10 changed files with 320 additions and 41 deletions

View file

@ -86,6 +86,10 @@ idCVar preload_CommonAssets( "preload_CommonAssets", "1", CVAR_SYSTEM | CVAR_BOO
idCVar net_inviteOnly( "net_inviteOnly", "1", CVAR_BOOL | CVAR_ARCHIVE, "whether or not the private server you create allows friends to join or invite only" );
// DG: add cvar for pause
idCVar com_pause( "com_pause", "0", CVAR_BOOL | CVAR_SYSTEM , "set to 1 to pause game, to 0 to unpause again" );
// DG end
extern idCVar g_demoMode;
idCVar com_engineHz( "com_engineHz", "60", CVAR_FLOAT | CVAR_ARCHIVE, "Frames per second the engine runs at", 10.0f, 1024.0f );

View file

@ -438,6 +438,8 @@ void idCommonLocal::ProcessGameReturn( const gameReturn_t& ret )
extern idCVar com_forceGenericSIMD;
extern idCVar com_pause;
/*
=================
idCommonLocal::Frame
@ -485,13 +487,16 @@ void idCommonLocal::Frame()
// if the console or another gui is down, we don't need to hold the mouse cursor
bool chatting = false;
// DG: Add pause from com_pause cvar
// RB begin
#if defined(USE_DOOMCLASSIC)
if( console->Active() || Dialog().IsDialogActive() || session->IsSystemUIShowing() || ( game && game->InhibitControls() && !IsPlayingDoomClassic() ) )
if( console->Active() || Dialog().IsDialogActive() || session->IsSystemUIShowing()
|| ( game && game->InhibitControls() && !IsPlayingDoomClassic() ) )
#else
if( console->Active() || Dialog().IsDialogActive() || session->IsSystemUIShowing() || ( game && game->InhibitControls() ) )
if( com_pause.GetInteger() || console->Active() || Dialog().IsDialogActive() || session->IsSystemUIShowing()
|| ( game && game->InhibitControls() ) )
#endif
// RB end
// RB end, DG end
{
Sys_GrabMouseCursor( false );
usercmdGen->InhibitUsercmd( INHIBIT_SESSION, true );
@ -505,9 +510,16 @@ void idCommonLocal::Frame()
// RB begin
#if defined(USE_DOOMCLASSIC)
const bool pauseGame = ( !mapSpawned || ( !IsMultiplayer() && ( Dialog().IsDialogPausing() || session->IsSystemUIShowing() || ( game && game->Shell_IsActive() ) ) ) ) && !IsPlayingDoomClassic();
const bool pauseGame = ( !mapSpawned
|| ( !IsMultiplayer()
&& ( Dialog().IsDialogPausing() || session->IsSystemUIShowing()
|| ( game && game->Shell_IsActive() ) || com_pause.GetInteger() ) ) )
&& !IsPlayingDoomClassic();
#else
const bool pauseGame = ( !mapSpawned || ( !IsMultiplayer() && ( Dialog().IsDialogPausing() || session->IsSystemUIShowing() || ( game && game->Shell_IsActive() ) ) ) );
const bool pauseGame = ( !mapSpawned
|| ( !IsMultiplayer()
&& ( Dialog().IsDialogPausing() || session->IsSystemUIShowing()
|| ( game && game->Shell_IsActive() ) || com_pause.GetInteger() ) ) );
#endif
// RB end

View file

@ -47,7 +47,7 @@ extern "C" {
//#define HAVE_BZIP2
#ifndef _ZLIB_H
#include "../../libs/zlib/zlib.h"
#include "../zlib.h"
#endif
#ifndef _ZLIBIOAPI_H

View file

@ -53,7 +53,13 @@ idCVar r_skipIntelWorkarounds( "r_skipIntelWorkarounds", "0", CVAR_RENDERER | CV
idCVar r_multiSamples( "r_multiSamples", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "number of antialiasing samples" );
idCVar r_vidMode( "r_vidMode", "0", CVAR_ARCHIVE | CVAR_RENDERER | CVAR_INTEGER, "fullscreen video mode number" );
idCVar r_displayRefresh( "r_displayRefresh", "0", CVAR_RENDERER | CVAR_INTEGER | CVAR_NOCHEAT, "optional display refresh rate option for vid mode", 0.0f, 240.0f );
#ifdef WIN32
idCVar r_fullscreen( "r_fullscreen", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "0 = windowed, 1 = full screen on monitor 1, 2 = full screen on monitor 2, etc" );
#else
// DG: add mode -2 for SDL, also defaulting to windowed mode, as that causes less trouble on linux
idCVar r_fullscreen( "r_fullscreen", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "-2 = use current monitor, -1 = (reserved), 0 = windowed, 1 = full screen on monitor 1, 2 = full screen on monitor 2, etc" );
// DG end
#endif
idCVar r_customWidth( "r_customWidth", "1280", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "custom screen width. set r_vidMode to -1 to activate" );
idCVar r_customHeight( "r_customHeight", "720", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "custom screen height. set r_vidMode to -1 to activate" );
idCVar r_windowX( "r_windowX", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Non-fullscreen parameter" );

View file

@ -42,6 +42,7 @@ If you have questions concerning this license or the applicable additional terms
#include <termios.h>
#include <signal.h>
#include <fcntl.h>
#include <fnmatch.h>
// RB begin
#if defined(__ANDROID__)
@ -358,21 +359,23 @@ int Sys_ListFiles( const char* directory, const char* extension, idStrList& list
list.Clear();
debug = cvarSystem->GetCVarBool( "fs_debug" );
// DG: handle "*" as special case that matches everything
// FIXME: handle * properly as a wildcase somewhere in the string?
if( !extension || ( extension[0] == '*' && extension[1] == '\0' ) )
extension = "";
// DG end
// DG: we use fnmatch for shell-style pattern matching
// so the pattern should at least contain "*" to match everything,
// the extension will be added behind that (if !dironly)
idStr pattern( "*" );
// passing a slash as extension will find directories
if( extension[0] == '/' && extension[1] == 0 )
{
extension = "";
dironly = true;
}
else
{
// so we have *<extension>, the same as in the windows code basically
pattern += extension;
}
// DG end
// search
// NOTE: case sensitivity of directory path can screw us up here
if( ( fdir = opendir( directory ) ) == NULL )
{
@ -399,8 +402,6 @@ int Sys_ListFiles( const char* directory, const char* extension, idStrList& list
return 0;
}
int extLen = idStr::Length( extension );
while( readdir_r( fdir, entry, &d ) == 0 && d != NULL )
{
// DG end
@ -410,14 +411,11 @@ int Sys_ListFiles( const char* directory, const char* extension, idStrList& list
if( !dironly )
{
// DG: the original code didn't work because d3 bfg abuses the extension
// to match whole filenames in the savegame-code, not just file extensions...
// the extension must be the last chars of the filename
// so start matching at startPos = strlen(d->d_name) - strlen(extension)
int startPos = idStr::Length( d->d_name ) - extLen;
// of course the extension can't match if it's longer than the filename, i.e. startPos < 0
if( startPos < 0 || idStr::FindText( d->d_name, extension, true, startPos ) < 0 )
// to match whole filenames and patterns in the savegame-code, not just file extensions...
// so just use fnmatch() which supports matching shell wildcard patterns ("*.foo" etc)
// if we should ever need case insensitivity, use FNM_CASEFOLD as third flag
if( fnmatch( pattern.c_str(), d->d_name, 0 ) != 0 )
continue;
// DG end
}
if( ( dironly && !( st.st_mode & S_IFDIR ) ) ||

View file

@ -456,10 +456,9 @@ idSessionLocalWin::IsSystemUIShowing
*/
bool idSessionLocalWin::IsSystemUIShowing() const
{
// RB: TODO track SDL_ACTIVEENT
// DG: pausing here when window is out of focus like originally done on windows is hacky
// it's done with com_pause now.
return isSysUIShowing;
//return !win32.activeApp || isSysUIShowing; // If the user alt+tabs away, treat it the same as bringing up the steam overlay
}
/*

View file

@ -5,6 +5,7 @@ Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
Copyright (C) 2012 dhewg (dhewm3)
Copyright (C) 2012 Robert Beckebans
Copyright (C) 2013 Daniel Gibson
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
@ -28,9 +29,10 @@ If you have questions concerning this license or the applicable additional terms
===========================================================================
*/
#include "../../idlib/precompiled.h"
#include <SDL.h>
#include "../../idlib/precompiled.h"
#include "renderer/tr_local.h"
#include "sdl_local.h"
#include "../posix/posix_public.h"
@ -58,6 +60,13 @@ If you have questions concerning this license or the applicable additional terms
// DG end
#endif
// DG: those are needed for moving/resizing windows
extern idCVar r_windowX;
extern idCVar r_windowY;
extern idCVar r_windowWidth;
extern idCVar r_windowHeight;
// DG end
const char* kbdNames[] =
{
"english", "french", "german", "italian", "spanish", "turkish", "norwegian", NULL
@ -732,28 +741,55 @@ sysEvent_t Sys_GetEvent()
newmod |= KMOD_CAPS;
SDL_SetModState( ( SDL_Keymod )newmod );
// DG: disabling the cursor is now done once in GLimp_Init() because it should always be disabled
GLimp_GrabInput( GRAB_ENABLE | GRAB_REENABLE );
// DG: un-pause the game when focus is gained, that also re-grabs the input
// disabling the cursor is now done once in GLimp_Init() because it should always be disabled
cvarSystem->SetCVarBool( "com_pause", false );
// DG end
break;
}
case SDL_WINDOWEVENT_FOCUS_LOST:
GLimp_GrabInput( 0 );
// DG: pause the game when focus is lost, that also un-grabs the input
cvarSystem->SetCVarBool( "com_pause", true );
// DG end
break;
// TODO: SDL_WINDOWEVENT_RESIZED
// DG: handle resizing and moving of window
case SDL_WINDOWEVENT_RESIZED:
{
int w = ev.window.data1;
int h = ev.window.data2;
r_windowWidth.SetInteger( w );
r_windowHeight.SetInteger( h );
glConfig.nativeScreenWidth = w;
glConfig.nativeScreenHeight = h;
break;
}
case SDL_WINDOWEVENT_MOVED:
{
int x = ev.window.data1;
int y = ev.window.data2;
r_windowX.SetInteger( x );
r_windowY.SetInteger( y );
break;
}
// DG end
}
return res_none;
#else
case SDL_ACTIVEEVENT:
{
int flags = 0;
// DG: (un-)pause the game when focus is gained, that also (un-)grabs the input
bool pause = true;
if( ev.active.gain )
{
flags = GRAB_ENABLE | GRAB_REENABLE | GRAB_HIDECURSOR;
pause = false;
// unset modifier, in case alt-tab was used to leave window and ALT is still set
// as that can cause fullscreen-toggling when pressing enter...
@ -765,23 +801,58 @@ sysEvent_t Sys_GetEvent()
SDL_SetModState( ( SDLMod )newmod );
}
GLimp_GrabInput( flags );
cvarSystem->SetCVarBool( "com_pause", pause );
}
return res_none;
case SDL_VIDEOEXPOSE:
return res_none;
// DG: handle resizing and moving of window
case SDL_VIDEORESIZE:
{
int w = ev.resize.w;
int h = ev.resize.h;
r_windowWidth.SetInteger( w );
r_windowHeight.SetInteger( h );
glConfig.nativeScreenWidth = w;
glConfig.nativeScreenHeight = h;
// for some reason this needs a vid_restart in SDL1 but not SDL2 so GLimp_SetScreenParms() is called
PushConsoleEvent( "vid_restart" );
return res_none;
}
// DG end
#endif
case SDL_KEYDOWN:
if( ev.key.keysym.sym == SDLK_RETURN && ( ev.key.keysym.mod & KMOD_ALT ) > 0 )
{
cvarSystem->SetCVarBool( "r_fullscreen", !renderSystem->IsFullScreen() );
// DG: go to fullscreen on current display, instead of always first display
int fullscreen = 0;
if( ! renderSystem->IsFullScreen() )
{
// this will be handled as "fullscreen on current window"
// r_fullscreen 1 means "fullscreen on first window" in d3 bfg
fullscreen = -2;
}
cvarSystem->SetCVarInteger( "r_fullscreen", fullscreen );
// DG end
PushConsoleEvent( "vid_restart" );
return res_none;
}
// DG: ctrl-g to un-grab mouse - yeah, left ctrl shoots, then just use right ctrl :)
if( ev.key.keysym.sym == SDLK_g && ( ev.key.keysym.mod & KMOD_CTRL ) > 0 )
{
bool grab = cvarSystem->GetCVarBool( "in_nograb" );
grab = !grab;
cvarSystem->SetCVarBool( "in_nograb", grab );
return res_none;
}
// DG end
// fall through
case SDL_KEYUP:
{

View file

@ -5,6 +5,7 @@ Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
Copyright (C) 2012 dhewg (dhewm3)
Copyright (C) 2012 Robert Beckebans
Copyright (C) 2013 Daniel Gibson
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
@ -54,6 +55,7 @@ static SDL_GLContext context = NULL;
static SDL_Surface* window = NULL;
#define SDL_WINDOW_OPENGL SDL_OPENGL
#define SDL_WINDOW_FULLSCREEN SDL_FULLSCREEN
#define SDL_WINDOW_RESIZABLE SDL_RESIZABLE
#endif
bool QGL_Init( const char* dllname );
@ -89,7 +91,9 @@ bool GLimp_Init( glimpParms_t parms )
GLimp_PreInit(); // DG: make sure SDL is initialized
Uint32 flags = SDL_WINDOW_OPENGL;
// DG: make window resizable
Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
// DG end
if( parms.fullScreen )
flags |= SDL_WINDOW_FULLSCREEN;
@ -198,10 +202,34 @@ bool GLimp_Init( glimpParms_t parms )
}
// RB end
// DG: set display num for fullscreen
int windowPos = SDL_WINDOWPOS_UNDEFINED;
if( parms.fullScreen > 0 )
{
if( parms.fullScreen > SDL_GetNumVideoDisplays() )
{
common->Warning( "Couldn't set display to num %i because we only have %i displays",
parms.fullScreen, SDL_GetNumVideoDisplays() );
}
else
{
// -1 because SDL starts counting displays at 0, while parms.fullScreen starts at 1
windowPos = SDL_WINDOWPOS_UNDEFINED_DISPLAY( ( parms.fullScreen - 1 ) );
}
}
// TODO: if parms.fullScreen == -1 there should be a borderless window spanning multiple displays
/*
* NOTE that this implicitly handles parms.fullScreen == -2 (from r_fullscreen -2) meaning
* "do fullscreen, but I don't care on what monitor", at least on my box it's the monitor with
* the mouse cursor.
*/
window = SDL_CreateWindow( GAME_NAME,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
windowPos,
windowPos,
parms.width, parms.height, flags );
// DG end
context = SDL_GL_CreateContext( window );
if( !window )
@ -273,6 +301,105 @@ bool GLimp_Init( glimpParms_t parms )
return true;
}
/*
===================
Helper functions for GLimp_SetScreenParms()
===================
*/
#if SDL_VERSION_ATLEAST(2, 0, 0)
// SDL1 doesn't support multiple displays, so the source is much shorter and doesn't need seperate functions
// makes sure the window will be full-screened on the right display and returns the SDL display index
static int ScreenParmsHandleDisplayIndex( glimpParms_t parms )
{
int displayIdx;
if( parms.fullScreen > 0 )
{
displayIdx = parms.fullScreen - 1; // first display for SDL is 0, in parms it's 1
}
else // -2 == use current display
{
displayIdx = SDL_GetWindowDisplay( window );
if( displayIdx < 0 ) // for some reason the display for the window couldn't be detected
displayIdx = 0;
}
if( parms.fullScreen > SDL_GetNumVideoDisplays() )
{
common->Warning( "Can't set fullscreen mode to display number %i, because SDL2 only knows about %i displays!",
parms.fullScreen, SDL_GetNumVideoDisplays() );
return -1;
}
if( parms.fullScreen != glConfig.isFullscreen )
{
// we have to switch to another display
if( glConfig.isFullscreen )
{
// if we're already in fullscreen mode but want to switch to another monitor
// we have to go to windowed mode first to move the window.. SDL-oddity.
SDL_SetWindowFullscreen( window, SDL_FALSE );
}
// select display ; SDL_WINDOWPOS_UNDEFINED_DISPLAY() doesn't work.
int x = SDL_WINDOWPOS_CENTERED_DISPLAY( displayIdx );
// move window to the center of selected display
SDL_SetWindowPosition( window, x, x );
}
return displayIdx;
}
static bool SetScreenParmsFullscreen( glimpParms_t parms )
{
SDL_DisplayMode m = {0};
int displayIdx = ScreenParmsHandleDisplayIndex( parms );
if( displayIdx < 0 )
return false;
// get current mode of display the window should be full-screened on
SDL_GetCurrentDisplayMode( displayIdx, &m );
// change settings in that display mode according to parms
// FIXME: check if refreshrate, width and height are supported?
// m.refresh_rate = parms.displayHz;
m.w = parms.width;
m.h = parms.height;
// set that displaymode
if( SDL_SetWindowDisplayMode( window, &m ) < 0 )
{
common->Warning( "Couldn't set window mode for fullscreen, reason: %s", SDL_GetError() );
return false;
}
// if we're currently not in fullscreen mode, we need to switch to fullscreen
if( !( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) )
{
if( SDL_SetWindowFullscreen( window, SDL_TRUE ) < 0 )
{
common->Warning( "Couldn't switch to fullscreen mode, reason: %s!", SDL_GetError() );
return false;
}
}
return true;
}
static bool SetScreenParmsWindowed( glimpParms_t parms )
{
SDL_SetWindowSize( window, parms.width, parms.height );
SDL_SetWindowPosition( window, parms.x, parms.y );
// if we're currently in fullscreen mode, we need to disable that
if( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN )
{
if( SDL_SetWindowFullscreen( window, SDL_FALSE ) < 0 )
{
common->Warning( "Couldn't switch to windowed mode, reason: %s!", SDL_GetError() );
return false;
}
}
return true;
}
#endif // SDL_VERSION_ATLEAST(2, 0, 0)
/*
===================
@ -281,7 +408,63 @@ GLimp_SetScreenParms
*/
bool GLimp_SetScreenParms( glimpParms_t parms )
{
common->DPrintf( "TODO: GLimp_SetScreenParms\n" );
#if SDL_VERSION_ATLEAST(2, 0, 0)
if( parms.fullScreen > 0 || parms.fullScreen == -2 )
{
if( !SetScreenParmsFullscreen( parms ) )
return false;
}
else if( parms.fullScreen == 0 ) // windowed mode
{
if( !SetScreenParmsWindowed( parms ) )
return false;
}
else
{
common->Warning( "GLimp_SetScreenParms: fullScreen -1 (borderless window for multiple displays) currently unsupported!" );
return false;
}
#else // SDL 1.2 - so much shorter, but doesn't handle multiple displays
SDL_Surface* s = SDL_GetVideoSurface();
if( s == NULL )
{
common->Warning( "GLimp_SetScreenParms: Couldn't get video information, reason: %s", SDL_GetError() );
return false;
}
int bitsperpixel = 24;
if( s->format )
bitsperpixel = s->format->BitsPerPixel;
Uint32 flags = s->flags;
if( parms.fullScreen )
flags |= SDL_FULLSCREEN;
else
flags &= ~SDL_FULLSCREEN;
s = SDL_SetVideoMode( parms.width, parms.height, bitsperpixel, flags );
if( s == NULL )
{
common->Warning( "GLimp_SetScreenParms: Couldn't set video information, reason: %s", SDL_GetError() );
return false;
}
#endif // SDL_VERSION_ATLEAST(2, 0, 0)
// Note: the following stuff would also work with SDL1.2
SDL_GL_SetAttribute( SDL_GL_STEREO, parms.stereo ? 1 : 0 );
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, parms.multiSamples ? 1 : 0 );
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, parms.multiSamples );
glConfig.isFullscreen = parms.fullScreen;
glConfig.isStereoPixelFormat = parms.stereo;
glConfig.nativeScreenWidth = parms.width;
glConfig.nativeScreenHeight = parms.height;
glConfig.displayFrequency = parms.displayHz;
glConfig.multisamples = parms.multiSamples;
return true;
}

View file

@ -456,7 +456,9 @@ idSessionLocalWin::IsSystemUIShowing
*/
bool idSessionLocalWin::IsSystemUIShowing() const
{
return !win32.activeApp || isSysUIShowing; // If the user alt+tabs away, treat it the same as bringing up the steam overlay
// DG: wtf, !win32.activeApp doesn't belong here, this is totally confusing and hacky.
// pause (when losing focus or invoking explicitly) is now handled properly by com_pause
return isSysUIShowing;
}
/*

View file

@ -288,6 +288,10 @@ LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
// start playing the game sound world
soundSystem->SetMute( !win32.activeApp );
// DG: set com_pause so game pauses when focus is lost
// and continues when focus is regained
cvarSystem->SetCVarBool( "com_pause", !win32.activeApp );
// DG end
// we do not actually grab or release the mouse here,
// that will be done next time through the main loop