mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-26 14:01:26 +00:00
* Sys_Dialog for more user friendly error reporting
* (bug #3932) Recovery from bad video settings
This commit is contained in:
parent
4876413217
commit
005f870ebe
13 changed files with 564 additions and 120 deletions
14
Makefile
14
Makefile
|
@ -366,6 +366,7 @@ else # ifeq Linux
|
|||
|
||||
ifeq ($(PLATFORM),darwin)
|
||||
HAVE_VM_COMPILED=true
|
||||
LIBS = -framework Cocoa
|
||||
CLIENT_LIBS=
|
||||
OPTIMIZEVM=
|
||||
|
||||
|
@ -422,7 +423,7 @@ ifeq ($(PLATFORM),darwin)
|
|||
# the file has been modified by each build.
|
||||
LIBSDLMAIN=$(B)/libSDLmain.a
|
||||
LIBSDLMAINSRC=$(LIBSDIR)/macosx/libSDLmain.a
|
||||
CLIENT_LIBS += -framework Cocoa -framework IOKit -framework OpenGL \
|
||||
CLIENT_LIBS += -framework IOKit -framework OpenGL \
|
||||
$(LIBSDIR)/macosx/libSDL-1.2.0.dylib
|
||||
|
||||
OPTIMIZEVM += -falign-loops=16
|
||||
|
@ -1557,7 +1558,7 @@ endif
|
|||
|
||||
ifeq ($(PLATFORM),darwin)
|
||||
Q3OBJ += \
|
||||
$(B)/client/sys_cocoa.o
|
||||
$(B)/client/sys_osx.o
|
||||
endif
|
||||
|
||||
ifeq ($(USE_MUMBLE),1)
|
||||
|
@ -1725,11 +1726,10 @@ else
|
|||
$(B)/ded/con_tty.o
|
||||
endif
|
||||
|
||||
# Not currently referenced in the dedicated server.
|
||||
#ifeq ($(PLATFORM),darwin)
|
||||
# Q3DOBJ += \
|
||||
# $(B)/ded/sys_cocoa.o
|
||||
#endif
|
||||
ifeq ($(PLATFORM),darwin)
|
||||
Q3DOBJ += \
|
||||
$(B)/ded/sys_osx.o
|
||||
endif
|
||||
|
||||
$(B)/ioq3ded$(FULLBINEXT): $(Q3DOBJ)
|
||||
$(echo_cmd) "LD $@"
|
||||
|
|
|
@ -3276,14 +3276,14 @@ CL_Shutdown
|
|||
|
||||
===============
|
||||
*/
|
||||
void CL_Shutdown( void ) {
|
||||
void CL_Shutdown( char *finalmsg ) {
|
||||
static qboolean recursive = qfalse;
|
||||
|
||||
// check whether the client is running at all.
|
||||
if(!(com_cl_running && com_cl_running->integer))
|
||||
return;
|
||||
|
||||
Com_Printf( "----- CL_Shutdown -----\n" );
|
||||
Com_Printf( "----- Client Shutdown (%s) -----\n", finalmsg );
|
||||
|
||||
if ( recursive ) {
|
||||
Com_Printf( "WARNING: Recursive shutdown\n" );
|
||||
|
|
|
@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
cvar_t *cl_shownet;
|
||||
|
||||
void CL_Shutdown( void ) {
|
||||
void CL_Shutdown( char *finalmsg ) {
|
||||
}
|
||||
|
||||
void CL_Init( void ) {
|
||||
|
|
|
@ -82,6 +82,7 @@ cvar_t *com_unfocused;
|
|||
cvar_t *com_maxfpsUnfocused;
|
||||
cvar_t *com_minimized;
|
||||
cvar_t *com_maxfpsMinimized;
|
||||
cvar_t *com_abnormalExit;
|
||||
cvar_t *com_standalone;
|
||||
|
||||
// com_speeds times
|
||||
|
@ -237,7 +238,7 @@ void QDECL Com_DPrintf( const char *fmt, ...) {
|
|||
Com_Error
|
||||
|
||||
Both client and server can use this, and it will
|
||||
do the apropriate things.
|
||||
do the appropriate thing.
|
||||
=============
|
||||
*/
|
||||
void QDECL Com_Error( int code, const char *fmt, ... ) {
|
||||
|
@ -322,7 +323,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) {
|
|||
com_errorEntered = qfalse;
|
||||
longjmp (abortframe, -1);
|
||||
} else {
|
||||
CL_Shutdown ();
|
||||
CL_Shutdown (va("Client fatal crashed: %s", com_errorMessage));
|
||||
SV_Shutdown (va("Server fatal crashed: %s", com_errorMessage));
|
||||
}
|
||||
|
||||
|
@ -346,7 +347,7 @@ void Com_Quit_f( void ) {
|
|||
char *p = Cmd_Args( );
|
||||
if ( !com_errorEntered ) {
|
||||
SV_Shutdown (p[0] ? p : "Server quit");
|
||||
CL_Shutdown ();
|
||||
CL_Shutdown (p[0] ? p : "Client quit");
|
||||
Com_Shutdown ();
|
||||
FS_Shutdown(qtrue);
|
||||
}
|
||||
|
@ -2737,6 +2738,7 @@ void Com_Init( char *commandLine ) {
|
|||
com_maxfpsUnfocused = Cvar_Get( "com_maxfpsUnfocused", "0", CVAR_ARCHIVE );
|
||||
com_minimized = Cvar_Get( "com_minimized", "0", CVAR_ROM );
|
||||
com_maxfpsMinimized = Cvar_Get( "com_maxfpsMinimized", "0", CVAR_ARCHIVE );
|
||||
com_abnormalExit = Cvar_Get( "com_abnormalExit", "0", CVAR_ROM );
|
||||
com_standalone = Cvar_Get( "com_standalone", "0", CVAR_INIT );
|
||||
|
||||
com_introPlayed = Cvar_Get( "com_introplayed", "0", CVAR_ARCHIVE);
|
||||
|
@ -2746,6 +2748,18 @@ void Com_Init( char *commandLine ) {
|
|||
|
||||
Sys_Init();
|
||||
|
||||
if( Sys_WritePIDFile( ) ) {
|
||||
#ifndef DEDICATED
|
||||
const char *message = "The last time " CLIENT_WINDOW_TITLE " ran, "
|
||||
"it didn't exit properly. This may be due to inappropriate video "
|
||||
"settings. Would you like to start with \"safe\" video settings?";
|
||||
|
||||
if( Sys_Dialog( DT_YES_NO, message, "Abnormal Exit" ) == DR_YES ) {
|
||||
Cvar_Set( "com_abnormalExit", "1" );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Pick a random port value
|
||||
Com_RandomBytes( (byte*)&qport, sizeof(int) );
|
||||
Netchan_Init( qport & 0xffff );
|
||||
|
|
|
@ -181,7 +181,7 @@ qboolean NET_CompareBaseAdrMask(netadr_t a, netadr_t b, int netmask);
|
|||
qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b);
|
||||
qboolean NET_IsLocalAddress (netadr_t adr);
|
||||
const char *NET_AdrToString (netadr_t a);
|
||||
const char *NET_AdrToStringwPort (netadr_t a);
|
||||
const char *NET_AdrToStringwPort (netadr_t a);
|
||||
int NET_StringToAdr ( const char *s, netadr_t *a, netadrtype_t family);
|
||||
qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, msg_t *net_message);
|
||||
void NET_JoinMulticast6(void);
|
||||
|
@ -937,7 +937,7 @@ void CL_InitKeyCommands( void );
|
|||
|
||||
void CL_Init( void );
|
||||
void CL_Disconnect( qboolean showMainMenu );
|
||||
void CL_Shutdown( void );
|
||||
void CL_Shutdown( char *finalmsg );
|
||||
void CL_Frame( int msec );
|
||||
qboolean CL_GameCommand( void );
|
||||
void CL_KeyEvent (int key, qboolean down, unsigned time);
|
||||
|
@ -1087,6 +1087,7 @@ char *Sys_DefaultAppPath(void);
|
|||
|
||||
void Sys_SetDefaultHomePath(const char *path);
|
||||
char *Sys_DefaultHomePath(void);
|
||||
const char *Sys_TempPath(void);
|
||||
const char *Sys_Dirname( char *path );
|
||||
const char *Sys_Basename( char *path );
|
||||
char *Sys_ConsoleInput(void);
|
||||
|
@ -1099,6 +1100,27 @@ qboolean Sys_LowPhysicalMemory( void );
|
|||
|
||||
void Sys_SetEnv(const char *name, const char *value);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DR_YES = 0,
|
||||
DR_NO = 1,
|
||||
DR_OK = 0,
|
||||
DR_CANCEL = 1
|
||||
} dialogResult_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DT_INFO,
|
||||
DT_WARNING,
|
||||
DT_ERROR,
|
||||
DT_YES_NO,
|
||||
DT_OK_CANCEL
|
||||
} dialogType_t;
|
||||
|
||||
dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title );
|
||||
|
||||
qboolean Sys_WritePIDFile( void );
|
||||
|
||||
/* This is based on the Adaptive Huffman algorithm described in Sayood's Data
|
||||
* Compression book. The ranks are not actually stored, but implicitly defined
|
||||
* by the location of a node within a doubly-linked list */
|
||||
|
|
|
@ -673,6 +673,14 @@ void GLimp_Init( void )
|
|||
r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE );
|
||||
r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE );
|
||||
|
||||
if( Cvar_VariableIntegerValue( "com_abnormalExit" ) )
|
||||
{
|
||||
ri.Cvar_Set( "r_mode", va( "%d", R_MODE_FALLBACK ) );
|
||||
ri.Cvar_Set( "r_fullscreen", "0" );
|
||||
ri.Cvar_Set( "r_centerWindow", "0" );
|
||||
ri.Cvar_Set( "com_abnormalExit", "0" );
|
||||
}
|
||||
|
||||
Sys_SetEnv( "SDL_VIDEO_CENTERED", r_centerWindow->integer ? "1" : "" );
|
||||
|
||||
Sys_GLimpInit( );
|
||||
|
@ -693,7 +701,7 @@ void GLimp_Init( void )
|
|||
ri.Printf( PRINT_ALL, "Setting r_mode %d failed, falling back on r_mode %d\n",
|
||||
r_mode->integer, R_MODE_FALLBACK );
|
||||
|
||||
if(GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, r_fullscreen->integer, qfalse))
|
||||
if(GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, qfalse, qfalse))
|
||||
goto success;
|
||||
}
|
||||
|
||||
|
|
|
@ -900,7 +900,7 @@ static void IN_ProcessEvents( void )
|
|||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
Sys_Quit( );
|
||||
Cbuf_ExecuteText(EXEC_NOW, "quit Closed window\n");
|
||||
break;
|
||||
|
||||
case SDL_VIDEORESIZE:
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code 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; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef MACOS_X
|
||||
#error This file is for Mac OS X only. You probably should not compile it.
|
||||
#endif
|
||||
|
||||
// Please note that this file is just some Mac-specific bits. Most of the
|
||||
// Mac OS X code is shared with other Unix platforms in sys_unix.c ...
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
void Cocoa_MsgBox( const char *text )
|
||||
{
|
||||
NSRunInformationalAlertPanel(@"ioquake3",
|
||||
[NSString stringWithUTF8String:text],
|
||||
@"OK", nil, nil);
|
||||
}
|
||||
|
||||
// end of sys_cocoa.m ...
|
||||
|
|
@ -54,3 +54,6 @@ void Sys_PlatformInit( void );
|
|||
void Sys_SigHandler( int signal );
|
||||
void Sys_ErrorDialog( const char *error );
|
||||
void Sys_AnsiColorPrint( const char *msg );
|
||||
|
||||
int Sys_PID( void );
|
||||
qboolean Sys_PIDIsRunning( int pid );
|
||||
|
|
|
@ -127,6 +127,60 @@ char *Sys_ConsoleInput(void)
|
|||
return CON_Input( );
|
||||
}
|
||||
|
||||
#ifdef DEDICATED
|
||||
# define PID_FILENAME PRODUCT_NAME "_server.pid"
|
||||
#else
|
||||
# define PID_FILENAME PRODUCT_NAME ".pid"
|
||||
#endif
|
||||
|
||||
/*
|
||||
=================
|
||||
Sys_PIDFileName
|
||||
=================
|
||||
*/
|
||||
static char *Sys_PIDFileName( void )
|
||||
{
|
||||
return va( "%s/%s", Sys_TempPath( ), PID_FILENAME );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Sys_WritePIDFile
|
||||
|
||||
Return qtrue if there is an existing stale PID file
|
||||
=================
|
||||
*/
|
||||
qboolean Sys_WritePIDFile( void )
|
||||
{
|
||||
char *pidFile = Sys_PIDFileName( );
|
||||
FILE *f;
|
||||
qboolean stale = qfalse;
|
||||
|
||||
// First, check if the pid file is already there
|
||||
if( ( f = fopen( pidFile, "r" ) ) != NULL )
|
||||
{
|
||||
char pidBuffer[ 64 ] = { 0 };
|
||||
int pid;
|
||||
|
||||
fread( pidBuffer, sizeof( char ), sizeof( pidBuffer ) - 1, f );
|
||||
fclose( f );
|
||||
|
||||
pid = atoi( pidBuffer );
|
||||
if( !Sys_PIDIsRunning( pid ) )
|
||||
stale = qtrue;
|
||||
}
|
||||
|
||||
if( ( f = fopen( pidFile, "w" ) ) != NULL )
|
||||
{
|
||||
fprintf( f, "%d", Sys_PID( ) );
|
||||
fclose( f );
|
||||
}
|
||||
else
|
||||
Com_Printf( S_COLOR_YELLOW "Couldn't write %s.\n", pidFile );
|
||||
|
||||
return stale;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Sys_Exit
|
||||
|
@ -134,7 +188,7 @@ Sys_Exit
|
|||
Single exit point (regular exit or in case of error)
|
||||
=================
|
||||
*/
|
||||
void Sys_Exit( int ex )
|
||||
static void Sys_Exit( int exitCode )
|
||||
{
|
||||
CON_Shutdown( );
|
||||
|
||||
|
@ -142,13 +196,13 @@ void Sys_Exit( int ex )
|
|||
SDL_Quit( );
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
exit( ex );
|
||||
#else
|
||||
// Cause a backtrace on error exits
|
||||
assert( ex == 0 );
|
||||
exit( ex );
|
||||
#endif
|
||||
if( exitCode < 2 )
|
||||
{
|
||||
// Normal exit
|
||||
remove( Sys_PIDFileName( ) );
|
||||
}
|
||||
|
||||
exit( exitCode );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -158,7 +212,6 @@ Sys_Quit
|
|||
*/
|
||||
void Sys_Quit( void )
|
||||
{
|
||||
CL_Shutdown( );
|
||||
Sys_Exit( 0 );
|
||||
}
|
||||
|
||||
|
@ -287,15 +340,14 @@ void Sys_Error( const char *error, ... )
|
|||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
CL_Shutdown ();
|
||||
|
||||
va_start (argptr,error);
|
||||
Q_vsnprintf (string, sizeof(string), error, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
CL_Shutdown( string );
|
||||
Sys_ErrorDialog( string );
|
||||
|
||||
Sys_Exit( 1 );
|
||||
Sys_Exit( 3 );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -450,7 +502,7 @@ void Sys_ParseArgs( int argc, char **argv )
|
|||
#else
|
||||
fprintf( stdout, Q3_VERSION " client (%s)\n", date );
|
||||
#endif
|
||||
Sys_Exit(0);
|
||||
Sys_Exit( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -480,14 +532,16 @@ void Sys_SigHandler( int signal )
|
|||
else
|
||||
{
|
||||
signalcaught = qtrue;
|
||||
fprintf( stderr, "Received signal %d, exiting...\n", signal );
|
||||
#ifndef DEDICATED
|
||||
CL_Shutdown();
|
||||
CL_Shutdown( va( "Received signal %d", signal ) );
|
||||
#endif
|
||||
SV_Shutdown( "Signal caught" );
|
||||
SV_Shutdown( va( "Received signal %d", signal ) );
|
||||
}
|
||||
|
||||
Sys_Exit( 0 ); // Exit with 0 to avoid recursive signals
|
||||
if( signal == SIGTERM || signal == SIGINT )
|
||||
Sys_Exit( 1 );
|
||||
else
|
||||
Sys_Exit( 2 );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -519,7 +573,10 @@ int main( int argc, char **argv )
|
|||
if( SDL_VERSIONNUM( ver->major, ver->minor, ver->patch ) <
|
||||
SDL_VERSIONNUM( MINSDL_MAJOR, MINSDL_MINOR, MINSDL_PATCH ) )
|
||||
{
|
||||
Sys_Print( "SDL version " MINSDL_VERSION " or greater required\n" );
|
||||
Sys_Dialog( DT_ERROR, va( "SDL version " MINSDL_VERSION " or greater is required, "
|
||||
"but only version %d.%d.%d was found. You may be able to obtain a more recent copy "
|
||||
"from http://www.libsdl.org/.", ver->major, ver->minor, ver->patch ), "SDL Library Too Old" );
|
||||
|
||||
Sys_Exit( 1 );
|
||||
}
|
||||
#endif
|
||||
|
|
131
code/sys/sys_osx.m
Normal file
131
code/sys/sys_osx.m
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code 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; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef MACOS_X
|
||||
#error This file is for Mac OS X only. You probably should not compile it.
|
||||
#endif
|
||||
|
||||
// Please note that this file is just some Mac-specific bits. Most of the
|
||||
// Mac OS X code is shared with other Unix platforms in sys_unix.c ...
|
||||
|
||||
#include "../qcommon/q_shared.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "sys_local.h"
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_TempPath
|
||||
================
|
||||
*/
|
||||
const char *Sys_TempPath( void )
|
||||
{
|
||||
static UInt8 posixPath[ MAX_OSPATH ];
|
||||
FSRef ref;
|
||||
if( FSFindFolder( kOnAppropriateDisk,
|
||||
kTemporaryFolderType, kCreateFolder, &ref ) == noErr )
|
||||
{
|
||||
if( FSRefMakePath( &ref, posixPath,
|
||||
sizeof( posixPath ) - 1 ) == noErr )
|
||||
{
|
||||
return (const char *)posixPath;
|
||||
}
|
||||
}
|
||||
|
||||
return "/tmp";
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Sys_Dialog
|
||||
|
||||
Display an OS X dialog box
|
||||
==============
|
||||
*/
|
||||
dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title )
|
||||
{
|
||||
NSAlert* alert = [NSAlert new];
|
||||
|
||||
[alert setMessageText: [NSString stringWithUTF8String: title]];
|
||||
[alert setInformativeText: [NSString stringWithUTF8String: message]];
|
||||
|
||||
if( type == DT_ERROR )
|
||||
[alert setAlertStyle: NSCriticalAlertStyle];
|
||||
else
|
||||
[alert setAlertStyle: NSWarningAlertStyle];
|
||||
|
||||
switch( type )
|
||||
{
|
||||
default:
|
||||
[alert runModal];
|
||||
return DR_OK;
|
||||
|
||||
case DT_YES_NO:
|
||||
[alert addButtonWithTitle: @"Yes"];
|
||||
[alert addButtonWithTitle: @"No"];
|
||||
switch( [alert runModal] )
|
||||
{
|
||||
default:
|
||||
case NSAlertFirstButtonReturn: return DR_YES;
|
||||
case NSAlertSecondButtonReturn: return DR_NO;
|
||||
}
|
||||
|
||||
case DT_OK_CANCEL:
|
||||
[alert addButtonWithTitle: @"OK"];
|
||||
[alert addButtonWithTitle: @"Cancel"];
|
||||
|
||||
switch( [alert runModal] )
|
||||
{
|
||||
default:
|
||||
case NSAlertFirstButtonReturn: return DR_OK;
|
||||
case NSAlertSecondButtonReturn: return DR_CANCEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Sys_StripAppBundle
|
||||
|
||||
Discovers if passed dir is suffixed with the directory structure of a Mac OS X
|
||||
.app bundle. If it is, the .app directory structure is stripped off the end and
|
||||
the result is returned. If not, dir is returned untouched.
|
||||
=================
|
||||
*/
|
||||
char *Sys_StripAppBundle( char *dir )
|
||||
{
|
||||
static char cwd[MAX_OSPATH];
|
||||
|
||||
Q_strncpyz(cwd, dir, sizeof(cwd));
|
||||
if(strcmp(Sys_Basename(cwd), "MacOS"))
|
||||
return dir;
|
||||
Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
|
||||
if(strcmp(Sys_Basename(cwd), "Contents"))
|
||||
return dir;
|
||||
Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
|
||||
if(!strstr(Sys_Basename(cwd), ".app"))
|
||||
return dir;
|
||||
Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
|
||||
return cwd;
|
||||
}
|
|
@ -68,6 +68,23 @@ char *Sys_DefaultHomePath(void)
|
|||
return homePath;
|
||||
}
|
||||
|
||||
#ifndef MACOS_X
|
||||
/*
|
||||
================
|
||||
Sys_TempPath
|
||||
================
|
||||
*/
|
||||
const char *Sys_TempPath( void )
|
||||
{
|
||||
const char *TMPDIR = getenv( "TMPDIR" );
|
||||
|
||||
if( TMPDIR == NULL || TMPDIR[ 0 ] == '\0' )
|
||||
return "/tmp";
|
||||
else
|
||||
return TMPDIR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Milliseconds
|
||||
|
@ -428,35 +445,6 @@ void Sys_FreeFileList( char **list )
|
|||
Z_Free( list );
|
||||
}
|
||||
|
||||
#ifdef MACOS_X
|
||||
/*
|
||||
=================
|
||||
Sys_StripAppBundle
|
||||
|
||||
Discovers if passed dir is suffixed with the directory structure of a Mac OS X
|
||||
.app bundle. If it is, the .app directory structure is stripped off the end and
|
||||
the result is returned. If not, dir is returned untouched.
|
||||
=================
|
||||
*/
|
||||
char *Sys_StripAppBundle( char *dir )
|
||||
{
|
||||
static char cwd[MAX_OSPATH];
|
||||
|
||||
Q_strncpyz(cwd, dir, sizeof(cwd));
|
||||
if(strcmp(Sys_Basename(cwd), "MacOS"))
|
||||
return dir;
|
||||
Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
|
||||
if(strcmp(Sys_Basename(cwd), "Contents"))
|
||||
return dir;
|
||||
Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
|
||||
if(!strstr(Sys_Basename(cwd), ".app"))
|
||||
return dir;
|
||||
Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
|
||||
return cwd;
|
||||
}
|
||||
#endif // MACOS_X
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_Sleep
|
||||
|
@ -517,40 +505,196 @@ void Sys_ErrorDialog( const char *error )
|
|||
|
||||
Sys_Print( va( "%s\n", error ) );
|
||||
|
||||
#if defined(MACOS_X) && !DEDICATED
|
||||
/* This function has to be in a separate file, compiled as Objective-C. */
|
||||
extern void Cocoa_MsgBox( const char *text );
|
||||
if (!com_dedicated || !com_dedicated->integer)
|
||||
Cocoa_MsgBox(error);
|
||||
#ifndef DEDICATED
|
||||
Sys_Dialog( DT_ERROR, va( "%s. See \"%s\" for details.", error, ospath ), "Error" );
|
||||
#endif
|
||||
|
||||
/* make sure the write path for the crashlog exists... */
|
||||
// Make sure the write path for the crashlog exists...
|
||||
if( FS_CreatePath( ospath ) ) {
|
||||
Com_Printf( "ERROR: couldn't create path '%s' for crash log.\n", ospath );
|
||||
return;
|
||||
}
|
||||
|
||||
/* we might be crashing because we maxed out the Quake MAX_FILE_HANDLES,
|
||||
which will come through here, so we don't want to recurse forever by
|
||||
calling FS_FOpenFileWrite()...use the Unix system APIs instead. */
|
||||
f = open(ospath, O_CREAT | O_TRUNC | O_WRONLY, 0640);
|
||||
// We might be crashing because we maxed out the Quake MAX_FILE_HANDLES,
|
||||
// which will come through here, so we don't want to recurse forever by
|
||||
// calling FS_FOpenFileWrite()...use the Unix system APIs instead.
|
||||
f = open( ospath, O_CREAT | O_TRUNC | O_WRONLY, 0640 );
|
||||
if( f == -1 )
|
||||
{
|
||||
Com_Printf( "ERROR: couldn't open %s\n", fileName );
|
||||
return;
|
||||
}
|
||||
|
||||
/* We're crashing, so we don't care much if write() or close() fails. */
|
||||
// We're crashing, so we don't care much if write() or close() fails.
|
||||
while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 ) {
|
||||
if (write( f, buffer, size ) != size) {
|
||||
if( write( f, buffer, size ) != size ) {
|
||||
Com_Printf( "ERROR: couldn't fully write to %s\n", fileName );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(f);
|
||||
close( f );
|
||||
}
|
||||
|
||||
#ifndef MACOS_X
|
||||
/*
|
||||
==============
|
||||
Sys_ZenityCommand
|
||||
==============
|
||||
*/
|
||||
static int Sys_ZenityCommand( dialogType_t type, const char *message, const char *title )
|
||||
{
|
||||
const char *options = "";
|
||||
char command[ 1024 ];
|
||||
|
||||
switch( type )
|
||||
{
|
||||
default:
|
||||
case DT_INFO: options = "--info"; break;
|
||||
case DT_WARNING: options = "--warning"; break;
|
||||
case DT_ERROR: options = "--error"; break;
|
||||
case DT_YES_NO: options = "--question --ok-label=\"Yes\" --cancel-label=\"No\""; break;
|
||||
case DT_OK_CANCEL: options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\""; break;
|
||||
}
|
||||
|
||||
Com_sprintf( command, sizeof( command ), "zenity %s --text=\"%s\" --title=\"%s\"",
|
||||
options, message, title );
|
||||
|
||||
return system( command );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Sys_KdialogCommand
|
||||
==============
|
||||
*/
|
||||
static int Sys_KdialogCommand( dialogType_t type, const char *message, const char *title )
|
||||
{
|
||||
const char *options = "";
|
||||
char command[ 1024 ];
|
||||
|
||||
switch( type )
|
||||
{
|
||||
default:
|
||||
case DT_INFO: options = "--msgbox"; break;
|
||||
case DT_WARNING: options = "--sorry"; break;
|
||||
case DT_ERROR: options = "--error"; break;
|
||||
case DT_YES_NO: options = "--warningyesno"; break;
|
||||
case DT_OK_CANCEL: options = "--warningcontinuecancel"; break;
|
||||
}
|
||||
|
||||
Com_sprintf( command, sizeof( command ), "kdialog %s \"%s\" --title \"%s\"",
|
||||
options, message, title );
|
||||
|
||||
return system( command );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Sys_XmessageCommand
|
||||
==============
|
||||
*/
|
||||
static int Sys_XmessageCommand( dialogType_t type, const char *message, const char *title )
|
||||
{
|
||||
const char *options = "";
|
||||
char command[ 1024 ];
|
||||
|
||||
switch( type )
|
||||
{
|
||||
default: options = "-buttons OK"; break;
|
||||
case DT_YES_NO: options = "-buttons Yes:0,No:1"; break;
|
||||
case DT_OK_CANCEL: options = "-buttons OK:0,Cancel:1"; break;
|
||||
}
|
||||
|
||||
Com_sprintf( command, sizeof( command ), "xmessage -center %s \"%s\"",
|
||||
options, message );
|
||||
|
||||
return system( command );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Sys_Dialog
|
||||
|
||||
Display a *nix dialog box
|
||||
==============
|
||||
*/
|
||||
dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title )
|
||||
{
|
||||
typedef enum
|
||||
{
|
||||
NONE = 0,
|
||||
ZENITY,
|
||||
KDIALOG,
|
||||
XMESSAGE,
|
||||
NUM_DIALOG_PROGRAMS
|
||||
} dialogCommandType_t;
|
||||
typedef int (*dialogCommandBuilder_t)( dialogType_t, const char *, const char * );
|
||||
|
||||
const char *session = getenv( "DESKTOP_SESSION" );
|
||||
qboolean tried[ NUM_DIALOG_PROGRAMS ] = { qfalse };
|
||||
dialogCommandBuilder_t commands[ NUM_DIALOG_PROGRAMS ] = { NULL };
|
||||
dialogCommandType_t preferredCommandType = NONE;
|
||||
|
||||
commands[ ZENITY ] = &Sys_ZenityCommand;
|
||||
commands[ KDIALOG ] = &Sys_KdialogCommand;
|
||||
commands[ XMESSAGE ] = &Sys_XmessageCommand;
|
||||
|
||||
// This may not be the best way
|
||||
if( !Q_stricmp( session, "gnome" ) )
|
||||
preferredCommandType = ZENITY;
|
||||
else if( !Q_stricmp( session, "kde" ) )
|
||||
preferredCommandType = KDIALOG;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
int i;
|
||||
int exitCode;
|
||||
|
||||
for( i = NONE + 1; i < NUM_DIALOG_PROGRAMS; i++ )
|
||||
{
|
||||
if( preferredCommandType != NONE && preferredCommandType != i )
|
||||
continue;
|
||||
|
||||
if( !tried[ i ] )
|
||||
{
|
||||
exitCode = commands[ i ]( type, message, title );
|
||||
|
||||
if( exitCode >= 0 )
|
||||
{
|
||||
switch( type )
|
||||
{
|
||||
case DT_YES_NO: return exitCode ? DR_NO : DR_YES;
|
||||
case DT_OK_CANCEL: return exitCode ? DR_CANCEL : DR_OK;
|
||||
default: return DR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
tried[ i ] = qtrue;
|
||||
|
||||
// The preference failed, so start again in order
|
||||
if( preferredCommandType != NONE )
|
||||
{
|
||||
preferredCommandType = NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( i = NONE + 1; i < NUM_DIALOG_PROGRAMS; i++ )
|
||||
{
|
||||
if( !tried[ i ] )
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Com_DPrintf( S_COLOR_YELLOW "WARNING: failed to show a dialog\n" );
|
||||
return DR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
==============
|
||||
Sys_GLimpSafeInit
|
||||
|
@ -611,3 +755,23 @@ void Sys_SetEnv(const char *name, const char *value)
|
|||
else
|
||||
unsetenv(name);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Sys_PID
|
||||
==============
|
||||
*/
|
||||
int Sys_PID( void )
|
||||
{
|
||||
return getpid( );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Sys_PIDIsRunning
|
||||
==============
|
||||
*/
|
||||
qboolean Sys_PIDIsRunning( int pid )
|
||||
{
|
||||
return kill( pid, 0 ) == 0;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include <conio.h>
|
||||
#include <wincrypt.h>
|
||||
#include <shlobj.h>
|
||||
#include <psapi.h>
|
||||
|
||||
// Used to determine where to store user-specific files
|
||||
static char homePath[ MAX_OSPATH ] = { 0 };
|
||||
|
@ -82,6 +83,24 @@ char *Sys_DefaultHomePath( void )
|
|||
return homePath;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_TempPath
|
||||
================
|
||||
*/
|
||||
const char *Sys_TempPath( void )
|
||||
{
|
||||
static TCHAR path[ MAX_PATH ];
|
||||
DWORD length;
|
||||
|
||||
length = GetTempPath( sizeof( path ), path );
|
||||
|
||||
if( length > sizeof( path ) || length == 0 )
|
||||
return Sys_DefaultHomePath( );
|
||||
else
|
||||
return path;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Milliseconds
|
||||
|
@ -543,8 +562,8 @@ Display an error message
|
|||
*/
|
||||
void Sys_ErrorDialog( const char *error )
|
||||
{
|
||||
if( MessageBox( NULL, va( "%s. Copy console log to clipboard?", error ),
|
||||
NULL, MB_YESNO|MB_ICONERROR ) == IDYES )
|
||||
if( Sys_Dialog( DT_YES_NO, va( "%s. Copy console log to clipboard?", error ),
|
||||
"Error" ) == DR_YES )
|
||||
{
|
||||
HGLOBAL memoryHandle;
|
||||
char *clipMemory;
|
||||
|
@ -575,6 +594,37 @@ void Sys_ErrorDialog( const char *error )
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Sys_Dialog
|
||||
|
||||
Display a win32 dialog box
|
||||
==============
|
||||
*/
|
||||
dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title )
|
||||
{
|
||||
UINT uType;
|
||||
|
||||
switch( type )
|
||||
{
|
||||
default:
|
||||
case DT_INFO: uType = MB_ICONINFORMATION|MB_OK; break;
|
||||
case DT_WARNING: uType = MB_ICONWARNING|MB_OK; break;
|
||||
case DT_ERROR: uType = MB_ICONERROR|MB_OK; break;
|
||||
case DT_YES_NO: uType = MB_ICONQUESTION|MB_YESNO; break;
|
||||
case DT_OK_CANCEL: uType = MB_ICONWARNING|MB_OKCANCEL; break;
|
||||
}
|
||||
|
||||
switch( MessageBox( NULL, message, title, uType ) )
|
||||
{
|
||||
default:
|
||||
case IDOK: return DR_OK;
|
||||
case IDCANCEL: return DR_CANCEL;
|
||||
case IDYES: return DR_YES;
|
||||
case IDNO: return DR_NO;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DEDICATED
|
||||
static qboolean SDL_VIDEODRIVER_externallySet = qfalse;
|
||||
#endif
|
||||
|
@ -658,8 +708,43 @@ Sys_SetEnv
|
|||
set/unset environment variables (empty value removes it)
|
||||
==============
|
||||
*/
|
||||
|
||||
void Sys_SetEnv(const char *name, const char *value)
|
||||
{
|
||||
_putenv(va("%s=%s", name, value));
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Sys_PID
|
||||
==============
|
||||
*/
|
||||
int Sys_PID( void )
|
||||
{
|
||||
return GetCurrentProcessId( );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Sys_PIDIsRunning
|
||||
==============
|
||||
*/
|
||||
qboolean Sys_PIDIsRunning( int pid )
|
||||
{
|
||||
DWORD processes[ 1024 ];
|
||||
DWORD numBytes, numProcesses;
|
||||
int i;
|
||||
|
||||
if( !EnumProcesses( processes, sizeof( processes ), &numBytes ) )
|
||||
return qfalse; // Assume it's not running
|
||||
|
||||
numProcesses = numBytes / sizeof( DWORD );
|
||||
|
||||
// Search for the pid
|
||||
for( i = 0; i < numProcesses; i++ )
|
||||
{
|
||||
if( processes[ i ] == pid )
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue