rpcsx/rpcs3/Gui/ConLogFrame.cpp
Nekotekina 38531459df Logging system rewritten
GUI doesn't freeze anymore
Some things simplified
2016-01-13 18:54:57 +03:00

211 lines
5.5 KiB
C++

#include "stdafx.h"
#include "stdafx_gui.h"
#include "Emu/state.h"
#include "Gui/ConLogFrame.h"
enum
{
id_log_copy, // Copy log to ClipBoard
id_log_clear, // Clear log
id_timer,
};
BEGIN_EVENT_TABLE(LogFrame, wxPanel)
EVT_CLOSE(LogFrame::OnQuit)
EVT_TIMER(id_timer, LogFrame::OnTimer)
END_EVENT_TABLE()
LogFrame::LogFrame(wxWindow* parent)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(600, 500))
, m_tabs(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS)
, m_log(new wxTextCtrl(&m_tabs, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2))
, m_tty(new wxTextCtrl(&m_tabs, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2))
, m_timer(this, id_timer)
{
// Open or create RPCS3.log; TTY.log
m_log_file.open(fs::get_config_dir() + "RPCS3.log", fom::read | fom::create);
m_tty_file.open(fs::get_config_dir() + "TTY.log", fom::read | fom::create);
// Check for updates every ~10 ms
m_timer.Start(10);
m_tty->SetBackgroundColour(wxColour("Black"));
m_log->SetBackgroundColour(wxColour("Black"));
m_tty->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
m_tabs.AddPage(m_log, "Log");
m_tabs.AddPage(m_tty, "TTY");
wxBoxSizer* s_main = new wxBoxSizer(wxVERTICAL);
s_main->Add(&m_tabs, 1, wxEXPAND);
SetSizer(s_main);
Layout();
m_log->Bind(wxEVT_RIGHT_DOWN, &LogFrame::OnRightClick, this);
Bind(wxEVT_MENU, &LogFrame::OnContextMenu, this, id_log_clear);
Bind(wxEVT_MENU, &LogFrame::OnContextMenu, this, id_log_copy);
Show();
}
LogFrame::~LogFrame()
{
}
bool LogFrame::Close(bool force)
{
return wxWindowBase::Close(force);
}
void LogFrame::OnQuit(wxCloseEvent& event)
{
event.Skip();
}
// Deals with the RightClick on Log Console, shows up the Context Menu.
void LogFrame::OnRightClick(wxMouseEvent& event)
{
wxMenu* menu = new wxMenu();
menu->Append(id_log_copy, "&Copy");
menu->AppendSeparator();
menu->Append(id_log_clear, "C&lear");
PopupMenu(menu);
}
// Well you can bind more than one control to a single handler.
void LogFrame::OnContextMenu(wxCommandEvent& event)
{
int id = event.GetId();
switch (id)
{
case id_log_clear:
m_log->Clear();
break;
case id_log_copy:
if (wxTheClipboard->Open())
{
m_tdo = new wxTextDataObject(m_log->GetStringSelection());
if (m_tdo->GetTextLength() > 0)
{
wxTheClipboard->SetData(new wxTextDataObject(m_log->GetStringSelection()));
}
wxTheClipboard->Close();
}
break;
default:
event.Skip();
}
}
void LogFrame::OnTimer(wxTimerEvent& event)
{
char buf[8192];
const auto stamp0 = std::chrono::high_resolution_clock::now();
auto get_utf8 = [&](const fs::file& file, u64 size) -> wxString
{
// Bruteforce valid UTF-8 (TODO)
for (u64 read = file.read(buf, size); read; read--)
{
wxString text = wxString::FromUTF8(buf, read);
if (!text.empty())
{
file.seek(read - size, fs::seek_cur);
return text;
}
}
return{};
};
// Check TTY logs
while (const u64 size = std::min<u64>(sizeof(buf), _log::g_tty_file.size() - m_tty_file.seek(0, fs::seek_cur)))
{
const wxString& text = get_utf8(m_tty_file, size);
if (text.size())
{
m_tty->SetDefaultStyle(wxColour(255, 255, 255));
m_tty->AppendText(text);
}
// Limit processing time
if (std::chrono::high_resolution_clock::now() >= stamp0 + 4ms)
{
break;
}
}
const auto stamp1 = std::chrono::high_resolution_clock::now();
// Check main logs
while (const u64 size = std::min<u64>(sizeof(buf), _log::g_log_file.size() - m_log_file.seek(0, fs::seek_cur)))
{
const wxString& text = get_utf8(m_log_file, size);
std::size_t start = 0, pos = 0;
for (; pos < text.size(); pos++)
{
if (text[pos] == L'·')
{
if (text.size() - pos <= 3)
{
// Cannot get log string: abort
m_log_file.seek(0 - text.substr(pos).ToUTF8().length(), fs::seek_cur);
break;
}
if (text[pos + 2] == ' ')
{
_log::level level;
wxColour color;
switch (text[pos + 1].GetValue())
{
case 'A': level = _log::level::always; color.Set(0x00, 0xFF, 0xFF); break; // Cyan
case 'F': level = _log::level::fatal; color.Set(0xFF, 0x00, 0xFF); break; // Fuchsia
case 'E': level = _log::level::error; color.Set(0xFF, 0x00, 0x00); break; // Red
case 'U': level = _log::level::todo; color.Set(0xFF, 0x60, 0x00); break; // Orange
case 'S': level = _log::level::success; color.Set(0x00, 0xFF, 0x00); break; // Green
case 'W': level = _log::level::warning; color.Set(0xFF, 0xFF, 0x00); break; // Yellow
case '!': level = _log::level::notice; color.Set(0xFF, 0xFF, 0xFF); break; // White
case 'T': level = _log::level::trace; color.Set(0x80, 0x80, 0x80); break; // Gray
default: continue;
}
if (pos != start && m_level <= rpcs3::config.misc.log.level.value())
{
m_log->SetDefaultStyle(m_color);
m_log->AppendText(text.substr(start, pos - start));
}
start = pos + 3;
m_level = level;
m_color = color;
}
}
}
if (pos != start && m_level <= rpcs3::config.misc.log.level.value())
{
m_log->SetDefaultStyle(m_color);
m_log->AppendText(text.substr(start, pos - start));
}
if (m_log->GetLastPosition() > 1024 * 1024)
{
m_log->Remove(0, m_log->GetLastPosition() - 512 * 1024);
}
// Limit processing time
if (std::chrono::high_resolution_clock::now() >= stamp1 + 3ms)
{
break;
}
}
}