diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 12dd040a77..f9f564174e 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -51,8 +51,11 @@ public: // Display position used if AutoDock is false (ignored otherwise) wxPoint DisplayPosition; wxSize DisplaySize; + + // Size of the font in points. + int FontSize; - void LoadSave( IniInterface& conf ); + 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; diff --git a/pcsx2/Plugins.cpp b/pcsx2/Plugins.cpp index b6c34d68d9..d46d070094 100644 --- a/pcsx2/Plugins.cpp +++ b/pcsx2/Plugins.cpp @@ -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) { diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index 13f941d098..00fd534615 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -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 m_table; - wxTextAttr m_color_default; + SafeArray 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(); @@ -190,6 +241,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() { diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 095e7bd995..b2254f79c8 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -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".." ); } diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp index d9acfb9ce3..be181c6a7b 100644 --- a/pcsx2/gui/ConsoleLogger.cpp +++ b/pcsx2/gui/ConsoleLogger.cpp @@ -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; } diff --git a/pcsx2/gui/MainFrame.cpp b/pcsx2/gui/MainFrame.cpp index 94b82e3a85..a9cf1cc718 100644 --- a/pcsx2/gui/MainFrame.cpp +++ b/pcsx2/gui/MainFrame.cpp @@ -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) ); diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index 2c5ff5a331..4085c469ff 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -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,18 +110,10 @@ 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; wxStaticBitmap m_background; @@ -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(); }; diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index accbcd36b8..d661dde467 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -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 ); } diff --git a/pcsx2/gui/main.cpp b/pcsx2/gui/main.cpp index 9c387bcead..b658c407fb 100644 --- a/pcsx2/gui/main.cpp +++ b/pcsx2/gui/main.cpp @@ -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(); diff --git a/pcsx2/gui/wxHelpers.cpp b/pcsx2/gui/wxHelpers.cpp index db8cb6b45d..844001b684 100644 --- a/pcsx2/gui/wxHelpers.cpp +++ b/pcsx2/gui/wxHelpers.cpp @@ -25,6 +25,27 @@ # include #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 { // ------------------------------------------------------------------------ diff --git a/pcsx2/gui/wxHelpers.h b/pcsx2/gui/wxHelpers.h index aa8ca22d45..c9de7676b9 100644 --- a/pcsx2/gui/wxHelpers.h +++ b/pcsx2/gui/wxHelpers.h @@ -3,7 +3,6 @@ #include #include - namespace wxHelpers { extern wxCheckBox& AddCheckBoxTo( wxWindow* parent, wxSizer& sizer, const wxString& label, const wxString& subtext=wxEmptyString, const wxString& tooltip=wxEmptyString, int wrapLen=wxDefaultCoord ); diff --git a/pcsx2_suite_2008.sln b/pcsx2_suite_2008.sln index 3cac384670..39dbffc7da 100644 --- a/pcsx2_suite_2008.sln +++ b/pcsx2_suite_2008.sln @@ -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