wxgui: Improved threading model used by the log window, plus a few minor fixes to main window startup/shutdown code.

git-svn-id: http://pcsx2.googlecode.com/svn/branches/wxgui@1572 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-07-26 23:53:52 +00:00
parent 3751c928d3
commit 6566f6a018
12 changed files with 451 additions and 244 deletions

View File

@ -52,7 +52,10 @@ public:
wxPoint DisplayPosition;
wxSize DisplaySize;
void LoadSave( IniInterface& conf );
// Size of the font in points.
int FontSize;
void LoadSave( IniInterface& conf, const wxChar* title );
};
// ------------------------------------------------------------------------
@ -213,7 +216,8 @@ public:
SpeedhackOptions Speedhacks;
GamefixOptions Gamefixes;
VideoOptions Video;
ConsoleLogOptions ConLogBox;
ConsoleLogOptions ProgLogBox;
ConsoleLogOptions Ps2ConBox;
FolderOptions Folders;
FilenameOptions BaseFilenames;
McdSysOptions MemoryCards;

View File

@ -203,13 +203,6 @@ DEV9handler dev9Handler;
USBhandler usbHandler;
uptr pDsp;
void PopulateListCtrls( const wxString& plugpath )
{
//if( CheckVersion( "GS", PS2E_LT_GS, PS2E_GS_VERSION ) )
// AddPlugin(hWC_GS, winConfig.GS);
}
// ------------------------------------------------------------------------
int OpenPlugins(const char* pTitleFilename)
{

View File

@ -29,44 +29,85 @@ using namespace Threading;
class MainEmuFrame;
class IniInterface;
class LogWriteEvent;
extern wxFileHistory* g_RecentIsoList;
class LogWriteEvent;
DECLARE_EVENT_TYPE(wxEVT_DockConsole, -1);
extern wxRect wxGetDisplayArea();
extern bool pxIsValidWindowPosition( const wxWindow& window, const wxPoint& windowPos );
static const bool EnableThreadedLoggingTest = true;
//////////////////////////////////////////////////////////////////////////////////////////
// ConsoleThreadTest -- useful class for unit testing the thread safety and general performance
// of the console logger.
//
class ConsoleTestThread : public Thread
{
protected:
volatile bool m_done;
int Callback();
public:
ConsoleTestThread() :
m_done( false )
{
}
~ConsoleTestThread()
{
m_done = true;
}
};
//////////////////////////////////////////////////////////////////////////////////////////
//
class ConsoleLogFrame : public wxFrame, public NoncopyableObject
{
public:
typedef AppConfig::ConsoleLogOptions ConLogConfig;
protected:
class ColorArray : public NoncopyableObject
{
protected:
SafeArray<wxTextAttr> m_table;
wxTextAttr m_color_default;
SafeArray<wxTextAttr> m_table;
wxTextAttr m_color_default;
public:
ColorArray();
virtual ~ColorArray();
ColorArray( int fontsize=8 );
void Create( int fontsize );
void Cleanup();
void SetFont( const wxFont& font );
void SetFont( int fontsize );
const wxTextAttr& operator[]( Console::Colors coloridx ) const
{
return m_table[(int)coloridx];
}
void SetFont( const wxFont& font );
const wxTextAttr& Default() { return m_table[0]; }
};
protected:
wxTextCtrl& m_TextCtrl;
ColorArray m_ColorTable;
Console::Colors m_curcolor;
volatile long m_msgcounter; // used to track queued messages and throttle load placed on the gui message pump
ConLogConfig m_conf;
wxTextCtrl& m_TextCtrl;
ColorArray m_ColorTable;
Console::Colors m_curcolor;
volatile long m_msgcounter; // used to track queued messages and throttle load placed on the gui message pump
Semaphore m_semaphore;
// Threaded log spammer, useful for testing console logging performance.
ConsoleTestThread* m_threadlogger;
public:
// ctor & dtor
ConsoleLogFrame( MainEmuFrame *pParent, const wxString& szTitle, const AppConfig::ConsoleLogOptions& options );
ConsoleLogFrame( MainEmuFrame *pParent, const wxString& szTitle, const ConLogConfig& options );
virtual ~ConsoleLogFrame();
virtual void Write( const wxString& text );
@ -74,6 +115,10 @@ public:
virtual void ClearColor();
virtual void DockedMove();
// Retreives the current configuration options settings for this box.
// (settings change if the user moves the window or changes the font size)
const ConLogConfig& GetConfig() const { return m_conf; }
void Write( Console::Colors color, const wxString& text );
void Newline();
void CountMessage();
@ -86,12 +131,16 @@ protected:
virtual void OnClose(wxMenuEvent& event);
virtual void OnSave (wxMenuEvent& event);
virtual void OnClear(wxMenuEvent& event);
void OnFontSize(wxMenuEvent& event);
virtual void OnCloseWindow(wxCloseEvent& event);
void OnWrite( wxCommandEvent& event );
void OnNewline( wxCommandEvent& event );
void OnSetTitle( wxCommandEvent& event );
void OnDockedMove( wxCommandEvent& event );
void OnSemaphoreWait( wxCommandEvent& event );
// common part of OnClose() and OnCloseWindow()
virtual void DoClose();
@ -169,6 +218,8 @@ public:
void OnInitCmdLine( wxCmdLineParser& parser );
bool OnCmdLineParsed( wxCmdLineParser& parser );
bool PrepForExit();
const wxBitmap& GetLogoBitmap();
wxImageList& GetImgList_Config();
wxImageList& GetImgList_Toolbars();
@ -191,6 +242,14 @@ public:
return m_Ps2ConLogBox;
}
void CloseProgramLog()
{
m_ProgramLogBox->Close();
// disable future console log messages from being sent to the window.
m_ProgramLogBox = NULL;
}
void ProgramLog_CountMsg()
{
if( m_ProgramLogBox == NULL ) return;

View File

@ -349,9 +349,9 @@ wxString AppConfig::FullpathToMcd( uint mcdidx ) const { return Path::Combine( F
// GCC Note: wxT() macro is required when using string token pasting. For some reason L generates
// syntax errors. >_<
//
#define IniEntry( varname, defval ) ini.Entry( wxT(#varname), varname, defval )
#define IniBitfield( varname, defval ) varname = ini.EntryBitfield( wxT(#varname), varname, defval )
#define IniBitBool( varname, defval ) varname = ini.EntryBitBool( wxT(#varname), varname, defval )
#define IniEntry( varname, defval ) ini.Entry( wxT(#varname), varname, defval )
#define IniBitfield( varname, defval ) varname = ini.EntryBitfield( wxT(#varname), varname, defval )
#define IniBitBool( varname, defval ) varname = ini.EntryBitBool( wxT(#varname), !!varname, defval )
// ------------------------------------------------------------------------
void AppConfig::LoadSaveUserMode( IniInterface& ini )
@ -376,7 +376,9 @@ void AppConfig::LoadSave( IniInterface& ini )
IniEntry( CdvdVerboseReads, false );
// Process various sub-components:
ConLogBox.LoadSave( ini );
ProgLogBox.LoadSave( ini, L"ProgramLog" );
Ps2ConBox.LoadSave( ini, L"Ps2Console" );
Speedhacks.LoadSave( ini );
Folders.LoadSave( ini );
BaseFilenames.LoadSave( ini );
@ -450,14 +452,15 @@ void AppConfig::Save()
}
// ------------------------------------------------------------------------
void AppConfig::ConsoleLogOptions::LoadSave( IniInterface& ini )
void AppConfig::ConsoleLogOptions::LoadSave( IniInterface& ini, const wxChar* logger )
{
ini.SetPath( L"ConsoleLog" );
ini.SetPath( logger );
IniEntry( Visible, false );
IniEntry( AutoDock, true );
IniEntry( DisplayPosition, wxDefaultPosition );
IniEntry( DisplaySize, wxSize( 540, 540 ) );
IniEntry( FontSize, 8 );
ini.SetPath( L".." );
}

View File

@ -34,15 +34,33 @@
DECLARE_EVENT_TYPE(wxEVT_LOG_Write, -1)
DECLARE_EVENT_TYPE(wxEVT_LOG_Newline, -1)
DECLARE_EVENT_TYPE(wxEVT_SetTitleText, -1)
DECLARE_EVENT_TYPE(wxEVT_SemaphoreWait, -1);
DEFINE_EVENT_TYPE(wxEVT_LOG_Write)
DEFINE_EVENT_TYPE(wxEVT_LOG_Newline)
DEFINE_EVENT_TYPE(wxEVT_SetTitleText)
DEFINE_EVENT_TYPE(wxEVT_DockConsole)
DEFINE_EVENT_TYPE(wxEVT_SemaphoreWait);
using Console::Colors;
//////////////////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
int ConsoleTestThread::Callback()
{
static int numtrack = 0;
while( !m_done )
{
// Two lines, both formatted, and varied colors. This makes for a fairly realistic
// worst case scenario (without being entirely unrealistic).
Console::WriteLn( wxsFormat( L"This is a threaded logging test. Something bad could happen... %d", ++numtrack ) );
Console::Status( wxsFormat( L"Testing high stress loads %s", L"(multi-color)" ) );
Sleep( 0 );
}
return 0;
}
// ----------------------------------------------------------------------------
// pass an uninitialized file object, the function will ask the user for the
// filename and try to open it, returns true on success (file was opened),
// false if file couldn't be opened/created and -1 if the file selection
@ -86,11 +104,24 @@ static bool OpenLogFile(wxFile& file, wxString& filename, wxWindow *parent)
}
// ------------------------------------------------------------------------
ConsoleLogFrame::ColorArray::ColorArray() :
// fontsize - size of the font specified in points.
// (actual font used is the system-selected fixed-width font)
//
ConsoleLogFrame::ColorArray::ColorArray( int fontsize ) :
m_table( 8 )
{
wxFont fixed( 8, wxMODERN, wxNORMAL, wxNORMAL );
wxFont fixedB( 8, wxMODERN, wxNORMAL, wxBOLD );
Create( fontsize );
}
ConsoleLogFrame::ColorArray::~ColorArray()
{
Cleanup();
}
void ConsoleLogFrame::ColorArray::Create( int fontsize )
{
wxFont fixed( fontsize, wxMODERN, wxNORMAL, wxNORMAL );
wxFont fixedB( fontsize, wxMODERN, wxNORMAL, wxBOLD );
// Standard R, G, B format:
new (&m_table[Color_Black]) wxTextAttr( wxColor( 0, 0, 0 ), wxNullColour, fixed );
@ -103,65 +134,187 @@ ConsoleLogFrame::ColorArray::ColorArray() :
new (&m_table[Color_White]) wxTextAttr( wxColor( 128, 128, 128 ), wxNullColour, fixed );
}
// ------------------------------------------------------------------------
// Threading: this function may employ the use of GDI objects in Win32, which means it's
// not safe to be clled from anything but the main gUI thread.
//
void ConsoleLogFrame::ColorArray::Cleanup()
{
// The contents of m_table were created with placement new, and must be
// disposed of manually:
for( int i=0; i<8; ++i )
m_table[i].~wxTextAttr();
}
// fixme - not implemented yet.
void ConsoleLogFrame::ColorArray::SetFont( const wxFont& font )
{
for( int i=0; i<8; ++i )
m_table[i].SetFont( font );
//for( int i=0; i<8; ++i )
// m_table[i].SetFont( font );
}
void ConsoleLogFrame::ColorArray::SetFont( int fontsize )
{
Cleanup();
Create( fontsize );
}
static const Console::Colors DefaultConsoleColor = Color_White;
enum MenuIDs_t
{
MenuID_FontSize_Small = 0x10,
MenuID_FontSize_Normal,
MenuID_FontSize_Large,
MenuID_FontSize_Huge,
};
// ------------------------------------------------------------------------
ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, const AppConfig::ConsoleLogOptions& options ) :
wxFrame(parent, wxID_ANY, title)
, m_conf( options )
, m_TextCtrl( *new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxHSCROLL | wxTE_READONLY | wxTE_RICH2 ) )
, m_ColorTable()
, m_ColorTable( options.FontSize )
, m_curcolor( DefaultConsoleColor )
, m_msgcounter( 0 )
, m_threadlogger( EnableThreadedLoggingTest ? new ConsoleTestThread() : NULL )
{
m_TextCtrl.SetBackgroundColour( wxColor( 230, 235, 242 ) );
// create menu
wxMenuBar *pMenuBar = new wxMenuBar;
wxMenu *pMenu = new wxMenu;
pMenu->Append(wxID_SAVE, L"&Save...", _("Save log contents to file"));
pMenu->Append(wxID_CLEAR, L"C&lear", _("Clear the log contents"));
pMenu->AppendSeparator();
pMenu->Append(wxID_CLOSE, L"&Close", _("Close this window"));
// create Log menu (contains most options)
wxMenuBar *pMenuBar = new wxMenuBar();
wxMenu& menuLog = *new wxMenu();
menuLog.Append(wxID_SAVE, _("&Save..."), _("Save log contents to file"));
menuLog.Append(wxID_CLEAR, _("C&lear"), _("Clear the log window contents"));
menuLog.AppendSeparator();
menuLog.Append(wxID_CLOSE, _("&Close"), _("Close this log window; contents are preserved"));
pMenuBar->Append(pMenu, L"&Log");
SetMenuBar(pMenuBar);
// create Appearance menu and submenus
// status bar for menu prompts
CreateStatusBar();
ClearColor();
wxMenu& menuFontSizes = *new wxMenu();
menuFontSizes.Append( MenuID_FontSize_Small, _("Small"), _("Fits a lot of log in a microcosmically small area."),
wxITEM_RADIO )->Check( options.FontSize == 7 );
menuFontSizes.Append( MenuID_FontSize_Normal, _("Normal"),_("It's what I use (the programmer guy)."),
wxITEM_RADIO )->Check( options.FontSize == 8 );
menuFontSizes.Append( MenuID_FontSize_Large, _("Large"), _("Its nice and readable."),
wxITEM_RADIO )->Check( options.FontSize == 10 );
menuFontSizes.Append( MenuID_FontSize_Huge, _("Huge"), _("In case you have a really high res display."),
wxITEM_RADIO )->Check( options.FontSize == 12 );
wxMenu& menuAppear = *new wxMenu();
menuAppear.Append( wxID_ANY, _("Always on Top"),
_("When checked the log window will be visible over other foreground windows."), wxITEM_CHECK );
menuAppear.Append( wxID_ANY, _("Font Size"), &menuFontSizes );
pMenuBar->Append(&menuLog, _("&Log"));
pMenuBar->Append(&menuAppear, _("&Appearance"));
SetMenuBar(pMenuBar);
// status bar for menu prompts
CreateStatusBar();
ClearColor();
SetSize( wxRect( options.DisplayPosition, options.DisplaySize ) );
Show( options.Visible );
// Bind Events:
Connect( wxID_OPEN, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ConsoleLogFrame::OnOpen ) );
Connect( wxID_CLOSE, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ConsoleLogFrame::OnClose ) );
Connect( wxID_SAVE, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ConsoleLogFrame::OnSave ) );
Connect( wxID_CLEAR, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ConsoleLogFrame::OnClear ) );
Connect( wxID_OPEN, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(ConsoleLogFrame::OnOpen) );
Connect( wxID_CLOSE, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(ConsoleLogFrame::OnClose) );
Connect( wxID_SAVE, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(ConsoleLogFrame::OnSave) );
Connect( wxID_CLEAR, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(ConsoleLogFrame::OnClear) );
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler(ConsoleLogFrame::OnCloseWindow) );
Connect( wxEVT_MOVE, wxMoveEventHandler(ConsoleLogFrame::OnMoveAround) );
Connect( wxEVT_SIZE, wxSizeEventHandler(ConsoleLogFrame::OnResize) );
Connect( MenuID_FontSize_Small, MenuID_FontSize_Huge, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ConsoleLogFrame::OnFontSize ) );
Connect( wxEVT_LOG_Write, wxCommandEventHandler(ConsoleLogFrame::OnWrite) );
Connect( wxEVT_LOG_Newline, wxCommandEventHandler(ConsoleLogFrame::OnNewline) );
Connect( wxEVT_SetTitleText,wxCommandEventHandler(ConsoleLogFrame::OnSetTitle) );
Connect( wxEVT_DockConsole, wxCommandEventHandler(ConsoleLogFrame::OnDockedMove) );
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler(ConsoleLogFrame::OnCloseWindow) );
Connect( wxEVT_MOVE, wxMoveEventHandler(ConsoleLogFrame::OnMoveAround) );
Connect( wxEVT_SIZE, wxSizeEventHandler(ConsoleLogFrame::OnResize) );
Connect( wxEVT_LOG_Write, wxCommandEventHandler(ConsoleLogFrame::OnWrite) );
Connect( wxEVT_LOG_Newline, wxCommandEventHandler(ConsoleLogFrame::OnNewline) );
Connect( wxEVT_SetTitleText, wxCommandEventHandler(ConsoleLogFrame::OnSetTitle) );
Connect( wxEVT_DockConsole, wxCommandEventHandler(ConsoleLogFrame::OnDockedMove) );
Connect( wxEVT_SemaphoreWait, wxCommandEventHandler(ConsoleLogFrame::OnSemaphoreWait) );
if( m_threadlogger != NULL )
m_threadlogger->Start();
}
ConsoleLogFrame::~ConsoleLogFrame() { }
ConsoleLogFrame::~ConsoleLogFrame()
{
safe_delete( m_threadlogger );
}
void ConsoleLogFrame::SetColor( Colors color )
{
if( color != m_curcolor )
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_curcolor=color] );
}
void ConsoleLogFrame::ClearColor()
{
if( DefaultConsoleColor != m_curcolor )
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_curcolor=DefaultConsoleColor] );
}
void ConsoleLogFrame::Write( const wxString& text )
{
// remove selection (WriteText is in fact ReplaceSelection)
// TODO : Optimize this to only replaceslection if some selection
// messages have been recieved since the last write.
#ifdef __WXMSW__
wxTextPos nLen = m_TextCtrl.GetLastPosition();
m_TextCtrl.SetSelection(nLen, nLen);
#endif
m_TextCtrl.AppendText( text );
// cap at 256k for now...
// fixme - 256k runs well on win32 but appears to be very sluggish on linux. Might
// need platform dependent defaults here. - air
if( m_TextCtrl.GetLastPosition() > 0x40000 )
{
m_TextCtrl.Remove( 0, 0x10000 );
}
}
// Implementation note: Calls SetColor and Write( text ). Override those virtuals
// and this one will magically follow suite. :)
void ConsoleLogFrame::Write( Colors color, const wxString& text )
{
SetColor( color );
Write( text );
}
void ConsoleLogFrame::Newline()
{
Write( L"\n" );
}
void ConsoleLogFrame::DoClose()
{
// instead of closing just hide the window to be able to Show() it later
Show(false);
if( wxFrame* main = wxGetApp().GetMainWindow() )
wxStaticCast( main, MainEmuFrame )->OnLogBoxHidden();
}
void ConsoleLogFrame::DockedMove()
{
SetPosition( m_conf.DisplayPosition );
}
// =================================================================================
// Section : Event Handlers
// * Misc Window Events (Move, Resize,etc)
// * Menu Events
// * Logging Events
// =================================================================================
// Special event recieved from a window we're docked against.
void ConsoleLogFrame::OnDockedMove( wxCommandEvent& event )
{
DockedMove();
}
void ConsoleLogFrame::OnMoveAround( wxMoveEvent& evt )
{
@ -173,30 +326,33 @@ void ConsoleLogFrame::OnMoveAround( wxMoveEvent& evt )
wxPoint topright( main->GetRect().GetTopRight() );
wxRect snapzone( topright - wxSize( 8,8 ), wxSize( 16,16 ) );
g_Conf->ConLogBox.AutoDock = snapzone.Contains( GetPosition() );
m_conf.AutoDock = snapzone.Contains( GetPosition() );
//Console::WriteLn( "DockCheck: %d", params g_Conf->ConLogBox.AutoDock );
if( g_Conf->ConLogBox.AutoDock )
if( m_conf.AutoDock )
{
SetPosition( topright + wxSize( 1,0 ) );
g_Conf->ConLogBox.AutoDock = true;
m_conf.AutoDock = true;
}
}
g_Conf->ConLogBox.DisplayPosition = GetPosition();
m_conf.DisplayPosition = GetPosition();
evt.Skip();
}
void ConsoleLogFrame::OnResize( wxSizeEvent& evt )
{
g_Conf->ConLogBox.DisplaySize = GetSize();
m_conf.DisplaySize = GetSize();
evt.Skip();
}
void ConsoleLogFrame::DoClose()
void ConsoleLogFrame::OnCloseWindow(wxCloseEvent& event)
{
// instead of closing just hide the window to be able to Show() it later
Show(false);
if( wxFrame* main = wxGetApp().GetMainWindow() )
wxStaticCast( main, MainEmuFrame )->OnLogBoxHidden();
if( event.CanVeto() )
DoClose();
else
{
safe_delete( m_threadlogger );
event.Skip();
}
}
void ConsoleLogFrame::OnOpen(wxMenuEvent& WXUNUSED(event))
@ -209,14 +365,6 @@ void ConsoleLogFrame::OnClose( wxMenuEvent& event )
DoClose();
}
void ConsoleLogFrame::OnCloseWindow(wxCloseEvent& event)
{
if( event.CanVeto() )
DoClose();
else
event.Skip();
}
void ConsoleLogFrame::OnSave(wxMenuEvent& WXUNUSED(event))
{
wxString filename;
@ -248,17 +396,32 @@ void ConsoleLogFrame::OnClear(wxMenuEvent& WXUNUSED(event))
m_TextCtrl.Clear();
}
void ConsoleLogFrame::SetColor( Colors color )
void ConsoleLogFrame::OnFontSize(wxMenuEvent& evt )
{
if( color != m_curcolor )
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_curcolor=color] );
int ptsize = 8;
switch( evt.GetId() )
{
case MenuID_FontSize_Small: ptsize = 7; break;
case MenuID_FontSize_Normal: ptsize = 8; break;
case MenuID_FontSize_Large: ptsize = 10; break;
case MenuID_FontSize_Huge: ptsize = 12; break;
}
if( ptsize == m_conf.FontSize ) return;
m_conf.FontSize = ptsize;
m_ColorTable.SetFont( ptsize );
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_curcolor] );
// TODO: Process the attributes of each character and upgrade the font size,
// while still retaining color and bold settings... (might be slow but then
// it hardly matters being a once-in-a-bluemoon action).
}
void ConsoleLogFrame::ClearColor()
{
if( DefaultConsoleColor != m_curcolor )
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_curcolor=DefaultConsoleColor] );
}
// ----------------------------------------------------------------------------
// Logging Events (typically recieved from Console class interfaces)
// ----------------------------------------------------------------------------
void ConsoleLogFrame::OnWrite( wxCommandEvent& event )
{
@ -277,48 +440,9 @@ void ConsoleLogFrame::OnSetTitle( wxCommandEvent& event )
SetTitle( event.GetString() );
}
void ConsoleLogFrame::OnDockedMove( wxCommandEvent& event )
void ConsoleLogFrame::OnSemaphoreWait( wxCommandEvent& event )
{
DockedMove();
}
void ConsoleLogFrame::DockedMove()
{
if( g_Conf != NULL )
SetPosition( g_Conf->ConLogBox.DisplayPosition );
}
void ConsoleLogFrame::Write( const wxString& text )
{
// remove selection (WriteText is in fact ReplaceSelection)
#ifdef __WXMSW__
wxTextPos nLen = m_TextCtrl.GetLastPosition();
m_TextCtrl.SetSelection(nLen, nLen);
#endif
m_TextCtrl.AppendText( text );
// cap at 256k for now...
// fixme - 256k runs well on win32 but appears to be very sluggish on linux. Might
// need platform dependent defaults here. - air
if( m_TextCtrl.GetLastPosition() > 0x40000 )
{
m_TextCtrl.Remove( 0, 0x10000 );
}
}
// Implementation note: Calls SetColor and Write( text ). Override those virtuals
// and this one will magically follow suite. :)
void ConsoleLogFrame::Write( Colors color, const wxString& text )
{
SetColor( color );
Write( text );
}
void ConsoleLogFrame::Newline()
{
Write( L"\n" );
m_semaphore.Post();
}
// ------------------------------------------------------------------------
@ -330,32 +454,43 @@ void ConsoleLogFrame::Newline()
// catch up.
void ConsoleLogFrame::CountMessage()
{
_InterlockedIncrement( &m_msgcounter );
long result = _InterlockedIncrement( &m_msgcounter );
if( m_msgcounter > 0x10 ) // 0x10 -- arbitrary value that seems to work well on my C2Q 3.2ghz
if( result > 0x20 ) // 0x20 -- arbitrary value that seems to work well (tested on P4 and C2D)
{
if( !wxThread::IsMain() )
{
// fixme : It'd be swell if this could be replaced with something that uses
// pthreads semaphores instead of Sleep, but I haven't been able to conjure up
// such an alternative yet.
// Append an event that'll post up our semaphore. It'll get run "in
// order" which means when it posts all queued messages will have been
// processed.
while( m_msgcounter > 1 ) { Sleep(1); }
Sleep(0); // give the main thread more time to catch up. :|
wxCommandEvent evt( wxEVT_SemaphoreWait );
GetEventHandler()->AddPendingEvent( evt );
m_semaphore.Wait();
}
}
}
// Thread Safety note: This function expects to be called from the Main GUI thread
// only. If called from a thread other than Main, it will generate an assertion failure.
//
void ConsoleLogFrame::DoMessage()
{
wxASSERT_MSG( wxThread::IsMain(), L"DoMessage must only be called from the main gui thread!" );
int cur = _InterlockedDecrement( &m_msgcounter );
// We need to freeze the control if there are more than 2 pending messages,
// otherwise the redraw of the console will prevent it from ever being able to
// catch up with the rate the queue is being filled, and the whole app could
// deadlock. >_<
if( m_TextCtrl.IsFrozen() )
{
if( cur <= 1 && wxThread::IsMain() )
if( cur < 1 )
m_TextCtrl.Thaw();
}
else if( cur >= 4 && wxThread::IsMain() )
else if( cur >= 3 )
{
m_TextCtrl.Freeze();
}
@ -391,9 +526,9 @@ namespace Console
if( emuLog != NULL )
fputs( "\n", emuLog );
wxGetApp().ProgramLog_CountMsg();
wxCommandEvent evt( wxEVT_LOG_Newline );
wxGetApp().ProgramLog_PostEvent( evt );
wxGetApp().ProgramLog_CountMsg();
return false;
}
@ -403,12 +538,11 @@ namespace Console
if( emuLog != NULL )
fputs( fmt, emuLog );
wxGetApp().ProgramLog_CountMsg();
wxCommandEvent evt( wxEVT_LOG_Write );
evt.SetString( wxString::FromAscii( fmt ) );
evt.SetExtraLong( th_CurrentColor );
wxGetApp().ProgramLog_PostEvent( evt );
wxGetApp().ProgramLog_CountMsg();
return false;
}
@ -418,12 +552,11 @@ namespace Console
if( emuLog != NULL )
fputs( fmt.ToAscii().data(), emuLog );
wxGetApp().ProgramLog_CountMsg();
wxCommandEvent evt( wxEVT_LOG_Write );
evt.SetString( fmt );
evt.SetExtraLong( th_CurrentColor );
wxGetApp().ProgramLog_PostEvent( evt );
wxGetApp().ProgramLog_CountMsg();
return false;
}
@ -439,12 +572,11 @@ namespace Console
fputs( "\n", emuLog );
}
wxGetApp().ProgramLog_CountMsg();
wxCommandEvent evt( wxEVT_LOG_Write );
evt.SetString( wxString::FromAscii( fmt ) + L"\n" );
evt.SetExtraLong( th_CurrentColor );
wxGetApp().ProgramLog_PostEvent( evt );
wxGetApp().ProgramLog_CountMsg();
return false;
}
@ -460,12 +592,11 @@ namespace Console
fputs( "\n", emuLog );
}
wxGetApp().ProgramLog_CountMsg();
wxCommandEvent evt( wxEVT_LOG_Write );
evt.SetString( fmt + L"\n" );
evt.SetExtraLong( th_CurrentColor );
wxGetApp().ProgramLog_PostEvent( evt );
wxGetApp().ProgramLog_CountMsg();
return false;
}

