]> git.mxchange.org Git - simgear.git/blobdiff - simgear/debug/logstream.cxx
Canvas: fix element mouse hit detection with OSG 3.3.2.
[simgear.git] / simgear / debug / logstream.cxx
index fd91aee5355698ceae4510c9eba2d0ddc3b3e690..4290f5ca9d0c3fc6a60c9df3e073501053504563 100644 (file)
 //
 // $Id$
 
+#include <simgear_config.h>
+
 #include "logstream.hxx"
 
 #include <iostream>
 #include <fstream>
+#include <sstream>
+#include <algorithm>
 
 #include <boost/foreach.hpp>
 
@@ -34,8 +38,8 @@
 
 #include <simgear/misc/sg_path.hxx>
 
-#ifdef _WIN32
-// for AllocConsole
+#ifdef SG_WINDOWS
+// for AllocConsole, OutputDebugString
     #include "windows.h"
 #endif
 
@@ -66,43 +70,64 @@ const char* debugClassToString(sgDebugClass c)
     case SG_ENVIRONMENT:return "environment";
     case SG_SOUND:      return "sound";
     case SG_NAVAID:     return "navaid";
+    case SG_GUI:        return "gui";
     default:            return "unknown";
     }
 }
 
 //////////////////////////////////////////////////////////////////////////////
 
+namespace simgear
+{
+
+LogCallback::LogCallback(sgDebugClass c, sgDebugPriority p) :
+       m_class(c),
+       m_priority(p)
+{
+}
+
+bool LogCallback::shouldLog(sgDebugClass c, sgDebugPriority p) const
+{
+        return ((c & m_class) != 0 && p >= m_priority);
+}
+
+void LogCallback::setLogLevels( sgDebugClass c, sgDebugPriority p )
+{
+       m_priority = p;
+       m_class = c;
+}
+
+} // of namespace simgear
+
+//////////////////////////////////////////////////////////////////////////////
+
 class FileLogCallback : public simgear::LogCallback
 {
 public:
     FileLogCallback(const std::string& aPath, sgDebugClass c, sgDebugPriority p) :
-        m_file(aPath.c_str(), std::ios_base::out | std::ios_base::trunc),
-        m_class(c),
-        m_priority(p)
+           simgear::LogCallback(c, p),
+        m_file(aPath.c_str(), std::ios_base::out | std::ios_base::trunc)
     {
     }
     
     virtual void operator()(sgDebugClass c, sgDebugPriority p, 
         const char* file, int line, const std::string& message)
     {
-        if ((c & m_class) == 0 || p < m_priority) return;
+        if (!shouldLog(c, p)) return;
         m_file << debugClassToString(c) << ":" << (int) p
             << ":" << file << ":" << line << ":" << message << std::endl;
     }
 private:
     std::ofstream m_file;   
-    sgDebugClass m_class;
-    sgDebugPriority m_priority;
 };
    
 class StderrLogCallback : public simgear::LogCallback
 {
 public:
     StderrLogCallback(sgDebugClass c, sgDebugPriority p) :
-        m_class(c),
-            m_priority(p)
+               simgear::LogCallback(c, p)
     {
-#ifdef _WIN32
+#ifdef SG_WINDOWS
         AllocConsole(); // but only if we want a console
         freopen("conin$", "r", stdin);
         freopen("conout$", "w", stdout);
@@ -110,76 +135,41 @@ public:
 #endif
     }
     
-    void setLogLevels( sgDebugClass c, sgDebugPriority p )
-    {
-        m_priority = p;
-        m_class = c;
-    }
-    
     virtual void operator()(sgDebugClass c, sgDebugPriority p, 
         const char* file, int line, const std::string& aMessage)
     {
-        if ((c & m_class) == 0 || p < m_priority) return;
-        
-        // if running under MSVC, we could use OutputDebugString here
+        if (!shouldLog(c, p)) return;
         
         fprintf(stderr, "%s\n", aMessage.c_str());
         //fprintf(stderr, "%s:%d:%s:%d:%s\n", debugClassToString(c), p,
         //    file, line, aMessage.c_str());
         fflush(stderr);
     }
-private:
-    sgDebugClass m_class;
-    sgDebugPriority m_priority;
 };
 
