2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #if defined (__linux__) || defined (__APPLE__)
37 #include <glib/gi18n.h>
40 #include <sys/types.h>
48 bool g_bBuildList = false;
52 // =============================================================================
55 // get rid of it when debugging
60 static GtkWidget *splash_screen;
62 // called based on a timer, or in particular cases when we don't want to keep it around
63 gint try_destroy_splash (gpointer data)
67 gtk_widget_destroy (splash_screen);
73 static void create_splash ()
75 GtkWidget *alert_frame, *alert_frame1, *pixmap;
77 splash_screen = gtk_window_new (GTK_WINDOW_POPUP);
78 gtk_window_position (GTK_WINDOW (splash_screen), GTK_WIN_POS_CENTER);
79 gtk_widget_realize (splash_screen);
81 alert_frame1 = gtk_frame_new (NULL);
82 gtk_widget_show (alert_frame1);
83 gtk_container_add (GTK_CONTAINER (splash_screen), alert_frame1);
84 gtk_frame_set_shadow_type (GTK_FRAME (alert_frame1), GTK_SHADOW_OUT);
86 alert_frame = gtk_frame_new (NULL);
87 gtk_widget_show (alert_frame);
89 gtk_container_add (GTK_CONTAINER (alert_frame1), alert_frame);
90 gtk_frame_set_shadow_type (GTK_FRAME (alert_frame), GTK_SHADOW_IN);
91 gtk_container_border_width (GTK_CONTAINER (alert_frame), 3);
93 pixmap = gtk_preview_new (GTK_PREVIEW_COLOR);
94 gtk_widget_show (pixmap);
95 gtk_container_add (GTK_CONTAINER (alert_frame), pixmap);
98 guint16 width, height;
101 str = g_strGameToolsPath;
102 str += "bitmaps/splash.bmp";
104 unsigned char* load_bitmap_file (const char* filename, guint16* width, guint16* height);
105 buf = load_bitmap_file (str.GetBuffer (), &width, &height);
109 str = g_strBitmapsPath;
112 buf = load_bitmap_file (str.GetBuffer (), &width, &height);
117 GtkPreview *preview = GTK_PREVIEW (pixmap);
118 gtk_preview_size (preview, width, height);
119 for (int y = 0; y < height; y++)
120 gtk_preview_draw_row (preview, buf+y*width*3, 0, y, width);
123 gtk_widget_show_all (splash_screen);
125 while (gtk_events_pending ())
126 gtk_main_iteration ();
129 // =============================================================================
132 #if defined (__linux__) || defined (__APPLE__)
134 /* A short game name, could be used as argv[0] */
135 static char game_name[100] = "";
137 /* The directory where the data files can be found (run directory) */
138 static char datapath[PATH_MAX];
140 char *loki_gethomedir(void)
144 home = getenv("HOME");
151 while ( (pwd = getpwent()) != NULL )
153 if ( pwd->pw_uid == id )
164 /* Must be called BEFORE loki_initialize */
165 void loki_setgamename(const char *n)
167 strncpy(game_name, n, sizeof(game_name));
171 /* Code to determine the mount point of a CD-ROM */
172 int loki_getmountpoint(const char *device, char *mntpt, int max_size)
174 char devpath[PATH_MAX], mntdevpath[PATH_MAX];
176 struct mntent *mntent;
179 /* Nothing to do with no device file */
180 if ( device == NULL )
186 /* Get the fully qualified path of the CD-ROM device */
187 if ( realpath(device, devpath) == NULL )
189 perror("realpath() on your CD-ROM failed");
193 /* Get the mount point */
195 memset(mntpt, 0, max_size);
196 mountfp = setmntent( _PATH_MNTTAB, "r" );
197 if ( mountfp != NULL )
200 while ( (mntent = getmntent( mountfp )) != NULL )
202 char *tmp, mntdev[1024];
204 strcpy(mntdev, mntent->mnt_fsname);
205 if ( strcmp(mntent->mnt_type, "supermount") == 0 )
207 tmp = strstr(mntent->mnt_opts, "dev=");
210 strcpy(mntdev, tmp+strlen("dev="));
211 tmp = strchr(mntdev, ',');
218 if ( strncmp(mntdev, "/dev", 4) ||
219 realpath(mntdev, mntdevpath) == NULL )
223 if ( strcmp( mntdevpath, devpath ) == 0 )
226 assert((int)strlen( mntent->mnt_dir ) < max_size);
227 strncpy( mntpt, mntent->mnt_dir, max_size-1);
228 mntpt[max_size-1] = '\0';
232 endmntent( mountfp );
239 This function gets the directory containing the running program.
240 argv0 - the 0'th argument to the program
243 // I don't understand this function. It looks like something cut from another piece of software
244 // we somehow get the g_strAppPath from it, but it's done through a weird scan across $PATH env. var.
245 // even worse, it doesn't behave the same in all cases .. works well when ran through gdb and borks when ran from a shell
246 void loki_initpaths(char *argv0)
248 char temppath[PATH_MAX]; //, env[100];
249 char *home; //, *ptr, *data_env;
251 home = loki_gethomedir();
257 if (*game_name == 0) /* Game name defaults to argv[0] */
258 loki_setgamename(argv0);
260 strcpy(temppath, argv0); /* If this overflows, it's your own fault :) */
261 if ( ! strrchr(temppath, '/') )
268 path = getenv("PATH");
271 /* Initialize our filename variable */
274 /* Get next entry from path variable */
275 last = strchr(path, ':');
277 last = path+strlen(path);
279 /* Perform tilde expansion */
282 strcpy(temppath, home);
286 /* Fill in the rest of the filename */
287 if ( last > (path+1) )
289 strncat(temppath, path, (last-path));
290 strcat(temppath, "/");
292 strcat(temppath, "./");
293 strcat(temppath, argv0);
295 /* See if it exists, and update path */
296 if ( access(temppath, X_OK) == 0 )
302 } while ( *last && !found );
306 /* Increment argv0 to the basename */
307 argv0 = strrchr(argv0, '/')+1;
310 /* Now canonicalize it to a full pathname for the data path */
311 if ( realpath(temppath, datapath) )
313 /* There should always be '/' in the path */
314 *(strrchr(datapath, '/')) = '\0';
318 char *loki_getdatapath(void)
326 // =============================================================================
328 void error_redirect (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
330 gboolean in_recursion;
334 in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
335 is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
336 log_level = (GLogLevelFlags) (log_level & G_LOG_LEVEL_MASK);
339 message = "(NULL) message";
342 strcpy (buf, domain);
349 case G_LOG_LEVEL_ERROR:
351 strcat (buf, "ERROR (recursed) **: ");
353 strcat (buf, "ERROR **: ");
355 case G_LOG_LEVEL_CRITICAL:
357 strcat (buf, "CRITICAL (recursed) **: ");
359 strcat (buf, "CRITICAL **: ");
361 case G_LOG_LEVEL_WARNING:
363 strcat (buf, "WARNING (recursed) **: ");
365 strcat (buf, "WARNING **: ");
367 case G_LOG_LEVEL_MESSAGE:
369 strcat (buf, "Message (recursed): ");
371 strcat (buf, "Message: ");
373 case G_LOG_LEVEL_INFO:
375 strcat (buf, "INFO (recursed): ");
377 strcat (buf, "INFO: ");
379 case G_LOG_LEVEL_DEBUG:
381 strcat (buf, "DEBUG (recursed): ");
383 strcat (buf, "DEBUG: ");
386 /* we are used for a log level that is not defined by GLib itself,
387 * try to make the best out of it.
390 strcat (buf, "LOG (recursed:");
392 strcat (buf, "LOG (");
395 gchar string[] = "0x00): ";
396 gchar *p = string + 2;
399 i = g_bit_nth_msf (log_level, -1);
402 *p = '0' + (i & 0xf);
406 strcat (buf, string);
411 strcat (buf, message);
413 strcat (buf, "\naborting...\n");
417 printf ("%s\n", buf);
418 Sys_FPrintf (SYS_WRN, buf);
419 // TTimo NOTE: in some cases it may be handy to log only to the file
420 // Sys_FPrintf (SYS_NOCON, buf);
423 #define GETTEXT_PACKAGE "radiant"
424 #define LOCALEDIR "lang"
426 int main( int argc, char* argv[] ) {
431 Rambetter on Sat Nov 13, 2010:
433 The following line fixes parsing and writing of floating point numbers in locales such as
434 Italy, Germany, and others outside of en_US. In particular, in such problem locales, users
435 are not able to use certain map entities such as "light" because the definitions of these entities
436 in the entity definition files contain floating point values written in the standard "C" format
437 (containing a dot instead of, for example, a comma). The call sscanf() is all over the code,
438 including parsing entity definition files and reading Radiant preferences. sscanf() is sensitive
439 to locale (in particular when reading floating point numbers).
441 The line below is the minimalistic way to address only this particular problem - the parsing
442 and writing of floating point values. There may be other yet-undiscovered bugs related to
443 locale still lingering in the code. When such bugs are discovered, they should be addressed by
444 setting more than just "LC_NUMERIC=C" (for example LC_CTYPE for regular expression matching)
445 or by fixing the problem in the actual code instead of fiddling with LC_* variables.
447 Another way to fix the floating point format problem is to locate all calls such as *scanf()
448 and *printf() in the code and replace them with other functions. However, we're also using
449 external libraries such as libxml and [maybe?] they use locale to parse their numeric values.
450 I'm just saying, it may get ugly if we try to fix the problem without setting LC_NUMERIC.
452 Usage of sscanf() throughout the code looks like so:
453 sscanf(str, "%f %f %f", &val1, &val2, &val3);
454 Code like this exists in many files, here are 4 examples:
455 tools/quake3/q3map2/light.c
456 tools/quake3/q3map2/model.c
457 radiant/preferences.cpp
458 plugins/entity/miscmodel.cpp
460 Also affected are printf() calls when using formats that contain "%f".
462 I did some research and putenv() seems to be the best choice for being cross-platform. It
463 used to be a function in Windows (now deprecated):
464 http://msdn.microsoft.com/en-us/library/ms235321(VS.80).aspx
465 And of course it's defined in UNIX.
467 One more thing. the gtk_init() call below modifies all of the locale settings. In fact if it
468 weren't for gtk_init(), we wouldn't have to set LC_NUMERIC (parsing of floating points with
469 a dot works just fine before the gtk_init() call on a sample Linux system). If we were to
470 just setlocale() here, it would get clobbered by gtk_init(). So instead of using setlocale()
471 _after_ gtk_init(), I chose to fix this problem via environment variable. I think it's cleaner
474 putenv("LC_NUMERIC=C");
477 libgl = "opengl32.dll";
480 #if defined (__linux__)
481 libgl = "libGL.so.1";
485 libgl = "/usr/X11R6/lib/libGL.1.dylib";
488 #if defined (__linux__) || defined (__APPLE__)
489 // Give away unnecessary root privileges.
490 // Important: must be done before calling gtk_init().
494 if ( geteuid() == 0 && ( loginname = getlogin() ) != NULL && ( pw = getpwnam(loginname) ) != NULL ) {
500 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
501 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
502 textdomain(GETTEXT_PACKAGE);
503 // gtk_disable_setlocale();
505 gtk_init(&argc, &argv);
507 if ((ptr = getenv ("Q3R_LIBGL")) != NULL)
510 for (i = 1; i < argc; i++)
512 char* param = argv[i];
514 if (param[0] == '-' && param[1] == '-')
518 if ((strcmp (param, "libgl") == 0) && (i != argc))
521 argv[i] = argv[i+1] = NULL;
523 } else if (strcmp (param, "builddefs") == 0)
531 for (i = 1; i < argc; i++)
533 for (k = i; k < argc; k++)
540 for (j = i + k; j < argc; j++)
549 g_strPluginsDir = "plugins/";
550 g_strModulesDir = "modules/";
553 // get path to the editor
554 char* pBuffer = g_strAppPath.GetBufferSetLength(_MAX_PATH + 1);
555 GetModuleFileName(NULL, pBuffer, _MAX_PATH);
556 pBuffer[g_strAppPath.ReverseFind('\\') + 1] = '\0';
557 QE_ConvertDOSToUnixName(pBuffer, pBuffer);
558 g_strAppPath.ReleaseBuffer();
560 g_strBitmapsPath = g_strAppPath;
561 g_strBitmapsPath += "bitmaps/";
563 CGameDialog::UpdateNetrun(false); // read the netrun configuration
565 if ( CGameDialog::GetNetrun() ) {
566 // we have to find a per-user g_strTempPath
567 // this behaves the same as on Linux
568 g_strTempPath = getenv("USERPROFILE");
569 if (!g_strTempPath.GetLength())
572 msg = "Radiant is configured to run from a network installation.\n";
573 msg += "I couldn't find the environement variable USERPROFILE\n";
574 msg += "I'm going to use C:\\RadiantSettings. Please set USERPROFILE\n";
575 gtk_MessageBox (NULL, msg, "Radiant - Network mode", MB_OK);
576 g_strTempPath = "C:\\";
578 g_strTempPath += "\\RadiantSettings\\";
579 Q_mkdir(g_strTempPath.GetBuffer(), 0755);
580 g_strTempPath += RADIANT_VERSION;
581 g_strTempPath += "\\";
582 Q_mkdir(g_strTempPath.GetBuffer(), 0755);
586 // use the core path as temp (to save commandlist.txt, and do the .pid files)
587 g_strTempPath = g_strAppPath;
592 #if defined (__linux__) || defined (__APPLE__)
594 home = g_get_home_dir ();
597 Q_mkdir (home.GetBuffer (), 0775);
598 home += RADIANT_VERSION;
599 Q_mkdir (home.GetBuffer (), 0775);
600 g_strTempPath = home.GetBuffer ();
601 AddSlash (g_strTempPath);
603 loki_initpaths(argv[0]);
605 // NOTE: we build g_strAppPath with a '/' (or '\' on WIN32)
606 // it's a general convention in Radiant to have the slash at the end of directories
608 realpath (loki_getdatapath(), real);
609 if (real[strlen(real)-1] != '/')
614 // radiant is installed in the parent dir of "tools/"
615 // NOTE: this is not very easy for debugging
616 // maybe add options to lookup in several places?
617 // (for now I had to create symlinks)
618 g_strBitmapsPath = g_strAppPath;
619 g_strBitmapsPath += "bitmaps/";
621 // we will set this right after the game selection is done
622 g_strGameToolsPath = g_strAppPath;
627 g_strDTDPath = g_strAppPath;
628 g_strDTDPath += "dtds/";
631 the global prefs loading / game selection dialog might fail for any reason we don't know about
632 we need to catch when it happens, to cleanup the stateful prefs which might be killing it
633 and to turn on console logging for lookup of the problem
634 this is the first part of the two step .pid system
636 g_pidFile = g_strTempPath.GetBuffer ();
637 g_pidFile += "radiant.pid";
640 pid = fopen( g_pidFile.GetBuffer(), "r" );
645 if (remove (g_pidFile.GetBuffer ()) == -1)
647 msg = "WARNING: Could not delete "; msg += g_pidFile;
648 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
651 // in debug, never prompt to clean registry, turn console logging auto after a failed start
653 msg = "Found the file ";
655 msg += ".\nThis indicates that Radiant failed during the game selection startup last time it was run.\n"
656 "Choose YES to clean Radiant's registry settings and shut down Radiant.\n"
657 "WARNING: the global prefs will be lost if you choose YES.";
659 if (gtk_MessageBox (NULL, msg, "Radiant - Reset global startup?", MB_YESNO | MB_ICONQUESTION) == IDYES)
661 // remove global prefs and shutdown
662 g_PrefsDlg.mGamesDialog.Reset();
663 // remove the prefs file (like a full reset of the registry)
664 //remove (g_PrefsDlg.m_inipath->str);
665 gtk_MessageBox(NULL, "Removed global settings, choose OK to close Radiant.", "Radiant", MB_OK );
668 msg = "Logging console output to ";
669 msg += g_strTempPath;
670 msg += "radiant.log\nRefer to the log if Radiant fails to start again.";
672 gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK);
675 // set without saving, the class is not in a coherent state yet
676 // just do the value change and call to start logging, CGamesDialog will pickup when relevant
677 g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
678 g_PrefsDlg.mGamesDialog.m_bForceLogConsole = true;
682 // create a primary .pid for global init run
683 pid = fopen( g_pidFile.GetBuffer(), "w" );
688 // a safe check to avoid people running broken installations
689 // (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing)
690 // make something idiot proof and someone will make better idiots, this may be overkill
691 // let's leave it disabled in debug mode in any case
693 //#define CHECK_VERSION
696 // locate and open RADIANT_MAJOR and RADIANT_MINOR
697 qboolean bVerIsGood = true;
699 ver_file_name = g_strAppPath;
700 ver_file_name += "RADIANT_MAJOR";
701 FILE *ver_file = fopen (ver_file_name.GetBuffer(), "r");
706 fread(buf, 1, 10, ver_file);
707 // chomp it (the hard way)
709 while(buf[chomp] >= '0' && buf[chomp] <= '9')
712 if (strcmp(buf, RADIANT_MAJOR_VERSION))
714 Sys_Printf("ERROR: file RADIANT_MAJOR doesn't match ('%s')\n", buf);
720 Sys_Printf("ERROR: can't find RADIANT_MAJOR in '%s'\n", ver_file_name.GetBuffer());
723 ver_file_name = g_strAppPath;
724 ver_file_name += "RADIANT_MINOR";
725 ver_file = fopen (ver_file_name.GetBuffer(), "r");
730 fread(buf, 1, 10, ver_file);
731 // chomp it (the hard way)
733 while(buf[chomp] >= '0' && buf[chomp] <= '9')
736 if (strcmp(buf, RADIANT_MINOR_VERSION))
738 Sys_Printf("ERROR: file RADIANT_MINOR doesn't match ('%s')\n", buf);
744 Sys_Printf("ERROR: can't find RADIANT_MINOR in '%s'\n", ver_file_name.GetBuffer());
750 msg = "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n";
751 msg += "Make sure you run the right/latest editor binary you installed\n";
752 msg += g_strAppPath; msg += "\n";
753 msg += "Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information";
754 gtk_MessageBox(NULL, msg.GetBuffer(), "Radiant", MB_OK, "http://www.qeradiant.com/faq/index.cgi?file=219");
759 g_qeglobals.disable_ini = false;
763 if ( remove( g_pidFile.GetBuffer () ) == -1 ) {
765 msg = "WARNING: Could not delete "; msg += g_pidGameFile;
766 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
770 now the secondary game dependant .pid file
772 g_pidGameFile = g_PrefsDlg.m_rc_path->str;
773 g_pidGameFile += "radiant-game.pid";
775 pid = fopen (g_pidGameFile.GetBuffer(), "r");
780 if (remove (g_pidGameFile.GetBuffer ()) == -1)
782 msg = "WARNING: Could not delete "; msg += g_pidGameFile;
783 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
786 msg = "Found the file ";
787 msg += g_pidGameFile;
788 msg += ".\nThis indicates that Radiant failed to load the last time it was run.\n"
789 "Choose YES to clean Radiant's registry settings and shut down Radiant.\n"
790 "WARNING: preferences will be lost if you choose YES.";
792 // in debug, never prompt to clean registry, turn console logging auto after a failed start
795 if (gtk_MessageBox (NULL, msg, "Radiant - Clean Registry?", MB_YESNO | MB_ICONQUESTION) == IDYES)
797 // remove the game prefs files
798 remove (g_PrefsDlg.m_inipath->str);
800 sprintf(buf, "%sSavedInfo.bin", g_PrefsDlg.m_rc_path->str);
802 // remove the global pref too
803 g_PrefsDlg.mGamesDialog.Reset();
804 gtk_MessageBox(NULL, "Cleaned registry settings, choose OK to close Radiant.\nThe next time Radiant runs it will use default settings.", "Radiant", MB_OK );
807 msg = "Logging console output to ";
808 msg += g_strTempPath;
809 msg += "radiant.log\nRefer to the log if Radiant fails to start again.";
811 gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK);
814 // force console logging on! (will go in prefs too)
815 g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
816 g_PrefsDlg.mGamesDialog.SavePrefs();
819 g_PrefsDlg.LoadPrefs();
823 // create one, will remove right after entering message loop
824 pid = fopen (g_pidGameFile.GetBuffer(), "w");
828 g_PrefsDlg.LoadPrefs();
830 #ifndef _DEBUG // I can't be arsed about that prompt in debug mode
831 // if console logging is on in the prefs, warn about performance hit
832 if (g_PrefsDlg.mGamesDialog.m_bLogConsole)
834 if (gtk_MessageBox (NULL, "Preferences indicate that console logging is on. This affects performance.\n"
835 "Turn it off?", "Radiant", MB_YESNO | MB_ICONQUESTION) == IDYES)
837 g_PrefsDlg.mGamesDialog.m_bLogConsole = false;
838 g_PrefsDlg.mGamesDialog.SavePrefs();
842 // toggle console logging if necessary
846 // we should search in g_strTempPath, then move over to look at g_strAppPath?
848 // fine tune the look of the app using a gtk rc file
849 // we try to load an RC file placed in the application directory
850 // build the full path
852 sRCFile = g_strAppPath;
853 sRCFile += "radiantgtkrc";
854 // we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\'
855 pBuffer = (char *)sRCFile.GetBuffer();
856 for (i=0; i<sRCFile.GetLength(); i++)
863 // check the file exists
864 if (access(sRCFile.GetBuffer(), R_OK) != 0)
865 Sys_Printf("RC file %s not found\n", sRCFile.GetBuffer());
868 Sys_Printf ("Attemping to load RC file %s\n", sRCFile.GetBuffer());
869 gtk_rc_parse (sRCFile.GetBuffer());
877 if (!QGL_Init(libgl, ""))
879 Sys_FPrintf (SYS_ERR, "Failed to load OpenGL libraries\n");
884 #if defined (__linux__) || defined (__APPLE__)
885 if ((qglXQueryExtension == NULL) || (qglXQueryExtension(GDK_DISPLAY(),NULL,NULL) != True))
887 Sys_FPrintf (SYS_ERR, "glXQueryExtension failed\n");
893 // redirect Gtk warnings to the console
894 g_log_set_handler( "Gdk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
895 G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL);
896 g_log_set_handler( "Gtk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
897 G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL);
899 // spog - creates new filters list for the first time
900 g_qeglobals.d_savedinfo.filters = NULL;
901 g_qeglobals.d_savedinfo.filters = FilterUpdate(g_qeglobals.d_savedinfo.filters);
903 g_pParentWnd = new MainFrame();
905 if ( g_PrefsDlg.m_bLoadLastMap && g_PrefsDlg.m_strLastMap.GetLength() > 0 ) {
906 Map_LoadFile(g_PrefsDlg.m_strLastMap.GetBuffer());
911 // load up shaders now that we have the map loaded
913 Texture_ShowStartupShaders();
916 gdk_window_raise(splash_screen->window);
917 gtk_window_set_transient_for( GTK_WINDOW( splash_screen ), GTK_WINDOW( g_pParentWnd->m_pWidget ) );
918 gtk_timeout_add( 1000, try_destroy_splash, NULL );
921 g_pParentWnd->GetSynapseServer().DumpActiveClients();
923 //++timo: temporary debug
924 g_pParentWnd->DoWatchBSP();
928 // close the log file if any
929 // NOTE: don't save prefs past this point!
930 g_PrefsDlg.mGamesDialog.m_bLogConsole = false;
931 // set the console window to NULL to avoid Sys_Printf crashing
932 g_qeglobals_gui.d_edit = NULL;
935 // NOTE TTimo not sure what this _exit(0) call is worth
936 // restricting it to linux build
943 // ydnar: quick and dirty fix, just make the buffer bigger
944 #define BIG_PATH_MAX 4096
946 // TTimo: decompose the BSP command into several steps so we can monitor them eventually
947 void QE_ExpandBspString (char *bspaction, GPtrArray *out_array, char *mapname)
951 char src[BIG_PATH_MAX];
952 char rsh[BIG_PATH_MAX];
953 char base[BIG_PATH_MAX];
955 strcpy(src, mapname);
957 in = strstr(src, "maps/");
960 in = strstr(src, "maps/");
977 ExtractFileName (mapname, base);
980 // this important step alters the map name to add fs_game
981 // NOTE: it used to add fs_basepath too
982 // the fs_basepath addition moved to being in the project file during the bug fixing rush
983 // but it may not have been the right thing to do
985 // HACK: halflife compiler tools don't support -fs_game
986 // HACK: neither does JKII/SoF2/ etc..
987 // do we use & have fs_game?
989 if (g_pGameDescription->mGameFile != "hl.game" &&
990 *ValueForKey(g_qeglobals.d_project_entity,"gamename") != '\0')
993 sprintf(src, "-fs_game %s \"%s\"", ValueForKey(g_qeglobals.d_project_entity,"gamename"), mapname);
997 sprintf(src, "\"%s\"", mapname);
1002 QE_ConvertDOSToUnixName(src, src);
1004 // initialise the first step
1005 out = new char[BIG_PATH_MAX]; //% PATH_MAX
1006 g_ptr_array_add( out_array, out );
1008 in = ValueForKey( g_qeglobals.d_project_entity, bspaction );
1021 // we process these only if monitoring
1022 if (g_PrefsDlg.m_bWatchBSP)
1024 // -connect global option (the only global option so far anyway)
1025 strcpy (tmp, " -connect 127.0.0.1:39000 ");
1052 out = new char[BIG_PATH_MAX]; //% PATH_MAX
1053 g_ptr_array_add( out_array, out );
1060 void FindReplace(CString& strContents, const char* pTag, const char* pValue)
1062 if (strcmp(pTag, pValue) == 0)
1064 for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag))
1066 int nRightLen = strContents.GetLength() - strlen(pTag) - nPos;
1067 CString strLeft = strContents.Left(nPos);
1068 CString strRight = strContents.Right(nRightLen);
1070 strLeft += strRight;
1071 strContents = strLeft;
1075 // save the map, deals with regioning
1076 void SaveWithRegion(char *name)
1078 strcpy (name, currentmap);
1081 // temporary cut the region to save regular map
1082 region_active = false;
1083 Map_SaveFile (name, false);
1084 region_active = true;
1085 StripExtension (name);
1086 strcat (name, ".reg");
1089 Map_SaveFile (name, region_active);
1092 void RunBsp (char *command)
1095 char batpath[BIG_PATH_MAX]; //% PATH_MAX
1096 char temppath[BIG_PATH_MAX]; //% PATH_MAX
1097 char name[BIG_PATH_MAX]; //% PATH_MAX
1098 char cWork[BIG_PATH_MAX]; //% PATH_MAX
1102 SetInspectorMode(W_CONSOLE);
1104 strcpy (temppath, g_strTempPath.GetBuffer ());
1106 SaveWithRegion(name);
1108 const char *rsh = ValueForKey(g_qeglobals.d_project_entity, "rshcmd");
1111 CString strPath, strFile;
1113 ExtractPath_and_Filename(name, strPath, strFile);
1115 strncpy(cWork, strPath, 1024);
1116 strcat(cWork, strFile);
1119 strcpy(cWork, name);
1122 // get the array ready
1123 //++timo TODO: free the array, free the strings ourselves with delete[]
1124 sys = g_ptr_array_new();
1126 QE_ExpandBspString (command, sys, cWork);
1128 if (g_PrefsDlg.m_bWatchBSP)
1130 // grab the file name for engine running
1131 char *bspname = new char[1024];
1132 ExtractFileName( currentmap, bspname );
1133 StripExtension( bspname );
1134 g_pParentWnd->GetWatchBSP()->DoMonitoringLoop( sys, bspname );
1137 // write all the steps in a single BAT / .sh file and run it, don't bother monitoring it
1139 for (i=0; i < sys->len; i++ )
1141 strSys += (char *)g_ptr_array_index( sys, i);
1142 #ifdef _WIN32 // write temp\junk.txt in win32... NOTE: stops output to shell prompt window
1149 strSys += "junk.txt\"";
1154 #if defined (__linux__) || defined (__APPLE__)
1157 sprintf (batpath, "%sqe3bsp.sh", temppath);
1158 Sys_Printf("Writing the compile script to '%s'\n", batpath);
1159 Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath);
1160 hFile = fopen(batpath, "w");
1162 Error ("Can't write to %s", batpath);
1163 fprintf (hFile, "#!/bin/sh \n\n");
1164 fprintf (hFile, strSys.GetBuffer());
1166 chmod (batpath, 0744);
1170 sprintf (batpath, "%sqe3bsp.bat", temppath);
1171 Sys_Printf("Writing the compile script to '%s'\n", batpath);
1172 Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath);
1173 hFile = fopen(batpath, "w");
1175 Error ("Can't write to %s", batpath);
1176 fprintf (hFile, strSys.GetBuffer());
1180 Pointfile_Delete ();
1182 #if defined (__linux__) || defined (__APPLE__)
1190 Error ("CreateProcess failed");
1193 execlp (batpath, batpath, NULL);
1194 printf ("execlp error !");
1203 Sys_Printf ("Running bsp command...\n");
1204 Sys_Printf ("\n%s\n", strSys.GetBuffer());
1206 WinExec( batpath, SW_SHOWNORMAL );
1210 // yeah, do it .. but not now right before 1.1-TA-beta release
1211 Sys_Printf("TODO: erase GPtrArray\n");
1219 int WINAPI QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer )
1221 static PIXELFORMATDESCRIPTOR pfd = {
1222 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1223 1, // version number
1224 PFD_DRAW_TO_WINDOW | // support window
1225 PFD_SUPPORT_OPENGL | // support OpenGL
1226 PFD_DOUBLEBUFFER, // double buffered
1227 PFD_TYPE_RGBA, // RGBA type
1228 24, // 24-bit color depth
1229 0, 0, 0, 0, 0, 0, // color bits ignored
1230 0, // no alpha buffer
1231 0, // shift bit ignored
1232 0, // no accumulation buffer
1233 0, 0, 0, 0, // accum bits ignored
1235 0, // no stencil buffer
1236 0, // no auxiliary buffer
1237 PFD_MAIN_PLANE, // main layer
1239 0, 0, 0 // layer masks ignored
1241 int pixelformat = 0;
1247 if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
1251 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1252 FORMAT_MESSAGE_FROM_SYSTEM |
1253 FORMAT_MESSAGE_IGNORE_INSERTS,
1256 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1261 Sys_FPrintf (SYS_WRN, "GetLastError: %s", lpMsgBuf);
1262 Error ("ChoosePixelFormat failed");
1265 if (!SetPixelFormat(hDC, pixelformat, &pfd))
1266 Error ("SetPixelFormat failed");