View File

@ -110,22 +110,23 @@ void MainEmuFrame::PopulatePadMenu()
//
void MainEmuFrame::OnCloseWindow(wxCloseEvent& evt)
{
wxCloseEvent conevt( wxEVT_CLOSE_WINDOW );
conevt.SetCanVeto( false ); // tells the console to close rather than hide
wxGetApp().ProgramLog_PostEvent( conevt );
// Note Closure Veting would be handled here (user prompt confirmation
// of closing the app)
wxGetApp().PrepForExit();
evt.Skip();
}
void MainEmuFrame::OnMoveAround( wxMoveEvent& evt )
{
// Uncomment this when going logger stress testing (and them move the window around)
// Uncomment this when doing logger stress testing (and then move the window around
// while the logger spams itself)
// ... makes for a good test of the message pump's responsiveness.
//Console::Notice( "Mess o' crashiness? It can't be!" );
Console::Notice( "Mess o' crashiness? It can't be!" );
// evt.GetPosition() returns the client area position, not the window frame position.
// So read the window position directly... hope there's no problem with this too. :| --air
g_Conf->MainGuiPosition = GetPosition();
// So read the window's screen-relative position directly.
g_Conf->MainGuiPosition = GetScreenPosition();
// wxGTK note: X sends gratuitous amounts of OnMove messages for various crap actions
// like selecting or deselecting a window, which muck up docking logic. We filter them
@ -135,11 +136,10 @@ void MainEmuFrame::OnMoveAround( wxMoveEvent& evt )
if( lastpos == evt.GetPosition() ) return;
lastpos = evt.GetPosition();
if( g_Conf->ConLogBox.AutoDock )
if( g_Conf->ProgLogBox.AutoDock )
{
g_Conf->ConLogBox.DisplayPosition = GetRect().GetTopRight();
wxCommandEvent conevt( wxEVT_DockConsole );
wxGetApp().ProgramLog_PostEvent( conevt );
g_Conf->ProgLogBox.DisplayPosition = GetRect().GetTopRight();
wxGetApp().GetProgramLog()->SetPosition( g_Conf->ProgLogBox.DisplayPosition );
}
//evt.Skip();
@ -147,7 +147,7 @@ void MainEmuFrame::OnMoveAround( wxMoveEvent& evt )
void MainEmuFrame::OnLogBoxHidden()
{
g_Conf->ConLogBox.Visible = false;
g_Conf->ProgLogBox.Visible = false;
m_MenuItem_Console.Check( false );
}
@ -182,6 +182,24 @@ void MainEmuFrame::ConnectMenus()
ConnectMenu( Menu_About, Menu_ShowAboutBox );
}
void MainEmuFrame::InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf )
{
conf.DisplaySize.Set(
std::min( std::max( conf.DisplaySize.GetWidth(), 160 ), wxGetDisplayArea().GetWidth() ),
std::min( std::max( conf.DisplaySize.GetHeight(), 160 ), wxGetDisplayArea().GetHeight() )
);
if( conf.AutoDock )
{
conf.DisplayPosition = GetScreenPosition() + wxSize( GetSize().x, 0 );
}
else if( conf.DisplayPosition != wxDefaultPosition )
{
if( !wxGetDisplayArea().Contains( wxRect( conf.DisplayPosition, conf.DisplaySize ) ) )
conf.DisplayPosition = wxDefaultPosition;
}
}
// ------------------------------------------------------------------------
MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
wxFrame(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~(wxMAXIMIZE_BOX | wxRESIZE_BORDER) ),
@ -239,36 +257,18 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
joe.Add( &m_background );
SetSizerAndFit( &joe );
// Valid zone for window positioning.
// Top/Left boundaries are fairly strict, since any more offscreen and the window titlebar
// would be obscured from being grabbable.
wxRect screenzone( wxPoint(), wxGetDisplaySize() );
// Use default window position if the configured windowpos is invalid (partially offscreen)
if( g_Conf->MainGuiPosition == wxDefaultPosition || !screenzone.Contains( wxRect( g_Conf->MainGuiPosition, GetSize() ) ) )
g_Conf->MainGuiPosition = GetPosition();
if( g_Conf->MainGuiPosition == wxDefaultPosition || !pxIsValidWindowPosition( *this, g_Conf->MainGuiPosition) )
g_Conf->MainGuiPosition = GetScreenPosition();
else
SetPosition( g_Conf->MainGuiPosition );
// ------------------------------------------------------------------------
// Sort out the console log window position (must be done after fitting the window
// sizer, to ensure correct 'docked mode' positioning).
// Updating console log positions after the main window has been fitted to its sizer ensures
// proper docked positioning, since the main window's size is invalid until after the sizer
// has been set/fit.
g_Conf->ConLogBox.DisplaySize.Set(
std::min( std::max( g_Conf->ConLogBox.DisplaySize.GetWidth(), 160 ), screenzone.GetWidth() ),
std::min( std::max( g_Conf->ConLogBox.DisplaySize.GetHeight(), 160 ), screenzone.GetHeight() )
);
if( g_Conf->ConLogBox.AutoDock )
{
g_Conf->ConLogBox.DisplayPosition = GetPosition() + wxSize( GetSize().x, 0 );
}
else if( g_Conf->ConLogBox.DisplayPosition != wxDefaultPosition )
{
if( !screenzone.Contains( wxRect( g_Conf->ConLogBox.DisplayPosition, wxSize( 75, 150 ) ) ) )
g_Conf->ConLogBox.DisplayPosition = wxDefaultPosition;
}
InitLogBoxPosition( g_Conf->ProgLogBox );
InitLogBoxPosition( g_Conf->Ps2ConBox );
// ------------------------------------------------------------------------
@ -330,7 +330,7 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
m_menuDebug.Append(Menu_Debug_MemoryDump, _("Memory Dump..."), wxEmptyString);
m_menuDebug.Append(Menu_Debug_Logging, _("Logging..."), wxEmptyString);
m_MenuItem_Console.Check( g_Conf->ConLogBox.Visible );
m_MenuItem_Console.Check( g_Conf->ProgLogBox.Visible );
ConnectMenus();
Connect( wxEVT_MOVE, wxMoveEventHandler (MainEmuFrame::OnMoveAround) );