-namespace simgear
-{
-class BufferedLogCallback::BufferedLogCallbackPrivate
-{
-public:
-    SGMutex m_mutex;
-    sgDebugClass m_class;
-    sgDebugPriority m_priority;
-    string_list m_buffer;
-};
-   
-BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) :
-    d(new BufferedLogCallbackPrivate)
-{
-    d->m_class = c;
-    d->m_priority = p;
-}
 
-BufferedLogCallback::~BufferedLogCallback()
-{
-}
-void BufferedLogCallback::operator()(sgDebugClass c, sgDebugPriority p, 
-        const char* file, int line, const std::string& aMessage)
+#ifdef SG_WINDOWS
+
+class WinDebugLogCallback : public simgear::LogCallback
 {
-    SG_UNUSED(file);
-    SG_UNUSED(line);
-    
-    if ((c & d->m_class) == 0 || p < d->m_priority) return;
+public:
+    WinDebugLogCallback(sgDebugClass c, sgDebugPriority p) :
+               simgear::LogCallback(c, p)
+    {
+    }
     
-    SGGuard<SGMutex> g(d->m_mutex);
-    d->m_buffer.push_back(aMessage);
-}
-void BufferedLogCallback::threadsafeCopy(string_list& aOutput)
-{
-    aOutput.clear();
-    SGGuard<SGMutex> g(d->m_mutex);
-    size_t sz = d->m_buffer.size();
-    aOutput.resize(sz);
-    for (unsigned int i=0; i<sz; ++i) {
-        aOutput[i] = d->m_buffer[i];
+    virtual void operator()(sgDebugClass c, sgDebugPriority p, 
+        const char* file, int line, const std::string& aMessage)
+    {
+        if (!shouldLog(c, p)) return;
+        
+        std::ostringstream os;
+               os << debugClassToString(c) << ":" << aMessage << std::endl;
+               OutputDebugStringA(os.str().c_str());
     }
-} 
+};
 
-} // of namespace simgear
+#endif
 
 class LogStreamPrivate : public SGThread
 {
@@ -205,23 +195,58 @@ private:
         int line;
         std::string message;
     };
+    
+    class PauseThread
+    {
+    public:
+        PauseThread(LogStreamPrivate* parent) : m_parent(parent)
+        {
+            m_wasRunning = m_parent->stop();
+        }
+        
+        ~PauseThread()
+        {
+            if (m_wasRunning) {
+                m_parent->startLog();
+            }
+        }
+    private:
+        LogStreamPrivate* m_parent;
+        bool m_wasRunning;
+    };
 public:
     LogStreamPrivate() :
         m_logClass(SG_ALL), 
         m_logPriority(SG_ALERT),
-        m_isRunning(false)
+        m_isRunning(false),
+               m_consoleRequested(false)
     { 
-        m_stderrCallback = new StderrLogCallback(m_logClass, m_logPriority);
-        addCallback(m_stderrCallback);
+
+#if !defined(SG_WINDOWS)
+        m_callbacks.push_back(new StderrLogCallback(m_logClass, m_logPriority));
+               m_consoleCallbacks.push_back(m_callbacks.back());
+               m_consoleRequested = true;
+#endif
+
+#if defined (SG_WINDOWS) && !defined(NDEBUG)
+               m_callbacks.push_back(new WinDebugLogCallback(m_logClass, m_logPriority));
+               m_consoleCallbacks.push_back(m_callbacks.back());
+#endif
     }
                     
     SGMutex m_lock;
     SGBlockingQueue<LogEntry> m_entries;
