]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/qe3.cpp
Remove <gtk/gtk.h> from most of radiant/*
[xonotic/netradiant.git] / radiant / qe3.cpp
index 201154ecb48cc393494685fc1377c56c26ebd5b2..193a0a49c2e8edf740e6d551554f459c669b7379 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (C) 1999-2007 id Software, Inc. and contributors.
+   Copyright (C) 1999-2006 Id Software, Inc. and contributors.
    For a list of contributors, see the accompanying CONTRIBUTORS file.
 
    This file is part of GtkRadiant.
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+/*
+   The following source code is licensed by Id Software and subject to the terms of
+   its LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included with
+   GtkRadiant. If you did not receive a LIMITED USE SOFTWARE LICENSE AGREEMENT,
+   please contact Id Software immediately at info@idsoftware.com.
+ */
+
 //
 // Linux stuff
 //
 // Leonardo Zide (leo@lokigames.com)
 //
 
-#include "stdafx.h"
-#include <gtk/gtk.h>
-#include <sys/stat.h>
-#include "gtkmisc.h"
-#include <glib/gi18n.h>
-#if defined ( __linux__ ) || defined ( __APPLE__ )
-#include <unistd.h>
-#include <X11/keysym.h>
-#include <gdk/gdkx.h>
-#include <gdk/gdkprivate.h>
-#endif
-// for the logging part
-#include <fcntl.h>
-#include <sys/types.h>
-
-QEGlobals_t g_qeglobals;
-QEGlobals_GUI_t g_qeglobals_gui;
-
-// leo: Track memory allocations for debugging
-// NOTE TTimo this was never used and probably not relevant
-//   there are tools to do that
-#ifdef MEM_DEBUG
+#include "qe3.h"
 
-static GList *memblocks;
+#include "debugging/debugging.h"
 
-void* debug_malloc( size_t size, const char* file, int line ){
-       void *buf = g_malloc( size + 8 );
+#include "ifilesystem.h"
+//#include "imap.h"
 
-       *( (const char**)buf ) = file;
-       buf = (char*)buf + 4;
-       *( (int*)buf ) = line;
-       buf = (char*)buf + 4;
+#include <map>
 
-       memblocks = g_list_append( memblocks, buf );
+#include <uilib/uilib.h>
 
-       return buf;
-}
+#include "stream/textfilestream.h"
+#include "cmdlib.h"
+#include "stream/stringstream.h"
+#include "os/path.h"
+#include "scenelib.h"
 
-void debug_free( void *buf, const char* file, int line ){
-       const char *f;
-       int l;
+#include "gtkutil/messagebox.h"
+#include "error.h"
+#include "map.h"
+#include "build.h"
+#include "points.h"
+#include "camwindow.h"
+#include "mainframe.h"
+#include "preferences.h"
+#include "watchbsp.h"
+#include "autosave.h"
+#include "convert.h"
 
-       if ( g_list_find( memblocks, buf ) ) {
-               memblocks = g_list_remove( memblocks, buf );
+QEGlobals_t g_qeglobals;
 
-               buf = (char*)buf - 4;
-               l = *( (int*)buf );
-               buf = (char*)buf - 4;
-               f = *( (const char**)buf );
 
-               Sys_FPrintf( SYS_DBG, "free: %s %d", file, line );
-               Sys_FPrintf( SYS_DBG, " allocated: %s %d\n", f, l );
+#if defined( WIN32 )
+#define PATH_MAX 260
+#endif
 
-               g_free( buf );
-       }
-//  else
-//    free (buf); // from qmalloc, will leak unless we add this same hack to cmdlib
-}
 
