rpcs3/rpcs3/Gui/ConLog.cpp
2013-11-23 23:27:58 +01:00

271 lines
5.1 KiB
C++

#include "stdafx.h"
#include "Gui/ConLog.h"
#include <wx/listctrl.h>
#include "Ini.h"
#include <fstream>
#include <vector>
LogWriter ConLog;
LogFrame* ConLogFrame;
wxCriticalSection g_cs_conlog;
static const uint max_item_count = 500;
static const uint buffer_size = 1024 * 64;
struct LogPacket
{
wxString m_prefix;
wxString m_text;
wxString m_colour;
LogPacket(const wxString& prefix, const wxString& text, const wxString& colour)
: m_prefix(prefix)
, m_text(text)
, m_colour(colour)
{
}
LogPacket()
{
}
};
struct _LogBuffer : public MTPacketBuffer<LogPacket>
{
_LogBuffer() : MTPacketBuffer<LogPacket>(buffer_size)
{
}
void _push(const LogPacket& data)
{
const u32 sprefix = data.m_prefix.Len();
const u32 stext = data.m_text.Len();
const u32 scolour = data.m_colour.Len();
m_buffer.Reserve(
sizeof(u32) + sprefix +
sizeof(u32) + stext +
sizeof(u32) + scolour);
u32 c_put = m_put;
memcpy(&m_buffer[c_put], &sprefix, sizeof(u32));
c_put += sizeof(u32);
memcpy(&m_buffer[c_put], data.m_prefix.c_str(), sprefix);
c_put += sprefix;
memcpy(&m_buffer[c_put], &stext, sizeof(u32));
c_put += sizeof(u32);
memcpy(&m_buffer[c_put], data.m_text.c_str(), stext);
c_put += stext;
memcpy(&m_buffer[c_put], &scolour, sizeof(u32));
c_put += sizeof(u32);
memcpy(&m_buffer[c_put], data.m_colour.c_str(), scolour);
c_put += scolour;
m_put = c_put;
CheckBusy();
}
LogPacket _pop()
{
LogPacket ret;
u32 c_get = m_get;
const u32& sprefix = *(u32*)&m_buffer[c_get];
c_get += sizeof(u32);
if(sprefix) memcpy(wxStringBuffer(ret.m_prefix, sprefix), &m_buffer[c_get], sprefix);
c_get += sprefix;
const u32& stext = *(u32*)&m_buffer[c_get];
c_get += sizeof(u32);
if(stext) memcpy(wxStringBuffer(ret.m_text, stext), &m_buffer[c_get], stext);
c_get += stext;
const u32& scolour = *(u32*)&m_buffer[c_get];
c_get += sizeof(u32);
if(scolour) memcpy(wxStringBuffer(ret.m_colour, scolour), &m_buffer[c_get], scolour);
c_get += scolour;
m_get = c_get;
if(!HasNewPacket()) Flush();
return ret;
}
} LogBuffer;
LogWriter::LogWriter()
{
if(!m_logfile.Open(_PRGNAME_ ".log", wxFile::write))
{
wxMessageBox("Cann't create log file! (" _PRGNAME_ ".log)", wxMessageBoxCaptionStr, wxICON_ERROR);
}
}
void LogWriter::WriteToLog(wxString prefix, wxString value, wxString colour/*, wxColour bgcolour*/)
{
if(ThreadBase* thr = GetCurrentNamedThread())
{
prefix = (prefix.IsEmpty() ? "" : prefix + " : ") + thr->GetThreadName();
}
if(m_logfile.IsOpened())
m_logfile.Write((prefix.IsEmpty() ? wxString(wxEmptyString) : "[" + prefix + "]: ") + value + "\n");
if(!ConLogFrame) return;
wxCriticalSectionLocker lock(g_cs_conlog);
if(wxThread::IsMain())
{
while(LogBuffer.IsBusy()) wxYieldIfNeeded();
}
else
{
while(LogBuffer.IsBusy()) Sleep(1);
}
//if(LogBuffer.put == LogBuffer.get) LogBuffer.Flush();
LogBuffer.Push(LogPacket(prefix, value, colour));
}
wxString FormatV(const wxString fmt, va_list args)
{
int length = 256;
wxString str;
for(;;)
{
str.Clear();
wxStringBuffer buf(str, length+1);
memset(buf, 0, length+1);
if(vsnprintf(buf, length, fmt, args) != -1) break;
length *= 2;
}
return str;
}
void LogWriter::Write(const wxString fmt, ...)
{
va_list list;
va_start(list, fmt);
const wxString& frmt = FormatV(fmt, list);
va_end(list);
WriteToLog("!", frmt, "White");
}
void LogWriter::Error(const wxString fmt, ...)
{
va_list list;
va_start(list, fmt);
const wxString& frmt = FormatV(fmt, list);
va_end(list);
WriteToLog("E", frmt, "Red");
}
void LogWriter::Warning(const wxString fmt, ...)
{
va_list list;
va_start(list, fmt);
const wxString& frmt = FormatV(fmt, list);
va_end(list);
WriteToLog("W", frmt, "Yellow");
}
void LogWriter::SkipLn()
{
WriteToLog(wxEmptyString, wxEmptyString, "Black");
}
BEGIN_EVENT_TABLE(LogFrame, wxPanel)
EVT_CLOSE(LogFrame::OnQuit)
END_EVENT_TABLE()
LogFrame::LogFrame(wxWindow* parent)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(600, 500))
, ThreadBase(false, "LogThread")
, m_log(*new wxListView(this))
{
m_log.InsertColumn(0, wxEmptyString);
m_log.InsertColumn(1, "Log");
m_log.SetBackgroundColour(wxColour("Black"));
wxBoxSizer& s_main = *new wxBoxSizer(wxVERTICAL);
s_main.Add(&m_log, 1, wxEXPAND);
SetSizer(&s_main);
Layout();
Show();
ThreadBase::Start();
}
LogFrame::~LogFrame()
{
}
bool LogFrame::Close(bool force)
{
Stop();
ConLogFrame = NULL;
return wxWindowBase::Close(force);
}
void LogFrame::Task()
{
while(!TestDestroy())
{
if(!LogBuffer.HasNewPacket())
{
Sleep(1);
continue;
}
else
{
wxThread::Yield();
}
const LogPacket item = LogBuffer.Pop();
while(m_log.GetItemCount() > max_item_count)
{
m_log.DeleteItem(0);
wxThread::Yield();
}
const int cur_item = m_log.GetItemCount();
m_log.InsertItem(cur_item, item.m_prefix);
m_log.SetItem(cur_item, 1, item.m_text);
m_log.SetItemTextColour(cur_item, item.m_colour);
m_log.SetColumnWidth(0, -1);
m_log.SetColumnWidth(1, -1);
::SendMessage((HWND)m_log.GetHWND(), WM_VSCROLL, SB_BOTTOM, 0);
}
LogBuffer.Flush();
}
void LogFrame::OnQuit(wxCloseEvent& event)
{
Stop();
ConLogFrame = NULL;
event.Skip();
}