-    std::vector<simgear::LogCallback*> m_callbacks;    
+    
+    typedef std::vector<simgear::LogCallback*> CallbackVec;
+    CallbackVec m_callbacks;    
+    /// subset of callbacks which correspond to stdout / console,
+       /// and hence should dynamically reflect console logging settings
+       CallbackVec m_consoleCallbacks;
+
     sgDebugClass m_logClass;
     sgDebugPriority m_logPriority;
     bool m_isRunning;
-    StderrLogCallback* m_stderrCallback;
+       bool m_consoleRequested;
     
     void startLog()
     {
@@ -267,22 +292,27 @@ public:
     
     void addCallback(simgear::LogCallback* cb)
     {
-        bool wasRunning = stop();
+        PauseThread pause(this);
         m_callbacks.push_back(cb);
-        if (wasRunning) {
-            startLog();
+    }
+    
+    void removeCallback(simgear::LogCallback* cb)
+    {
+        PauseThread pause(this);
+        CallbackVec::iterator it = std::find(m_callbacks.begin(), m_callbacks.end(), cb);
+        if (it != m_callbacks.end()) {
+            m_callbacks.erase(it);
         }
     }
     
     void setLogLevels( sgDebugClass c, sgDebugPriority p )
     {
-        bool wasRunning = stop();
+        PauseThread pause(this);
         m_logPriority = p;
         m_logClass = c;
-        m_stderrCallback->setLogLevels(c, p);
-        if (wasRunning) {
-            startLog();
-        }
+               BOOST_FOREACH(simgear::LogCallback* cb, m_consoleCallbacks) {
+               cb->setLogLevels(c, p);
+               }
     }
     
     bool would_log( sgDebugClass c, sgDebugPriority p ) const
@@ -297,6 +327,18 @@ public:
         LogEntry entry(c, p, fileName, line, msg);
         m_entries.push(entry);
     }
+
+       void requestConsole()
+       {
+               PauseThread pause(this);
+               if (m_consoleRequested) {
+                       return;
+               }
+
+               m_consoleRequested = true;
+               m_callbacks.push_back(new StderrLogCallback(m_logClass, m_logPriority));
+               m_consoleCallbacks.push_back(m_callbacks.back());
+       }
 };
 
 /////////////////////////////////////////////////////////////////////////////
@@ -322,6 +364,12 @@ logstream::addCallback(simgear::LogCallback* cb)
     global_privateLogstream->addCallback(cb);
 }
 
+void
+logstream::removeCallback(simgear::LogCallback* cb)
+{   
+    global_privateLogstream->removeCallback(cb);
+}
+
 void
 logstream::log( sgDebugClass c, sgDebugPriority p,
         const char* fileName, int line, const std::string& msg)
@@ -350,13 +398,13 @@ logstream::get_log_priority() const
 void
 logstream::set_log_priority( sgDebugPriority p)
 {
-    global_privateLogstream->m_logPriority = p;
+    global_privateLogstream->setLogLevels(global_privateLogstream->m_logClass, p);
 }
     
 void
 logstream::set_log_classes( sgDebugClass c)
 {
-    global_privateLogstream->m_logClass = c;
+    global_privateLogstream->setLogLevels(c, global_privateLogstream->m_logPriority);
 }
 
 logstream&
@@ -364,6 +412,13 @@ sglog()
 {
     // Force initialization of cerr.
     static std::ios_base::Init initializer;
+    
+    // http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
+    // in the absence of portable memory barrier ops in Simgear,
+    // let's keep this correct & safe
+    static SGMutex m;
+    SGGuard<SGMutex> g(m);
+    
     if( !global_logstream )
         global_logstream = new logstream();
     return *global_logstream;
@@ -375,3 +430,13 @@ logstream::logToFile( const SGPath& aPath, sgDebugClass c, sgDebugPriority p )
     global_privateLogstream->addCallback(new FileLogCallback(aPath.str(), c, p));
 }
 
+namespace simgear
+{
+
+void requestConsole()
+{
+       sglog(); // force creation
+       global_privateLogstream->requestConsole();
+}
+
+} // of namespace simgear