X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fmain.cpp;h=028983443a8551965a14891dbf078ed85cbfcb0f;hb=refs%2Fheads%2FTimePath%2Fdevelop;hp=31a8511f3703fb6b0904b3b7aa1228823982a4fb;hpb=e4b1c1a55c5db801601ce3459bc061dd3f3a4ebd;p=xonotic%2Fnetradiant.git diff --git a/radiant/main.cpp b/radiant/main.cpp index 31a8511f..02898344 100644 --- a/radiant/main.cpp +++ b/radiant/main.cpp @@ -1,1224 +1,698 @@ /* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#if defined (__linux__) || defined (__APPLE__) - #include - #include - #include - #ifdef __linux__ - #include - #endif - #include - #include - #include - #include - #include -#endif + Copyright (C) 1999-2006 Id Software, Inc. and contributors. + For a list of contributors, see the accompanying CONTRIBUTORS file. -#include -#include -#include "stdafx.h" -#include -#include -#include + This file is part of GtkRadiant. -#include + GtkRadiant 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. -#include "watchbsp.h" -#include "filters.h" + GtkRadiant 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. -bool g_bBuildList = false; -int g_argc; -char** g_argv; + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ -// ============================================================================= -// Splash screen +/*! \mainpage GtkRadiant Documentation Index -// get rid of it when debugging -#if defined (_DEBUG) - #define SKIP_SPLASH -#endif + \section intro_sec Introduction -static GtkWidget *splash_screen; + This documentation is generated from comments in the source code. -// called based on a timer, or in particular cases when we don't want to keep it around -gint try_destroy_splash (gpointer data) -{ - if (splash_screen) - { - gtk_widget_destroy (splash_screen); - splash_screen = NULL; - } - return FALSE; -} + \section links_sec Useful Links -static void create_splash () -{ - GtkWidget *alert_frame, *alert_frame1, *pixmap; + \link include/itextstream.h include/itextstream.h \endlink - Global output and error message streams, similar to std::cout and std::cerr. \n - splash_screen = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_position (GTK_WINDOW (splash_screen), GTK_WIN_POS_CENTER); - gtk_widget_realize (splash_screen); + FileInputStream - similar to std::ifstream (binary mode) \n + FileOutputStream - similar to std::ofstream (binary mode) \n + TextFileInputStream - similar to std::ifstream (text mode) \n + TextFileOutputStream - similar to std::ofstream (text mode) \n + StringOutputStream - similar to std::stringstream \n - alert_frame1 = gtk_frame_new (NULL); - gtk_widget_show (alert_frame1); - gtk_container_add (GTK_CONTAINER (splash_screen), alert_frame1); - gtk_frame_set_shadow_type (GTK_FRAME (alert_frame1), GTK_SHADOW_OUT); + \link string/string.h string/string.h \endlink - C-style string comparison and memory management. \n + \link os/path.h os/path.h \endlink - Path manipulation for radiant's standard path format \n + \link os/file.h os/file.h \endlink - OS file-system access. \n - alert_frame = gtk_frame_new (NULL); - gtk_widget_show (alert_frame); + ::CopiedString - automatic string memory management \n + Array - automatic array memory management \n + HashTable - generic hashtable, similar to std::hash_map \n - gtk_container_add (GTK_CONTAINER (alert_frame1), alert_frame); - gtk_frame_set_shadow_type (GTK_FRAME (alert_frame), GTK_SHADOW_IN); - gtk_container_border_width (GTK_CONTAINER (alert_frame), 3); + \link math/vector.h math/vector.h \endlink - Vectors \n + \link math/matrix.h math/matrix.h \endlink - Matrices \n + \link math/quaternion.h math/quaternion.h \endlink - Quaternions \n + \link math/plane.h math/plane.h \endlink - Planes \n + \link math/aabb.h math/aabb.h \endlink - AABBs \n - pixmap = gtk_preview_new (GTK_PREVIEW_COLOR); - gtk_widget_show (pixmap); - gtk_container_add (GTK_CONTAINER (alert_frame), pixmap); + Callback MemberCaller0 FunctionCaller - callbacks similar to using boost::function with boost::bind \n + SmartPointer SmartReference - smart-pointer and smart-reference similar to Loki's SmartPtr \n - CString str; - guint16 width, height; - unsigned char *buf; + \link generic/bitfield.h generic/bitfield.h \endlink - Type-safe bitfield \n + \link generic/enumeration.h generic/enumeration.h \endlink - Type-safe enumeration \n - str = g_strGameToolsPath; - str += "bitmaps/splash.bmp"; + DefaultAllocator - Memory allocation using new/delete, compliant with std::allocator interface \n - unsigned char* load_bitmap_file (const char* filename, guint16* width, guint16* height); - buf = load_bitmap_file (str.GetBuffer (), &width, &height); + \link debugging/debugging.h debugging/debugging.h \endlink - Debugging macros \n - if (!buf) - { - str = g_strBitmapsPath; - str += "splash.bmp"; + */ - buf = load_bitmap_file (str.GetBuffer (), &width, &height); - } +#include +#include "main.h" +#include "globaldefs.h" - if (buf) - { - GtkPreview *preview = GTK_PREVIEW (pixmap); - gtk_preview_size (preview, width, height); - for (int y = 0; y < height; y++) - gtk_preview_draw_row (preview, buf+y*width*3, 0, y, width); - } +#include "version.h" - gtk_widget_show_all (splash_screen); +#include "debugging/debugging.h" - while (gtk_events_pending ()) - gtk_main_iteration (); -} +#include "iundo.h" + +#include "uilib/uilib.h" -// ============================================================================= -// Loki stuff +#include "cmdlib.h" +#include "os/file.h" +#include "os/path.h" +#include "stream/stringstream.h" +#include "stream/textfilestream.h" -#if defined (__linux__) || defined (__APPLE__) +#include "gtkutil/messagebox.h" +#include "gtkutil/image.h" +#include "console.h" +#include "texwindow.h" +#include "map.h" +#include "mainframe.h" +#include "commands.h" +#include "preferences.h" +#include "environment.h" +#include "referencecache.h" +#include "stacktrace.h" -/* A short game name, could be used as argv[0] */ -static char game_name[100] = ""; +#if GDEF_OS_WINDOWS +#include +#endif -/* The directory where the data files can be found (run directory) */ -static char datapath[PATH_MAX]; +void show_splash(); -char *loki_gethomedir(void) +void hide_splash(); + +void error_redirect(const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { - char *home = NULL; + gboolean in_recursion; + gboolean is_fatal; + char buf[256]; - home = getenv("HOME"); - if ( home == NULL ) - { - uid_t id = getuid(); - struct passwd *pwd; + in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0; + is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; + log_level = (GLogLevelFlags) (log_level & G_LOG_LEVEL_MASK); - setpwent(); - while ( (pwd = getpwent()) != NULL ) - { - if ( pwd->pw_uid == id ) - { - home = pwd->pw_dir; - break; - } + if (!message) { + message = "(0) message"; } - endpwent(); - } - return home; -} -/* Must be called BEFORE loki_initialize */ -void loki_setgamename(const char *n) -{ - strncpy(game_name, n, sizeof(game_name)); -} + if (domain) { + strcpy(buf, domain); + } else { + strcpy(buf, "**"); + } + strcat(buf, "-"); + + switch (log_level) { + case G_LOG_LEVEL_ERROR: + if (in_recursion) { + strcat(buf, "ERROR (recursed) **: "); + } else { + strcat(buf, "ERROR **: "); + } + break; + case G_LOG_LEVEL_CRITICAL: + if (in_recursion) { + strcat(buf, "CRITICAL (recursed) **: "); + } else { + strcat(buf, "CRITICAL **: "); + } + break; + case G_LOG_LEVEL_WARNING: + if (in_recursion) { + strcat(buf, "WARNING (recursed) **: "); + } else { + strcat(buf, "WARNING **: "); + } + break; + case G_LOG_LEVEL_MESSAGE: + if (in_recursion) { + strcat(buf, "Message (recursed): "); + } else { + strcat(buf, "Message: "); + } + break; + case G_LOG_LEVEL_INFO: + if (in_recursion) { + strcat(buf, "INFO (recursed): "); + } else { + strcat(buf, "INFO: "); + } + break; + case G_LOG_LEVEL_DEBUG: + if (in_recursion) { + strcat(buf, "DEBUG (recursed): "); + } else { + strcat(buf, "DEBUG: "); + } + break; + default: + /* we are used for a log level that is not defined by GLib itself, + * try to make the best out of it. + */ + if (in_recursion) { + strcat(buf, "LOG (recursed:"); + } else { + strcat(buf, "LOG ("); + } + if (log_level) { + gchar string[] = "0x00): "; + gchar *p = string + 2; + guint i; + + i = g_bit_nth_msf(log_level, -1); + *p = i >> 4; + p++; + *p = '0' + (i & 0xf); + if (*p > '9') { + *p += 'A' - '9' - 1; + } + + strcat(buf, string); + } else { + strcat(buf, "): "); + } + } - #ifdef __linux__ -/* Code to determine the mount point of a CD-ROM */ -int loki_getmountpoint(const char *device, char *mntpt, int max_size) -{ - char devpath[PATH_MAX], mntdevpath[PATH_MAX]; - FILE * mountfp; - struct mntent *mntent; - int mounted; - - /* Nothing to do with no device file */ - if ( device == NULL ) - { - *mntpt = '\0'; - return -1; - } - - /* Get the fully qualified path of the CD-ROM device */ - if ( realpath(device, devpath) == NULL ) - { - perror("realpath() on your CD-ROM failed"); - return(-1); - } - - /* Get the mount point */ - mounted = -1; - memset(mntpt, 0, max_size); - mountfp = setmntent( _PATH_MNTTAB, "r" ); - if ( mountfp != NULL ) - { - mounted = 0; - while ( (mntent = getmntent( mountfp )) != NULL ) - { - char *tmp, mntdev[1024]; - - strcpy(mntdev, mntent->mnt_fsname); - if ( strcmp(mntent->mnt_type, "supermount") == 0 ) - { - tmp = strstr(mntent->mnt_opts, "dev="); - if ( tmp ) - { - strcpy(mntdev, tmp+strlen("dev=")); - tmp = strchr(mntdev, ','); - if ( tmp ) - { - *tmp = '\0'; - } - } - } - if ( strncmp(mntdev, "/dev", 4) || - realpath(mntdev, mntdevpath) == NULL ) - { - continue; - } - if ( strcmp( mntdevpath, devpath ) == 0 ) - { - mounted = 1; - assert((int)strlen( mntent->mnt_dir ) < max_size); - strncpy( mntpt, mntent->mnt_dir, max_size-1); - mntpt[max_size-1] = '\0'; - break; - } + strcat(buf, message); + if (is_fatal) { + strcat(buf, "\naborting...\n"); + } else { + strcat(buf, "\n"); } - endmntent( mountfp ); - } - return(mounted); -} - #endif -/* - This function gets the directory containing the running program. - argv0 - the 0'th argument to the program -*/ -// FIXME TTimo -// I don't understand this function. It looks like something cut from another piece of software -// we somehow get the g_strAppPath from it, but it's done through a weird scan across $PATH env. var. -// even worse, it doesn't behave the same in all cases .. works well when ran through gdb and borks when ran from a shell -void loki_initpaths(char *argv0) -{ - char temppath[PATH_MAX]; //, env[100]; - char *home; //, *ptr, *data_env; - - home = loki_gethomedir(); - if ( home == NULL ) - { - home = "."; - } - - if (*game_name == 0) /* Game name defaults to argv[0] */ - loki_setgamename(argv0); - - strcpy(temppath, argv0); /* If this overflows, it's your own fault :) */ - if ( ! strrchr(temppath, '/') ) - { - char *path; - char *last; - int found; - - found = 0; - path = getenv("PATH"); - do - { - /* Initialize our filename variable */ - temppath[0] = '\0'; - - /* Get next entry from path variable */ - last = strchr(path, ':'); - if ( ! last ) - last = path+strlen(path); - - /* Perform tilde expansion */ - if ( *path == '~' ) - { - strcpy(temppath, home); - ++path; - } - - /* Fill in the rest of the filename */ - if ( last > (path+1) ) - { - strncat(temppath, path, (last-path)); - strcat(temppath, "/"); - } - strcat(temppath, "./"); - strcat(temppath, argv0); - - /* See if it exists, and update path */ - if ( access(temppath, X_OK) == 0 ) - { - ++found; - } - path = last+1; - - } while ( *last && !found ); - - } else - { - /* Increment argv0 to the basename */ - argv0 = strrchr(argv0, '/')+1; - } - - /* Now canonicalize it to a full pathname for the data path */ - if ( realpath(temppath, datapath) ) - { - /* There should always be '/' in the path */ - *(strrchr(datapath, '/')) = '\0'; - } -} + // spam it... + globalErrorStream() << buf << "\n"; -char *loki_getdatapath(void) -{ - return(datapath); + if (is_fatal) { + ERROR_MESSAGE("GTK+ error: " << buf); + } } +#if GDEF_COMPILER_MSVC && GDEF_DEBUG +#include "crtdbg.h" #endif -// end of Loki stuff -// ============================================================================= - -void error_redirect (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) +void crt_init() { - gboolean in_recursion; - gboolean is_fatal; - char buf[256]; - - in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0; - is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; - log_level = (GLogLevelFlags) (log_level & G_LOG_LEVEL_MASK); - - if (!message) - message = "(NULL) message"; - - if (domain) - strcpy (buf, domain); - else - strcpy (buf, "**"); - strcat (buf, "-"); - - switch (log_level) - { - case G_LOG_LEVEL_ERROR: - if (in_recursion) - strcat (buf, "ERROR (recursed) **: "); - else - strcat (buf, "ERROR **: "); - break; - case G_LOG_LEVEL_CRITICAL: - if (in_recursion) - strcat (buf, "CRITICAL (recursed) **: "); - else - strcat (buf, "CRITICAL **: "); - break; - case G_LOG_LEVEL_WARNING: - if (in_recursion) - strcat (buf, "WARNING (recursed) **: "); - else - strcat (buf, "WARNING **: "); - break; - case G_LOG_LEVEL_MESSAGE: - if (in_recursion) - strcat (buf, "Message (recursed): "); - else - strcat (buf, "Message: "); - break; - case G_LOG_LEVEL_INFO: - if (in_recursion) - strcat (buf, "INFO (recursed): "); - else - strcat (buf, "INFO: "); - break; - case G_LOG_LEVEL_DEBUG: - if (in_recursion) - strcat (buf, "DEBUG (recursed): "); - else - strcat (buf, "DEBUG: "); - break; - default: - /* we are used for a log level that is not defined by GLib itself, - * try to make the best out of it. - */ - if (in_recursion) - strcat (buf, "LOG (recursed:"); - else - strcat (buf, "LOG ("); - if (log_level) - { - gchar string[] = "0x00): "; - gchar *p = string + 2; - guint i; - - i = g_bit_nth_msf (log_level, -1); - *p = i >> 4; - p++; - *p = '0' + (i & 0xf); - if (*p > '9') - *p += 'A' - '9' - 1; - - strcat (buf, string); - } else - strcat (buf, "): "); - } - - strcat (buf, message); - if (is_fatal) - strcat (buf, "\naborting...\n"); - else - strcat (buf, "\n"); - - printf ("%s\n", buf); - Sys_FPrintf (SYS_WRN, buf); - // TTimo NOTE: in some cases it may be handy to log only to the file -// Sys_FPrintf (SYS_NOCON, buf); -} - -int main( int argc, char* argv[] ) { - char *libgl, *ptr; - int i, j, k; - -#ifdef _WIN32 - libgl = "opengl32.dll"; -#endif - -#if defined (__linux__) - libgl = "libGL.so.1"; +#if GDEF_COMPILER_MSVC && GDEF_DEBUG + _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif +} -#ifdef __APPLE__ - libgl = "/usr/X11R6/lib/libGL.1.dylib"; -#endif +class Lock { + bool m_locked; +public: + Lock() : m_locked(false) + { + } -#if defined (__linux__) || defined (__APPLE__) - // Give away unnecessary root privileges. - // Important: must be done before calling gtk_init(). - char *loginname; - struct passwd *pw; - seteuid(getuid()); - if ( geteuid() == 0 && ( loginname = getlogin() ) != NULL && ( pw = getpwnam(loginname) ) != NULL ) { - setuid(pw->pw_uid); - } -#endif + void lock() + { + m_locked = true; + } - gtk_disable_setlocale(); + void unlock() + { + m_locked = false; + } - gtk_init(&argc, &argv); + bool locked() const + { + return m_locked; + } +}; - if ((ptr = getenv ("Q3R_LIBGL")) != NULL) - libgl = ptr; +class ScopedLock { + Lock &m_lock; +public: + ScopedLock(Lock &lock) : m_lock(lock) + { + m_lock.lock(); + } - for (i = 1; i < argc; i++) - { - char* param = argv[i]; + ~ScopedLock() + { + m_lock.unlock(); + } +}; + +class LineLimitedTextOutputStream : public TextOutputStream { + TextOutputStream &outputStream; + std::size_t count; +public: + LineLimitedTextOutputStream(TextOutputStream &outputStream, std::size_t count) + : outputStream(outputStream), count(count) + { + } - if (param[0] == '-' && param[1] == '-') + std::size_t write(const char *buffer, std::size_t length) { - param += 2; - - if ((strcmp (param, "libgl") == 0) && (i != argc)) - { - libgl = argv[i+1]; - argv[i] = argv[i+1] = NULL; - i++; - } else if (strcmp (param, "builddefs") == 0) - { - g_bBuildList = true; - argv[i] = NULL; - } + if (count != 0) { + const char *p = buffer; + const char *end = buffer + length; + for (;;) { + p = std::find(p, end, '\n'); + if (p == end) { + break; + } + ++p; + if (--count == 0) { + length = p - buffer; + break; + } + } + outputStream.write(buffer, length); + } + return length; } - } +}; - for (i = 1; i < argc; i++) - { - for (k = i; k < argc; k++) - if (argv[k] != NULL) - break; +class PopupDebugMessageHandler : public DebugMessageHandler { + StringOutputStream m_buffer; + Lock m_lock; +public: + TextOutputStream &getOutputStream() + { + if (!m_lock.locked()) { + return m_buffer; + } + return globalErrorStream(); + } - if (k > i) + bool handleMessage() { - k -= i; - for (j = i + k; j < argc; j++) - argv[j-k] = argv[j]; - argc -= k; + getOutputStream() << "----------------\n"; + LineLimitedTextOutputStream outputStream(getOutputStream(), 24); + write_stack_trace(outputStream); + getOutputStream() << "----------------\n"; + globalErrorStream() << m_buffer.c_str(); + if (!m_lock.locked()) { + ScopedLock lock(m_lock); + if (GDEF_DEBUG) { + m_buffer << "Break into the debugger?\n"; + bool handled = ui::alert(ui::root, m_buffer.c_str(), "Radiant - Runtime Error", ui::alert_type::YESNO, + ui::alert_icon::Error) == ui::alert_response::NO; + m_buffer.clear(); + return handled; + } else { + m_buffer << "Please report this error to the developers\n"; + ui::alert(ui::root, m_buffer.c_str(), "Radiant - Runtime Error", ui::alert_type::OK, + ui::alert_icon::Error); + m_buffer.clear(); + } + } + return true; } - } +}; - g_argc = argc; - g_argv = argv; +typedef Static GlobalPopupDebugMessageHandler; - g_strPluginsDir = "plugins/"; - g_strModulesDir = "modules/"; +void streams_init() +{ + GlobalErrorStream::instance().setOutputStream(getSysPrintErrorStream()); + GlobalOutputStream::instance().setOutputStream(getSysPrintOutputStream()); +} -#ifdef _WIN32 - // get path to the editor - char* pBuffer = g_strAppPath.GetBufferSetLength(_MAX_PATH + 1); - GetModuleFileName(NULL, pBuffer, _MAX_PATH); - pBuffer[g_strAppPath.ReverseFind('\\') + 1] = '\0'; - QE_ConvertDOSToUnixName(pBuffer, pBuffer); - g_strAppPath.ReleaseBuffer(); +void paths_init() +{ + g_strSettingsPath = environment_get_home_path(); - g_strBitmapsPath = g_strAppPath; - g_strBitmapsPath += "bitmaps/"; + Q_mkdir(g_strSettingsPath.c_str()); - CGameDialog::UpdateNetrun(false); // read the netrun configuration + g_strAppPath = environment_get_app_path(); - if ( CGameDialog::GetNetrun() ) { - // we have to find a per-user g_strTempPath - // this behaves the same as on Linux - g_strTempPath = getenv("USERPROFILE"); - if (!g_strTempPath.GetLength()) + // radiant is installed in the parent dir of "tools/" + // NOTE: this is not very easy for debugging + // maybe add options to lookup in several places? + // (for now I had to create symlinks) { - CString msg; - msg = "Radiant is configured to run from a network installation.\n"; - msg += "I couldn't find the environement variable USERPROFILE\n"; - msg += "I'm going to use C:\\RadiantSettings. Please set USERPROFILE\n"; - gtk_MessageBox (NULL, msg, "Radiant - Network mode", MB_OK); - g_strTempPath = "C:\\"; + StringOutputStream path(256); + path << g_strAppPath.c_str() << "bitmaps/"; + BitmapsPath_set(path.c_str()); } - g_strTempPath += "\\RadiantSettings\\"; - Q_mkdir(g_strTempPath.GetBuffer(), 0755); - g_strTempPath += RADIANT_VERSION; - g_strTempPath += "\\"; - Q_mkdir(g_strTempPath.GetBuffer(), 0755); - } - else - { - // use the core path as temp (to save commandlist.txt, and do the .pid files) - g_strTempPath = g_strAppPath; - } - -#endif -#if defined (__linux__) || defined (__APPLE__) - Str home; - home = g_get_home_dir (); - AddSlash (home); - home += ".radiant/"; - Q_mkdir (home.GetBuffer (), 0775); - home += RADIANT_VERSION; - Q_mkdir (home.GetBuffer (), 0775); - g_strTempPath = home.GetBuffer (); - AddSlash (g_strTempPath); - - loki_initpaths(argv[0]); - - // NOTE: we build g_strAppPath with a '/' (or '\' on WIN32) - // it's a general convention in Radiant to have the slash at the end of directories - char real[PATH_MAX]; - realpath (loki_getdatapath(), real); - if (real[strlen(real)-1] != '/') - strcat(real, "/"); - - g_strAppPath = real; - - // radiant is installed in the parent dir of "tools/" - // NOTE: this is not very easy for debugging - // maybe add options to lookup in several places? - // (for now I had to create symlinks) - g_strBitmapsPath = g_strAppPath; - g_strBitmapsPath += "bitmaps/"; - - // we will set this right after the game selection is done - g_strGameToolsPath = g_strAppPath; + // we will set this right after the game selection is done + g_strGameToolsPath = g_strAppPath; +} -#endif +bool check_version_file(const char *filename, const char *version) +{ + TextFileInputStream file(filename); + if (!file.failed()) { + char buf[10]; + buf[file.read(buf, 9)] = '\0'; + + // chomp it (the hard way) + int chomp = 0; + while (buf[chomp] >= '0' && buf[chomp] <= '9') { + chomp++; + } + buf[chomp] = '\0'; - // init the DTD path - g_strDTDPath = g_strAppPath; - g_strDTDPath += "dtds/"; - - /*! - the global prefs loading / game selection dialog might fail for any reason we don't know about - we need to catch when it happens, to cleanup the stateful prefs which might be killing it - and to turn on console logging for lookup of the problem - this is the first part of the two step .pid system - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 - */ - g_pidFile = g_strTempPath.GetBuffer (); - g_pidFile += "radiant.pid"; - - FILE *pid; - pid = fopen( g_pidFile.GetBuffer(), "r" ); - if ( pid != NULL ) { - fclose (pid); - CString msg; - - if (remove (g_pidFile.GetBuffer ()) == -1) - { - msg = "WARNING: Could not delete "; msg += g_pidFile; - gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); + return string_equal(buf, version); } + return false; +} - // in debug, never prompt to clean registry, turn console logging auto after a failed start -#if !defined(_DEBUG) - msg = "Found the file "; - msg += g_pidFile; - msg += ".\nThis indicates that Radiant failed during the game selection startup last time it was run.\n" - "Choose YES to clean Radiant's registry settings and shut down Radiant.\n" - "WARNING: the global prefs will be lost if you choose YES."; - - if (gtk_MessageBox (NULL, msg, "Radiant - Reset global startup?", MB_YESNO | MB_ICONQUESTION) == IDYES) - { - // remove global prefs and shutdown - g_PrefsDlg.mGamesDialog.Reset(); - // remove the prefs file (like a full reset of the registry) - //remove (g_PrefsDlg.m_inipath->str); - gtk_MessageBox(NULL, "Removed global settings, choose OK to close Radiant.", "Radiant", MB_OK ); - _exit(-1); +bool check_version() +{ + // a safe check to avoid people running broken installations + // (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing) + // make something idiot proof and someone will make better idiots, this may be overkill + // let's leave it disabled in debug mode in any case + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431 + if (GDEF_DEBUG) { + return true; } - msg = "Logging console output to "; - msg += g_strTempPath; - msg += "radiant.log\nRefer to the log if Radiant fails to start again."; - - gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK); -#endif - - // set without saving, the class is not in a coherent state yet - // just do the value change and call to start logging, CGamesDialog will pickup when relevant - g_PrefsDlg.mGamesDialog.m_bLogConsole = true; - g_PrefsDlg.mGamesDialog.m_bForceLogConsole = true; - Sys_LogFile(); - } - - // create a primary .pid for global init run - pid = fopen( g_pidFile.GetBuffer(), "w" ); - if ( pid ) { - fclose( pid ); - } - - // a safe check to avoid people running broken installations - // (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing) - // make something idiot proof and someone will make better idiots, this may be overkill - // let's leave it disabled in debug mode in any case - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431 -#ifndef _DEBUG - //#define CHECK_VERSION -#endif -#ifdef CHECK_VERSION - // locate and open RADIANT_MAJOR and RADIANT_MINOR - qboolean bVerIsGood = true; - Str ver_file_name; - ver_file_name = g_strAppPath; - ver_file_name += "RADIANT_MAJOR"; - FILE *ver_file = fopen (ver_file_name.GetBuffer(), "r"); - if (ver_file) - { - char buf[10]; - int chomp; - fread(buf, 1, 10, ver_file); - // chomp it (the hard way) - chomp = 0; - while(buf[chomp] >= '0' && buf[chomp] <= '9') - chomp++; - buf[chomp] = '\0'; - if (strcmp(buf, RADIANT_MAJOR_VERSION)) + // locate and open RADIANT_MAJOR and RADIANT_MINOR + bool bVerIsGood = true; { - Sys_Printf("ERROR: file RADIANT_MAJOR doesn't match ('%s')\n", buf); - bVerIsGood = false; + StringOutputStream ver_file_name(256); + ver_file_name << AppPath_get() << "RADIANT_MAJOR"; + bVerIsGood = check_version_file(ver_file_name.c_str(), RADIANT_MAJOR_VERSION); } - } - else - { - Sys_Printf("ERROR: can't find RADIANT_MAJOR in '%s'\n", ver_file_name.GetBuffer()); - bVerIsGood = false; - } - ver_file_name = g_strAppPath; - ver_file_name += "RADIANT_MINOR"; - ver_file = fopen (ver_file_name.GetBuffer(), "r"); - if (ver_file) - { - char buf[10]; - int chomp; - fread(buf, 1, 10, ver_file); - // chomp it (the hard way) - chomp = 0; - while(buf[chomp] >= '0' && buf[chomp] <= '9') - chomp++; - buf[chomp] = '\0'; - if (strcmp(buf, RADIANT_MINOR_VERSION)) { - Sys_Printf("ERROR: file RADIANT_MINOR doesn't match ('%s')\n", buf); - bVerIsGood = false; + StringOutputStream ver_file_name(256); + ver_file_name << AppPath_get() << "RADIANT_MINOR"; + bVerIsGood = check_version_file(ver_file_name.c_str(), RADIANT_MINOR_VERSION); } - } - else - { - Sys_Printf("ERROR: can't find RADIANT_MINOR in '%s'\n", ver_file_name.GetBuffer()); - bVerIsGood = false; - } - if (!bVerIsGood) - { - CString msg; - msg = "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n"; - msg += "Make sure you run the right/latest editor binary you installed\n"; - msg += g_strAppPath; msg += "\n"; - msg += "Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information"; - gtk_MessageBox(NULL, msg.GetBuffer(), "Radiant", MB_OK, "http://www.qeradiant.com/faq/index.cgi?file=219"); - _exit(-1); - } -#endif - g_qeglobals.disable_ini = false; - g_PrefsDlg.Init(); - - // close the primary - if ( remove( g_pidFile.GetBuffer () ) == -1 ) { - CString msg; - msg = "WARNING: Could not delete "; msg += g_pidGameFile; - gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); - } - - /*! - now the secondary game dependant .pid file - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 - */ - g_pidGameFile = g_PrefsDlg.m_rc_path->str; - g_pidGameFile += "radiant-game.pid"; - - pid = fopen (g_pidGameFile.GetBuffer(), "r"); - if (pid != NULL) - { - fclose (pid); - CString msg; - if (remove (g_pidGameFile.GetBuffer ()) == -1) - { - msg = "WARNING: Could not delete "; msg += g_pidGameFile; - gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); + if (!bVerIsGood) { + StringOutputStream msg(256); + msg + << "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n" + "Make sure you run the right/latest editor binary you installed\n" + << AppPath_get(); + ui::alert(ui::root, msg.c_str(), "Radiant", ui::alert_type::OK, ui::alert_icon::Default); } + return bVerIsGood; +} - msg = "Found the file "; - msg += g_pidGameFile; - msg += ".\nThis indicates that Radiant failed to load the last time it was run.\n" - "Choose YES to clean Radiant's registry settings and shut down Radiant.\n" - "WARNING: preferences will be lost if you choose YES."; +void create_global_pid() +{ + /*! + the global prefs loading / game selection dialog might fail for any reason we don't know about + we need to catch when it happens, to cleanup the stateful prefs which might be killing it + and to turn on console logging for lookup of the problem + this is the first part of the two step .pid system + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 + */ + StringOutputStream g_pidFile(256); ///< the global .pid file (only for global part of the startup) - // in debug, never prompt to clean registry, turn console logging auto after a failed start -#if !defined(_DEBUG) - //bleh - if (gtk_MessageBox (NULL, msg, "Radiant - Clean Registry?", MB_YESNO | MB_ICONQUESTION) == IDYES) - { - // remove the game prefs files - remove (g_PrefsDlg.m_inipath->str); - char buf[PATH_MAX]; - sprintf(buf, "%sSavedInfo.bin", g_PrefsDlg.m_rc_path->str); - remove(buf); - // remove the global pref too - g_PrefsDlg.mGamesDialog.Reset(); - gtk_MessageBox(NULL, "Cleaned registry settings, choose OK to close Radiant.\nThe next time Radiant runs it will use default settings.", "Radiant", MB_OK ); - _exit(-1); - } - msg = "Logging console output to "; - msg += g_strTempPath; - msg += "radiant.log\nRefer to the log if Radiant fails to start again."; + g_pidFile << SettingsPath_get() << "radiant.pid"; - gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK); -#endif + FILE *pid; + pid = fopen(g_pidFile.c_str(), "r"); + if (pid != 0) { + fclose(pid); - // force console logging on! (will go in prefs too) - g_PrefsDlg.mGamesDialog.m_bLogConsole = true; - g_PrefsDlg.mGamesDialog.SavePrefs(); - Sys_LogFile(); + if (remove(g_pidFile.c_str()) == -1) { + StringOutputStream msg(256); + msg << "WARNING: Could not delete " << g_pidFile.c_str(); + ui::alert(ui::root, msg.c_str(), "Radiant", ui::alert_type::OK, ui::alert_icon::Error); + } - g_PrefsDlg.LoadPrefs(); + // in debug, never prompt to clean registry, turn console logging auto after a failed start + if (!GDEF_DEBUG) { + StringOutputStream msg(256); + msg << "Radiant failed to start properly the last time it was run.\n" + "The failure may be related to current global preferences.\n" + "Do you want to reset global preferences to defaults?"; - } else - { - // create one, will remove right after entering message loop - pid = fopen (g_pidGameFile.GetBuffer(), "w"); - if (pid) - fclose (pid); + if (ui::alert(ui::root, msg.c_str(), "Radiant - Startup Failure", ui::alert_type::YESNO, + ui::alert_icon::Question) == ui::alert_response::YES) { + g_GamesDialog.Reset(); + } - g_PrefsDlg.LoadPrefs(); + msg.clear(); + msg << "Logging console output to " << SettingsPath_get() + << "radiant.log\nRefer to the log if Radiant fails to start again."; -#ifndef _DEBUG // I can't be arsed about that prompt in debug mode - // if console logging is on in the prefs, warn about performance hit - if (g_PrefsDlg.mGamesDialog.m_bLogConsole) - { - if (gtk_MessageBox (NULL, "Preferences indicate that console logging is on. This affects performance.\n" - "Turn it off?", "Radiant", MB_YESNO | MB_ICONQUESTION) == IDYES) - { - g_PrefsDlg.mGamesDialog.m_bLogConsole = false; - g_PrefsDlg.mGamesDialog.SavePrefs(); - } + ui::alert(ui::root, msg.c_str(), "Radiant - Console Log", ui::alert_type::OK); + } + + // set without saving, the class is not in a coherent state yet + // just do the value change and call to start logging, CGamesDialog will pickup when relevant + g_GamesDialog.m_bForceLogConsole = true; + Sys_LogFile(true); } -#endif - // toggle console logging if necessary - Sys_LogFile(); - } - - // FIXME http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 - // we should search in g_strTempPath, then move over to look at g_strAppPath? -#ifdef _WIN32 - // fine tune the look of the app using a gtk rc file - // we try to load an RC file placed in the application directory - // build the full path - Str sRCFile; - sRCFile = g_strAppPath; - sRCFile += "radiantgtkrc"; - // we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\' - pBuffer = (char *)sRCFile.GetBuffer(); - for (i=0; imGameFile.c_str() << "/radiant-game.pid"; + + FILE *pid = fopen(g_pidGameFile.c_str(), "r"); + if (pid != 0) { + fclose(pid); + if (remove(g_pidGameFile.c_str()) == -1) { + StringOutputStream msg; + msg << "WARNING: Could not delete " << g_pidGameFile.c_str(); + ui::alert(ui::root, msg.c_str(), "Radiant", ui::alert_type::OK, ui::alert_icon::Error); + } - // redirect Gtk warnings to the console - g_log_set_handler( "Gdk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING| - G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL); - g_log_set_handler( "Gtk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING| - G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, NULL); + // in debug, never prompt to clean registry, turn console logging auto after a failed start + if (!GDEF_DEBUG) { + StringOutputStream msg; + msg << "Radiant failed to start properly the last time it was run.\n" + "The failure may be caused by current preferences.\n" + "Do you want to reset all preferences to defaults?"; - // spog - creates new filters list for the first time - g_qeglobals.d_savedinfo.filters = NULL; - g_qeglobals.d_savedinfo.filters = FilterUpdate(g_qeglobals.d_savedinfo.filters); + if (ui::alert(ui::root, msg.c_str(), "Radiant - Startup Failure", ui::alert_type::YESNO, + ui::alert_icon::Question) == ui::alert_response::YES) { + Preferences_Reset(); + } - g_pParentWnd = new MainFrame(); + msg.clear(); + msg << "Logging console output to " << SettingsPath_get() + << "radiant.log\nRefer to the log if Radiant fails to start again."; - if ( g_PrefsDlg.m_bLoadLastMap && g_PrefsDlg.m_strLastMap.GetLength() > 0 ) { - Map_LoadFile(g_PrefsDlg.m_strLastMap.GetBuffer()); - } else { - Map_New(); - } + ui::alert(ui::root, msg.c_str(), "Radiant - Console Log", ui::alert_type::OK); + } - // load up shaders now that we have the map loaded - // eviltypeguy - Texture_ShowStartupShaders(); + // force console logging on! (will go in prefs too) + g_GamesDialog.m_bForceLogConsole = true; + Sys_LogFile(true); + } else { + // create one, will remove right after entering message loop + pid = fopen(g_pidGameFile.c_str(), "w"); + if (pid) { + fclose(pid); + } + } +} -#ifndef SKIP_SPLASH - gdk_window_raise(splash_screen->window); - gtk_window_set_transient_for( GTK_WINDOW( splash_screen ), GTK_WINDOW( g_pParentWnd->m_pWidget ) ); - gtk_timeout_add( 1000, try_destroy_splash, NULL ); -#endif - g_pParentWnd->GetSynapseServer().DumpActiveClients(); +/*! + now the secondary game dependant .pid file + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 + */ +void remove_local_pid() +{ + StringOutputStream g_pidGameFile(256); + g_pidGameFile << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << "/radiant-game.pid"; + remove(g_pidGameFile.c_str()); +} - //++timo: temporary debug - g_pParentWnd->DoWatchBSP(); +void user_shortcuts_init() +{ + StringOutputStream path(256); + path << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << '/'; + LoadCommandMap(path.c_str()); + SaveCommandMap(path.c_str()); +} - gtk_main(); +void user_shortcuts_save() +{ + StringOutputStream path(256); + path << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << '/'; + SaveCommandMap(path.c_str()); +} - // close the log file if any - // NOTE: don't save prefs past this point! - g_PrefsDlg.mGamesDialog.m_bLogConsole = false; - // set the console window to NULL to avoid Sys_Printf crashing - g_qeglobals_gui.d_edit = NULL; - Sys_LogFile(); +int main(int argc, char *argv[]) +{ + crt_init(); - // NOTE TTimo not sure what this _exit(0) call is worth - // restricting it to linux build -#ifdef __linux__ - _exit( 0 ); + streams_init(); + +#if GDEF_OS_WINDOWS + HMODULE lib; + lib = LoadLibrary( "dwmapi.dll" ); + if ( lib != 0 ) { + void ( WINAPI *qDwmEnableComposition )( bool bEnable ) = ( void (WINAPI *) ( bool bEnable ) )GetProcAddress( lib, "DwmEnableComposition" ); + if ( qDwmEnableComposition ) { + qDwmEnableComposition( FALSE ); + } + FreeLibrary( lib ); + } #endif - return 0; -} -// ydnar: quick and dirty fix, just make the buffer bigger -#define BIG_PATH_MAX 4096 + const char *mapname = NULL; + char const *error = NULL; + if (!ui::init(&argc, &argv, "", &error)) { + g_print("%s\n", error); + return -1; + } -// TTimo: decompose the BSP command into several steps so we can monitor them eventually -void QE_ExpandBspString (char *bspaction, GPtrArray *out_array, char *mapname) -{ - const char *in; - char *out; - char src[BIG_PATH_MAX]; - char rsh[BIG_PATH_MAX]; - char base[BIG_PATH_MAX]; - - strcpy(src, mapname); - strlwr(src); - in = strstr(src, "maps/"); - if (!in) - { - in = strstr(src, "maps/"); - } - if (in) - { - in += 5; - strcpy(base, in); - out = base; - while (*out) - { - if (*out == '\\') - { - *out = '/'; - } - out++; + // Gtk already removed parsed `--options` + if (argc == 2) { + if (strlen(argv[1]) > 1) { + if (g_str_has_suffix(argv[1], ".map")) { + if (g_path_is_absolute(argv[1])) { + mapname = argv[1]; + } else { + mapname = g_build_filename(g_get_current_dir(), argv[1], NULL); + } + } else { + g_print("bad file name, will not load: %s\n", argv[1]); + } + } + } else if (argc > 2) { + g_print("%s\n", "too many arguments"); + return -1; } - } else - { - ExtractFileName (mapname, base); - } - - // this important step alters the map name to add fs_game - // NOTE: it used to add fs_basepath too - // the fs_basepath addition moved to being in the project file during the bug fixing rush - // but it may not have been the right thing to do - - // HACK: halflife compiler tools don't support -fs_game - // HACK: neither does JKII/SoF2/ etc.. - // do we use & have fs_game? - - if (g_pGameDescription->mGameFile != "hl.game" && - *ValueForKey(g_qeglobals.d_project_entity,"gamename") != '\0') - { - // set with fs_game - sprintf(src, "-fs_game %s \"%s\"", ValueForKey(g_qeglobals.d_project_entity,"gamename"), mapname); + + // redirect Gtk warnings to the console + g_log_set_handler("Gdk", (GLogLevelFlags) (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | + G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | + G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), error_redirect, 0); + g_log_set_handler("Gtk", (GLogLevelFlags) (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | + G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | + G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), error_redirect, 0); + g_log_set_handler("GtkGLExt", (GLogLevelFlags) (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | + G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | + G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), error_redirect, 0); + g_log_set_handler("GLib", (GLogLevelFlags) (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | + G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | + G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), error_redirect, 0); + g_log_set_handler(0, (GLogLevelFlags) (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | + G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | + G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), error_redirect, 0); + + GlobalDebugMessageHandler::instance().setHandler(GlobalPopupDebugMessageHandler::instance()); + + environment_init(argc, (char const **) argv); + + paths_init(); + + if (!check_version()) { + return EXIT_FAILURE; } - else - { - sprintf(src, "\"%s\"", mapname); - } - rsh[0] = 0; + show_splash(); - QE_ConvertDOSToUnixName(src, src); + create_global_pid(); - // initialise the first step - out = new char[BIG_PATH_MAX]; //% PATH_MAX - g_ptr_array_add( out_array, out ); + GlobalPreferences_Init(); - in = ValueForKey( g_qeglobals.d_project_entity, bspaction ); - while (*in) - { - if (in[0] == '!') - { - strcpy (out, rsh); - out += strlen(rsh); - in++; - continue; - } - if (in[0] == '#') - { - char tmp[2048]; - // we process these only if monitoring - if (g_PrefsDlg.m_bWatchBSP) - { - // -connect global option (the only global option so far anyway) - strcpy (tmp, " -connect 127.0.0.1:39000 "); - strcpy (out, tmp); - out += strlen(tmp); - } - in++; - continue; - } - if (in[0] == '$') - { - // $ expansion - strcpy (out, src); - out += strlen(src); - in++; - continue; - } - if (in[0] == '@') - { - *out++ = '"'; - in++; - continue; + g_GamesDialog.Init(); + + g_strGameToolsPath = g_pGameDescription->mGameToolsPath; + + remove_global_pid(); + + g_Preferences.Init(); // must occur before create_local_pid() to allow preferences to be reset + + create_local_pid(); + + // in a very particular post-.pid startup + // we may have the console turned on and want to keep it that way + // so we use a latching system + if (g_GamesDialog.m_bForceLogConsole) { + Sys_LogFile(true); + g_Console_enableLogging = true; + g_GamesDialog.m_bForceLogConsole = false; } - if (in[0] == '&') - if (in[1] == '&') - { - // start a new step - *out = 0; - in = in + 2; - out = new char[BIG_PATH_MAX]; //% PATH_MAX - g_ptr_array_add( out_array, out ); - } - *out++ = *in++; - } - *out = 0; -} -void FindReplace(CString& strContents, const char* pTag, const char* pValue) -{ - if (strcmp(pTag, pValue) == 0) - return; - for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag)) - { - int nRightLen = strContents.GetLength() - strlen(pTag) - nPos; - CString strLeft = strContents.Left(nPos); - CString strRight = strContents.Right(nRightLen); - strLeft += pValue; - strLeft += strRight; - strContents = strLeft; - } -} -// save the map, deals with regioning -void SaveWithRegion(char *name) -{ - strcpy (name, currentmap); - if (region_active) - { - // temporary cut the region to save regular map - region_active = false; - Map_SaveFile (name, false); - region_active = true; - StripExtension (name); - strcat (name, ".reg"); - } - - Map_SaveFile (name, region_active); -} + Radiant_Initialise(); -void RunBsp (char *command) -{ - GPtrArray *sys; - char batpath[BIG_PATH_MAX]; //% PATH_MAX - char temppath[BIG_PATH_MAX]; //% PATH_MAX - char name[BIG_PATH_MAX]; //% PATH_MAX - char cWork[BIG_PATH_MAX]; //% PATH_MAX - FILE *hFile; - unsigned int i; - - SetInspectorMode(W_CONSOLE); - - strcpy (temppath, g_strTempPath.GetBuffer ()); - - SaveWithRegion(name); - - const char *rsh = ValueForKey(g_qeglobals.d_project_entity, "rshcmd"); - if (rsh == NULL) - { - CString strPath, strFile; - - ExtractPath_and_Filename(name, strPath, strFile); - AddSlash(strPath); - strncpy(cWork, strPath, 1024); - strcat(cWork, strFile); - } else - { - strcpy(cWork, name); - } - - // get the array ready - //++timo TODO: free the array, free the strings ourselves with delete[] - sys = g_ptr_array_new(); - - QE_ExpandBspString (command, sys, cWork); - - if (g_PrefsDlg.m_bWatchBSP) - { - // grab the file name for engine running - char *bspname = new char[1024]; - ExtractFileName( currentmap, bspname ); - StripExtension( bspname ); - g_pParentWnd->GetWatchBSP()->DoMonitoringLoop( sys, bspname ); - } else - { - // write all the steps in a single BAT / .sh file and run it, don't bother monitoring it - CString strSys; - for (i=0; i < sys->len; i++ ) - { - strSys += (char *)g_ptr_array_index( sys, i); -#ifdef _WIN32 // write temp\junk.txt in win32... NOTE: stops output to shell prompt window - if (i==0) - strSys += " >"; - else - strSys += " >>"; - strSys += "\""; - strSys += temppath; - strSys += "junk.txt\""; -#endif - strSys += "\n"; - }; - -#if defined (__linux__) || defined (__APPLE__) - - // write qe3bsp.sh - sprintf (batpath, "%sqe3bsp.sh", temppath); - Sys_Printf("Writing the compile script to '%s'\n", batpath); - Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath); - hFile = fopen(batpath, "w"); - if (!hFile) - Error ("Can't write to %s", batpath); - fprintf (hFile, "#!/bin/sh \n\n"); - fprintf (hFile, strSys.GetBuffer()); - fclose (hFile); - chmod (batpath, 0744); -#endif + user_shortcuts_init(); -#ifdef _WIN32 - sprintf (batpath, "%sqe3bsp.bat", temppath); - Sys_Printf("Writing the compile script to '%s'\n", batpath); - Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath); - hFile = fopen(batpath, "w"); - if (!hFile) - Error ("Can't write to %s", batpath); - fprintf (hFile, strSys.GetBuffer()); - fclose (hFile); -#endif + OpenGLBinding &GL = GlobalOpenGLModule::getTable(); + g_pParentWnd = new MainFrame(GL); + + hide_splash(); - Pointfile_Delete (); + if (mapname != NULL) { + Map_LoadFile(mapname); + } else if (g_bLoadLastMap && !g_strLastMap.empty()) { + Map_LoadFile(g_strLastMap.c_str()); + } else { + Map_New(); + } -#if defined (__linux__) || defined (__APPLE__) + // load up shaders now that we have the map loaded + // eviltypeguy + TextureBrowser_ShowStartupShaders(GlobalTextureBrowser()); - pid_t pid; - pid = fork (); - switch (pid) - { - case -1: - Error ("CreateProcess failed"); - break; - case 0: - execlp (batpath, batpath, NULL); - printf ("execlp error !"); - _exit (0); - break; - default: - break; + remove_local_pid(); + + ui::main(); + + // avoid saving prefs when the app is minimized + if (g_pParentWnd->IsSleeping()) { + globalOutputStream() << "Shutdown while sleeping, not saving prefs\n"; + g_preferences_globals.disable_ini = true; } -#endif -#ifdef _WIN32 - Sys_Printf ("Running bsp command...\n"); - Sys_Printf ("\n%s\n", strSys.GetBuffer()); + Map_Free(); - WinExec( batpath, SW_SHOWNORMAL ); -#endif - } -#ifdef _DEBUG - // yeah, do it .. but not now right before 1.1-TA-beta release - Sys_Printf("TODO: erase GPtrArray\n"); -#endif -} + if (!Map_Unnamed(g_map)) { + g_strLastMap = Map_Name(g_map); + } -#if 0 + delete g_pParentWnd; -#ifdef _WIN32 + user_shortcuts_save(); -int WINAPI QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer ) -{ - static PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd - 1, // version number - PFD_DRAW_TO_WINDOW | // support window - PFD_SUPPORT_OPENGL | // support OpenGL - PFD_DOUBLEBUFFER, // double buffered - PFD_TYPE_RGBA, // RGBA type - 24, // 24-bit color depth - 0, 0, 0, 0, 0, 0, // color bits ignored - 0, // no alpha buffer - 0, // shift bit ignored - 0, // no accumulation buffer - 0, 0, 0, 0, // accum bits ignored - 32, // depth bits - 0, // no stencil buffer - 0, // no auxiliary buffer - PFD_MAIN_PLANE, // main layer - 0, // reserved - 0, 0, 0 // layer masks ignored - }; // - int pixelformat = 0; - - zbuffer = true; - if ( !zbuffer ) - pfd.cDepthBits = 0; - - if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 ) - { - LPVOID lpMsgBuf; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL - ); - Sys_FPrintf (SYS_WRN, "GetLastError: %s", lpMsgBuf); - Error ("ChoosePixelFormat failed"); - } - - if (!SetPixelFormat(hDC, pixelformat, &pfd)) - Error ("SetPixelFormat failed"); - - return pixelformat; -} + Radiant_Shutdown(); -#endif + // close the log file if any + Sys_LogFile(false); -#endif + return EXIT_SUCCESS; +}