2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
22 #if defined (__linux__) || defined (__APPLE__)
\r
23 #include <gdk/gdkx.h>
\r
25 #include <unistd.h>
\r
30 #include <pthread.h>
\r
31 #include <sys/wait.h>
\r
33 #include <sys/stat.h>
\r
36 #include <gtk/gtk.h>
\r
39 #include <sys/types.h>
\r
40 #include <sys/stat.h>
\r
44 #include "watchbsp.h"
\r
45 #include "filters.h"
\r
47 bool g_bBuildList = false;
\r
51 // =============================================================================
\r
54 // get rid of it when debugging
\r
55 #if defined (_DEBUG)
\r
59 static GtkWidget *splash_screen;
\r
61 // called based on a timer, or in particular cases when we don't want to keep it around
\r
62 gint try_destroy_splash (gpointer data)
\r
66 gtk_widget_destroy (splash_screen);
\r
67 splash_screen = NULL;
\r
72 static void create_splash ()
\r
74 GtkWidget *alert_frame, *alert_frame1, *pixmap;
\r
76 splash_screen = gtk_window_new (GTK_WINDOW_POPUP);
\r
77 gtk_window_position (GTK_WINDOW (splash_screen), GTK_WIN_POS_CENTER);
\r
78 gtk_widget_realize (splash_screen);
\r
80 alert_frame1 = gtk_frame_new (NULL);
\r
81 gtk_widget_show (alert_frame1);
\r
82 gtk_container_add (GTK_CONTAINER (splash_screen), alert_frame1);
\r
83 gtk_frame_set_shadow_type (GTK_FRAME (alert_frame1), GTK_SHADOW_OUT);
\r
85 alert_frame = gtk_frame_new (NULL);
\r
86 gtk_widget_show (alert_frame);
\r
88 gtk_container_add (GTK_CONTAINER (alert_frame1), alert_frame);
\r
89 gtk_frame_set_shadow_type (GTK_FRAME (alert_frame), GTK_SHADOW_IN);
\r
90 gtk_container_border_width (GTK_CONTAINER (alert_frame), 3);
\r
92 pixmap = gtk_preview_new (GTK_PREVIEW_COLOR);
\r
93 gtk_widget_show (pixmap);
\r
94 gtk_container_add (GTK_CONTAINER (alert_frame), pixmap);
\r
97 guint16 width, height;
\r
100 str = g_strGameToolsPath;
\r
101 str += "bitmaps/splash.bmp";
\r
103 unsigned char* load_bitmap_file (const char* filename, guint16* width, guint16* height);
\r
104 buf = load_bitmap_file (str.GetBuffer (), &width, &height);
\r
108 str = g_strBitmapsPath;
\r
109 str += "splash.bmp";
\r
111 buf = load_bitmap_file (str.GetBuffer (), &width, &height);
\r
116 GtkPreview *preview = GTK_PREVIEW (pixmap);
\r
117 gtk_preview_size (preview, width, height);
\r
118 for (int y = 0; y < height; y++)
\r
119 gtk_preview_draw_row (preview, buf+y*width*3, 0, y, width);
\r
122 gtk_widget_show_all (splash_screen);
\r
124 while (gtk_events_pending ())
\r
125 gtk_main_iteration ();
\r
128 // =============================================================================
\r
131 #if defined (__linux__) || defined (__APPLE__)
\r
133 /* A short game name, could be used as argv[0] */
\r
134 static char game_name[100] = "";
\r
136 /* The directory where the data files can be found (run directory) */
\r
137 static char datapath[PATH_MAX];
\r
139 char *loki_gethomedir(void)
\r
143 home = getenv("HOME");
\r
144 if ( home == NULL )
\r
146 uid_t id = getuid();
\r
147 struct passwd *pwd;
\r
150 while ( (pwd = getpwent()) != NULL )
\r
152 if ( pwd->pw_uid == id )
\r
154 home = pwd->pw_dir;
\r
163 /* Must be called BEFORE loki_initialize */
\r
164 void loki_setgamename(const char *n)
\r
166 strncpy(game_name, n, sizeof(game_name));
\r
170 /* Code to determine the mount point of a CD-ROM */
\r
171 int loki_getmountpoint(const char *device, char *mntpt, int max_size)
\r
173 char devpath[PATH_MAX], mntdevpath[PATH_MAX];
\r
175 struct mntent *mntent;
\r
178 /* Nothing to do with no device file */
\r
179 if ( device == NULL )
\r
185 /* Get the fully qualified path of the CD-ROM device */
\r
186 if ( realpath(device, devpath) == NULL )
\r
188 perror("realpath() on your CD-ROM failed");
\r
192 /* Get the mount point */
\r
194 memset(mntpt, 0, max_size);
\r
195 mountfp = setmntent( _PATH_MNTTAB, "r" );
\r
196 if ( mountfp != NULL )
\r
199 while ( (mntent = getmntent( mountfp )) != NULL )
\r
201 char *tmp, mntdev[1024];
\r
203 strcpy(mntdev, mntent->mnt_fsname);
\r
204 if ( strcmp(mntent->mnt_type, "supermount") == 0 )
\r
206 tmp = strstr(mntent->mnt_opts, "dev=");
\r
209 strcpy(mntdev, tmp+strlen("dev="));
\r
210 tmp = strchr(mntdev, ',');
\r
217 if ( strncmp(mntdev, "/dev", 4) ||
\r
218 realpath(mntdev, mntdevpath) == NULL )
\r
222 if ( strcmp( mntdevpath, devpath ) == 0 )
\r
225 assert((int)strlen( mntent->mnt_dir ) < max_size);
\r
226 strncpy( mntpt, mntent->mnt_dir, max_size-1);
\r
227 mntpt[max_size-1] = '\0';
\r
231 endmntent( mountfp );
\r
238 This function gets the directory containing the running program.
\r
239 argv0 - the 0'th argument to the program
\r
242 // I don't understand this function. It looks like something cut from another piece of software
\r
243 // we somehow get the g_strAppPath from it, but it's done through a weird scan across $PATH env. var.
\r
244 // even worse, it doesn't behave the same in all cases .. works well when ran through gdb and borks when ran from a shell
\r
245 void loki_initpaths(char *argv0)
\r
247 char temppath[PATH_MAX]; //, env[100];
\r
248 char *home; //, *ptr, *data_env;
\r
250 home = loki_gethomedir();
\r
251 if ( home == NULL )
\r
256 if (*game_name == 0) /* Game name defaults to argv[0] */
\r
257 loki_setgamename(argv0);
\r
259 strcpy(temppath, argv0); /* If this overflows, it's your own fault :) */
\r
260 if ( ! strrchr(temppath, '/') )
\r
267 path = getenv("PATH");
\r
270 /* Initialize our filename variable */
\r
271 temppath[0] = '\0';
\r
273 /* Get next entry from path variable */
\r
274 last = strchr(path, ':');
\r
276 last = path+strlen(path);
\r
278 /* Perform tilde expansion */
\r
279 if ( *path == '~' )
\r
281 strcpy(temppath, home);
\r
285 /* Fill in the rest of the filename */
\r
286 if ( last > (path+1) )
\r
288 strncat(temppath, path, (last-path));
\r
289 strcat(temppath, "/");
\r
291 strcat(temppath, "./");
\r
292 strcat(temppath, argv0);
\r
294 /* See if it exists, and update path */
\r
295 if ( access(temppath, X_OK) == 0 )
\r
301 } while ( *last && !found );
\r
305 /* Increment argv0 to the basename */
\r
306 argv0 = strrchr(argv0, '/')+1;
\r
309 /* Now canonicalize it to a full pathname for the data path */
\r
310 if ( realpath(temppath, datapath) )
\r
312 /* There should always be '/' in the path */
\r
313 *(strrchr(datapath, '/')) = '\0';
\r
317 char *loki_getdatapath(void)
\r
324 // end of Loki stuff
\r
325 // =============================================================================
\r
327 void error_redirect (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
\r
329 gboolean in_recursion;
\r
333 in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
\r
334 is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
\r
335 log_level = (GLogLevelFlags) (log_level & G_LOG_LEVEL_MASK);
\r
338 message = "(NULL) message";
\r
341 strcpy (buf, domain);
\r
343 strcpy (buf, "**");
\r
348 case G_LOG_LEVEL_ERROR:
\r
350 strcat (buf, "ERROR (recursed) **: ");
\r
352 strcat (buf, "ERROR **: ");
\r
354 case G_LOG_LEVEL_CRITICAL:
\r
356 strcat (buf, "CRITICAL (recursed) **: ");
\r
358 strcat (buf, "CRITICAL **: ");
\r
360 case G_LOG_LEVEL_WARNING:
\r
362 strcat (buf, "WARNING (recursed) **: ");
\r
364 strcat (buf, "WARNING **: ");
\r
366 case G_LOG_LEVEL_MESSAGE:
\r
368 strcat (buf, "Message (recursed): ");
\r
370 strcat (buf, "Message: ");
\r
372 case G_LOG_LEVEL_INFO:
\r
374 strcat (buf, "INFO (recursed): ");
\r
376 strcat (buf, "INFO: ");
\r
378 case G_LOG_LEVEL_DEBUG:
\r
380 strcat (buf, "DEBUG (recursed): ");
\r
382 strcat (buf, "DEBUG: ");
\r
385 /* we are used for a log level that is not defined by GLib itself,
\r
386 * try to make the best out of it.
\r
389 strcat (buf, "LOG (recursed:");
\r
391 strcat (buf, "LOG (");
\r
394 gchar string[] = "0x00): ";
\r
395 gchar *p = string + 2;
\r
398 i = g_bit_nth_msf (log_level, -1);
\r
401 *p = '0' + (i & 0xf);
\r
403 *p += 'A' - '9' - 1;
\r
405 strcat (buf, string);
\r
407 strcat (buf, "): ");
\r
410 strcat (buf, message);
\r
412 strcat (buf, "\naborting...\n");
\r
414 strcat (buf, "\n");
\r
416 printf ("%s\n", buf);
\r
417 Sys_FPrintf (SYS_WRN, buf);
\r
418 // TTimo NOTE: in some cases it may be handy to log only to the file
\r
419 // Sys_FPrintf (SYS_NOCON, buf);
\r
422 int main (int argc, char* argv[])
\r
428 libgl = "opengl32.dll";
\r
431 #if defined (__linux__)
\r
432 libgl = "libGL.so.1";
\r
436 libgl = "/usr/X11R6/lib/libGL.1.dylib";
\r
439 #if defined (__linux__) || defined (__APPLE__)
\r
440 // Give away unnecessary root privileges.
\r
441 // Important: must be done before calling gtk_init().
\r
445 if (geteuid() == 0 && (loginname = getlogin()) != NULL &&
\r
446 (pw = getpwnam(loginname)) != NULL)
\r
447 setuid(pw->pw_uid);
\r
450 gtk_disable_setlocale();
\r
452 gtk_init(&argc, &argv);
\r
454 if ((ptr = getenv ("Q3R_LIBGL")) != NULL)
\r
457 for (i = 1; i < argc; i++)
\r
459 char* param = argv[i];
\r
461 if (param[0] == '-' && param[1] == '-')
\r
465 if ((strcmp (param, "libgl") == 0) && (i != argc))
\r
468 argv[i] = argv[i+1] = NULL;
\r
470 } else if (strcmp (param, "builddefs") == 0)
\r
472 g_bBuildList = true;
\r
478 for (i = 1; i < argc; i++)
\r
480 for (k = i; k < argc; k++)
\r
481 if (argv[k] != NULL)
\r
487 for (j = i + k; j < argc; j++)
\r
488 argv[j-k] = argv[j];
\r
496 g_strPluginsDir = "plugins/";
\r
497 g_strModulesDir = "modules/";
\r
500 // get path to the editor
\r
501 char* pBuffer = g_strAppPath.GetBufferSetLength(_MAX_PATH + 1);
\r
502 GetModuleFileName(NULL, pBuffer, _MAX_PATH);
\r
503 pBuffer[g_strAppPath.ReverseFind('\\') + 1] = '\0';
\r
504 QE_ConvertDOSToUnixName(pBuffer, pBuffer);
\r
505 g_strAppPath.ReleaseBuffer();
\r
507 g_strBitmapsPath = g_strAppPath;
\r
508 g_strBitmapsPath += "bitmaps/";
\r
511 // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639
\r
512 // now check if we are running from a network installation
\r
513 // use a dummy file as the flag
\r
516 strNetrun = g_strAppPath; strNetrun += NETRUN_FILENAME;
\r
517 f_netrun = fopen(strNetrun.GetBuffer(), "r");
\r
521 g_PrefsDlg.m_bUseHomePath = true;
\r
524 CGameDialog::UpdateNetrun(false); // read the netrun configuration
\r
526 if (CGameDialog::GetNetrun())
\r
528 // we have to find a per-user g_strTempPath
\r
529 // this behaves the same as on Linux
\r
530 g_strTempPath = getenv("USERPROFILE");
\r
531 if (!g_strTempPath.GetLength())
\r
534 msg = "Radiant is configured to run from a network installation.\n";
\r
535 msg += "I couldn't find the environement variable USERPROFILE\n";
\r
536 msg += "I'm going to use C:\\RadiantSettings. Please set USERPROFILE\n";
\r
537 gtk_MessageBox (NULL, msg, "Radiant - Network mode", MB_OK);
\r
538 g_strTempPath = "C:\\";
\r
540 g_strTempPath += "\\RadiantSettings\\";
\r
541 Q_mkdir(g_strTempPath.GetBuffer(), 0755);
\r
542 g_strTempPath += RADIANT_VERSION;
\r
543 g_strTempPath += "\\";
\r
544 Q_mkdir(g_strTempPath.GetBuffer(), 0755);
\r
548 // use the core path as temp (to save commandlist.txt, and do the .pid files)
\r
549 g_strTempPath = g_strAppPath;
\r
554 #if defined (__linux__) || defined (__APPLE__)
\r
556 home = g_get_home_dir ();
\r
558 home += ".radiant/";
\r
559 Q_mkdir (home.GetBuffer (), 0775);
\r
560 home += RADIANT_VERSION;
\r
561 Q_mkdir (home.GetBuffer (), 0775);
\r
562 g_strTempPath = home.GetBuffer ();
\r
563 AddSlash (g_strTempPath);
\r
565 loki_initpaths(argv[0]);
\r
567 // NOTE: we build g_strAppPath with a '/' (or '\' on WIN32)
\r
568 // it's a general convention in Radiant to have the slash at the end of directories
\r
569 char real[PATH_MAX];
\r
570 realpath (loki_getdatapath(), real);
\r
571 if (real[strlen(real)-1] != '/')
\r
574 g_strAppPath = real;
\r
577 printf("g_strAppPath: %s\n", g_strAppPath.GetBuffer());
\r
580 // radiant is installed in the parent dir of "tools/"
\r
581 // NOTE: this is not very easy for debugging
\r
582 // maybe add options to lookup in several places?
\r
583 // (for now I had to create symlinks)
\r
584 g_strBitmapsPath = g_strAppPath;
\r
585 g_strBitmapsPath += "bitmaps/";
\r
587 printf("g_strBitmapsPath: %s\n", g_strBitmapsPath.GetBuffer());
\r
590 // we will set this right after the game selection is done
\r
591 g_strGameToolsPath = g_strAppPath;
\r
595 // init the DTD path
\r
596 g_strDTDPath = g_strAppPath;
\r
597 g_strDTDPath += "dtds/";
\r
600 the global prefs loading / game selection dialog might fail for any reason we don't know about
\r
601 we need to catch when it happens, to cleanup the stateful prefs which might be killing it
\r
602 and to turn on console logging for lookup of the problem
\r
603 this is the first part of the two step .pid system
\r
604 http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297
\r
606 g_pidFile = g_strTempPath.GetBuffer ();
\r
607 g_pidFile += "radiant.pid";
\r
610 pid = fopen (g_pidFile.GetBuffer(), "r");
\r
616 if (remove (g_pidFile.GetBuffer ()) == -1)
\r
618 msg = "WARNING: Could not delete "; msg += g_pidFile;
\r
619 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
\r
622 // in debug, never prompt to clean registry, turn console logging auto after a failed start
\r
623 #if !defined(_DEBUG)
\r
624 msg = "Found the file ";
\r
626 msg += ".\nThis indicates that Radiant failed during the game selection startup last time it was run.\n"
\r
627 "Choose YES to clean Radiant's registry settings and shut down Radiant.\n"
\r
628 "WARNING: the global prefs will be lost if you choose YES.";
\r
630 if (gtk_MessageBox (NULL, msg, "Radiant - Reset global startup?", MB_YESNO | MB_ICONQUESTION) == IDYES)
\r
632 // remove global prefs and shutdown
\r
633 g_PrefsDlg.mGamesDialog.Reset();
\r
634 // remove the prefs file (like a full reset of the registry)
\r
635 //remove (g_PrefsDlg.m_inipath->str);
\r
636 gtk_MessageBox(NULL, "Removed global settings, choose OK to close Radiant.", "Radiant", MB_OK );
\r
639 msg = "Logging console output to ";
\r
640 msg += g_strTempPath;
\r
641 msg += "radiant.log\nRefer to the log if Radiant fails to start again.";
\r
643 gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK);
\r
646 // set without saving, the class is not in a coherent state yet
\r
647 // just do the value change and call to start logging, CGamesDialog will pickup when relevant
\r
648 g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
\r
649 g_PrefsDlg.mGamesDialog.m_bForceLogConsole = true;
\r
653 // create a primary .pid for global init run
\r
654 pid = fopen (g_pidFile.GetBuffer(), "w");
\r
658 // a safe check to avoid people running broken installations
\r
659 // (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing)
\r
660 // make something idiot proof and someone will make better idiots, this may be overkill
\r
661 // let's leave it disabled in debug mode in any case
\r
662 // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431
\r
664 #define CHECK_VERSION
\r
666 #ifdef CHECK_VERSION
\r
667 // locate and open RADIANT_MAJOR and RADIANT_MINOR
\r
668 qboolean bVerIsGood = true;
\r
670 ver_file_name = g_strAppPath;
\r
671 ver_file_name += "RADIANT_MAJOR";
\r
672 FILE *ver_file = fopen (ver_file_name.GetBuffer(), "r");
\r
677 fread(buf, 1, 10, ver_file);
\r
678 // chomp it (the hard way)
\r
680 while(buf[chomp] >= '0' && buf[chomp] <= '9')
\r
683 if (strcmp(buf, RADIANT_MAJOR_VERSION))
\r
685 Sys_Printf("ERROR: file RADIANT_MAJOR doesn't match ('%s')\n", buf);
\r
686 bVerIsGood = false;
\r
691 Sys_Printf("ERROR: can't find RADIANT_MAJOR in '%s'\n", ver_file_name.GetBuffer());
\r
692 bVerIsGood = false;
\r
694 ver_file_name = g_strAppPath;
\r
695 ver_file_name += "RADIANT_MINOR";
\r
696 ver_file = fopen (ver_file_name.GetBuffer(), "r");
\r
701 fread(buf, 1, 10, ver_file);
\r
702 // chomp it (the hard way)
\r
704 while(buf[chomp] >= '0' && buf[chomp] <= '9')
\r
707 if (strcmp(buf, RADIANT_MINOR_VERSION))
\r
709 Sys_Printf("ERROR: file RADIANT_MINOR doesn't match ('%s')\n", buf);
\r
710 bVerIsGood = false;
\r
715 Sys_Printf("ERROR: can't find RADIANT_MINOR in '%s'\n", ver_file_name.GetBuffer());
\r
716 bVerIsGood = false;
\r
721 msg = "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n";
\r
722 msg += "Make sure you run the right/latest editor binary you installed\n";
\r
723 msg += g_strAppPath; msg += "\n";
\r
724 msg += "Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information";
\r
725 gtk_MessageBox(NULL, msg.GetBuffer(), "Radiant", MB_OK, "http://www.qeradiant.com/faq/index.cgi?file=219");
\r
730 g_qeglobals.disable_ini = false;
\r
731 g_PrefsDlg.Init ();
\r
733 // close the primary
\r
734 if (remove (g_pidFile.GetBuffer ()) == -1)
\r
737 msg = "WARNING: Could not delete "; msg += g_pidGameFile;
\r
738 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
\r
742 now the secondary game dependant .pid file
\r
743 http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297
\r
745 g_pidGameFile = g_PrefsDlg.m_rc_path->str;
\r
746 g_pidGameFile += "radiant-game.pid";
\r
748 pid = fopen (g_pidGameFile.GetBuffer(), "r");
\r
753 if (remove (g_pidGameFile.GetBuffer ()) == -1)
\r
755 msg = "WARNING: Could not delete "; msg += g_pidGameFile;
\r
756 gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR );
\r
759 msg = "Found the file ";
\r
760 msg += g_pidGameFile;
\r
761 msg += ".\nThis indicates that Radiant failed to load the last time it was run.\n"
\r
762 "Choose YES to clean Radiant's registry settings and shut down Radiant.\n"
\r
763 "WARNING: preferences will be lost if you choose YES.";
\r
765 // in debug, never prompt to clean registry, turn console logging auto after a failed start
\r
766 #if !defined(_DEBUG)
\r
768 if (gtk_MessageBox (NULL, msg, "Radiant - Clean Registry?", MB_YESNO | MB_ICONQUESTION) == IDYES)
\r
770 // remove the game prefs files
\r
771 remove (g_PrefsDlg.m_inipath->str);
\r
772 char buf[PATH_MAX];
\r
773 sprintf(buf, "%sSavedInfo.bin", g_PrefsDlg.m_rc_path->str);
\r
775 // remove the global pref too
\r
776 g_PrefsDlg.mGamesDialog.Reset();
\r
777 gtk_MessageBox(NULL, "Cleaned registry settings, choose OK to close Radiant.\nThe next time Radiant runs it will use default settings.", "Radiant", MB_OK );
\r
780 msg = "Logging console output to ";
\r
781 msg += g_strTempPath;
\r
782 msg += "radiant.log\nRefer to the log if Radiant fails to start again.";
\r
784 gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK);
\r
787 // force console logging on! (will go in prefs too)
\r
788 g_PrefsDlg.mGamesDialog.m_bLogConsole = true;
\r
789 g_PrefsDlg.mGamesDialog.SavePrefs();
\r
792 g_PrefsDlg.LoadPrefs();
\r
796 // create one, will remove right after entering message loop
\r
797 pid = fopen (g_pidGameFile.GetBuffer(), "w");
\r
801 g_PrefsDlg.LoadPrefs();
\r
803 #ifndef _DEBUG // I can't be arsed about that prompt in debug mode
\r
804 // if console logging is on in the prefs, warn about performance hit
\r
805 if (g_PrefsDlg.mGamesDialog.m_bLogConsole)
\r
807 if (gtk_MessageBox (NULL, "Preferences indicate that console logging is on. This affects performance.\n"
\r
808 "Turn it off?", "Radiant", MB_YESNO | MB_ICONQUESTION) == IDYES)
\r
810 g_PrefsDlg.mGamesDialog.m_bLogConsole = false;
\r
811 g_PrefsDlg.mGamesDialog.SavePrefs();
\r
815 // toggle console logging if necessary
\r
819 // FIXME http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639
\r
820 // we should search in g_strTempPath, then move over to look at g_strAppPath?
\r
822 // fine tune the look of the app using a gtk rc file
\r
823 // we try to load an RC file placed in the application directory
\r
824 // build the full path
\r
826 sRCFile = g_strAppPath;
\r
827 sRCFile += "radiantgtkrc";
\r
828 // we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\'
\r
829 pBuffer = (char *)sRCFile.GetBuffer();
\r
830 for (i=0; i<sRCFile.GetLength(); i++)
\r
832 if (pBuffer[i]=='/')
\r
837 // check the file exists
\r
838 if (access(sRCFile.GetBuffer(), R_OK) != 0)
\r
839 Sys_Printf("RC file %s not found\n", sRCFile.GetBuffer());
\r
842 Sys_Printf ("Attemping to load RC file %s\n", sRCFile.GetBuffer());
\r
843 gtk_rc_parse (sRCFile.GetBuffer());
\r
847 #ifndef SKIP_SPLASH
\r
851 if (!QGL_Init(libgl, ""))
\r
853 Sys_FPrintf (SYS_ERR, "Failed to load OpenGL libraries\n");
\r
858 #if defined (__linux__) || defined (__APPLE__)
\r
859 if ((qglXQueryExtension == NULL) || (qglXQueryExtension(GDK_DISPLAY(),NULL,NULL) != True))
\r
861 Sys_FPrintf (SYS_ERR, "glXQueryExtension failed\n");
\r
867 // redirect Gtk warnings to the console
\r
868 g_log_set_handler ("Gdk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
\r
869 G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL);
\r
870 g_log_set_handler ("Gtk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
\r
871 G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL);
\r
873 // spog - creates new filters list for the first time
\r
874 g_qeglobals.d_savedinfo.filters = NULL; //initialise to NULL
\r
875 g_qeglobals.d_savedinfo.filters = FilterUpdate(g_qeglobals.d_savedinfo.filters);
\r
877 g_pParentWnd = new MainFrame ();
\r
879 if (g_PrefsDlg.m_bLoadLastMap && g_PrefsDlg.m_strLastMap.GetLength() > 0)
\r
880 Map_LoadFile(g_PrefsDlg.m_strLastMap.GetBuffer());
\r
884 // load up shaders now that we have the map loaded
\r
886 Texture_ShowStartupShaders ();
\r
888 #ifndef SKIP_SPLASH
\r
889 gdk_window_raise (splash_screen->window);
\r
890 gtk_window_set_transient_for (GTK_WINDOW (splash_screen), GTK_WINDOW (g_pParentWnd->m_pWidget));
\r
891 gtk_timeout_add (1000, try_destroy_splash, NULL);
\r
894 g_pParentWnd->GetSynapseServer().DumpActiveClients();
\r
896 //++timo: temporary debug
\r
897 g_pParentWnd->DoWatchBSP();
\r
901 // close the log file if any
\r
902 // NOTE: don't save prefs past this point!
\r
903 g_PrefsDlg.mGamesDialog.m_bLogConsole = false;
\r
904 // set the console window to NULL to avoid Sys_Printf crashing
\r
905 g_qeglobals_gui.d_edit = NULL;
\r
908 // NOTE TTimo not sure what this _exit(0) call is worth
\r
909 // restricting it to linux build
\r
916 // ydnar: quick and dirty fix, just make the buffer bigger
\r
917 #define BIG_PATH_MAX 4096
\r
919 // TTimo: decompose the BSP command into several steps so we can monitor them eventually
\r
920 void QE_ExpandBspString (char *bspaction, GPtrArray *out_array, char *mapname)
\r
924 char src[BIG_PATH_MAX];
\r
925 char rsh[BIG_PATH_MAX];
\r
926 char base[BIG_PATH_MAX];
\r
928 strcpy(src, mapname);
\r
930 in = strstr(src, "maps/");
\r
933 in = strstr(src, "maps/");
\r
950 ExtractFileName (mapname, base);
\r
953 // this important step alters the map name to add fs_game
\r
954 // NOTE: it used to add fs_basepath too
\r
955 // the fs_basepath addition moved to being in the project file during the bug fixing rush
\r
956 // but it may not have been the right thing to do
\r
958 // HACK: halflife compiler tools don't support -fs_game
\r
959 // HACK: neither does JKII/SoF2/ etc..
\r
960 // do we use & have fs_game?
\r
962 if (g_pGameDescription->mGameFile != "hl.game" &&
\r
963 *ValueForKey(g_qeglobals.d_project_entity,"gamename") != '\0')
\r
965 // set with fs_game
\r
966 sprintf(src, "-fs_game %s \"%s\"", ValueForKey(g_qeglobals.d_project_entity,"gamename"), mapname);
\r
970 sprintf(src, "\"%s\"", mapname);
\r
975 QE_ConvertDOSToUnixName(src, src);
\r
977 // initialise the first step
\r
978 out = new char[BIG_PATH_MAX]; //% PATH_MAX
\r
979 g_ptr_array_add( out_array, out );
\r
981 in = ValueForKey( g_qeglobals.d_project_entity, bspaction );
\r
987 out += strlen(rsh);
\r
994 // we process these only if monitoring
\r
995 if (g_PrefsDlg.m_bWatchBSP)
\r
997 // -connect global option (the only global option so far anyway)
\r
998 strcpy (tmp, " -connect 127.0.0.1:39000 ");
\r
1000 out += strlen(tmp);
\r
1008 strcpy (out, src);
\r
1009 out += strlen(src);
\r
1022 // start a new step
\r
1025 out = new char[BIG_PATH_MAX]; //% PATH_MAX
\r
1026 g_ptr_array_add( out_array, out );
\r
1033 void FindReplace(CString& strContents, const char* pTag, const char* pValue)
\r
1035 if (strcmp(pTag, pValue) == 0)
\r
1037 for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag))
\r
1039 int nRightLen = strContents.GetLength() - strlen(pTag) - nPos;
\r
1040 CString strLeft = strContents.Left(nPos);
\r
1041 CString strRight = strContents.Right(nRightLen);
\r
1042 strLeft += pValue;
\r
1043 strLeft += strRight;
\r
1044 strContents = strLeft;
\r
1048 // save the map, deals with regioning
\r
1049 void SaveWithRegion(char *name)
\r
1051 strcpy (name, currentmap);
\r
1052 if (region_active)
\r
1054 // temporary cut the region to save regular map
\r
1055 region_active = false;
\r
1056 Map_SaveFile (name, false);
\r
1057 region_active = true;
\r
1058 StripExtension (name);
\r
1059 strcat (name, ".reg");
\r
1062 Map_SaveFile (name, region_active);
\r
1065 void RunBsp (char *command)
\r
1068 char batpath[BIG_PATH_MAX]; //% PATH_MAX
\r
1069 char temppath[BIG_PATH_MAX]; //% PATH_MAX
\r
1070 char name[BIG_PATH_MAX]; //% PATH_MAX
\r
1071 char cWork[BIG_PATH_MAX]; //% PATH_MAX
\r
1075 SetInspectorMode(W_CONSOLE);
\r
1077 strcpy (temppath, g_strTempPath.GetBuffer ());
\r
1079 SaveWithRegion(name);
\r
1081 const char *rsh = ValueForKey(g_qeglobals.d_project_entity, "rshcmd");
\r
1084 CString strPath, strFile;
\r
1086 ExtractPath_and_Filename(name, strPath, strFile);
\r
1087 AddSlash(strPath);
\r
1088 strncpy(cWork, strPath, 1024);
\r
1089 strcat(cWork, strFile);
\r
1092 strcpy(cWork, name);
\r
1095 // get the array ready
\r
1096 //++timo TODO: free the array, free the strings ourselves with delete[]
\r
1097 sys = g_ptr_array_new();
\r
1099 QE_ExpandBspString (command, sys, cWork);
\r
1101 if (g_PrefsDlg.m_bWatchBSP)
\r
1103 // grab the file name for engine running
\r
1104 char *bspname = new char[1024];
\r
1105 ExtractFileName( currentmap, bspname );
\r
1106 StripExtension( bspname );
\r
1107 g_pParentWnd->GetWatchBSP()->DoMonitoringLoop( sys, bspname );
\r
1110 // write all the steps in a single BAT / .sh file and run it, don't bother monitoring it
\r
1112 for (i=0; i < sys->len; i++ )
\r
1114 strSys += (char *)g_ptr_array_index( sys, i);
\r
1115 #ifdef _WIN32 // write temp\junk.txt in win32... NOTE: stops output to shell prompt window
\r
1121 strSys += temppath;
\r
1122 strSys += "junk.txt\"";
\r
1127 #if defined (__linux__) || defined (__APPLE__)
\r
1129 // write qe3bsp.sh
\r
1130 sprintf (batpath, "%sqe3bsp.sh", temppath);
\r
1131 Sys_Printf("Writing the compile script to '%s'\n", batpath);
\r
1132 Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath);
\r
1133 hFile = fopen(batpath, "w");
\r
1135 Error ("Can't write to %s", batpath);
\r
1136 fprintf (hFile, "#!/bin/sh \n\n");
\r
1137 fprintf (hFile, strSys.GetBuffer());
\r
1139 chmod (batpath, 0744);
\r
1143 sprintf (batpath, "%sqe3bsp.bat", temppath);
\r
1144 Sys_Printf("Writing the compile script to '%s'\n", batpath);
\r
1145 Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath);
\r
1146 hFile = fopen(batpath, "w");
\r
1148 Error ("Can't write to %s", batpath);
\r
1149 fprintf (hFile, strSys.GetBuffer());
\r
1153 Pointfile_Delete ();
\r
1155 #if defined (__linux__) || defined (__APPLE__)
\r
1163 Error ("CreateProcess failed");
\r
1166 execlp (batpath, batpath, NULL);
\r
1167 printf ("execlp error !");
\r
1176 Sys_Printf ("Running bsp command...\n");
\r
1177 Sys_Printf ("\n%s\n", strSys.GetBuffer());
\r
1179 WinExec( batpath, SW_SHOWNORMAL );
\r
1183 // yeah, do it .. but not now right before 1.1-TA-beta release
\r
1184 Sys_Printf("TODO: erase GPtrArray\n");
\r
1192 int WINAPI QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer )
\r
1194 static PIXELFORMATDESCRIPTOR pfd = {
\r
1195 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
\r
1196 1, // version number
\r
1197 PFD_DRAW_TO_WINDOW | // support window
\r
1198 PFD_SUPPORT_OPENGL | // support OpenGL
\r
1199 PFD_DOUBLEBUFFER, // double buffered
\r
1200 PFD_TYPE_RGBA, // RGBA type
\r
1201 24, // 24-bit color depth
\r
1202 0, 0, 0, 0, 0, 0, // color bits ignored
\r
1203 0, // no alpha buffer
\r
1204 0, // shift bit ignored
\r
1205 0, // no accumulation buffer
\r
1206 0, 0, 0, 0, // accum bits ignored
\r
1208 0, // no stencil buffer
\r
1209 0, // no auxiliary buffer
\r
1210 PFD_MAIN_PLANE, // main layer
\r
1212 0, 0, 0 // layer masks ignored
\r
1214 int pixelformat = 0;
\r
1218 pfd.cDepthBits = 0;
\r
1220 if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
\r
1224 FORMAT_MESSAGE_ALLOCATE_BUFFER |
\r
1225 FORMAT_MESSAGE_FROM_SYSTEM |
\r
1226 FORMAT_MESSAGE_IGNORE_INSERTS,
\r
1229 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
\r
1230 (LPTSTR) &lpMsgBuf,
\r
1234 Sys_FPrintf (SYS_WRN, "GetLastError: %s", lpMsgBuf);
\r
1235 Error ("ChoosePixelFormat failed");
\r
1238 if (!SetPixelFormat(hDC, pixelformat, &pfd))
\r
1239 Error ("SetPixelFormat failed");
\r
1241 return pixelformat;
\r