View File

@ -28,12 +28,10 @@
//
class MainEmuFrame: public wxFrame
{
public:
MainEmuFrame(wxWindow* parent, const wxString& title);
void OnLogBoxHidden();
protected:
// ------------------------------------------------------------------------
// All Menu Options for the Main Window! :D
// ------------------------------------------------------------------------
enum Identifiers
{
@ -112,17 +110,9 @@ protected:
Menu_Language_Start = 1000
};
wxMenu* MakeStatesSubMenu( int baseid ) const;
wxMenu* MakeStatesMenu();
wxMenu* MakeLanguagesMenu() const;
wxMenu* MakeIsoMenu();
wxMenu* MakeCdvdMenu();
void PopulateVideoMenu();
void PopulateAudioMenu();
void PopulatePadMenu();
void ConnectMenus();
// ------------------------------------------------------------------------
// MainEmuFrame Protected Variables
// ------------------------------------------------------------------------
protected:
wxStatusBar& m_statusbar;
@ -144,10 +134,17 @@ protected:
wxMenuItem& m_MenuItem_Console;
//////////////////////////////////////////////////////////////////////////////////////////
// Menu Options for the Main Window! :D
// ------------------------------------------------------------------------
// MainEmuFrame Constructors and Member Methods
// ------------------------------------------------------------------------
public:
MainEmuFrame(wxWindow* parent, const wxString& title);
void OnLogBoxHidden();
protected:
void InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf );
void OnCloseWindow(wxCloseEvent& evt);
void OnMoveAround( wxMoveEvent& evt );
@ -173,5 +170,20 @@ protected:
void Menu_ShowConsole(wxCommandEvent &event);
void Menu_ShowAboutBox(wxCommandEvent &event);
// ------------------------------------------------------------------------
// MainEmuFram Internal API for Populating Main Menu Contents
// ------------------------------------------------------------------------
wxMenu* MakeStatesSubMenu( int baseid ) const;
wxMenu* MakeStatesMenu();
wxMenu* MakeLanguagesMenu() const;
wxMenu* MakeIsoMenu();
wxMenu* MakeCdvdMenu();
void PopulateVideoMenu();
void PopulateAudioMenu();
void PopulatePadMenu();
void ConnectMenus();
};

