X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fconsole.cpp;h=489f8d61f4773dcae99d991ffab2c7d6d7236ed8;hb=578b01e8cb2bf425c24cbeee3bbb6a5f7c59b1cb;hp=82b08e3c2ab5468ca1919e0a094dd0a99af7a9e7;hpb=ee4b663ef7227a42b5eb051698265bed514ab3c0;p=xonotic%2Fnetradiant.git diff --git a/radiant/console.cpp b/radiant/console.cpp index 82b08e3c..489f8d61 100644 --- a/radiant/console.cpp +++ b/radiant/console.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "gtkutil/accelerator.h" #include "gtkutil/messagebox.h" @@ -33,7 +34,6 @@ #include "stream/stringstream.h" #include "convert.h" -#include "version.h" #include "aboutmsg.h" #include "gtkmisc.h" #include "mainframe.h" @@ -46,8 +46,15 @@ FILE* g_hLogFile; bool g_Console_enableLogging = false; +struct Gtk_Idle_Print_Data { + int level; + char *buf; + std::size_t length; + bool contains_newline; +}; + // called whenever we need to open/close/check the console log file -void Sys_LogFile( bool enable ){ +void Sys_EnableLogFile( bool enable ){ if ( enable && !g_hLogFile ) { // settings say we should be logging and we don't have a log file .. so create it if ( !SettingsPath_get()[0] ) { @@ -64,10 +71,10 @@ void Sys_LogFile( bool enable ){ time_t localtime; time( &localtime ); globalOutputStream() << "Today is: " << ctime( &localtime ) - << "This is NetRadiant '" RADIANT_VERSION "' compiled " __DATE__ "\n" RADIANT_ABOUTMSG "\n"; + << "This is " RADIANT_NAME " " RADIANT_VERSION " compiled " __DATE__ "\n" RADIANT_ABOUTMSG "\n"; } else{ - ui::alert( ui::root, "Failed to create log file, check write permissions in Radiant directory.\n", + ui::alert( ui::root, "Failed to create log file, check write permissions in " RADIANT_NAME " directory.\n", "Console logging", ui::alert_type::OK, ui::alert_icon::Error ); } } @@ -133,6 +140,9 @@ ui::Widget Console_constructWindow( ui::Window toplevel ){ return scr; } +//#pragma GCC push_options +//#pragma GCC optimize ("O0") + class GtkTextBufferOutputStream : public TextOutputStream { GtkTextBuffer* textBuffer; @@ -141,28 +151,19 @@ GtkTextTag* tag; public: GtkTextBufferOutputStream( GtkTextBuffer* textBuffer, GtkTextIter* iter, GtkTextTag* tag ) : textBuffer( textBuffer ), iter( iter ), tag( tag ){ } -std::size_t write( const char* buffer, std::size_t length ){ +std::size_t __attribute__((optimize("O0"))) write( const char* buffer, std::size_t length ){ gtk_text_buffer_insert_with_tags( textBuffer, iter, buffer, gint( length ), tag, NULL ); return length; } }; -std::size_t Sys_Print( int level, const char* buf, std::size_t length ){ - bool contains_newline = std::find( buf, buf + length, '\n' ) != buf + length; - - if ( level == SYS_ERR ) { - Sys_LogFile( true ); - } +//#pragma GCC pop_options - if ( g_hLogFile != 0 ) { - fwrite( buf, 1, length, g_hLogFile ); - if ( contains_newline ) { - fflush( g_hLogFile ); - } - } +// This function is meant to be used with gtk_idle_add. It will free its argument. +static gboolean Gtk_Idle_Print( gpointer data ){ + Gtk_Idle_Print_Data *args = reinterpret_cast(data); + g_assert(g_console); - if ( level != SYS_NOCON ) { - if ( g_console ) { auto buffer = gtk_text_view_get_buffer( g_console ); GtkTextIter iter; @@ -177,7 +178,7 @@ std::size_t Sys_Print( int level, const char* buf, std::size_t length ){ static auto warning_tag = gtk_text_buffer_create_tag( buffer, "yellow_foreground", "foreground-gdk", &yellow, NULL ); static auto standard_tag = gtk_text_buffer_create_tag( buffer, "black_foreground", NULL ); GtkTextTag* tag; - switch ( level ) + switch ( args->level ) { case SYS_WRN: tag = warning_tag; @@ -192,29 +193,61 @@ std::size_t Sys_Print( int level, const char* buf, std::size_t length ){ break; } - { GtkTextBufferOutputStream textBuffer( buffer, &iter, tag ); if ( !globalCharacterSet().isUTF8() ) { BufferedTextOutputStream buffered( textBuffer ); - buffered << StringRange( buf, buf + length ); + buffered << StringRange( args->buf, args->buf + args->length ); } else { - textBuffer << StringRange( buf, buf + length ); + textBuffer << StringRange( args->buf, args->buf + args->length ); } } // update console widget immediatly if we're doing something time-consuming - if ( contains_newline ) { + if ( args->contains_newline ) { gtk_text_view_scroll_mark_onscreen( g_console, end ); if ( !ScreenUpdates_Enabled() && gtk_widget_get_realized( g_console ) ) { ScreenUpdates_process(); } } + + free( args->buf ); + free( args ); + + return FALSE; // call this once, not repeatedly } + +// Print logs to the in-game console and/or to the log file. +// This function is thread safe. +std::size_t Sys_Print( int level, const char* buf, std::size_t length ){ + bool contains_newline = std::find( buf, buf + length, '\n' ) != buf + length; + + if ( level == SYS_ERR ) { + Sys_EnableLogFile( true ); } + + if ( g_hLogFile != 0 ) { + // prevent parallel write + static std::mutex log_file_mutex; + std::lock_guard guard(log_file_mutex); + + fwrite( buf, 1, length, g_hLogFile ); + if ( contains_newline ) { + fflush( g_hLogFile ); + } + } + + if ( level != SYS_NOCON && g_console ) { + auto data = reinterpret_cast( malloc( sizeof(struct Gtk_Idle_Print_Data) ) ); + if (data != nullptr) { + *data = { level, g_strndup(buf, length), length, contains_newline }; + gdk_threads_add_idle(Gtk_Idle_Print, (gpointer)data); + } + } + return length; }