Index: code/unix/sdl_glimp.c =================================================================== --- code/unix/sdl_glimp.c (revision 1048) +++ code/unix/sdl_glimp.c (working copy) @@ -115,6 +115,8 @@ static qboolean mouse_active = qfalse; static qboolean sdlrepeatenabled = qfalse; +static qboolean fullscreen_minimized = qfalse; + static cvar_t *in_mouse; cvar_t *in_subframe; cvar_t *in_nograb; // this is strictly for developers @@ -368,6 +370,21 @@ { switch (e.type) { + + case SDL_ACTIVEEVENT: + if( ( e.active.state & SDL_APPACTIVE ) && e.active.gain ) + { + if( fullscreen_minimized ) + { +#ifdef MACOS_X + Cvar_Set( "r_fullscreen", "1" ); +#endif + fullscreen_minimized = qfalse; + } + install_grabs(); + } + break; + case SDL_KEYDOWN: printkey(&e); p = XLateKey(&e.key.keysym, &key); @@ -1114,6 +1131,41 @@ SDL_GL_SwapBuffers(); } + if( r_minimize && r_minimize->integer ) + { + SDL_Surface *s = SDL_GetVideoSurface( ); + qboolean fullscreen = qfalse; + qboolean minimized = qfalse; + + fullscreen = ( s && ( s->flags & SDL_FULLSCREEN ) ); + +#ifdef MACOS_X + // this is a bit crap, but the mac SDL_WM_IconifyWindow does not work + // on fullscreen windows, nor does the SDL_WM_ToggleFullscreen work + if( !fullscreen ) + { + if( SDL_WM_IconifyWindow( ) ) + uninstall_grabs(); + Cvar_Set( "r_minimize", "0" ); + } + else if( r_fullscreen->integer ) + { + Cvar_Set( "r_fullscreen", "0" ); + fullscreen_minimized = qtrue; + } +#else + minimized = ( SDL_WM_IconifyWindow( ) != 0 ); + if( fullscreen && minimized ) + fullscreen_minimized = qtrue; + + // this shouldn't be necessary, but seems to prevent X11 mouse problems + if( minimized ) + uninstall_grabs(); + + Cvar_Set( "r_minimize", "0" ); +#endif // MACOS_X + } + if( r_fullscreen->modified ) { qboolean fullscreen; Index: code/win32/win_gamma.c =================================================================== --- code/win32/win_gamma.c (revision 1048) +++ code/win32/win_gamma.c (working copy) @@ -140,6 +140,9 @@ return; } + if (!g_wv.activeApp) + return; + //mapGammaMax(); for ( i = 0; i < 256; i++ ) { Index: code/win32/win_glimp.c =================================================================== --- code/win32/win_glimp.c (revision 1048) +++ code/win32/win_glimp.c (working copy) @@ -43,6 +43,7 @@ extern void WG_CheckHardwareGamma( void ); extern void WG_RestoreGamma( void ); +extern void R_SetColorMappings( void ); typedef enum { RSERR_OK, @@ -76,6 +77,7 @@ // variable declarations // glwstate_t glw_state; +static DEVMODE glw_fs_dm; cvar_t *r_allowSoftwareGL; // don't abort out if the pixelformat claims software cvar_t *r_maskMinidriver; // allow a different dll name to be treated as if it were opengl32.dll @@ -108,6 +110,27 @@ return qtrue; } + +qboolean GLW_ResetDesktopMode( void ) +{ + WG_RestoreGamma(); + ChangeDisplaySettings( 0, 0 ); + return qtrue; +} + + +qboolean GLW_ResetFullScreenMode( void ) +{ + if( !glw_fs_dm.dmSize ) + return qfalse; + + // restore the last working fullscreen DEVMODE + ChangeDisplaySettings( &glw_fs_dm, CDS_FULLSCREEN ); + + R_SetColorMappings(); + return qtrue; +} + /* ** ChoosePFD ** @@ -580,6 +603,9 @@ int x, y, w, h; int exstyle; + // fullscreen DEVMODE for use with win_allowAltTab + memset( &glw_fs_dm, 0, sizeof( glw_fs_dm ) ); + // // register the window class if necessary // @@ -629,7 +655,7 @@ else { exstyle = 0; - stylebits = WINDOW_STYLE|WS_SYSMENU; + stylebits = WINDOW_STYLE|WS_SYSMENU|WS_MINIMIZEBOX; AdjustWindowRect (&r, stylebits, FALSE); } @@ -922,6 +948,10 @@ } } } + if( glw_state.cdsFullscreen ) + memcpy( &glw_fs_dm, &dm, sizeof( glw_fs_dm ) ); + else + memset( &glw_fs_dm, 0, sizeof( glw_fs_dm ) ); } else { @@ -1266,6 +1296,11 @@ */ void GLimp_EndFrame (void) { + if( r_minimize && r_minimize->integer ) { + ri.Cvar_Set( "r_minimize", "0" ); + ShowWindow( g_wv.hWnd, SW_MINIMIZE ); + } + // // swapinterval stuff // Index: code/win32/win_wndproc.c =================================================================== --- code/win32/win_wndproc.c (revision 1048) +++ code/win32/win_wndproc.c (working copy) @@ -35,6 +35,7 @@ cvar_t *vid_xpos; // X coordinate of window position cvar_t *vid_ypos; // Y coordinate of window position cvar_t *r_fullscreen; +cvar_t *win_fastModeChange; #define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) ) @@ -49,7 +50,7 @@ if ( !Q_stricmp( Cvar_VariableString( "arch" ), "winnt" ) ) { - RegisterHotKey( 0, 0, MOD_ALT, VK_TAB ); + RegisterHotKey( g_wv.hWnd, 0, MOD_ALT, VK_TAB ); } else { @@ -66,7 +67,7 @@ { if ( !Q_stricmp( Cvar_VariableString( "arch" ), "winnt" ) ) { - UnregisterHotKey( 0, 0 ); + UnregisterHotKey( g_wv.hWnd, 0 ); } else { @@ -84,8 +85,13 @@ VID_AppActivate ================== */ +extern qboolean GLW_ResetFullScreenMode( void ); +extern qboolean GLW_ResetDesktopMode( void ); + static void VID_AppActivate(BOOL fActive, BOOL minimize) { + BOOL wasMinimized = g_wv.isMinimized; + g_wv.isMinimized = minimize; Com_DPrintf("VID_AppActivate: %i\n", fActive ); @@ -106,10 +112,25 @@ if (!g_wv.activeApp ) { IN_Activate (qfalse); + if ( r_fullscreen->integer ) + { + ShowWindow ( g_wv.hWnd, SW_MINIMIZE ); + GLW_ResetDesktopMode(); + WIN_EnableAltTab(); + } } else { IN_Activate (qtrue); + if ( r_fullscreen->integer && wasMinimized ) + { + WIN_DisableAltTab(); + if( !win_fastModeChange->integer || + !GLW_ResetFullScreenMode() ) + { + Cbuf_AddText( "vid_restart\n" ); + } + } } } @@ -311,8 +332,8 @@ vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE); vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE); - r_fullscreen = Cvar_Get ("r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH ); - + r_fullscreen = Cvar_Get ("r_fullscreen", "1", CVAR_ARCHIVE ); + win_fastModeChange = Cvar_Get( "win_fastModeChange", "0", CVAR_ARCHIVE ); MSH_MOUSEWHEEL = RegisterWindowMessage("MSWHEEL_ROLLMSG"); if ( r_fullscreen->integer ) { @@ -426,6 +447,16 @@ return 0; break; + case WM_HOTKEY: + // RegisterHotKey 0 is for Alt-Tab, pass tab along + if( wParam == 0 ) + { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, VK_TAB, + qtrue, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, VK_TAB, + qfalse, 0, NULL ); + } + break; case WM_SYSKEYDOWN: if ( wParam == 13 ) { Index: code/renderer/tr_local.h =================================================================== --- code/renderer/tr_local.h (revision 1048) +++ code/renderer/tr_local.h (working copy) @@ -1035,6 +1035,7 @@ extern cvar_t *r_mode; // video mode extern cvar_t *r_fullscreen; +extern cvar_t *r_minimize; extern cvar_t *r_gamma; extern cvar_t *r_displayRefresh; // optional display refresh option extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities Index: code/renderer/tr_init.c =================================================================== --- code/renderer/tr_init.c (revision 1048) +++ code/renderer/tr_init.c (working copy) @@ -129,6 +129,7 @@ cvar_t *r_lodCurveError; cvar_t *r_fullscreen; +cvar_t *r_minimize; cvar_t *r_customwidth; cvar_t *r_customheight; @@ -943,6 +944,7 @@ #else r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH ); #endif + r_minimize = ri.Cvar_Get( "r_minimize", "0", 0 ); r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH ); r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH ); r_customPixelAspect = ri.Cvar_Get( "r_customPixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH ); Index: code/client/client.h =================================================================== --- code/client/client.h (revision 1048) +++ code/client/client.h (working copy) @@ -373,6 +373,8 @@ extern cvar_t *cl_lanForcePackets; extern cvar_t *cl_autoRecordDemo; +extern cvar_t *cl_altTab; + //================================================= // Index: code/client/cl_main.c =================================================================== --- code/client/cl_main.c (revision 1048) +++ code/client/cl_main.c (working copy) @@ -76,6 +76,8 @@ cvar_t *cl_guidServerUniq; +cvar_t *cl_altTab; + clientActive_t cl; clientConnection_t clc; clientStatic_t cls; @@ -2648,6 +2650,8 @@ cl_lanForcePackets = Cvar_Get ("cl_lanForcePackets", "1", CVAR_ARCHIVE); cl_guidServerUniq = Cvar_Get ("cl_guidServerUniq", "1", CVAR_ARCHIVE); + + cl_altTab = Cvar_Get ("cl_altTab", "1", CVAR_ARCHIVE); // userinfo Cvar_Get ("name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE ); Index: code/client/cl_keys.c =================================================================== --- code/client/cl_keys.c (revision 1048) +++ code/client/cl_keys.c (working copy) @@ -1178,6 +1178,14 @@ } #endif + if( cl_altTab->integer && key == K_TAB && down && keys[K_ALT].down ) + { + Key_ClearStates(); + Cvar_SetValue( "r_minimize", 1 ); + return; + } + + // console key is hardcoded, so the user can never unbind it if (key == '`' || key == '~' || ( key == K_ESCAPE && keys[K_SHIFT].down ) ) { Index: README =================================================================== --- README (revision 1048) +++ README (working copy) @@ -27,6 +27,7 @@ * HTTP/FTP download redirection (using cURL) * Multiuser support on Windows systems (user specific game data is stored in "%APPDATA%\Quake3") + * Fullscreen Alt-Tab support * Many, many bug fixes The map editor and associated compiling tools are not included. We suggest you @@ -154,6 +155,14 @@ cl_cURLLib - filename of cURL library to load sv_dlURL - the base of the HTTP or FTP site that holds custom pk3 files for your server + r_minimize - when set to non-0, ioq3 will be minimized + then the value will be reset to 0 + cl_altTab - Alt-Tab key combo will minimize when in + fullscreen mode + win_fastModeChange - when set to non-0 a vid_restart will + not be forced when switching display + resolution (e.g. Alt-Tab). This may + cause texture corruption on some drivers. New commands video [filename] - start video capture (use with demo command)