View File

@ -101,8 +101,8 @@ void MainEmuFrame::Menu_ShowConsole(wxCommandEvent &event)
{
// Use messages to relay open/close commands (thread-safe)
g_Conf->ConLogBox.Visible = event.IsChecked();
wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED, g_Conf->ConLogBox.Visible ? wxID_OPEN : wxID_CLOSE );
g_Conf->ProgLogBox.Visible = event.IsChecked();
wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED, g_Conf->ProgLogBox.Visible ? wxID_OPEN : wxID_CLOSE );
wxGetApp().ProgramLog_PostEvent( evt );
}

View File

@ -28,8 +28,8 @@
IMPLEMENT_APP(Pcsx2App)
AppConfig* g_Conf = NULL;
wxFileHistory* g_RecentIsoList = NULL;
AppConfig* g_Conf = NULL;
wxFileHistory* g_RecentIsoList = NULL;
namespace Exception
{
@ -159,27 +159,6 @@ bool Pcsx2App::OnCmdLineParsed(wxCmdLineParser& parser)
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
// ConsoleThreadTest -- useful class for unit testing the thread safety and general performance
// of the console logger.
//
class ConsoleTestThread : public Thread
{
int Callback()
{
static int numtrack = 0;
while( true )
{
// Two lines, both formatted, and varied colors. This makes for a fairly realistic
// worst case scenario (without being entirely unrealistic).
Console::WriteLn( wxsFormat( L"This is a threaded logging test. Something bad could happen... %d", ++numtrack ) );
Console::Status( wxsFormat( L"Testing high stress loads %s", L"(multi-color)" ) );
Sleep( 0 );
}
}
};
// ------------------------------------------------------------------------
bool Pcsx2App::OnInit()
{
@ -218,10 +197,16 @@ bool Pcsx2App::OnInit()
g_Conf->Folders.Logs.Mkdir();
m_ProgramLogBox = new ConsoleLogFrame( NULL, L"PCSX2 Program Log", g_Conf->ConLogBox );
m_Ps2ConLogBox = m_ProgramLogBox; // just use a single logger for now.
m_MainFrame = new MainEmuFrame( NULL, L"PCSX2" );
m_ProgramLogBox = new ConsoleLogFrame( m_MainFrame, L"PCSX2 Program Log", g_Conf->ProgLogBox );
m_Ps2ConLogBox = m_ProgramLogBox; // just use a single logger for now.
//m_Ps2ConLogBox = new ConsoleLogFrame( NULL, L"PS2 Console Log" );
SetTopWindow( m_MainFrame ); // not really needed...
SetExitOnFrameDelete( true ); // but being explicit doesn't hurt...
m_MainFrame->Show();
SysInit();
}
catch( Exception::StartupAborted& )
@ -229,15 +214,6 @@ bool Pcsx2App::OnInit()
return false;
}
m_MainFrame = new MainEmuFrame( NULL, L"PCSX2" );
SetTopWindow( m_MainFrame );
SetExitOnFrameDelete( true );
m_MainFrame->Show();
// Logger Stress Test: See ConsoleTestThread defined above for details
//ConsoleTestThread* woo = new ConsoleTestThread();
//woo->Start();
// Check to see if the user needs to perform initial setup:
/*bool needsConfigured = false;
@ -259,6 +235,14 @@ bool Pcsx2App::OnInit()
return true;
}
// Common exit handler which can be called from any event (though really it should
// be called only from CloseWindow handlers since that's the more appropriate way
// to handle window closures)
bool Pcsx2App::PrepForExit()
{
return true;
}
int Pcsx2App::OnExit()
{
g_Conf->Save();

View File

@ -25,6 +25,27 @@
# include <wx/tooltip.h>
#endif
// Retrieves the area of the screen, which can be used to enforce a valid zone for
// window positioning. (top/left coords are almost always (0,0) and bottom/right
// is the resolution of the desktop).
wxRect wxGetDisplayArea()
{
return wxRect( wxPoint(), wxGetDisplaySize() );
}
// Returns FALSE if the window position is considered invalid, which means that it's title
// bar is most likely not easily grabble. Such a window should be moved to a valid or
// default position.
bool pxIsValidWindowPosition( const wxWindow& window, const wxPoint& windowPos )
{
// The height of the window is only revlevant to the height of a title bar, which is
// all we need visible for the user to be able to drag the window into view. But
// there's no way to get that info from wx, so we'll just have to guesstimate...
wxSize sizeMatters( window.GetSize().GetWidth(), 32 ); // if some gui has 32 pixels of undraggable title bar, the user deserves to suffer.
return wxGetDisplayArea().Contains( wxRect( windowPos, sizeMatters ) );
}
namespace wxHelpers
{
// ------------------------------------------------------------------------

View File

@ -3,7 +3,6 @@
#include <wx/wx.h>
#include <wx/filepicker.h>
namespace wxHelpers
{
extern wxCheckBox& AddCheckBoxTo( wxWindow* parent, wxSizer& sizer, const wxString& label, const wxString& subtext=wxEmptyString, const wxString& tooltip=wxEmptyString, int wrapLen=wxDefaultCoord );

View File

@ -88,6 +88,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Include", "Include", "{0FAD
common\include\Pcsx2Config.h = common\include\Pcsx2Config.h
common\include\Pcsx2Defs.h = common\include\Pcsx2Defs.h
common\include\Pcsx2Types.h = common\include\Pcsx2Types.h
common\include\PluginCallbacks.h = common\include\PluginCallbacks.h
common\include\PS2Edefs.h = common\include\PS2Edefs.h
common\include\PS2Etypes.h = common\include\PS2Etypes.h
EndProjectSection