-#endif
+void QE_InitVFS(){
+       // VFS initialization -----------------------
+       // we will call GlobalFileSystem().initDirectory, giving the directories to look in (for files in pk3's and for standalone files)
+       // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order
+       // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too
 
-vec_t Rad_rint( vec_t in ){
-       if ( g_PrefsDlg.m_bNoClamp ) {
-               return in;
-       }
-       else{
-               return (float)floor( in + 0.5 );
-       }
-}
+       const char* gamename = gamename_get();
+       const char* basegame = basegame_get();
+       const char* userRoot = g_qeglobals.m_userEnginePath.c_str();
+       const char* globalRoot = EnginePath_get();
 
-void WINAPI QE_CheckOpenGLForErrors( void ){
-       char strMsg[1024];
-       int i = qglGetError();
-       if ( i != GL_NO_ERROR ) {
-               if ( i == GL_OUT_OF_MEMORY ) {
-                       sprintf( strMsg, "OpenGL out of memory error %s\nDo you wish to save before exiting?", qgluErrorString( (GLenum)i ) );
-                       if ( gtk_MessageBox( g_pParentWnd->m_pWidget, strMsg, "Radiant Error", MB_YESNO ) == IDYES ) {
-                               Map_SaveFile( NULL, false );
-                       }
-                       _exit( 1 );
+       // if we have a mod dir
+       if ( !string_equal( gamename, basegame ) ) {
+               // ~/.<gameprefix>/<fs_game>
+               if ( userRoot ) {
+                       StringOutputStream userGamePath( 256 );
+                       userGamePath << userRoot << gamename << '/';
+                       GlobalFileSystem().initDirectory( userGamePath.c_str() );
                }
-               else
+
+               // <fs_basepath>/<fs_game>
                {
-                       Sys_Printf( "Warning: OpenGL Error %s\n", qgluErrorString( (GLenum)i ) );
+                       StringOutputStream globalGamePath( 256 );
+                       globalGamePath << globalRoot << gamename << '/';
+                       GlobalFileSystem().initDirectory( globalGamePath.c_str() );
                }
        }
-}
 
-// NOTE: don't this function, use VFS instead
-char *ExpandReletivePath( char *p ){
-       static char temp[1024];
-       const char  *base;
-
-       if ( !p || !p[0] ) {
-               return NULL;
-       }
-       if ( p[0] == '/' || p[0] == '\\' ) {
-               return p;
+       // ~/.<gameprefix>/<fs_main>
+       if ( userRoot ) {
+               StringOutputStream userBasePath( 256 );
+               userBasePath << userRoot << basegame << '/';
+               GlobalFileSystem().initDirectory( userBasePath.c_str() );
        }
 
-       base = ValueForKey( g_qeglobals.d_project_entity, "basepath" );
-       sprintf( temp, "%s/%s", base, p );
-       return temp;
-}
-
-char *copystring( char *s ){
-       char    *b;
-       b = (char*)malloc( strlen( s ) + 1 );
-       strcpy( b,s );
-       return b;
-}
-
-
-bool DoesFileExist( const char* pBuff, long& lSize ){
-       FileStream file;
-       if ( file.Open( pBuff, "r" ) ) {
-               lSize += file.GetLength();
-               file.Close();
-               return true;
+       // <fs_basepath>/<fs_main>
+       {
+               StringOutputStream globalBasePath( 256 );
+               globalBasePath << globalRoot << basegame << '/';
+               GlobalFileSystem().initDirectory( globalBasePath.c_str() );
        }
-       return false;
 }
 
+int g_numbrushes = 0;
+int g_numentities = 0;
 
-void Map_Snapshot(){
-       CString strMsg;
-
-       // I hope the modified flag is kept correctly up to date
-       if ( !modified ) {
-               return;
-       }
+void QE_UpdateStatusBar(){
+       char buffer[128];
+       sprintf( buffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities );
+       g_pParentWnd->SetStatusText( g_pParentWnd->m_brushcount_status, buffer );
+}
 
-       // we need to do the following
-       // 1. make sure the snapshot directory exists (create it if it doesn't)
-       // 2. find out what the lastest save is based on number
-       // 3. inc that and save the map
-       CString strOrgPath, strOrgFile;
-       ExtractPath_and_Filename( currentmap, strOrgPath, strOrgFile );
-       AddSlash( strOrgPath );
-       strOrgPath += "snapshots";
-       bool bGo = true;
-       struct stat Stat;
-       if ( stat( strOrgPath, &Stat ) == -1 ) {
-#ifdef _WIN32
-               bGo = ( _mkdir( strOrgPath ) != -1 );
-#endif
+SimpleCounter g_brushCount;
 
-#if defined ( __linux__ ) || defined ( __APPLE__ )
-               bGo = ( mkdir( strOrgPath,0755 ) != -1 );
-#endif
-       }
-       AddSlash( strOrgPath );
-       if ( bGo ) {
-               int nCount = 0;
-               long lSize = 0;
-               CString strNewPath;
-               strNewPath = strOrgPath;
-               strNewPath += strOrgFile;
-               CString strFile;
-               while ( bGo )
-               {
-                       char buf[PATH_MAX];
-                       sprintf( buf, "%s.%i", strNewPath.GetBuffer(), nCount );
-                       strFile = buf;
-                       bGo = DoesFileExist( strFile, lSize );
-                       nCount++;
-               }
-               // strFile has the next available slot
-               Map_SaveFile( strFile, false );
-               // it is still a modified map (we enter this only if this is a modified map)
-               Sys_SetTitle( currentmap );
-               Sys_MarkMapModified();
-               if ( lSize > 12 * 1024 * 1024 ) { // total size of saves > 4 mb
-                       Sys_Printf( "The snapshot files in %s total more than 4 megabytes. You might consider cleaning up.", strOrgPath.GetBuffer() );
-               }
-       }
-       else
-       {
-               strMsg.Format( "Snapshot save failed.. unabled to create directory\n%s", strOrgPath.GetBuffer() );
-               gtk_MessageBox( g_pParentWnd->m_pWidget, strMsg );
-       }
-       strOrgPath = "";
-       strOrgFile = "";
+void QE_brushCountChanged(){
+       g_numbrushes = int(g_brushCount.get() );
+       QE_UpdateStatusBar();
 }
-/*
-   ===============
-   QE_CheckAutoSave
-
-   If five minutes have passed since making a change
-   and the map hasn't been saved, save it out.
-   ===============
- */
 
+SimpleCounter g_entityCount;
 
-void QE_CheckAutoSave( void ){
-       static time_t s_start;
-       time_t now;
-       time( &now );
+void QE_entityCountChanged(){
+       g_numentities = int(g_entityCount.get() );
+       QE_UpdateStatusBar();
+}
 
-       if ( modified != 1 || !s_start ) {
-               s_start = now;
-               return;
+bool ConfirmModified( const char* title ){
+       if ( !Map_Modified( g_map ) ) {
+               return true;
        }
 
-       if ( ( now - s_start ) > ( 60 * g_PrefsDlg.m_nAutoSave ) ) {
-               if ( g_PrefsDlg.m_bAutoSave ) {
-                       CString strMsg;
-                       strMsg = g_PrefsDlg.m_bSnapShots ? "Autosaving snapshot..." : "Autosaving...";
-                       Sys_Printf( strMsg );
-                       Sys_Printf( "\n" );
-                       Sys_Status( strMsg,0 );
-
-                       // only snapshot if not working on a default map
-                       if ( g_PrefsDlg.m_bSnapShots && stricmp( currentmap, "unnamed.map" ) != 0 ) {
-                               Map_Snapshot();
-                       }
-                       else
-                       {
-                               Map_SaveFile( ValueForKey( g_qeglobals.d_project_entity, "autosave" ), false );
-                       }
-
-                       Sys_Status( "Autosaving...Saved.", 0 );
-                       modified = 2;
+       auto result = MainFrame_getWindow().alert( "The current map has changed since it was last saved.\nDo you want to save the current map before continuing?", title, ui::alert_type::YESNOCANCEL, ui::alert_icon::Question );
+       if ( result == ui::alert_response::CANCEL ) {
+               return false;
+       }
+       if ( result == ui::alert_response::YES ) {
+               if ( Map_Unnamed( g_map ) ) {
+                       return Map_SaveAs();
                }
                else
                {
-                       Sys_Printf( "Autosave skipped...\n" );
-                       Sys_Status( "Autosave skipped...", 0 );
+                       return Map_Save();
                }
-               s_start = now;
        }
+       return true;
 }
 
+void bsp_init(){
+       build_set_variable( "RadiantPath", AppPath_get() );
+       build_set_variable( "ExecutableType", RADIANT_EXECUTABLE );
+       build_set_variable( "EnginePath", EnginePath_get() );
+       build_set_variable( "UserEnginePath", g_qeglobals.m_userEnginePath.c_str() );
+       build_set_variable( "MonitorAddress", ( g_WatchBSP_Enabled ) ? "127.0.0.1:39000" : "" );
+       build_set_variable( "GameName", gamename_get() );
 
-// NOTE TTimo we don't like that BuildShortPathName too much
-//   the VFS provides a vfsCleanFileName which should perform the cleanup tasks
-//   in the long run I'd like to completely get rid of this
+       const char* mapname = Map_Name( g_map );
+       StringOutputStream name( 256 );
+       name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".bsp";
 
-// used to be disabled, but caused problems
-
-// can't work with long win32 names until the BSP commands are not working differently
-#ifdef _WIN32
-int BuildShortPathName( const char* pPath, char* pBuffer, int nBufferLen ){
-       char *pFile = NULL;
-       int nResult = GetFullPathName( pPath, nBufferLen, pBuffer, &pFile );
-       nResult = GetShortPathName( pPath, pBuffer, nBufferLen );
-       if ( nResult == 0 ) {
-               strcpy( pBuffer, pPath );               // Use long filename
-       }
-       return nResult;
+       build_set_variable( "MapFile", mapname );
+       build_set_variable( "BspFile", name.c_str() );
 }
-#endif
-
-#if defined ( __linux__ ) || defined ( __APPLE__ )
-int BuildShortPathName( const char* pPath, char* pBuffer, int nBufferLen ){
-       // remove /../ from directories
-       const char *scr = pPath; char *dst = pBuffer;
-       for ( int i = 0; ( i < nBufferLen ) && ( *scr != 0 ); i++ )
-       {
-               if ( *scr == '/' && *( scr + 1 ) == '.' && *( scr + 2 ) == '.' ) {
-                       scr += 3;
-                       while ( dst != pBuffer && *( --dst ) != '/' )
-                       {
-                               i--;
-                       }
-               }
-
-               *dst = *scr;
 
-               scr++; dst++;
-       }
-       *dst = 0;
-
-       return strlen( pBuffer );
+void bsp_shutdown(){
+       build_clear_variables();
 }
-#endif
-
-/*
-   const char *g_pPathFixups[]=
-   {
-   "basepath",
-   "autosave",
-   };
-
-   const int g_nPathFixupCount = sizeof(g_pPathFixups) / sizeof(const char*);
-
-   void QE_CheckProjectEntity()
-   {
-   char *pFile;
-   char pBuff[PATH_MAX];
-   char pNewPath[PATH_MAX];
-   for (int i = 0; i < g_nPathFixupCount; i++)
-   {
-    char *pPath = ValueForKey (g_qeglobals.d_project_entity, g_pPathFixups[i]);
-
-    strcpy (pNewPath, pPath);
-    if (pPath[0] != '\\' && pPath[0] != '/')
-      if (GetFullPathName(pPath, PATH_MAX, pBuff, &pFile))
-          strcpy (pNewPath, pBuff);
 
-    BuildShortPathName (pNewPath, pBuff, PATH_MAX);
-
-    // check it's not ending with a filename seperator
-    if (pBuff[strlen(pBuff)-1] == '/' || pBuff[strlen(pBuff)-1] == '\\')
-    {
-      Sys_FPrintf(SYS_WRN, "WARNING: \"%s\" path in the project file has an ending file seperator, fixing.\n", g_pPathFixups[i]);
-      pBuff[strlen(pBuff)-1]=0;
-    }
-
-    SetKeyValue(g_qeglobals.d_project_entity, g_pPathFixups[i], pBuff);
-   }
-   }
- */
-
-void HandleXMLError( void* ctxt, const char* text, ... ){
-       va_list argptr;
-       static char buf[32768];
-
-       va_start( argptr,text );
-       vsprintf( buf, text, argptr );
-       Sys_FPrintf( SYS_ERR, "XML %s\n", buf );
-       va_end( argptr );
+class ArrayCommandListener : public CommandListener
+{
+GPtrArray* m_array;
+public:
+ArrayCommandListener(){
+       m_array = g_ptr_array_new();
 }
-
-#define DTD_BUFFER_LENGTH 1024
-xmlDocPtr ParseXMLStream( IDataStream *stream, bool validate = false ){
-       xmlDocPtr doc = NULL;
-       bool wellFormed = false, valid = false;
-       int res, size = 1024;
-       char chars[1024];
-       xmlParserCtxtPtr ctxt;
-
-       //if(validate)
-       //  xmlDoValidityCheckingDefaultValue = 1;
-       //else
-       xmlDoValidityCheckingDefaultValue = 0;
-       xmlSetGenericErrorFunc( NULL, HandleXMLError );
-
-       // SPoG
-       // HACK: use AppPath to resolve DTD location
-       // do a buffer-safe string copy and concatenate
-       int i;
-       char* w;
-       const char* r;
-       char buf[DTD_BUFFER_LENGTH];
-
-       w = buf;
-       i = 0;
-       // copy
-       //assert(g_strAppPath.GetBuffer() != NULL);
-       for ( r = g_strAppPath.GetBuffer(); i < DTD_BUFFER_LENGTH && *r != '\0'; i++, r++ ) w[i] = *r;
-       // concatenate
-       for ( r = "dtds/"; i < DTD_BUFFER_LENGTH && *r != '\0'; i++, r++ ) w[i] = *r;
-       // terminate
-       w[i] = '\0';
-
-       if ( i == DTD_BUFFER_LENGTH ) {
-               HandleXMLError( NULL, "ERROR: buffer overflow: DTD path length too large\n" );
-               return NULL;
-       }
-
-       res = stream->Read( chars, 4 );
-       if ( res > 0 ) {
-               ctxt = xmlCreatePushParserCtxt( NULL, NULL, chars, res, buf );
-
-               while ( ( res = stream->Read( chars, size ) ) > 0 )
-               {
-                       xmlParseChunk( ctxt, chars, res, 0 );
-               }
-               xmlParseChunk( ctxt, chars, 0, 1 );
-               doc = ctxt->myDoc;
-
-               wellFormed = ( ctxt->wellFormed == 1 );
-               valid = ( ctxt->valid == 1 );
-
-               xmlFreeParserCtxt( ctxt );
-       }
-
-       if ( wellFormed && ( !validate || ( validate && valid ) ) ) {
-               return doc;
-       }
-
-       if ( doc != NULL ) {
-               xmlFreeDoc( doc );
-       }
-
-       return NULL;
+~ArrayCommandListener(){
+       g_ptr_array_free( m_array, TRUE );
 }
 
-xmlDocPtr ParseXMLFile( const char* filename, bool validate = false ){
-       FileStream stream;
-       if ( stream.Open( filename, "r" ) ) {
-               return ParseXMLStream( &stream, validate );
-       }
-
-       Sys_FPrintf( SYS_ERR, "Failed to open file: %s\n",filename );
-       return NULL;
+void execute( const char* command ){
+       g_ptr_array_add( m_array, g_strdup( command ) );
 }
 
-// copy a string r to a buffer w
-// replace $string as appropriate
-void ReplaceTemplates( char* w, const char* r ){
-       const char *p;
-       const char *__ENGINEPATH = "TEMPLATEenginepath";
-       const char *__USERHOMEPATH = "TEMPLATEuserhomepath";
-       const char *__TOOLSPATH = "TEMPLATEtoolspath";
-       const char *__BASEDIR = "TEMPLATEbasedir";
-       const char *__APPPATH = "TEMPLATEapppath";
-
-       // iterate through string r
-       while ( *r != '\0' )
-       {
-               // check for special character
-               if ( *r == '$' ) {
-                       if ( strncmp( r + 1, __ENGINEPATH, strlen( __ENGINEPATH ) ) == 0 ) {
-                               r += strlen( __ENGINEPATH ) + 1;
-                               p = g_pGameDescription->mEnginePath.GetBuffer();
-                       }
-                       else if ( strncmp( r + 1, __USERHOMEPATH, strlen( __USERHOMEPATH ) ) == 0 ) {
-                               r += strlen( __USERHOMEPATH ) + 1;
-                               p = g_qeglobals.m_strHomeGame.GetBuffer();
-                       }
-                       else if ( strncmp( r + 1, __BASEDIR, strlen( __BASEDIR ) ) == 0 ) {
-                               r += strlen( __BASEDIR ) + 1;
-                               p = g_pGameDescription->mBaseGame;
-                       }
-                       else if ( strncmp( r + 1, __TOOLSPATH, strlen( __TOOLSPATH ) ) == 0 ) {
-                               r += strlen( __TOOLSPATH ) + 1;
-                               p = g_strGameToolsPath.GetBuffer();
-                       }
-                       else if ( strncmp( r + 1, __APPPATH, strlen( __APPPATH ) ) == 0 ) {
-                               r += strlen( __APPPATH ) + 1;
-                               p = g_strAppPath.GetBuffer();
-                       }
-                       else
-                       {
-                               r++;
-                               p = "$";
-                       }
-
-                       while ( *p != '\0' ) *w++ = *p++;
-               }
-               else{ *w++ = *r++; }
-       }
-       *w = '\0';
+GPtrArray* array() const {
+       return m_array;
 }
+};
 
-/*
-   ===========
-   QE_LoadProject
-   TODO TODO TODO (don't think this got fully merged in)
-   TTimo: added project file "version", version 2 adds '#' chars to the BSP command strings
-   version 3 was .. I don't remember .. version 4 adds q3map2 commands
-   TTimo: when QE_LoadProject is called, the prefs are updated with path to the latest project and saved on disk
-   ===========
- */
-/*\todo decide on a sensible location/name for project files.*/
-bool QE_LoadProject( const char *projectfile ){
-       char buf[1024];
-       xmlDocPtr doc;
-       xmlNodePtr node, project;
-
-       Sys_Printf( "Loading project file: \"%s\"\n", projectfile );
-       doc = ParseXMLFile( projectfile, true );
-
-       if ( doc == NULL ) {
-               return false;
-       }
-
-       node = doc->children;
-       while ( node != NULL && node->type != XML_DTD_NODE ) node = node->next;
-       if ( node == NULL || strcmp( (char*)node->name, "project" ) != 0 ) {
-               Sys_FPrintf( SYS_ERR, "ERROR: invalid file type\n" );
-               return false;
-       }
-
-       while ( node->type != XML_ELEMENT_NODE ) node = node->next;
-       // <project>
-       project = node;
-
-       if ( g_qeglobals.d_project_entity != NULL ) {
-               Entity_Free( g_qeglobals.d_project_entity );
-       }
-       g_qeglobals.d_project_entity = Entity_Alloc();
-
-       for ( node = project->children; node != NULL; node = node->next )
-       {
-               if ( node->type != XML_ELEMENT_NODE ) {
-                       continue;
-               }
-
-               // <key>
-               ReplaceTemplates( buf, (char*)node->properties->next->children->content );
-
-               SetKeyValue( g_qeglobals.d_project_entity, (char*)node->properties->children->content, buf );
-       }
-
-       xmlFreeDoc( doc );
-
-       // project file version checking
-       // add a version checking to avoid people loading later versions of the project file and bitching
-       int ver = IntForKey( g_qeglobals.d_project_entity, "version" );
-       if ( ver > PROJECT_VERSION ) {
-               char strMsg[1024];
-               sprintf( strMsg, "This is a version %d project file. This build only supports <=%d project files.\n"
-                                                "Please choose another project file or upgrade your version of Radiant.", ver, PROJECT_VERSION );
-               gtk_MessageBox( g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK );
-               // set the project file to nothing so we are sure we'll ask next time?
-               g_PrefsDlg.m_strLastProject = "";
-               g_PrefsDlg.SavePrefs();
-               return false;
-       }
-
-       // set here some default project settings you need
-       if ( strlen( ValueForKey( g_qeglobals.d_project_entity, "brush_primit" ) ) == 0 ) {
-               SetKeyValue( g_qeglobals.d_project_entity, "brush_primit", "0" );
-       }
-
-       g_qeglobals.m_bBrushPrimitMode = IntForKey( g_qeglobals.d_project_entity, "brush_primit" );
-
-       g_qeglobals.m_strHomeMaps = g_qeglobals.m_strHomeGame;
-       const char* str = ValueForKey( g_qeglobals.d_project_entity, "gamename" );
-       if ( str[0] == '\0' ) {
-               str = g_pGameDescription->mBaseGame.GetBuffer();
-       }
-       g_qeglobals.m_strHomeMaps += str;
-       g_qeglobals.m_strHomeMaps += '/';
-
-       // don't forget to create the dirs
-       Q_mkdir( g_qeglobals.m_strHomeGame.GetBuffer(), 0775 );
-       Q_mkdir( g_qeglobals.m_strHomeMaps.GetBuffer(), 0775 );
-
-       // usefull for the log file and debuggin fucked up configurations from users:
-       // output the basic information of the .qe4 project file
-       // SPoG
-       // all these paths should be unix format, with a trailing slash at the end
-       // if not.. to debug, check that the project file paths are set up correctly
-       Sys_Printf( "basepath    : %s\n", ValueForKey( g_qeglobals.d_project_entity, "basepath" ) );
-       Sys_Printf( "entitypath  : %s\n", ValueForKey( g_qeglobals.d_project_entity, "entitypath" ) );
-
-
-       // check whether user_project key exists..
-       // if not, save the current project under a new name
-       if ( ValueForKey( g_qeglobals.d_project_entity, "user_project" )[0] == '\0' ) {
-               Sys_Printf( "Loaded a template project file\n" );
-
-               // create the user_project key
-               SetKeyValue( g_qeglobals.d_project_entity, "user_project", "1" );
-
-               if ( IntForKey( g_qeglobals.d_project_entity, "version" ) != PROJECT_VERSION ) {
-                       char strMsg[2048];
-                       sprintf( strMsg,
-                                        "The template project '%s' has version %d. The editor binary is configured for version %d.\n"
-                                        "This indicates a problem in your setup.\n"
-                                        "I will keep going with this project till you fix this",
-                                        projectfile, IntForKey( g_qeglobals.d_project_entity, "version" ), PROJECT_VERSION );
-                       gtk_MessageBox( g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK );
-               }
+class BatchCommandListener : public CommandListener
+{
+TextOutputStream& m_file;
+std::size_t m_commandCount;
+const char* m_outputRedirect;
+public:
+BatchCommandListener( TextOutputStream& file, const char* outputRedirect ) : m_file( file ), m_commandCount( 0 ), m_outputRedirect( outputRedirect ){
+}
 
-               // create the writable project file path
-               strcpy( buf, g_qeglobals.m_strHomeGame.GetBuffer() );
-               strcat( buf, g_pGameDescription->mBaseGame.GetBuffer() );
-               strcat( buf, "/scripts/" );
-               // while the filename is already in use, increment the number we add to the end
-               int counter = 0;
-               char pUser[PATH_MAX];
-               while ( 1 )
-               {
-                       sprintf( pUser, "%suser%d." PROJECT_FILETYPE, buf, counter );
-                       counter++;
-                       if ( access( pUser, R_OK ) != 0 ) {
-                               // this is the one
-                               strcpy( buf, pUser );
-                               break;
-                       }
-               }
-               // saving project will cause a save prefs
-               g_PrefsDlg.m_strLastProject = buf;
-               g_PrefsDlg.m_nLastProjectVer = IntForKey( g_qeglobals.d_project_entity, "version" );
-               QE_SaveProject( buf );
+void execute( const char* command ){
+       m_file << command;
+       if ( m_commandCount == 0 ) {
+               m_file << " > ";
        }
        else
        {
-               // update preferences::LastProject with path of this successfully-loaded project
-               // save preferences
-               Sys_Printf( "Setting current project in prefs to \"%s\"\n", g_PrefsDlg.m_strLastProject.GetBuffer() );
-               g_PrefsDlg.m_strLastProject = projectfile;
-               g_PrefsDlg.SavePrefs();
+               m_file << " >> ";
        }
-
-       return true;
+       m_file << "\"" << m_outputRedirect << "\"";
+       m_file << "\n";
+       ++m_commandCount;
 }
+};
 
-/*
-   ===========
-   QE_SaveProject
-   TTimo: whenever QE_SaveProject is called, prefs are updated and saved with the path to the project
-   ===========
- */
-qboolean QE_SaveProject( const char* filename ){
-       Sys_Printf( "Save project file '%s'\n", filename );
-
-       xmlNodePtr node;
-       xmlDocPtr doc = xmlNewDoc( (xmlChar *)"1.0" );
-       // create DTD node
-       xmlCreateIntSubset( doc, (xmlChar *)"project", NULL, (xmlChar *)"project.dtd" );
-       // create project node
-       doc->children->next = xmlNewDocNode( doc, NULL, (xmlChar *)"project", NULL );
-
-       for ( epair_t* epair = g_qeglobals.d_project_entity->epairs; epair != NULL; epair = epair->next )
-       {
-               node = xmlNewChild( doc->children->next, NULL, (xmlChar *)"key", NULL );
-               xmlSetProp( node, (xmlChar*)"name", (xmlChar*)epair->key );
-               xmlSetProp( node, (xmlChar*)"value", (xmlChar*)epair->value );
-       }
+bool Region_cameraValid(){
+       Vector3 vOrig( vector3_snapped( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ) ) );
 
-       CreateDirectoryPath( filename );
-       if ( xmlSaveFormatFile( filename, doc, 1 ) != -1 ) {
-               xmlFreeDoc( doc );
-               Sys_Printf( "Setting current project in prefs to \"%s\"\n", filename );
-               g_PrefsDlg.m_strLastProject = filename;
-               g_PrefsDlg.SavePrefs();
-               return TRUE;
-       }
-       else
+       for ( int i = 0 ; i < 3 ; i++ )
        {
-               xmlFreeDoc( doc );
-               Sys_FPrintf( SYS_ERR, "failed to save project file: \"%s\"\n", filename );
-               return FALSE;
+               if ( vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i] ) {
+                       return false;
+               }
        }
+       return true;
 }
 
 
-
-/*
-   ===========
-   QE_KeyDown
-   ===========
- */
-#define SPEED_MOVE  32
-#define SPEED_TURN  22.5
-
-
-/*
-   ===============
-   ConnectEntities
-
-   Sets target / targetname on the two entities selected
-   from the first selected to the secon
-   ===============
- */
-void ConnectEntities( void ){
-       entity_t    *e1, *e2;
-       const char      *target;
-       char        *newtarg = NULL;
-
-       if ( g_qeglobals.d_select_count != 2 ) {
-               Sys_Status( "Must have two brushes selected", 0 );
-               Sys_Beep();
+void RunBSP( const char* name ){
+       // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503
+       // make sure we don't attempt to region compile a map with the camera outside the region
+       if ( region_active && !Region_cameraValid() ) {
+               globalErrorStream() << "The camera must be in the region to start a region compile.\n";
                return;
        }
 
-       e1 = g_qeglobals.d_select_order[0]->owner;
-       e2 = g_qeglobals.d_select_order[1]->owner;
-
-       if ( e1 == world_entity || e2 == world_entity ) {
-               Sys_Status( "Can't connect to the world", 0 );
-               Sys_Beep();
-               return;
-       }
+       SaveMap();
 
-       if ( e1 == e2 ) {
-               Sys_Status( "Brushes are from same entity", 0 );
-               Sys_Beep();
+       if ( Map_Unnamed( g_map ) ) {
+               globalOutputStream() << "build cancelled\n";
                return;
        }
 
-       target = ValueForKey( e1, "target" );
-       if ( target && target[0] ) {
-               newtarg = g_strdup( target );
-       }
-       else
-       {
-               target = ValueForKey( e2, "targetname" );
-               if ( target && target[0] ) {
-                       newtarg = g_strdup( target );
-               }
-               else{
-                       Entity_Connect( e1, e2 );
-               }
-       }
-
-       if ( newtarg != NULL ) {
-               SetKeyValue( e1, "target", newtarg );
-               SetKeyValue( e2, "targetname", newtarg );
-               g_free( newtarg );
+       if ( g_SnapShots_Enabled && !Map_Unnamed( g_map ) && Map_Modified( g_map ) ) {
+               Map_Snapshot();
        }
 
-       Sys_UpdateWindows( W_XY | W_CAMERA );
-
-       Select_Deselect();
-       Select_Brush( g_qeglobals.d_select_order[1] );
-}
-
-qboolean QE_SingleBrush( bool bQuiet ){
-       if ( ( selected_brushes.next == &selected_brushes )
-                || ( selected_brushes.next->next != &selected_brushes ) ) {
-               if ( !bQuiet ) {
-                       Sys_Printf( "Error: you must have a single brush selected\n" );
-               }
-               return false;
-       }
-       if ( selected_brushes.next->owner->eclass->fixedsize ) {
-               if ( !bQuiet ) {
-                       Sys_Printf( "Error: you cannot manipulate fixed size entities\n" );
-               }
-               return false;
+       if ( region_active ) {
+               const char* mapname = Map_Name( g_map );
+               StringOutputStream name( 256 );
+               name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".reg";
+               Map_SaveRegion( name.c_str() );
        }
 
-       return true;
-}
-
-void QE_InitVFS( void ){
-       // VFS initialization -----------------------
-       // we will call vfsInitDirectory, giving the directories to look in (for files in pk3's and for standalone files)
-       // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order
-       // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too
-       Str directory,prefabs;
+       Pointfile_Delete();
 
-       // TTimo: let's leave this to HL mode for now
-       if ( g_pGameDescription->mGameFile == "hl.game" ) {
-               // Hydra: we search the "gametools" path first so that we can provide editor
-               // specific pk3's wads and misc files for use by the editor.
-               // the relevant map compiler tools will NOT use this directory, so this helps
-               // to ensure that editor files are not used/required in release versions of maps
-               // it also helps keep your editor files all in once place, with the editor modules,
-               // plugins, scripts and config files.
-               // it also helps when testing maps, as you'll know your files won't/can't be used
-               // by the game engine itself.
+       bsp_init();
 
-               // <gametools>
-               directory = g_pGameDescription->mGameToolsPath;
-               vfsInitDirectory( directory.GetBuffer() );
+       if ( g_WatchBSP_Enabled ) {
+               ArrayCommandListener listener;
+               build_run( name, listener );
+               // grab the file name for engine running
+               const char* fullname = Map_Name( g_map );
+               StringOutputStream bspname( 64 );
+               bspname << StringRange( path_get_filename_start( fullname ), path_get_filename_base_end( fullname ) );
+               BuildMonitor_Run( listener.array(), bspname.c_str() );
        }
-
-       // NOTE TTimo about the mymkdir calls .. this is a bit dirty, but a safe thing on *nix
-
-       // if we have a mod dir
-       if ( *ValueForKey( g_qeglobals.d_project_entity, "gamename" ) != '\0' ) {
-
-#if defined ( __linux__ ) || defined ( __APPLE__ )
-               // ~/.<gameprefix>/<fs_game>
-               directory = g_qeglobals.m_strHomeGame.GetBuffer();
-               Q_mkdir( directory.GetBuffer(), 0775 );
-               directory += ValueForKey( g_qeglobals.d_project_entity, "gamename" );
-               Q_mkdir( directory.GetBuffer(), 0775 );
-               vfsInitDirectory( directory.GetBuffer() );
-               AddSlash( directory );
-               prefabs = directory;
-               // also create the maps dir, it will be used as prompt for load/save
-               directory += "/maps";
-               Q_mkdir( directory, 0775 );
-               // and the prefabs dir
-               prefabs += "/prefabs";
-               Q_mkdir( prefabs, 0775 );
-
+       else
+       {
+               char junkpath[PATH_MAX];
+               strcpy( junkpath, SettingsPath_get() );
+               strcat( junkpath, "junk.txt" );
+
+               char batpath[PATH_MAX];
+#if defined( POSIX )
+               strcpy( batpath, SettingsPath_get() );
+               strcat( batpath, "qe3bsp.sh" );
+#elif defined( WIN32 )
+               strcpy( batpath, SettingsPath_get() );
+               strcat( batpath, "qe3bsp.bat" );
+#else
+#error "unsupported platform"
 #endif
-
-               // <fs_basepath>/<fs_game>
-               directory = g_pGameDescription->mEnginePath;
-               directory += ValueForKey( g_qeglobals.d_project_entity, "gamename" );
-               Q_mkdir( directory.GetBuffer(), 0775 );
-               vfsInitDirectory( directory.GetBuffer() );
-               AddSlash( directory );
-               prefabs = directory;
-               // also create the maps dir, it will be used as prompt for load/save
-               directory += "/maps";
-               Q_mkdir( directory.GetBuffer(), 0775 );
-               // and the prefabs dir
-               prefabs += "/prefabs";
-               Q_mkdir( prefabs, 0775 );
-       }
-
-#if defined ( __linux__ ) || defined ( __APPLE__ )
-       // ~/.<gameprefix>/<fs_main>
-       directory = g_qeglobals.m_strHomeGame.GetBuffer();
-       directory += g_pGameDescription->mBaseGame;
-       vfsInitDirectory( directory.GetBuffer() );
+               bool written = false;
+               {
+                       TextFileOutputStream batchFile( batpath );
+                       if ( !batchFile.failed() ) {
+#if defined ( POSIX )
+                               batchFile << "#!/bin/sh \n\n";
 #endif
-
-       // <fs_basepath>/<fs_main>
-       directory = g_pGameDescription->mEnginePath;
-       directory += g_pGameDescription->mBaseGame;
-       vfsInitDirectory( directory.GetBuffer() );
-}
-
-void QE_Init( void ){
-       /*
-       ** initialize variables
-       */
-       g_qeglobals.d_gridsize = 8;
-       g_qeglobals.d_showgrid = true;
-
-       QE_InitVFS();
-
-       Eclass_Init();
-       FillClassList();    // list in entity window
-       Map_Init();
-
-       FillTextureMenu();
-       FillBSPMenu();
-
-       /*
-       ** other stuff
-       */
-       Z_Init();
-}
-
-void WINAPI QE_ConvertDOSToUnixName( char *dst, const char *src ){
-       while ( *src )
-       {
-               if ( *src == '\\' ) {
-                       *dst = '/';
+                               BatchCommandListener listener( batchFile, junkpath );
+                               build_run( name, listener );
+                               written = true;
+                       }
                }
-               else{
-                       *dst = *src;
+               if ( written ) {
+#if defined ( POSIX )
+                       chmod( batpath, 0744 );
+#endif
+                       globalOutputStream() << "Writing the compile script to '" << batpath << "'\n";
+                       globalOutputStream() << "The build output will be saved in '" << junkpath << "'\n";
+                       Q_Exec( batpath, NULL, NULL, true, false );
                }
-               dst++; src++;
        }
-       *dst = 0;
-}
 
-int g_numbrushes, g_numentities;
-
-void QE_CountBrushesAndUpdateStatusBar( void ){
-       static int s_lastbrushcount, s_lastentitycount;
-       static qboolean s_didonce;
+       bsp_shutdown();
+}
 
-       //entity_t   *e;
-       brush_t    *b, *next;
+// =============================================================================
+// Sys_ functions
 
-       g_numbrushes = 0;
-       g_numentities = 0;
+void Sys_SetTitle( const char *text, bool modified ){
+       StringOutputStream title;
+       title << text;
 
-       if ( active_brushes.next != NULL ) {
-               for ( b = active_brushes.next ; b != NULL && b != &active_brushes ; b = next )
-               {
-                       next = b->next;
-                       if ( b->brush_faces ) {
-                               if ( !b->owner->eclass->fixedsize ) {
-                                       g_numbrushes++;
-                               }
-                               else{
-                                       g_numentities++;
-                               }
-                       }
-               }
+       if ( modified ) {
+               title << " *";
        }
-/*
-    if ( entities.next != NULL )
-    {
-        for ( e = entities.next ; e != &entities && g_numentities != MAX_MAP_ENTITIES ; e = e->next)
-        {
-            g_numentities++;
-        }
-    }
- */
-       if ( ( ( g_numbrushes != s_lastbrushcount ) || ( g_numentities != s_lastentitycount ) ) || ( !s_didonce ) ) {
-               Sys_UpdateStatusBar();
 
-               s_lastbrushcount = g_numbrushes;
-               s_lastentitycount = g_numentities;
-               s_didonce = true;
-       }
+       gtk_window_set_title(MainFrame_getWindow(), title.c_str() );
 }
 
-char com_token[1024];
-qboolean com_eof;
-
-/*
-   ================
-   I_FloatTime
-   ================
- */
-double I_FloatTime( void ){
-       time_t t;
-
-       time( &t );
-
-       return t;
-#if 0
-// more precise, less portable
-       struct timeval tp;
-       struct timezone tzp;
-       static int secbase;
-
-       gettimeofday( &tp, &tzp );
-
-       if ( !secbase ) {
-               secbase = tp.tv_sec;
-               return tp.tv_usec / 1000000.0;
-       }
+bool g_bWaitCursor = false;
 
-       return ( tp.tv_sec - secbase ) + tp.tv_usec / 1000000.0;
-#endif
+void Sys_BeginWait( void ){
+       ScreenUpdates_Disable( "Processing...", "Please Wait" );
+       GdkCursor *cursor = gdk_cursor_new( GDK_WATCH );
+       gdk_window_set_cursor( gtk_widget_get_window(MainFrame_getWindow()), cursor );
+       gdk_cursor_unref( cursor );
+       g_bWaitCursor = true;
 }
 
-
-/*
-   ==============
-   COM_Parse
-
-   Parse a token out of a string
-   ==============
- */
-char *COM_Parse( char *data ){
-       int c;
-       int len;
-
-       len = 0;
-       com_token[0] = 0;
-
-       if ( !data ) {
-               return NULL;
-       }
-
-// skip whitespace
-skipwhite:
-       while ( ( c = *data ) <= ' ' )
-       {
-               if ( c == 0 ) {
-                       com_eof = true;
-                       return NULL;            // end of file;
-               }
-               data++;
-       }
-
-// skip // comments
-       if ( c == '/' && data[1] == '/' ) {
-               while ( *data && *data != '\n' )
-                       data++;
-               goto skipwhite;
-       }
-
-
-// handle quoted strings specially
-       if ( c == '\"' ) {
-               data++;
-               do
-               {
-                       c = *data++;
-                       if ( c == '\"' ) {
-                               com_token[len] = 0;
-                               return data;
-                       }
-                       com_token[len] = c;
-                       len++;
-               } while ( 1 );
-       }
-
-// parse single characters
-       if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
-               com_token[len] = c;
-               len++;
-               com_token[len] = 0;
-               return data + 1;
-       }
-
-// parse a regular word
-       do
-       {
-               com_token[len] = c;
-               data++;
-               len++;
-               c = *data;
-               if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
-                       break;
-               }
-       } while ( c > 32 );
-
-       com_token[len] = 0;
-       return data;
-}
-
-char* Get_COM_Token(){
-       return com_token;
-}
-
-/*
-   =============================================================================
-
-                        MISC FUNCTIONS
-
-   =============================================================================
- */
-
-
-int argc;
-char    *argv[MAX_NUM_ARGVS];
-
-/*
-   ============
-   ParseCommandLine
-   ============
- */
-void ParseCommandLine( char *lpCmdLine ){
-       argc = 1;
-       argv[0] = "programname";
-
-       while ( *lpCmdLine && ( argc < MAX_NUM_ARGVS ) )
-       {
-               while ( *lpCmdLine && ( ( *lpCmdLine <= 32 ) || ( *lpCmdLine > 126 ) ) )
-                       lpCmdLine++;
-
-               if ( *lpCmdLine ) {
-                       argv[argc] = lpCmdLine;
-                       argc++;
-
-                       while ( *lpCmdLine && ( ( *lpCmdLine > 32 ) && ( *lpCmdLine <= 126 ) ) )
-                               lpCmdLine++;
-
-                       if ( *lpCmdLine ) {
-                               *lpCmdLine = 0;
-                               lpCmdLine++;
-                       }
-
-               }
-       }
-}
-
-
-
-/*
-   =================
-   CheckParm
-
-   Checks for the given parameter in the program's command line arguments
-   Returns the argument number (1 to argc-1) or 0 if not present
-   =================
- */
-int CheckParm( const char *check ){
-       int i;
-
-       for ( i = 1; i < argc; i++ )
-       {
-               if ( stricmp( check, argv[i] ) ) {
-                       return i;
-               }
-       }
-
-       return 0;
-}
-
-
-
-
-/*
-   ==============
-   ParseNum / ParseHex
-   ==============
- */
-int ParseHex( const char *hex ){
-       const char    *str;
-       int num;
-
-       num = 0;
-       str = hex;
-
-       while ( *str )
-       {
-               num <<= 4;
-               if ( *str >= '0' && *str <= '9' ) {
-                       num += *str - '0';
-               }
-               else if ( *str >= 'a' && *str <= 'f' ) {
-                       num += 10 + *str - 'a';
-               }
-               else if ( *str >= 'A' && *str <= 'F' ) {
-                       num += 10 + *str - 'A';
-               }
-               else{
-                       Error( "Bad hex number: %s",hex );
-               }
-               str++;
-       }
-
-       return num;
-}
-
-
-int ParseNum( const char *str ){
-       if ( str[0] == '$' ) {
-               return ParseHex( str + 1 );
-       }
-       if ( str[0] == '0' && str[1] == 'x' ) {
-               return ParseHex( str + 2 );
-       }
-       return atol( str );
-}
-
-// BSP frontend plugin
-// global flag for BSP frontend plugin is g_qeglobals.bBSPFrontendPlugin
-_QERPlugBSPFrontendTable g_BSPFrontendTable;
-
-// =============================================================================
-// Sys_ functions
-
-bool Sys_AltDown(){
-#ifdef _WIN32
-       return ( GetKeyState( VK_MENU ) & 0x8000 ) != 0;
-#endif
-
-#if defined ( __linux__ ) || defined ( __APPLE__ )
-       char keys[32];
-       int x;
-
-       XQueryKeymap( GDK_DISPLAY(), keys );
-
-       x = XKeysymToKeycode( GDK_DISPLAY(), XK_Alt_L );
-       if ( keys[x / 8] & ( 1 << ( x % 8 ) ) ) {
-               return true;
-       }
-
-       x = XKeysymToKeycode( GDK_DISPLAY(), XK_Alt_R );
-       if ( keys[x / 8] & ( 1 << ( x % 8 ) ) ) {
-               return true;
-       }
-
-       return false;
-#endif
-}
-
-bool Sys_ShiftDown(){
-#ifdef _WIN32
-       return ( GetKeyState( VK_SHIFT ) & 0x8000 ) != 0;
-#endif
-
-#if defined ( __linux__ ) || defined ( __APPLE__ )
-       char keys[32];
-       int x;
-
-       XQueryKeymap( GDK_DISPLAY(), keys );
-
-       x = XKeysymToKeycode( GDK_DISPLAY(), XK_Shift_L );
-       if ( keys[x / 8] & ( 1 << ( x % 8 ) ) ) {
-               return true;
-       }
-
-       x = XKeysymToKeycode( GDK_DISPLAY(), XK_Shift_R );
-       if ( keys[x / 8] & ( 1 << ( x % 8 ) ) ) {
-               return true;
-       }
-
-       return false;
-#endif
-}
-
-void Sys_MarkMapModified( void ){
-       char title[PATH_MAX];
-
-       if ( modified != 1 ) {
-               modified = true; // mark the map as changed
-               sprintf( title, "%s *", currentmap );
-
-               QE_ConvertDOSToUnixName( title, title );
-               Sys_SetTitle( title );
-       }
-}
-
-void Sys_SetTitle( const char *text ){
-       gtk_window_set_title( GTK_WINDOW( g_qeglobals_gui.d_main_window ), text );
-}
-
-bool g_bWaitCursor = false;
-
-void WINAPI Sys_BeginWait( void ){
-       GdkCursor *cursor = gdk_cursor_new( GDK_WATCH );
-       gdk_window_set_cursor( g_pParentWnd->m_pWidget->window, cursor );
-       gdk_cursor_unref( cursor );
-       g_bWaitCursor = true;
-}
-
-void WINAPI Sys_EndWait( void ){
-       GdkCursor *cursor = gdk_cursor_new( GDK_LEFT_PTR );
-       gdk_window_set_cursor( g_pParentWnd->m_pWidget->window, cursor );
-       gdk_cursor_unref( cursor );
-       g_bWaitCursor = false;
-}
-
-void Sys_GetCursorPos( int *x, int *y ){
-       // FIXME: not multihead safe
-       gdk_window_get_pointer( NULL, x, y, NULL );
-}
-
-void Sys_SetCursorPos( int x, int y ){
-       // NOTE: coordinates are in GDK space, not OS space
-#ifdef _WIN32
-       int sys_x = x - g_pParentWnd->GetGDKOffsetX();
-       int sys_y = y - g_pParentWnd->GetGDKOffsetY();
-
-       SetCursorPos( sys_x, sys_y );
-#endif
-
-#if defined ( __linux__ ) || defined ( __APPLE__ )
-       XWarpPointer( GDK_DISPLAY(), None, GDK_ROOT_WINDOW(), 0, 0, 0, 0, x, y );
-#endif
-}
+void Sys_EndWait( void ){
+       ScreenUpdates_Enable();
+       gdk_window_set_cursor(gtk_widget_get_window(MainFrame_getWindow()), 0 );
+       g_bWaitCursor = false;
+}
 
 void Sys_Beep( void ){
-#if defined ( __linux__ ) || defined ( __APPLE__ )
        gdk_beep();
-#else
-       MessageBeep( MB_ICONASTERISK );
-#endif
-}
-
-double Sys_DoubleTime( void ){
-       return clock() / 1000.0;
-}
-
-/*
-   ===============================================================
-
-   STATUS WINDOW
-
-   ===============================================================
- */
-
-void Sys_UpdateStatusBar( void ){
-       extern int g_numbrushes, g_numentities;
-
-       char numbrushbuffer[100] = "";
-
-       sprintf( numbrushbuffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities );
-       g_pParentWnd->SetStatusText( 2, numbrushbuffer );
-       //Sys_Status( numbrushbuffer, 2 );
-}
-
-void Sys_Status( const char *psz, int part ){
-       g_pParentWnd->SetStatusText( part, psz );
-}
-
-// =============================================================================
-// MRU
-
-#define MRU_MAX 4
-static GtkWidget *MRU_items[MRU_MAX];
-static int MRU_used;
-typedef char MRU_filename_t[PATH_MAX];
-MRU_filename_t MRU_filenames[MRU_MAX];
-
-static char* MRU_GetText( int index ){
-       return MRU_filenames[index];
-}
-
-void buffer_write_escaped_mnemonic( char* buffer, const char* string ){
-       while ( *string != '\0' )
-       {
-               if ( *string == '_' ) {
-                       *buffer++ = '_';
-               }
-
-               *buffer++ = *string++;
-       }
-       *buffer = '\0';
-}
-
-static void MRU_SetText( int index, const char *filename ){
-       strcpy( MRU_filenames[index], filename );
-
-       char mnemonic[PATH_MAX * 2 + 4];
-       mnemonic[0] = '_';
-       sprintf( mnemonic + 1, "%d", index + 1 );
-       mnemonic[2] = '-';
-       mnemonic[3] = ' ';
-       buffer_write_escaped_mnemonic( mnemonic + 4, filename );
-       gtk_label_set_text_with_mnemonic( GTK_LABEL( GTK_BIN( MRU_items[index] )->child ), mnemonic );
-}
-
-void MRU_Load(){
-       int i = g_PrefsDlg.m_nMRUCount;
-
-       if ( i > 4 ) {
-               i = 4; //FIXME: make this a define
-
-       }
-       for (; i > 0; i-- )
-               MRU_AddFile( g_PrefsDlg.m_strMRUFiles[i - 1].GetBuffer() );
-}
-
-void MRU_Save(){
-       g_PrefsDlg.m_nMRUCount = MRU_used;
-
-       for ( int i = 0; i < MRU_used; i++ )
-               g_PrefsDlg.m_strMRUFiles[i] = MRU_GetText( i );
-}
-
-void MRU_AddWidget( GtkWidget *widget, int pos ){
-       if ( pos < MRU_MAX ) {
-               MRU_items[pos] = widget;
-       }
-}
-
-void MRU_AddFile( const char *str ){
-       int i;
-       char* text;
-
-       // check if file is already in our list
-       for ( i = 0; i < MRU_used; i++ )
-       {
-               text = MRU_GetText( i );
-
-               if ( strcmp( text, str ) == 0 ) {
-                       // reorder menu
-                       for (; i > 0; i-- )
-                               MRU_SetText( i, MRU_GetText( i - 1 ) );
-
-                       MRU_SetText( 0, str );
-
-                       return;
-               }
-       }
-
-       if ( MRU_used < MRU_MAX ) {
-               MRU_used++;
-       }
-
-       // move items down
-       for ( i = MRU_used - 1; i > 0; i-- )
-               MRU_SetText( i, MRU_GetText( i - 1 ) );
-
-       MRU_SetText( 0, str );
-       gtk_widget_set_sensitive( MRU_items[0], TRUE );
-       gtk_widget_show( MRU_items[MRU_used - 1] );
-}
-
-void MRU_Activate( int index ){
-       char *text = MRU_GetText( index );
-
-       if ( access( text, R_OK ) == 0 ) {
-               text = strdup( text );
-               MRU_AddFile( text );
-               Map_LoadFile( text );
-               free( text );
-       }
-       else
-       {
-               MRU_used--;
-
-               for ( int i = index; i < MRU_used; i++ )
-                       MRU_SetText( i, MRU_GetText( i + 1 ) );
-
-               if ( MRU_used == 0 ) {
-                       gtk_label_set_text( GTK_LABEL( GTK_BIN( MRU_items[0] )->child ), "Recent Files" );
-                       gtk_widget_set_sensitive( MRU_items[0], FALSE );
-               }
-               else
-               {
-                       gtk_widget_hide( MRU_items[MRU_used] );
-               }
-       }
-}
-
-/*
-   ======================================================================
-
-   FILE DIALOGS
-
-   ======================================================================
- */
-
-qboolean ConfirmModified(){
-       if ( !modified ) {
-               return true;
-       }
-
-       if ( gtk_MessageBox( g_pParentWnd->m_pWidget, "This will lose changes to the map", "warning", MB_OKCANCEL ) == IDCANCEL ) {
-               return false;
-       }
-       return true;
-}
-
-void ProjectDialog(){
-       const char *filename;
-       char buffer[NAME_MAX];
-
-       /*
-        * Obtain the system directory name and
-        * store it in buffer.
-        */
-
-       strcpy( buffer, g_qeglobals.m_strHomeGame.GetBuffer() );
-       strcat( buffer, g_pGameDescription->mBaseGame.GetBuffer() );
-       strcat( buffer, "/scripts/" );
-
-       // Display the Open dialog box
-       filename = file_dialog( NULL, TRUE, _( "Open File" ), buffer, "project" );
-
-       if ( filename == NULL ) {
-               return; // canceled
-
-       }
-       // Open the file.
-       // NOTE: QE_LoadProject takes care of saving prefs with new path to the project file
-       if ( !QE_LoadProject( filename ) ) {
-               Sys_Printf( "Failed to load project from file: %s\n", filename );
-       }
-       else{
-               // FIXME TTimo QE_Init is probably broken if you don't call it during startup right now ..
-               QE_Init();
-       }
-}
-
-/*
-   =======================================================
-
-   Menu modifications
-
-   =======================================================
- */
-
-/*
-   ==================
-   FillBSPMenu
-
-   ==================
- */
-char *bsp_commands[256];
-
-void FillBSPMenu(){
-       GtkWidget *item, *menu; // menu points to a GtkMenu (not an item)
-       epair_t *ep;
-       GList *lst;
-       int i;
-
-       menu = GTK_WIDGET( g_object_get_data( G_OBJECT( g_qeglobals_gui.d_main_window ), "menu_bsp" ) );
-
-       while ( ( lst = gtk_container_children( GTK_CONTAINER( menu ) ) ) != NULL )
-               gtk_container_remove( GTK_CONTAINER( menu ), GTK_WIDGET( lst->data ) );
-
-       if ( g_PrefsDlg.m_bDetachableMenus ) {
-               item = gtk_tearoff_menu_item_new();
-               gtk_menu_append( GTK_MENU( menu ), item );
-               gtk_widget_set_sensitive( item, TRUE );
-               gtk_widget_show( item );
-       }
-
-       if ( g_qeglobals.bBSPFrontendPlugin ) {
-               CString str = g_BSPFrontendTable.m_pfnGetBSPMenu();
-               char cTemp[1024];
-               strcpy( cTemp, str );
-               char* token = strtok( cTemp, ",;" );
-               if ( token && *token == ' ' ) {
-                       while ( *token == ' ' )
-                               token++;
-               }
-               i = 0;
-
-               // first token is menu name
-               item = gtk_menu_get_attach_widget( GTK_MENU( menu ) );
-               gtk_label_set_text( GTK_LABEL( GTK_BIN( item )->child ), token );
-
-               token = strtok( NULL, ",;" );
-               while ( token != NULL )
-               {
-                       g_BSPFrontendCommands = g_slist_append( g_BSPFrontendCommands, g_strdup( token ) );
-                       item = gtk_menu_item_new_with_label( token );
-                       gtk_widget_show( item );
-                       gtk_container_add( GTK_CONTAINER( menu ), item );
-                       gtk_signal_connect( GTK_OBJECT( item ), "activate",
-                                                               GTK_SIGNAL_FUNC( HandleCommand ), GINT_TO_POINTER( CMD_BSPCOMMAND + i ) );
-                       token = strtok( NULL, ",;" );
-                       i++;
-               }
-       }
-       else
-       {
-               i = 0;
-               for ( ep = g_qeglobals.d_project_entity->epairs; ep; ep = ep->next )
-               {
-                       if ( strncmp( ep->key, "bsp_", 4 ) == 0 ) {
-                               bsp_commands[i] = ep->key;
-                               item = gtk_menu_item_new_with_label( ep->key + 4 );
-                               gtk_widget_show( item );
-                               gtk_container_add( GTK_CONTAINER( menu ), item );
-                               gtk_signal_connect( GTK_OBJECT( item ), "activate",
-                                                                       GTK_SIGNAL_FUNC( HandleCommand ), GINT_TO_POINTER( CMD_BSPCOMMAND + i ) );
-                               i++;
-                       }
-               }
-       }
-}
-
-//==============================================
-
-void AddSlash( CString& strPath ){
-       if ( strPath.GetLength() > 0 ) {
-               if ( ( strPath.GetAt( strPath.GetLength() - 1 ) != '/' ) &&
-                        ( strPath.GetAt( strPath.GetLength() - 1 ) != '\\' ) ) {
-                       strPath += '/';
-               }
-       }
-}
-
-bool ExtractPath_and_Filename( const char* pPath, CString& strPath, CString& strFilename ){
-       CString strPathName;
-       strPathName = pPath;
-       int nSlash = strPathName.ReverseFind( '\\' );
-       if ( nSlash == -1 ) {
-               // TTimo: try forward slash, some are using forward
-               nSlash = strPathName.ReverseFind( '/' );
-       }
-       if ( nSlash >= 0 ) {
-               strPath = strPathName.Left( nSlash + 1 );
-               strFilename = strPathName.Right( strPathName.GetLength() - nSlash - 1 );
-       }
-       // TTimo: try forward slash, some are using forward
-       else{
-               strFilename = pPath;
-       }
-       return true;
-}
-
-//===========================================
-
-//++timo FIXME: no longer used .. remove!
-char *TranslateString( char *buf ){
-       static char buf2[32768];
-       int i, l;
-       char          *out;
-
-       l = strlen( buf );
-       out = buf2;
-       for ( i = 0 ; i < l ; i++ )
-       {
-               if ( buf[i] == '\n' ) {
-                       *out++ = '\r';
-                       *out++ = '\n';
-               }
-               else{
-                       *out++ = buf[i];
-               }
-       }
-       *out++ = 0;
-
-       return buf2;
-}
-
-// called whenever we need to open/close/check the console log file
-void Sys_LogFile( void ){
-       if ( g_PrefsDlg.mGamesDialog.m_bLogConsole && !g_qeglobals.hLogFile ) {
-               // settings say we should be logging and we don't have a log file .. so create it
-               // open a file to log the console (if user prefs say so)
-               // the file handle is g_qeglobals.hLogFile
-               // the log file is erased
-               Str name;
-               name = g_strTempPath;
-               name += "radiant.log";
-#if defined ( __linux__ ) || defined ( __APPLE__ )
-               g_qeglobals.hLogFile = open( name.GetBuffer(), O_TRUNC | O_CREAT | O_WRONLY, S_IREAD | S_IWRITE );
-#endif
-#ifdef _WIN32
-               g_qeglobals.hLogFile = _open( name.GetBuffer(), _O_TRUNC | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE );
-#endif
-               if ( g_qeglobals.hLogFile ) {
-                       Sys_Printf( "Started logging to %s\n", name.GetBuffer() );
-                       time_t localtime;
-                       time( &localtime );
-                       Sys_Printf( "Today is: %s", ctime( &localtime ) );
-                       Sys_Printf( "This is radiant '" RADIANT_VERSION "' compiled " __DATE__ "\n" );
-                       Sys_Printf( RADIANT_ABOUTMSG "\n" );
-               }
-               else{
-                       gtk_MessageBox( NULL, "Failed to create log file, check write permissions in Radiant directory.\n",
-                                                       "Console logging", MB_OK );
-               }
-       }
-       else if ( !g_PrefsDlg.mGamesDialog.m_bLogConsole && g_qeglobals.hLogFile ) {
-               // settings say we should not be logging but still we have an active logfile .. close it
-               time_t localtime;
-               time( &localtime );
-               Sys_Printf( "Closing log file at %s\n", ctime( &localtime ) );
-               #ifdef _WIN32
-               _close( g_qeglobals.hLogFile );
-               #endif
-               #if defined ( __linux__ ) || defined ( __APPLE__ )
-               close( g_qeglobals.hLogFile );
-               #endif
-               g_qeglobals.hLogFile = 0;
-       }
-}
-
-void Sys_ClearPrintf( void ){
-       GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( g_qeglobals_gui.d_edit ) );
-       gtk_text_buffer_set_text( buffer, "", -1 );
-}
-
-// used to be around 32000, that should be way enough already
-#define BUFFER_SIZE 4096
-
-extern "C" void Sys_FPrintf_VA( int level, const char *text, va_list args ) {
-       char buf[BUFFER_SIZE];
-
-       buf[0] = 0;
-       vsnprintf( buf, BUFFER_SIZE, text, args );
-       buf[BUFFER_SIZE - 1] = 0;
-       const unsigned int length = strlen( buf );
-
-       if ( g_qeglobals.hLogFile ) {
-#ifdef _WIN32
-               _write( g_qeglobals.hLogFile, buf, length );
-               _commit( g_qeglobals.hLogFile );
-#endif
-#if defined ( __linux__ ) || defined ( __APPLE__ )
-               write( g_qeglobals.hLogFile, buf, length );
-#endif
-       }
-
-       if ( level != SYS_NOCON ) {
-               // TTimo: FIXME: killed the console to avoid GDI leak fuckup
-               if ( g_qeglobals_gui.d_edit != NULL ) {
-                       GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( g_qeglobals_gui.d_edit ) );
-
-                       GtkTextIter iter;
-                       gtk_text_buffer_get_end_iter( buffer, &iter );
-
-                       static GtkTextMark* end = gtk_text_buffer_create_mark( buffer, "end", &iter, FALSE );
-
-                       const GdkColor yellow = { 0, 0xb0ff, 0xb0ff, 0x0000 };
-                       const GdkColor red = { 0, 0xffff, 0x0000, 0x0000 };
-                       const GdkColor black = { 0, 0x0000, 0x0000, 0x0000 };
-
-                       static GtkTextTag* error_tag = gtk_text_buffer_create_tag( buffer, "red_foreground", "foreground-gdk", &red, NULL );
-                       static GtkTextTag* warning_tag = gtk_text_buffer_create_tag( buffer, "yellow_foreground", "foreground-gdk", &yellow, NULL );
-                       static GtkTextTag* standard_tag = gtk_text_buffer_create_tag( buffer, "black_foreground", "foreground-gdk", &black, NULL );
-                       GtkTextTag* tag;
-                       switch ( level )
-                       {
-                       case SYS_WRN:
-                               tag = warning_tag;
-                               break;
-                       case SYS_ERR:
-                               tag = error_tag;
-                               break;
-                       case SYS_STD:
-                       case SYS_VRB:
-                       default:
-                               tag = standard_tag;
-                               break;
-                       }
-                       gtk_text_buffer_insert_with_tags( buffer, &iter, buf, length, tag, NULL );
-
-                       gtk_text_view_scroll_mark_onscreen( GTK_TEXT_VIEW( g_qeglobals_gui.d_edit ), end );
-
-                       // update console widget immediatly if we're doing something time-consuming
-                       if ( !g_bScreenUpdates && GTK_WIDGET_REALIZED( g_qeglobals_gui.d_edit ) ) {
-                               gtk_grab_add( g_qeglobals_gui.d_edit );
-
-                               while ( gtk_events_pending() )
-                                       gtk_main_iteration();
-
-                               gtk_grab_remove( g_qeglobals_gui.d_edit );
-                       }
-               }
-       }
-}
-
-// NOTE: this is the handler sent to synapse
-// must match PFN_SYN_PRINTF_VA
-extern "C" void Sys_Printf_VA( const char *text, va_list args ){
-       Sys_FPrintf_VA( SYS_STD, text, args );
-}
-
-extern "C" void Sys_Printf( const char *text, ... ) {
-       va_list args;
-
-       va_start( args, text );
-       Sys_FPrintf_VA( SYS_STD, text, args );
-       va_end( args );
-}
-
-extern "C" void Sys_FPrintf( int level, const char *text, ... ){
-       va_list args;
-
-       va_start( args, text );
-       Sys_FPrintf_VA( level, text, args );
-       va_end( args );
 }