[quake3-commits] r1773 - in trunk: . code/client code/null code/qcommon code/sdl code/sys

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Mon Feb 15 11:20:33 EST 2010


Author: tma
Date: 2010-02-15 11:20:33 -0500 (Mon, 15 Feb 2010)
New Revision: 1773

Added:
   trunk/code/sys/sys_osx.m
Removed:
   trunk/code/sys/sys_cocoa.m
Modified:
   trunk/Makefile
   trunk/code/client/cl_main.c
   trunk/code/null/null_client.c
   trunk/code/qcommon/common.c
   trunk/code/qcommon/qcommon.h
   trunk/code/sdl/sdl_glimp.c
   trunk/code/sdl/sdl_input.c
   trunk/code/sys/sys_local.h
   trunk/code/sys/sys_main.c
   trunk/code/sys/sys_unix.c
   trunk/code/sys/sys_win32.c
Log:
* Sys_Dialog for more user friendly error reporting
* (bug #3932) Recovery from bad video settings

Modified: trunk/Makefile
===================================================================
--- trunk/Makefile	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/Makefile	2010-02-15 16:20:33 UTC (rev 1773)
@@ -366,6 +366,7 @@
 
 ifeq ($(PLATFORM),darwin)
   HAVE_VM_COMPILED=true
+  LIBS = -framework Cocoa
   CLIENT_LIBS=
   OPTIMIZEVM=
   
@@ -422,7 +423,7 @@
   #  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 @@
 
 ifeq ($(PLATFORM),darwin)
   Q3OBJ += \
-    $(B)/client/sys_cocoa.o
+    $(B)/client/sys_osx.o
 endif
 
 ifeq ($(USE_MUMBLE),1)
@@ -1725,11 +1726,10 @@
     $(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 $@"

Modified: trunk/code/client/cl_main.c
===================================================================
--- trunk/code/client/cl_main.c	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/client/cl_main.c	2010-02-15 16:20:33 UTC (rev 1773)
@@ -3276,14 +3276,14 @@
 
 ===============
 */
-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" );

Modified: trunk/code/null/null_client.c
===================================================================
--- trunk/code/null/null_client.c	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/null/null_client.c	2010-02-15 16:20:33 UTC (rev 1773)
@@ -25,7 +25,7 @@
 
 cvar_t *cl_shownet;
 
-void CL_Shutdown( void ) {
+void CL_Shutdown( char *finalmsg ) {
 }
 
 void CL_Init( void ) {

Modified: trunk/code/qcommon/common.c
===================================================================
--- trunk/code/qcommon/common.c	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/qcommon/common.c	2010-02-15 16:20:33 UTC (rev 1773)
@@ -82,6 +82,7 @@
 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 @@
 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 @@
 		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 @@
 	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 @@
 	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 @@
 
 	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 );

Modified: trunk/code/qcommon/qcommon.h
===================================================================
--- trunk/code/qcommon/qcommon.h	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/qcommon/qcommon.h	2010-02-15 16:20:33 UTC (rev 1773)
@@ -181,7 +181,7 @@
 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_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 @@
 
 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 @@
 
 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 */

Modified: trunk/code/sdl/sdl_glimp.c
===================================================================
--- trunk/code/sdl/sdl_glimp.c	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/sdl/sdl_glimp.c	2010-02-15 16:20:33 UTC (rev 1773)
@@ -673,6 +673,14 @@
 	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 @@
 		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;
 	}
 

Modified: trunk/code/sdl/sdl_input.c
===================================================================
--- trunk/code/sdl/sdl_input.c	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/sdl/sdl_input.c	2010-02-15 16:20:33 UTC (rev 1773)
@@ -900,7 +900,7 @@
 				break;
 
 			case SDL_QUIT:
-				Sys_Quit( );
+				Cbuf_ExecuteText(EXEC_NOW, "quit Closed window\n");
 				break;
 
 			case SDL_VIDEORESIZE:

Deleted: trunk/code/sys/sys_cocoa.m
===================================================================
--- trunk/code/sys/sys_cocoa.m	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/sys/sys_cocoa.m	2010-02-15 16:20:33 UTC (rev 1773)
@@ -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 ...
-

Modified: trunk/code/sys/sys_local.h
===================================================================
--- trunk/code/sys/sys_local.h	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/sys/sys_local.h	2010-02-15 16:20:33 UTC (rev 1773)
@@ -54,3 +54,6 @@
 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 );

Modified: trunk/code/sys/sys_main.c
===================================================================
--- trunk/code/sys/sys_main.c	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/sys/sys_main.c	2010-02-15 16:20:33 UTC (rev 1773)
@@ -127,14 +127,68 @@
 	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
 
 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 @@
 	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 @@
 */
 void Sys_Quit( void )
 {
-	CL_Shutdown( );
 	Sys_Exit( 0 );
 }
 
@@ -287,15 +340,14 @@
 	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 @@
 #else
 			fprintf( stdout, Q3_VERSION " client (%s)\n", date );
 #endif
-			Sys_Exit(0);
+			Sys_Exit( 0 );
 		}
 	}
 }
@@ -480,14 +532,16 @@
 	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 @@
 	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

Copied: trunk/code/sys/sys_osx.m (from rev 1772, trunk/code/sys/sys_cocoa.m)
===================================================================
--- trunk/code/sys/sys_osx.m	                        (rev 0)
+++ trunk/code/sys/sys_osx.m	2010-02-15 16:20:33 UTC (rev 1773)
@@ -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;
+}

Modified: trunk/code/sys/sys_unix.c
===================================================================
--- trunk/code/sys/sys_unix.c	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/sys/sys_unix.c	2010-02-15 16:20:33 UTC (rev 1773)
@@ -68,8 +68,25 @@
 	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,36 +445,7 @@
 	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,42 +505,198 @@
 
 	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
 
 Unix specific "safe" GL implementation initialisation
@@ -611,3 +755,23 @@
 	else
 		unsetenv(name);
 }
+
+/*
+==============
+Sys_PID
+==============
+*/
+int Sys_PID( void )
+{
+	return getpid( );
+}
+
+/*
+==============
+Sys_PIDIsRunning
+==============
+*/
+qboolean Sys_PIDIsRunning( int pid )
+{
+	return kill( pid, 0 ) == 0;
+}

Modified: trunk/code/sys/sys_win32.c
===================================================================
--- trunk/code/sys/sys_win32.c	2010-01-16 10:55:51 UTC (rev 1772)
+++ trunk/code/sys/sys_win32.c	2010-02-15 16:20:33 UTC (rev 1773)
@@ -36,6 +36,7 @@
 #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 };
@@ -84,6 +85,24 @@
 
 /*
 ================
+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 @@
 */
 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 @@
 	}
 }
 
+/*
+==============
+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 @@
 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;
+}



More information about the quake3-commits mailing list