diff --git a/common/include/PluginCallbacks.h b/common/include/PluginCallbacks.h index fc01cdea90..2b1d1e4280 100644 --- a/common/include/PluginCallbacks.h +++ b/common/include/PluginCallbacks.h @@ -268,8 +268,13 @@ typedef struct _PS2E_MenuItemInfo // Specifies the handle of a sub menu to bind to this menu. If NULL, the menu is // created normally. If non-NULL, the menu item will use sub-menu mode and will // ignore the Style field. - PS2E_MenuHandle* SubMenu; + PS2E_MenuHandle SubMenu; + // Menu that this item is attached to. When this struct is passed into AddMenuItem, + // the menu item will be automatically appended to the menu specified in this field + // if the field is non-NULL (if the field is NULL then no action is taken). + PS2E_MenuHandle OwnerMenu; + // When FALSE the menu item will appear grayed out to the user, and unselectable. BOOL Enabled; @@ -340,7 +345,7 @@ typedef struct _PS2E_MenuItemAPI // fashion. When a submenu is assigned, the Style attribute of the menu will be // ignored. Passing NULL into this function will clear the submenu and return the // menu item to whatever it's current Style attribute is set to. - void (PS2E_CALLBACK* MenuItem_SetSubMenu)( PS2E_MenuItemHandle mitem, PS2E_MenuHandle* submenu ); + void (PS2E_CALLBACK* MenuItem_SetSubMenu)( PS2E_MenuItemHandle mitem, PS2E_MenuHandle submenu ); // Assigns the callback function for this menu (important!). If passed NULL, the menu // item will be automatically disabled (grayed out) by the emulator. @@ -352,6 +357,8 @@ typedef struct _PS2E_MenuItemAPI // Returns the current enable status of the specified menu item. BOOL (PS2E_CALLBACK* MenuItem_IsEnabled)( PS2E_MenuItemHandle mitem ); + void* reserved[4]; + } PS2E_MenuItemAPI; // -------------------------------------------------------------------------------------- @@ -437,6 +444,18 @@ typedef struct _PS2E_EmulatorInfo // resources. int LogicalCores; + // Specifies the size of the wchar_t of the emulator, in bytes. Plugin authors should be + // sure to check this against your own sizeof(wchar_t) before using any API that has + // a wchar_t parameter (such as the ConsoleWriterWide interface). wchar_t is a loosely + // defined type that can range from 8 bits to 32 bits (realistically, although there is + // no actual limit on size), and can vary between compilers for the same platform. + int Sizeof_wchar_t; + + + // Reserved area for future expansion of the structure (avoids having to upgrade the + // plugin api for amending new extensions). + int reserved1[6]; + // GetInt // Self-explanatory. // @@ -496,19 +515,19 @@ typedef struct _PS2E_EmulatorInfo // void (PS2E_CALLBACK* OSD_WriteLn)( int icon, const char* msg ); - void (PS2E_CALLBACK* AddMenuItem)( const PS2E_MenuItemInfo* item ); - // ---------------------------------------------------------------------------- // Menu / MenuItem Section // ---------------------------------------------------------------------------- + void (PS2E_CALLBACK* AddMenuItem)( const PS2E_MenuItemInfo* item ); + // Allocates a new menu handle and returns it. The returned menu can have any valid existing // menu items bound to it, and can be assigned as a submenu to any created MenuItem. The menu // can belong to multiple menu items, however menu items can only belong to a single menu. PS2E_MenuHandle (PS2E_CALLBACK* Menu_Create)( PS2E_THISPTR thisptr ); // Deletes the specified menu and frees its allocated memory resources. NULL pointers are - // safely ignored. Any menu itels also attached to this menu will be deleted. Even if you + // safely ignored. Any menu items also attached to this menu will be deleted. Even if you // do not explicitly delete your plugin's menu resources, the emulator will do automatic // cleanup after the plugin's instance is free'd. void (PS2E_CALLBACK* Menu_Delete)( PS2E_MenuHandle handle ); @@ -533,6 +552,8 @@ typedef struct _PS2E_EmulatorInfo // side before using this interface. See PS2E_ConsoleWriterWideAPI comments for more info. PS2E_ConsoleWriterWideAPI ConsoleW; + void* reserved2[8]; + } PS2E_EmulatorInfo; @@ -797,7 +818,7 @@ typedef struct _PS2E_LibraryAPI // Reserved area at the end of the structure, for future API expansion. This area // should always be zeroed out, so that future versions of emulators that may have - // defined functions here will recognize the functions as not supported. + // defined functions here will recognize the functions as not supported by the plugin. void* reserved[12]; } PS2E_LibraryAPI; diff --git a/pcsx2/HwWrite.cpp b/pcsx2/HwWrite.cpp index a2dfc4a4e8..d6dfa2fdae 100644 --- a/pcsx2/HwWrite.cpp +++ b/pcsx2/HwWrite.cpp @@ -179,8 +179,11 @@ void hwWrite8(u32 mem, u8 value) if (( value == '\r' ) || ( sio_count == 1023 ) || ( value == '\n' && sio_count != 0 )) { + // Use "%s" below even though it feels indirect -- it's necessary to avoid + // errors if/when games use printf formatting control chars. + sio_buffer[sio_count] = 0; - Console.WriteLn( ConColor_EE, ShiftJIS_ConvertString(sio_buffer) ); + Console.WriteLn( ConColor_EE, L"%s", ShiftJIS_ConvertString(sio_buffer).c_str() ); sio_count = 0; } else if( value != '\n' ) diff --git a/pcsx2/IopBios.cpp b/pcsx2/IopBios.cpp index 05a1985302..e7da2c291c 100644 --- a/pcsx2/IopBios.cpp +++ b/pcsx2/IopBios.cpp @@ -174,9 +174,7 @@ void bios_write() // 0x35/0x03 if (a0 == 1) // stdout { const char *ptr = Ra1; - - //Console.Write( ConColor_IOP, "%.*s", a2, ptr); - Console.Write( ConColor_IOP, ShiftJIS_ConvertString(ptr, a2) ); + Console.Write( ConColor_IOP, L"%s", ShiftJIS_ConvertString(ptr, a2).c_str() ); } else { @@ -284,10 +282,13 @@ _start: } *ptmp = 0; - // Note: Use Read to obtain a write pointer here, since we're just writing back the + // Use Read to obtain a write pointer here, since we're just writing back the // temp buffer we saved earlier. memcpy( (void*)iopVirtMemR(sp), save, 4*4); - Console.Write( ConColor_IOP, ShiftJIS_ConvertString(tmp), 1023 ); + + // Use "%s" even though it seems indirect: this avoids chaos if/when the IOP decides + // to feed us strings that contain percentages or other printf formatting control chars. + Console.Write( ConColor_IOP, L"%s", ShiftJIS_ConvertString(tmp).c_str(), 1023 ); pc0 = ra; } @@ -300,7 +301,7 @@ void bios_putchar () // 3d void bios_puts () // 3e/3f { - Console.Write( ConColor_IOP, Ra0 ); + Console.Write( ConColor_IOP, L"%s", ShiftJIS_ConvertString(Ra0).c_str() ); pc0 = ra; } diff --git a/pcsx2/IopHw.cpp b/pcsx2/IopHw.cpp index ffa3da6f9e..bfcf3e827f 100644 --- a/pcsx2/IopHw.cpp +++ b/pcsx2/IopHw.cpp @@ -673,7 +673,7 @@ void psxHwWrite8(u32 add, u8 value) { ( value == '\n' && g_pbufi != 0 ) ) { g_pbuf[g_pbufi] = 0; - Console.WriteLn( ConColor_IOP, g_pbuf ); + Console.WriteLn( ConColor_IOP, "%s", g_pbuf ); g_pbufi = 0; } else if( value != '\n' ) diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp index 1d57f8a318..9b92dcc26c 100644 --- a/pcsx2/Linux/pcsx2.cbp +++ b/pcsx2/Linux/pcsx2.cbp @@ -1,469 +1,470 @@ - - - - - - + + + + + + diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index 9c7a26a29e..3d8b38df3f 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -690,6 +690,21 @@ PluginManager::PluginManager( const wxString (&folders)[PluginId_Count] ) //m_libs[i].GetSymbol( L"PS2E_InitAPI" ); + // Fetch plugin name and version information + + _PS2EgetLibName GetLibName = (_PS2EgetLibName)m_info[pid].Lib.GetSymbol( L"PS2EgetLibName" ); + _PS2EgetLibVersion2 GetLibVersion2 = (_PS2EgetLibVersion2)m_info[pid].Lib.GetSymbol( L"PS2EgetLibVersion2" ); + + if( GetLibName == NULL || GetLibVersion2 == NULL ) + throw Exception::PluginLoadError( pid, m_info[pid].Filename, + wxsFormat( L"\nMethod binding failure on GetLibName or GetLibVersion2.\n" ), + _( "Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2." ) + ); + + m_info[pid].Name = fromUTF8( GetLibName() ); + int version = GetLibVersion2( tbl_PluginInfo[pid].typemask ); + m_info[pid].Version.Printf( L"%d.%d.%d", (version>>8)&0xff, version&0xff, (version>>24)&0xff ); + // Bind Required Functions // (generate critical error if binding fails) @@ -720,6 +735,9 @@ PluginManager::PluginManager( const wxString (&folders)[PluginId_Count] ) x86caps.PhysicalCores, x86caps.LogicalCores, + sizeof(wchar_t), + + 0,0,0,0,0,0, pcsx2_GetInt, pcsx2_GetBoolean, @@ -1116,15 +1134,6 @@ void PluginManager::Configure( PluginsEnum_t pid ) m_info[pid].CommonBindings.Configure(); } -// Creates an instance of a plugin manager, using the specified plugin filenames for sources. -// Impl Note: Have to use this stupid effing 'friend' declaration because static members of -// classes can't access their own protected members. W-T-F? -// -PluginManager* PluginManager_Create( const wxString (&folders)[PluginId_Count] ) -{ - return new PluginManager( folders ); -} - PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] ) { wxString passins[PluginId_Count]; @@ -1133,7 +1142,7 @@ PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] ) passins[pi->id] = folders[pi->id]; } while( ++pi, pi->shortname != NULL ); - return PluginManager_Create( passins ); + return new PluginManager( passins ); } static PluginManagerBase s_pluginman_placebo; diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index a2e3722637..7e50fe2e44 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -272,7 +272,10 @@ protected: { bool IsInitialized; bool IsOpened; + wxString Filename; + wxString Name; + wxString Version; LegacyPluginAPI_Common CommonBindings; wxDynamicLibrary Lib; @@ -280,7 +283,6 @@ protected: PluginStatus_t() : IsInitialized( false ) , IsOpened( false ) - , Filename() , CommonBindings() , Lib() { @@ -295,6 +297,7 @@ public: // hack until we unsuck plugins... PluginStatus_t m_info[PluginId_Count]; public: + PluginManager( const wxString (&folders)[PluginId_Count] ); virtual ~PluginManager() throw(); void Init(); @@ -310,13 +313,12 @@ public: bool KeyEvent( const keyEvent& evt ); void Configure( PluginsEnum_t pid ); - friend PluginManager* PluginManager_Create( const wxString (&folders)[PluginId_Count] ); + const wxString& GetName( PluginsEnum_t pid ) const { return m_info[pid].Name; } + const wxString& GetVersion( PluginsEnum_t pid ) const { return m_info[pid].Version; } + friend PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] ); protected: - // Internal constructor, should be called by Create only. - PluginManager( const wxString (&folders)[PluginId_Count] ); - void BindCommon( PluginsEnum_t pid ); void BindRequired( PluginsEnum_t pid ); void BindOptional( PluginsEnum_t pid ); @@ -327,7 +329,6 @@ protected: extern const PluginInfo tbl_PluginInfo[]; extern PluginManager* g_plugins; -extern PluginManager* PluginManager_Create( const wxString (&folders)[PluginId_Count] ); extern PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] ); extern PluginManagerBase& GetPluginManager(); diff --git a/pcsx2/R5900OpcodeImpl.cpp b/pcsx2/R5900OpcodeImpl.cpp index 3c42cc4017..f16bc5e425 100644 --- a/pcsx2/R5900OpcodeImpl.cpp +++ b/pcsx2/R5900OpcodeImpl.cpp @@ -790,7 +790,7 @@ int __Deci2Call(int call, u32 *addr) pdeciaddr += (deci2addr[4]+0xc)%16; memcpy(deci2buffer, pdeciaddr, deci2addr[1]-0xc); deci2buffer[deci2addr[1]-0xc>=255?255:deci2addr[1]-0xc]='\0'; - Console.Write( ConColor_EE, ShiftJIS_ConvertString(deci2buffer) ); + Console.Write( ConColor_EE, L"%s", ShiftJIS_ConvertString(deci2buffer).c_str() ); } deci2addr[3] = 0; return 1; @@ -809,7 +809,7 @@ int __Deci2Call(int call, u32 *addr) case 0x10://kputs if( addr != NULL ) - Console.Write( ConColor_EE, ShiftJIS_ConvertString((char*)PSM(*addr)) ); + Console.Write( ConColor_EE, L"%s", ShiftJIS_ConvertString((char*)PSM(*addr)).c_str() ); return 1; } @@ -831,7 +831,7 @@ void SYSCALL() if (call == 0x7c) { if(cpuRegs.GPR.n.a0.UL[0] == 0x10) - Console.Write( ConColor_EE, ShiftJIS_ConvertString((char*)PSM(memRead32(cpuRegs.GPR.n.a1.UL[0]))) ); + Console.Write( ConColor_EE, L"%s", ShiftJIS_ConvertString((char*)PSM(memRead32(cpuRegs.GPR.n.a1.UL[0]))).c_str() ); else __Deci2Call( cpuRegs.GPR.n.a0.UL[0], (u32*)PSM(cpuRegs.GPR.n.a1.UL[0]) ); } diff --git a/pcsx2/System/SysCoreThread.cpp b/pcsx2/System/SysCoreThread.cpp index 5114d00164..efa5d8a031 100644 --- a/pcsx2/System/SysCoreThread.cpp +++ b/pcsx2/System/SysCoreThread.cpp @@ -96,6 +96,16 @@ void SysCoreThread::Reset() m_resetVirtualMachine = true; } +// This function *will* reset the emulator in order to allow the specified elf file to +// take effect. This is because it really doesn't make sense to change the elf file outside +// the context of a reset/restart. +void SysCoreThread::SetElfOverride( const wxString& elf ) +{ + pxAssertDev( !m_hasValidState, "Thread synchronization error while assigning ELF override." ); + m_elf_override = elf; +} + + // Applies a full suite of new settings, which will automatically facilitate the necessary // resets of the core and components (including plugins, if needed). The scope of resetting // is determined by comparing the current settings against the new settings. @@ -128,6 +138,24 @@ bool SysCoreThread::HasPendingStateChangeRequest() const return m_CoreCancelDamnit || mtgsThread.HasPendingException() || _parent::HasPendingStateChangeRequest(); } +struct ScopedBool_ClearOnError +{ + bool& m_target; + bool m_success; + + ScopedBool_ClearOnError( bool& target ) : + m_target( target ), m_success( false ) + { + m_target = true; + } + + virtual ~ScopedBool_ClearOnError() + { + m_target = m_success; + } + + void Success() { m_success = true; } +}; void SysCoreThread::CpuInitializeMess() { @@ -139,8 +167,10 @@ void SysCoreThread::CpuInitializeMess() m_resetRecompilers = false; m_resetProfilers = false; - wxString elf_file; - if( EmuConfig.SkipBiosSplash ) + ScopedBool_ClearOnError sbcoe( m_hasValidState ); + + wxString elf_file( m_elf_override ); + if( elf_file.IsEmpty() && EmuConfig.SkipBiosSplash ) { // Fetch the ELF filename and CD type from the CDVD provider. wxString ename; @@ -164,19 +194,19 @@ void SysCoreThread::CpuInitializeMess() if( !elf_file.IsEmpty() ) { - // Skip Bios Hack -- Runs the PS2 BIOS stub, and then manually loads the ELF - // executable data, and injects the cpuRegs.pc with the address of the - // execution start point. + // Skip Bios Hack *or* Manual ELF override: + // Runs the PS2 BIOS stub, and then manually loads the ELF executable data, and + // injects the cpuRegs.pc with the address of the execution start point. // - // This hack is necessary for non-CD ELF files, and is optional for game CDs - // (though not recommended for games because of rare ill side effects). + // This hack is necessary for non-CD ELF files, and is optional for game CDs as a + // fast bott up option. (though not recommended for games because of rare ill side + // effects). - m_hasValidState = true; cpuExecuteBios(); - m_hasValidState = false; // because loadElfFile might error... loadElfFile( elf_file ); } - m_hasValidState = true; + + sbcoe.Success(); } void SysCoreThread::StateCheckInThread() @@ -227,6 +257,8 @@ void SysCoreThread::OnResumeInThread( bool isSuspended ) // Invoked by the pthread_exit or pthread_cancel. void SysCoreThread::OnCleanupInThread() { + m_hasValidState = false; + Threading::DisableHiresScheduler(); if( g_plugins != NULL ) diff --git a/pcsx2/System/SysThreadBase.cpp b/pcsx2/System/SysThreadBase.cpp index 7d7158089b..f9469c1b06 100644 --- a/pcsx2/System/SysThreadBase.cpp +++ b/pcsx2/System/SysThreadBase.cpp @@ -188,7 +188,6 @@ void SysThreadBase::Resume() { if( IsSelf() ) return; if( m_ExecMode == ExecMode_Opened ) return; - if( !pxAssert( g_plugins != NULL ) ) return; ScopedLock locker( m_ExecModeMutex ); diff --git a/pcsx2/System/SysThreads.h b/pcsx2/System/SysThreads.h index 8d7dd0d8e0..65e8369d81 100644 --- a/pcsx2/System/SysThreads.h +++ b/pcsx2/System/SysThreads.h @@ -186,6 +186,8 @@ protected: // Used by SETJMP only, but ifdef'ing it out clutters up the code. bool m_CoreCancelDamnit; + wxString m_elf_override; + public: static SysCoreThread& Get(); @@ -204,8 +206,10 @@ public: } bool HasPendingStateChangeRequest() const; - virtual void StateCheckInThread(); + + virtual const wxString& GetElfOverride() const { return m_elf_override; } + virtual void SetElfOverride( const wxString& elf ); protected: void CpuInitializeMess(); diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index 02aa72a5f7..a4ed2336ec 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include "Utilities/EventSource.h" @@ -56,6 +55,9 @@ END_DECLARE_EVENT_TYPES() // the universal Accelerator table. static const int pxID_PadHandler_Keydown = 8030; +// Plugin ID sections are spaced out evenly at intervals to make it easy to use a +// single for-loop to create them. +static const int PluginMenuId_Interval = 0x10; // ------------------------------------------------------------------------ // All Menu Options for the Main Window! :D @@ -82,6 +84,7 @@ enum MenuIdentifiers MenuId_Src_Plugin, MenuId_Src_NoDisc, MenuId_Boot_Iso, // Opens submenu with Iso browser, and recent isos. + MenuId_IsoSelector, // Contains a submenu of selectable "favorite" isos MenuId_IsoBrowse, // Open dialog, runs selected iso. MenuId_Boot_CDVD, // opens a submenu filled by CDVD plugin (usually list of drives) MenuId_Boot_ELF, @@ -122,20 +125,17 @@ enum MenuIdentifiers MenuId_Config_Multitap0Toggle, MenuId_Config_Multitap1Toggle, - // Video Subsection - // Top items are PCSX2-controlled. GS plugin items are inserted beneath. - MenuId_Video_Basics, // includes frame timings and skippings settings - MenuId_Video_Advanced, // inserted at the bottom of the menu + // Plugin Sections + // --------------- + // Each plugin menu begins with its name, which is a grayed out option that's + // intended for display purposes only. Plugin ID sections are spaced out evenly + // at intervals to make it easy to use a single for-loop to create them. - // Audio subsection - // Top items are PCSX2-controlled. SPU2 plugin items are inserted beneath. - // [no items at this time] - MenuId_Audio_Advanced, // inserted at the bottom of the menu + MenuId_PluginBase_Name = 0x100, + MenuId_PluginBase_Settings = 0x101, + + MenuId_Video_CoreSettings = 0x200,// includes frame timings and skippings settings - // Controller subsection - // Top items are PCSX2-controlled. Pad plugin items are inserted beneath. - // [no items at this time] - MenuId_Pad_Advanced, // Miscellaneous Menu! (Misc) MenuId_Website, // Visit our awesome website! @@ -163,6 +163,17 @@ enum AppEventType AppStatus_Exiting }; +enum PluginEventType +{ + PluginsEvt_Loaded, + PluginsEvt_Init, + PluginsEvt_Open, + PluginsEvt_Close, + PluginsEvt_Shutdown, + PluginsEvt_Unloaded, +}; + + // -------------------------------------------------------------------------------------- // KeyAcceleratorCode // A custom keyboard accelerator that I like better than wx's wxAcceleratorEntry. @@ -251,6 +262,54 @@ public: }; +// -------------------------------------------------------------------------------------- +// RecentIsoList +// -------------------------------------------------------------------------------------- +class RecentIsoList : public wxEvtHandler +{ +protected: + struct RecentItem + { + wxString Filename; + wxMenuItem* ItemPtr; + + RecentItem() { ItemPtr = NULL; } + + RecentItem( const wxString& src ) : + Filename( src ) + , ItemPtr( NULL ) + { + } + }; + + std::vector m_Items; + + wxMenu* m_Menu; + uint m_MaxLength; + int m_cursel; + + wxMenuItem* m_Separator; + + EventListenerBinding m_Listener_SettingsLoadSave; + +public: + RecentIsoList( wxMenu* menu ); + virtual ~RecentIsoList() throw(); + + void RemoveAllFromMenu(); + void Repopulate(); + void Add( const wxString& src ); + +protected: + void InsertIntoMenu( int id ); + void DoSettingsLoadSave( IniInterface& ini ); + + void OnChangedSelection( wxCommandEvent& evt ); + + static void __evt_fastcall OnSettingsLoadSave( void* obj, IniInterface& evt ); +}; + + // -------------------------------------------------------------------------------------- // AppImageIds - Config and Toolbar Images and Icons // -------------------------------------------------------------------------------------- @@ -265,14 +324,11 @@ struct AppImageIds Video, Cpu; - ConfigIds() : - Paths( -1 ) - , Plugins( -1 ) - , Speedhacks( -1 ) - , Gamefixes( -1 ) - , Video( -1 ) - , Cpu( -1 ) + ConfigIds() { + Paths = Plugins = + Speedhacks = Gamefixes = + Video = Cpu = -1; } } Config; @@ -285,13 +341,12 @@ struct AppImageIds PluginAudio, PluginPad; - ToolbarIds() : - Settings( -1 ) - , Play( -1 ) - , PluginVideo( -1 ) - , PluginAudio( -1 ) - , PluginPad( -1 ) + ToolbarIds() { + Settings = Play = + PluginVideo = + PluginAudio = + PluginPad = -1; } } Toolbars; }; @@ -324,12 +379,31 @@ public: virtual ~AppIniLoader() {} }; -// -------------------------------------------------------------------------------------- +// ===================================================================================================== // Pcsx2App - main wxApp class -// -------------------------------------------------------------------------------------- - +// ===================================================================================================== class Pcsx2App : public wxApp { + // ---------------------------------------------------------------------------- + // Event Sources! + // ---------------------------------------------------------------------------- + // These need to be at the top of the App class, because a lot of other things depend + // on them and they are, themselves, fairly self-contained. + +protected: + EventSourcem_evtsrc_CorePluginStatus; + CmdEvt_Source m_evtsrc_CoreThreadStatus; + EventSource m_evtsrc_SettingsApplied; + EventSource m_evtsrc_SettingsLoadSave; + EventSource m_evtsrc_AppStatus; + +public: + CmdEvt_Source& Source_CoreThreadStatus() { return m_evtsrc_CoreThreadStatus; } + EventSource& Source_SettingsApplied() { return m_evtsrc_SettingsApplied; } + EventSource& Source_AppStatus() { return m_evtsrc_AppStatus; } + EventSource& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; } + EventSource& Source_SettingsLoadSave() { return m_evtsrc_SettingsLoadSave; } + public: CommandDictionary GlobalCommands; AcceleratorDictionary GlobalAccels; @@ -342,6 +416,9 @@ protected: ScopedPtr m_StdoutRedirHandle; ScopedPtr m_StderrRedirHandle; + ScopedPtr m_RecentIsoMenu; + ScopedPtr m_RecentIsoList; + public: ScopedPtr m_CoreAllocs; ScopedPtr m_CorePlugins; @@ -368,7 +445,7 @@ public: bool PrepForExit( bool canCancel ); void SysExecute(); - void SysExecute( CDVD_SourceType cdvdsrc ); + void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString ); void SysReset(); const wxBitmap& GetLogoBitmap(); @@ -376,6 +453,8 @@ public: wxImageList& GetImgList_Toolbars(); const AppImageIds& GetImgId() const { return m_ImageId; } + wxMenu& GetRecentIsoMenu() { return *m_RecentIsoMenu; } + RecentIsoList& GetRecentIsoList() { return *m_RecentIsoList; } MainEmuFrame& GetMainFrame() const; MainEmuFrame* GetMainFramePtr() const { return m_MainFrame; } @@ -409,24 +488,6 @@ public: void DisableDiskLogging() const; void OnProgramLogClosed(); - // ---------------------------------------------------------------------------- - // Event Sources! - // ---------------------------------------------------------------------------- - -protected: - CmdEvt_Source m_evtsrc_CorePluginStatus; - CmdEvt_Source m_evtsrc_CoreThreadStatus; - EventSource m_evtsrc_SettingsApplied; - EventSource m_evtsrc_SettingsLoadSave; - EventSource m_evtsrc_AppStatus; - -public: - CmdEvt_Source& Source_CoreThreadStatus() { return m_evtsrc_CoreThreadStatus; } - CmdEvt_Source& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; } - EventSource& Source_SettingsApplied() { return m_evtsrc_SettingsApplied; } - EventSource& Source_SettingsLoadSave() { return m_evtsrc_SettingsLoadSave; } - EventSource& Source_AppStatus() { return m_evtsrc_AppStatus; } - protected: void InitDefaultGlobalAccelerators(); void BuildCommandHash(); diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 4123646e5f..8fef51115b 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -323,6 +323,7 @@ AppConfig::AppConfig() : , CloseGSonEsc( true ) , CurrentIso() +, CurrentELF() , CdvdSource( CDVDsrc_Iso ) , ProgLogBox() @@ -394,6 +395,7 @@ void AppConfig::LoadSaveRootItems( IniInterface& ini ) IniEntry( Toolbar_ShowLabels ); IniEntry( CurrentIso ); + IniEntry( CurrentELF ); ini.EnumEntry( L"CdvdSource", CdvdSource, CDVD_SourceLabels, defaults.CdvdSource ); } @@ -459,6 +461,7 @@ AppConfig::FolderOptions::FolderOptions() : , Logs( PathDefs::GetLogs() ) , RunIso( PathDefs::GetDocuments() ) // raw default is always the Documents folder. +, RunELF( PathDefs::GetDocuments() ) // raw default is always the Documents folder. { } @@ -488,6 +491,7 @@ void AppConfig::FolderOptions::LoadSave( IniInterface& ini ) IniEntry( Logs ); IniEntry( RunIso ); + IniEntry( RunELF ); if( ini.IsLoading() ) { diff --git a/pcsx2/gui/AppConfig.h b/pcsx2/gui/AppConfig.h index 11d4eea7dc..8b9eef4e91 100644 --- a/pcsx2/gui/AppConfig.h +++ b/pcsx2/gui/AppConfig.h @@ -76,6 +76,7 @@ public: Logs; wxDirName RunIso; // last used location for Iso loading. + wxDirName RunELF; // last used location for ELF loading. FolderOptions(); void LoadSave( IniInterface& conf ); @@ -142,6 +143,7 @@ public: bool CloseGSonEsc; wxString CurrentIso; + wxString CurrentELF; CDVD_SourceType CdvdSource; McdOptions Mcd[2][4]; diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index 647faa22b6..0248b86932 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -31,10 +31,6 @@ bool AppCoreThread::Suspend( bool isBlocking ) { bool retval = _parent::Suspend( isBlocking ); - /*wxCommandEvent evt( pxEVT_CoreThreadStatus ); - evt.SetInt( CoreStatus_Suspended ); - wxGetApp().AddPendingEvent( evt );*/ - // Clear the sticky key statuses, because hell knows what'll change while the PAD // plugin is suspended. @@ -52,6 +48,8 @@ void AppCoreThread::Resume() { // Thread control (suspend / resume) should only be performed from the main/gui thread. if( !AllowFromMainThreadOnly() ) return; + if( m_ExecMode == ExecMode_Opened ) return; + if( !pxAssert( g_plugins != NULL ) ) return; if( sys_resume_lock > 0 ) { diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index eaa1860bc1..18a45ad6ca 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -263,10 +263,11 @@ bool Pcsx2App::OnInit() try { InitDefaultGlobalAccelerators(); - delete wxLog::SetActiveTarget( new pxLogConsole() ); - ReadUserModeSettings(); + m_RecentIsoList = new RecentIsoList( m_RecentIsoMenu ); + + ReadUserModeSettings(); AppConfig_OnChangedSettingsFolder(); m_MainFrame = new MainEmuFrame( NULL, L"PCSX2" ); @@ -396,9 +397,12 @@ Pcsx2App::Pcsx2App() : , m_ConfigImagesAreLoaded( false ) , m_ToolbarImages( NULL ) , m_Bitmap_Logo( NULL ) +, m_RecentIsoMenu( new wxMenu() ) { SetAppName( L"pcsx2" ); BuildCommandHash(); + + m_RecentIsoMenu->Append( MenuId_IsoBrowse, _("Browse..."), _("Browse for an Iso that is not in your recent history.") ); } Pcsx2App::~Pcsx2App() @@ -434,7 +438,7 @@ Pcsx2App::~Pcsx2App() // this feature you need to execute pcsx in no-gui mode, and then not move the mouse or use // the keyboard until you get to the leak. >_< // -// (but this tool is still still better than nothing!) +// (but this tool is still better than nothing!) #ifdef PCSX2_DEBUG struct CrtDebugBreak @@ -447,6 +451,6 @@ struct CrtDebugBreak } }; -//CrtDebugBreak breakAt( 7586 ); +//CrtDebugBreak breakAt( 4327 ); #endif \ No newline at end of file diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index f91be5da2a..df07998691 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -42,6 +42,7 @@ DEFINE_EVENT_TYPE( pxEVT_FreezeThreadFinished ); #include "Utilities/EventSource.inl" EventSource_ImplementType( IniInterface ); EventSource_ImplementType( AppEventType ); +EventSource_ImplementType( PluginEventType ); bool UseAdminMode = false; wxDirName SettingsFolder; @@ -442,6 +443,7 @@ void Pcsx2App::OnMainFrameClosed() // -------------------------------------------------------------------------------------- static int _sysexec_cdvdsrc_type = -1; +static wxString _sysexec_elf_override; static void _sendmsg_SysExecute() { @@ -461,6 +463,7 @@ static void OnSysExecuteAfterPlugins( const wxCommandEvent& loadevt ) void Pcsx2App::SysExecute() { _sysexec_cdvdsrc_type = -1; + _sysexec_elf_override = CoreThread.GetElfOverride(); if( !m_CorePlugins ) { LoadPluginsPassive( OnSysExecuteAfterPlugins ); @@ -472,9 +475,11 @@ void Pcsx2App::SysExecute() // Executes the specified cdvd source and optional elf file. This command performs a // full closure of any existing VM state and starts a fresh VM with the requested // sources. -void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc ) +void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override ) { _sysexec_cdvdsrc_type = (int)cdvdsrc; + _sysexec_elf_override = elf_override; + if( !m_CorePlugins ) { LoadPluginsPassive( OnSysExecuteAfterPlugins ); @@ -498,7 +503,9 @@ void Pcsx2App::OnSysExecute( wxCommandEvent& evt ) if( evt.GetInt() != -1 ) CoreThread.Reset(); else CoreThread.Suspend(); CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso ); if( evt.GetInt() != -1 ) CDVDsys_ChangeSource( (CDVD_SourceType)evt.GetInt() ); - + + if( !CoreThread.HasValidState() ) + CoreThread.SetElfOverride( _sysexec_elf_override ); CoreThread.Resume(); } diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp index c882f115ad..c3e6d0f111 100644 --- a/pcsx2/gui/ConsoleLogger.cpp +++ b/pcsx2/gui/ConsoleLogger.cpp @@ -25,7 +25,6 @@ #ifdef __WXMSW__ # include // needed for OutputDebugStirng -# include #endif BEGIN_DECLARE_EVENT_TYPES() @@ -206,14 +205,14 @@ 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 ) + for( int i=0; iAppend( MenuId_Src_Iso, _("Iso"), wxEmptyString, wxITEM_RADIO ); - mnuCdvd->Append( MenuId_Src_Plugin, _("Plugin"), wxEmptyString, wxITEM_RADIO ); - mnuCdvd->Append( MenuId_Src_NoDisc, _("No disc"), wxEmptyString, wxITEM_RADIO ); - - mnuCdvd->AppendSeparator(); - mnuCdvd->Append( MenuId_IsoBrowse, _("Iso Browser..."), _("Select the Iso source image.") ); - mnuCdvd->Append( MenuId_Config_CDVD, _("Plugin settings..."), - _("Opens the CDVD plugin configuration dialog") ); - - return mnuCdvd; -} - void MainEmuFrame::UpdateIsoSrcSelection() { MenuIdentifiers cdsrc = MenuId_Src_Iso; @@ -81,47 +65,8 @@ void MainEmuFrame::UpdateIsoSrcFile() if( !exists ) g_Conf->CurrentIso.Clear(); - wxString label; - label.Printf( L"%s -> %s", _("Iso"), - exists ? g_Conf->CurrentIso.c_str() : _("Empty") - ); - sMenuBar.SetLabel( MenuId_Src_Iso, label ); -} - -void MainEmuFrame::LoadSaveRecentIsoList( IniInterface& conf ) -{ - if( conf.IsLoading() ) - m_RecentIsoList->Load( conf.GetConfig() ); - else - m_RecentIsoList->Save( conf.GetConfig() ); -} - -// ------------------------------------------------------------------------ -// Video / Audio / Pad "Extensible" Menus -// ------------------------------------------------------------------------ - -void MainEmuFrame::PopulateVideoMenu() -{ - m_menuVideo.Append( MenuId_Video_Basics, _("Basic Settings..."), wxEmptyString, wxITEM_CHECK ); - m_menuVideo.AppendSeparator(); - - // Populate options from the plugin here. - - m_menuVideo.Append( MenuId_Video_Advanced, _("Advanced..."), wxEmptyString, wxITEM_NORMAL ); -} - -void MainEmuFrame::PopulateAudioMenu() -{ - // Populate options from the plugin here. - - m_menuAudio.Append( MenuId_Audio_Advanced, _("Advanced..."), wxEmptyString, wxITEM_NORMAL ); -} - -void MainEmuFrame::PopulatePadMenu() -{ - // Populate options from the plugin here. - - m_menuPad.Append( MenuId_Pad_Advanced, _("Advanced..."), wxEmptyString, wxITEM_NORMAL ); + //sMenuBar.SetLabel( MenuId_Src_Iso, wxsFormat( L"%s -> %s", _("Iso"), + // exists ? Path::GetFilename(g_Conf->CurrentIso).c_str() : _("Empty") ) ); } // ------------------------------------------------------------------------ @@ -206,9 +151,8 @@ void MainEmuFrame::ConnectMenus() ConnectMenuRange(MenuId_Config_GS, PluginId_Count, Menu_ConfigPlugin_Click); ConnectMenuRange(MenuId_Src_Iso, 3, Menu_CdvdSource_Click); - ConnectMenu( MenuId_Video_Advanced, Menu_ConfigPlugin_Click); - ConnectMenu( MenuId_Audio_Advanced, Menu_ConfigPlugin_Click); - ConnectMenu( MenuId_Pad_Advanced, Menu_ConfigPlugin_Click); + for( int i=0; iGetMenuBar()!=NULL, "Mainframe menu bar is NULL!" ) ) return; + mframe->ApplyCoreStatus(); } -void __evt_fastcall MainEmuFrame::OnCorePluginStatusChanged( void* obj, wxCommandEvent& evt ) +void __evt_fastcall MainEmuFrame::OnCorePluginStatusChanged( void* obj, PluginEventType& evt ) { if( obj == NULL ) return; - MainEmuFrame* mframe = (MainEmuFrame*)obj; - mframe->ApplyCoreStatus(); + if( (evt != PluginsEvt_Loaded) && (evt != PluginsEvt_Unloaded) ) return; // everything else we don't care about + + MainEmuFrame& mframe = *(MainEmuFrame*)obj; + if( !pxAssertMsg( mframe.GetMenuBar()!=NULL, "Mainframe menu bar is NULL!" ) ) return; + + mframe.ApplyCoreStatus(); + mframe.ApplyPluginStatus(); } void __evt_fastcall MainEmuFrame::OnSettingsApplied( void* obj, int& evt ) { if( obj == NULL ) return; MainEmuFrame* mframe = (MainEmuFrame*)obj; + if( !pxAssertMsg( mframe->GetMenuBar()!=NULL, "Mainframe menu bar is NULL!" ) ) return; + mframe->ApplySettings(); } @@ -280,15 +233,22 @@ void __evt_fastcall MainEmuFrame::OnSettingsLoadSave( void* obj, IniInterface& e if( obj == NULL ) return; MainEmuFrame* mframe = (MainEmuFrame*)obj; - mframe->LoadSaveRecentIsoList( evt ); +} + +static int GetPluginMenuId_Settings( PluginsEnum_t pid ) +{ + return MenuId_PluginBase_Settings + ((int)pid * PluginMenuId_Interval); +} + +static int GetPluginMenuId_Name( PluginsEnum_t pid ) +{ + return MenuId_PluginBase_Name + ((int)pid * PluginMenuId_Interval); } // ------------------------------------------------------------------------ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title): wxFrame(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~(wxMAXIMIZE_BOX | wxRESIZE_BORDER) ), - m_RecentIsoList( new wxFileHistory( g_Conf->RecentFileCount ) ), - m_statusbar( *CreateStatusBar(2, 0) ), m_background( this, wxID_ANY, wxGetApp().GetLogoBitmap() ), @@ -297,34 +257,34 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title): m_menubar( *new wxMenuBar() ), m_menuBoot ( *new wxMenu() ), - m_menuEmu ( *new wxMenu() ), + m_menuCDVD ( *new wxMenu() ), + m_menuSys ( *new wxMenu() ), m_menuConfig( *new wxMenu() ), m_menuMisc ( *new wxMenu() ), - - m_menuVideo ( *new wxMenu() ), - m_menuAudio ( *new wxMenu() ), - m_menuPad ( *new wxMenu() ), m_menuDebug ( *new wxMenu() ), - + m_LoadStatesSubmenu( *MakeStatesSubMenu( MenuId_State_Load01 ) ), m_SaveStatesSubmenu( *MakeStatesSubMenu( MenuId_State_Save01 ) ), m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, MenuId_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) ), m_Listener_CoreThreadStatus( wxGetApp().Source_CoreThreadStatus(), CmdEvt_Listener( this, OnCoreThreadStatusChanged ) ), - m_Listener_CorePluginStatus( wxGetApp().Source_CorePluginStatus(), CmdEvt_Listener( this, OnCorePluginStatusChanged ) ), + m_Listener_CorePluginStatus( wxGetApp().Source_CorePluginStatus(), EventListener( this, OnCorePluginStatusChanged ) ), m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener( this, OnSettingsApplied ) ), m_Listener_SettingsLoadSave( wxGetApp().Source_SettingsLoadSave(), EventListener( this, OnSettingsLoadSave ) ) { + + for( int i=0; iUseMenu( recentRunMenu ); - m_RecentIsoList->AddFilesToMenu( recentRunMenu ); - - m_menuBoot.AppendSeparator(); - m_menuBoot.Append(MenuId_Cdvd_Source, _("Select CDVD source"), MakeCdvdMenu() ); - m_menuBoot.Append(MenuId_SkipBiosToggle,_("BIOS Skip Hack"), - _("Skips PS2 splash screens when booting from Iso or CDVD media"), wxITEM_CHECK ); - m_menuBoot.AppendSeparator(); m_menuBoot.Append(MenuId_Exit, _("Exit"), _("Closing PCSX2 may be hazardous to your health")); // ------------------------------------------------------------------------ - m_menuEmu.Append(MenuId_Sys_SuspendResume, _("Suspend") )->Enable( SysHasValidState() ); + wxMenu& isoRecents( wxGetApp().GetRecentIsoMenu() ); - m_menuEmu.AppendSeparator(); + //m_menuCDVD.AppendSeparator(); + m_menuCDVD.Append( MenuId_IsoSelector, _("Iso Selector"), &isoRecents ); + m_menuCDVD.Append( GetPluginMenuId_Settings(PluginId_CDVD), _("Plugin Menu"), m_PluginMenuPacks[PluginId_CDVD] ); - //m_menuEmu.Append(MenuId_Sys_Close, _("Close"), + m_menuCDVD.AppendSeparator(); + m_menuCDVD.Append( MenuId_Src_Iso, _("Iso"), _("Makes the specified ISO image the CDVD source."), wxITEM_RADIO ); + m_menuCDVD.Append( MenuId_Src_Plugin, _("Plugin"), _("Uses an external plugin as the CDVD source."), wxITEM_RADIO ); + m_menuCDVD.Append( MenuId_Src_NoDisc, _("No disc"), _("Use this to boot into your virtual PS2's BIOS configuration."), wxITEM_RADIO ); + + m_menuCDVD.AppendSeparator(); + m_menuCDVD.Append( MenuId_SkipBiosToggle,_("Enable Skip BIOS Hack"), + _("Skips PS2 splash screens when booting from Iso or CDVD media"), wxITEM_CHECK ); + + // ------------------------------------------------------------------------ + m_menuSys.Append(MenuId_Sys_SuspendResume, _("Suspend") )->Enable( SysHasValidState() ); + + m_menuSys.AppendSeparator(); + + //m_menuSys.Append(MenuId_Sys_Close, _("Close"), // _("Stops emulation and closes the GS window.")); - m_menuEmu.Append(MenuId_Sys_LoadStates, _("Load state"), &m_LoadStatesSubmenu); - m_menuEmu.Append(MenuId_Sys_SaveStates, _("Save state"), &m_SaveStatesSubmenu); + m_menuSys.Append(MenuId_Sys_LoadStates, _("Load state"), &m_LoadStatesSubmenu); + m_menuSys.Append(MenuId_Sys_SaveStates, _("Save state"), &m_SaveStatesSubmenu); - m_menuEmu.AppendSeparator(); - m_menuEmu.Append(MenuId_EnablePatches, _("Enable Patches"), + m_menuSys.AppendSeparator(); + m_menuSys.Append(MenuId_EnablePatches, _("Enable Patches"), wxEmptyString, wxITEM_CHECK); - m_menuEmu.AppendSeparator(); - m_menuEmu.Append(MenuId_Sys_Reset, _("Reset"), + m_menuSys.AppendSeparator(); + m_menuSys.Append(MenuId_Sys_Reset, _("Reset"), _("Resets emulation state and re-runs current image")); // ------------------------------------------------------------------------ @@ -429,13 +397,13 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title): m_menuConfig.Append(MenuId_Config_Settings, _("General &Settings") ); m_menuConfig.AppendSeparator(); - m_menuConfig.Append(MenuId_Config_PAD, _("PAD"), &m_menuPad ); - // Query installed "tertiary" plugins for name and menu options. - m_menuConfig.Append(MenuId_Config_CDVD, _("CDVD"), wxEmptyString); - m_menuConfig.Append(MenuId_Config_DEV9, _("Dev9"), wxEmptyString); - m_menuConfig.Append(MenuId_Config_USB, _("USB"), wxEmptyString); - m_menuConfig.Append(MenuId_Config_FireWire, _("Firewire"), wxEmptyString); + m_menuConfig.Append(MenuId_Config_GS, _("Video (GS)"), m_PluginMenuPacks[PluginId_GS]); + m_menuConfig.Append(MenuId_Config_SPU2, _("Audio (SPU2)"), m_PluginMenuPacks[PluginId_SPU2]); + m_menuConfig.Append(MenuId_Config_PAD, _("Controllers (PAD)"), m_PluginMenuPacks[PluginId_PAD]); + m_menuConfig.Append(MenuId_Config_DEV9, _("Dev9"), m_PluginMenuPacks[PluginId_DEV9]); + m_menuConfig.Append(MenuId_Config_USB, _("USB"), m_PluginMenuPacks[PluginId_USB]); + m_menuConfig.Append(MenuId_Config_FireWire, _("Firewire"), m_PluginMenuPacks[PluginId_FW]); m_menuConfig.AppendSeparator(); m_menuConfig.Append(MenuId_Config_Patches, _("Patches"), wxEmptyString); @@ -451,12 +419,6 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title): // ------------------------------------------------------------------------ - PopulateVideoMenu(); - PopulateAudioMenu(); - PopulatePadMenu(); - - // ------------------------------------------------------------------------ - m_menuMisc.Append( &m_MenuItem_Console ); m_menuMisc.Append(MenuId_Profiler, _("Show Profiler"), wxEmptyString, wxITEM_CHECK); m_menuMisc.AppendSeparator(); @@ -487,36 +449,18 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title): MainEmuFrame::~MainEmuFrame() throw() { - try - { - if( m_RecentIsoList && GetAppConfig() ) - m_RecentIsoList->Save( *GetAppConfig() ); - } - DESTRUCTOR_CATCHALL + m_menuCDVD.Remove( MenuId_IsoSelector ); } // This should be called whenever major changes to the ini configs have occurred, // or when the recent file count mismatches the max filecount. void MainEmuFrame::ReloadRecentLists() { - // Always perform delete and reload of the Recent Iso List. This handles cases where - // the recent file count has been changed, and it's a helluva lot easier than trying - // to make a clone copy of this complex object. ;) - - wxConfigBase* cfg = GetAppConfig(); - pxAssert( cfg != NULL ); - - if( m_RecentIsoList ) - m_RecentIsoList->Save( *cfg ); - m_RecentIsoList.Reassign( new wxFileHistory(g_Conf->RecentFileCount) )->Load( *cfg ); - UpdateIsoSrcFile(); - cfg->Flush(); } void MainEmuFrame::ApplyCoreStatus() { wxMenuBar& menubar( *GetMenuBar() ); - if( !pxAssertMsg( &menubar!=NULL, "Mainframe menu bar is NULL!" ) ) return; wxMenuItem& susres( *menubar.FindItem( MenuId_Sys_SuspendResume ) ); if( !pxAssertMsg( &susres!=NULL, "Suspend/Resume Menubar Item is NULL!" ) ) return; @@ -544,19 +488,96 @@ void MainEmuFrame::ApplyCoreStatus() menubar.Enable( MenuId_Sys_Reset, SysHasValidState() || (g_plugins!=NULL) ); } +void MainEmuFrame::ApplyPluginStatus() +{ + wxMenuBar& menubar( *GetMenuBar() ); + + if( g_plugins == NULL ) + { + for( int i=0; iGetName( PluginId_CDVD ).c_str() ) ); + } + + // Re-populate plugin menus. + + // Delete any menu options added by plugins (typically a plugin will have already + // done its own proper cleanup when the plugin was shutdown or unloaded, but lets + // not trust them, shall we?) + +} + void MainEmuFrame::ApplySettings() { wxMenuBar& menubar( *GetMenuBar() ); - if( !pxAssertMsg( &menubar!=NULL, "Mainframe menu bar is NULL!" ) ) return; menubar.Check( MenuId_SkipBiosToggle, g_Conf->EmuOptions.SkipBiosSplash ); menubar.Check( MenuId_Config_Multitap0Toggle, g_Conf->EmuOptions.MultitapPort0_Enabled ); menubar.Check( MenuId_Config_Multitap1Toggle, g_Conf->EmuOptions.MultitapPort1_Enabled ); - if( m_RecentIsoList ) - { - if( m_RecentIsoList->GetMaxFiles() != g_Conf->RecentFileCount ) - ReloadRecentLists(); - } + UpdateIsoSrcFile(); } + +// ------------------------------------------------------------------------ +// "Extensible" Plugin Menus +// ------------------------------------------------------------------------ + +PerPluginMenuInfo::~PerPluginMenuInfo() throw() +{ +} + +void PerPluginMenuInfo::Populate( PluginsEnum_t pid ) +{ + if( !pxAssert(pid < PluginId_Count) ) return; + + PluginId = pid; + + MyMenu.Append( GetPluginMenuId_Name(PluginId), _("No plugin loaded") )->Enable( false ); + MyMenu.AppendSeparator(); + + if( PluginId == PluginId_GS ) + { + MyMenu.Append( MenuId_Video_CoreSettings, _("Core Settings..."), + _("Modify video emulation settings regulated by the PCSX2 core virtual machine."), wxITEM_CHECK ); + MyMenu.AppendSeparator(); + } + + // Populate options from the plugin here. + + MyMenu.Append( GetPluginMenuId_Settings(PluginId), _("Plugin Settings..."), + wxsFormat( _("Opens the %s plugin's advanced settings dialog."), tbl_PluginInfo[pid].GetShortname() ) + ); +} + +// deletes menu items belonging to (created by) the plugin. Leaves menu items created +// by the PCSX2 core intact. +void PerPluginMenuInfo::OnUnloaded() +{ + MenuItemAddonList& curlist( m_PluginMenuItems ); + for( uint mx=0; mxGetName( PluginId ) + L" " + g_plugins->GetVersion( PluginId ) + ); + MyMenu.Enable( GetPluginMenuId_Settings(PluginId), true ); +} \ No newline at end of file diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index 725abbda40..b7040b722b 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -36,6 +36,59 @@ protected: void OnKeyDown( wxKeyEvent& evt ); }; +struct PluginMenuAddition +{ + wxString Text; + wxString HelpText; + PS2E_MenuItemStyle Flags; + + wxMenuItem* Item; + int ItemId; + + // Optional user data pointer (or typecast integer value) + void* UserPtr; + + void (PS2E_CALLBACK *OnClicked)( PS2E_THISPTR* thisptr, void* userptr ); +}; + +// -------------------------------------------------------------------------------------- +// PerPluginMenuInfo +// -------------------------------------------------------------------------------------- +class PerPluginMenuInfo +{ +protected: + typedef std::vector MenuItemAddonList; + + // A list of menu items belonging to this plugin's menu. + MenuItemAddonList m_PluginMenuItems; + + // Base index for inserting items, usually points to the position + // after the heading entry and separator. + int m_InsertIndexBase; + + // Current index for inserting menu items; increments with each item + // added by a plugin. + int m_InsertIndexCur; + +public: + PluginsEnum_t PluginId; + wxMenu& MyMenu; + +public: + PerPluginMenuInfo() : MyMenu( *new wxMenu() ) + { + } + + virtual ~PerPluginMenuInfo() throw(); + + void Populate( PluginsEnum_t pid ); + void OnUnloaded(); + void OnLoaded(); + + operator wxMenu*() { return &MyMenu; } + operator const wxMenu*() const { return &MyMenu; } +}; + class MainEmuFrame : public wxFrame { // ------------------------------------------------------------------------ @@ -43,31 +96,29 @@ class MainEmuFrame : public wxFrame // ------------------------------------------------------------------------ protected: - ScopedPtr m_RecentIsoList; wxStatusBar& m_statusbar; wxStaticBitmap m_background; wxMenuBar& m_menubar; wxMenu& m_menuBoot; - wxMenu& m_menuEmu; + wxMenu& m_menuCDVD; + wxMenu& m_menuSys; wxMenu& m_menuConfig; wxMenu& m_menuMisc; wxMenu& m_menuDebug; - wxMenu& m_menuVideo; - wxMenu& m_menuAudio; - wxMenu& m_menuPad; - wxMenu& m_LoadStatesSubmenu; wxMenu& m_SaveStatesSubmenu; wxMenuItem& m_MenuItem_Console; + + PerPluginMenuInfo m_PluginMenuPacks[PluginId_Count]; - CmdEvt_ListenerBinding m_Listener_CoreThreadStatus; - CmdEvt_ListenerBinding m_Listener_CorePluginStatus; - EventListenerBinding m_Listener_SettingsApplied; - EventListenerBinding m_Listener_SettingsLoadSave; + CmdEvt_ListenerBinding m_Listener_CoreThreadStatus; + EventListenerBinding m_Listener_CorePluginStatus; + EventListenerBinding m_Listener_SettingsApplied; + EventListenerBinding m_Listener_SettingsLoadSave; // ------------------------------------------------------------------------ // MainEmuFrame Constructors and Member Methods @@ -86,13 +137,13 @@ public: protected: static void __evt_fastcall OnCoreThreadStatusChanged( void* obj, wxCommandEvent& evt ); - static void __evt_fastcall OnCorePluginStatusChanged( void* obj, wxCommandEvent& evt ); + static void __evt_fastcall OnCorePluginStatusChanged( void* obj, PluginEventType& evt ); static void __evt_fastcall OnSettingsApplied( void* obj, int& evt ); static void __evt_fastcall OnSettingsLoadSave( void* obj, IniInterface& evt ); - void LoadSaveRecentIsoList( IniInterface& conf ); void ApplySettings(); void ApplyCoreStatus(); + void ApplyPluginStatus(); void InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf ); @@ -131,6 +182,7 @@ protected: void Menu_ShowAboutBox(wxCommandEvent &event); bool _DoSelectIsoBrowser(); + bool _DoSelectELFBrowser(); // ------------------------------------------------------------------------ // MainEmuFram Internal API for Populating Main Menu Contents @@ -139,11 +191,7 @@ protected: wxMenu* MakeStatesSubMenu( int baseid ) const; wxMenu* MakeStatesMenu(); wxMenu* MakeLanguagesMenu() const; - wxMenu* MakeCdvdMenu(); - void PopulateVideoMenu(); - void PopulateAudioMenu(); - void PopulatePadMenu(); void ConnectMenus(); friend class Pcsx2App; diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index 33c8eed057..d4992f8cb2 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -65,8 +65,9 @@ bool MainEmuFrame::_DoSelectIsoBrowser() { g_Conf->Folders.RunIso = wxFileName( ctrl.GetPath() ).GetPath(); g_Conf->CurrentIso = ctrl.GetPath(); - AppSaveSettings(); + sApp.GetRecentIsoList().Add( g_Conf->CurrentIso ); + AppSaveSettings(); UpdateIsoSrcFile(); return true; } @@ -74,6 +75,26 @@ bool MainEmuFrame::_DoSelectIsoBrowser() return false; } +bool MainEmuFrame::_DoSelectELFBrowser() +{ + static const wxChar* elfFilterTypes = + L"ELF Files (.elf)|*.elf|" + L"All Files (*.*)|*.*"; + + wxFileDialog ctrl( this, _("Select ELF file..."), g_Conf->Folders.RunELF.ToString(), wxEmptyString, + elfFilterTypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + + if( ctrl.ShowModal() != wxID_CANCEL ) + { + g_Conf->Folders.RunELF = wxFileName( ctrl.GetPath() ).GetPath(); + g_Conf->CurrentELF = ctrl.GetPath(); + AppSaveSettings(); + return true; + } + + return false; +} + void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event ) { CoreThread.Suspend(); @@ -116,13 +137,12 @@ void MainEmuFrame::Menu_RunIso_Click( wxCommandEvent &event ) { CoreThread.Suspend(); - if( !_DoSelectIsoBrowser() ) + if( _DoSelectIsoBrowser() ) { - CoreThread.Resume(); - return; + sApp.SysExecute( CDVDsrc_Iso ); } - sApp.SysExecute( CDVDsrc_Iso ); + CoreThread.Resume(); } void MainEmuFrame::Menu_IsoRecent_Click(wxCommandEvent &event) @@ -153,6 +173,13 @@ void MainEmuFrame::Menu_SkipBiosToggle_Click( wxCommandEvent &event ) void MainEmuFrame::Menu_OpenELF_Click(wxCommandEvent &event) { + CoreThread.Suspend(); + if( _DoSelectELFBrowser() ) + { + sApp.SysExecute( g_Conf->CdvdSource, g_Conf->CurrentELF ); + } + + CoreThread.Resume(); } void MainEmuFrame::Menu_LoadStates_Click(wxCommandEvent &event) @@ -206,7 +233,9 @@ void MainEmuFrame::Menu_SysReset_Click(wxCommandEvent &event) sApp.SysReset(); if( resume ) + { sApp.SysExecute(); + } GetMenuBar()->Enable( MenuId_Sys_Reset, resume ); } @@ -214,22 +243,10 @@ void MainEmuFrame::Menu_SysReset_Click(wxCommandEvent &event) void MainEmuFrame::Menu_ConfigPlugin_Click(wxCommandEvent &event) { typedef void (CALLBACK* PluginConfigureFnptr)(); - const int eventId = event.GetId(); - PluginsEnum_t pid; - switch (eventId) { - case MenuId_Video_Advanced: - pid = PluginId_GS; - break; - case MenuId_Audio_Advanced: - pid = PluginId_SPU2; - break; - case MenuId_Pad_Advanced: - pid = PluginId_PAD; - break; - default: - pid = (PluginsEnum_t)( event.GetId() - MenuId_Config_GS ); - break; - } + const int eventId = event.GetId() - MenuId_PluginBase_Settings; + + PluginsEnum_t pid = (PluginsEnum_t)(eventId / PluginMenuId_Interval); + if( !pxAssertDev( (eventId >= 0) || (pid < PluginId_Count), "Invalid plugin identifier passed to ConfigPlugin event handler." ) ) return; LoadPluginsImmediate(); if( g_plugins == NULL ) return; diff --git a/pcsx2/gui/Plugins.cpp b/pcsx2/gui/Plugins.cpp index c33f64a576..a5f56c775e 100644 --- a/pcsx2/gui/Plugins.cpp +++ b/pcsx2/gui/Plugins.cpp @@ -29,6 +29,54 @@ using namespace Threading; static FnType_OnThreadComplete* Callback_PluginsLoadComplete = NULL; +class AppPluginManager : public PluginManager +{ + typedef PluginManager _parent; + +public: + AppPluginManager( const wxString (&folders)[PluginId_Count] ) : PluginManager( folders ) + { + } + + virtual ~AppPluginManager() throw() + { + PluginEventType pevt = PluginsEvt_Unloaded; + sApp.Source_CorePluginStatus().Dispatch( pevt ); + } + + void Init() + { + _parent::Init(); + + PluginEventType pevt = PluginsEvt_Init; + sApp.Source_CorePluginStatus().Dispatch( pevt ); + } + + void Shutdown() + { + _parent::Shutdown(); + + PluginEventType pevt = PluginsEvt_Shutdown; + sApp.Source_CorePluginStatus().Dispatch( pevt ); + } + + void Close() + { + _parent::Close(); + + PluginEventType pevt = PluginsEvt_Close; + sApp.Source_CorePluginStatus().Dispatch( pevt ); + } + + void Open() + { + _parent::Open(); + + PluginEventType pevt = PluginsEvt_Open; + sApp.Source_CorePluginStatus().Dispatch( pevt ); + } +}; + // -------------------------------------------------------------------------------------- // LoadPluginsTask // -------------------------------------------------------------------------------------- @@ -74,7 +122,7 @@ void LoadPluginsTask::ExecuteTaskInThread() // This is for testing of the error handler... uncomment for fun? //throw Exception::PluginError( PluginId_PAD, "This one is for testing the error handler!" ); - Result = PluginManager_Create( m_folders ); + Result = new AppPluginManager( m_folders ); } void LoadPluginsTask::OnCleanupInThread() @@ -166,7 +214,9 @@ void Pcsx2App::OnLoadPluginsComplete( wxCommandEvent& evt ) if( fn_tmp != NULL ) fn_tmp( evt ); - //m_evtsrc_PluginLoadFinished.Dispatch( evt ); + PluginEventType pevt = PluginsEvt_Loaded; + sApp.Source_CorePluginStatus().Dispatch( pevt ); + Source_CorePluginStatus().Dispatch( pevt ); } // Posts a message to the App to reload plugins. Plugins are loaded via a background thread @@ -206,12 +256,12 @@ void LoadPluginsImmediate() wxString passins[PluginId_Count]; ConvertPluginFilenames( passins ); - wxGetApp().m_CorePlugins = PluginManager_Create( passins ); + wxGetApp().m_CorePlugins = new AppPluginManager( passins ); } void UnloadPlugins() { CoreThread.Cancel(); - wxGetApp().m_CorePlugins = NULL; + sApp.m_CorePlugins = NULL; } diff --git a/pcsx2/gui/RecentIsoList.cpp b/pcsx2/gui/RecentIsoList.cpp new file mode 100644 index 0000000000..faefc7910a --- /dev/null +++ b/pcsx2/gui/RecentIsoList.cpp @@ -0,0 +1,167 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "MainFrame.h" + +RecentIsoList::RecentIsoList( wxMenu* menu ) : + m_Menu( menu ) +, m_MaxLength( g_Conf->RecentFileCount ) +, m_cursel( 0 ) +, m_Separator( NULL ) +, m_Listener_SettingsLoadSave( wxGetApp().Source_SettingsLoadSave(), EventListener( this, OnSettingsLoadSave ) ) +{ + m_Menu->Connect( wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(RecentIsoList::OnChangedSelection) ); +} + +RecentIsoList::~RecentIsoList() throw() +{ +} + +void RecentIsoList::OnChangedSelection( wxCommandEvent& evt ) +{ + uint cnt = m_Items.size(); + uint i=0; + for( ; iGetId() != evt.GetId()) ) continue; + } + + if( i >= m_Items.size() ) return; + + m_cursel = i; + g_Conf->CurrentIso = m_Items[i].Filename; + sMainFrame.UpdateIsoSrcFile(); +} + +void RecentIsoList::RemoveAllFromMenu() +{ + if( m_Menu == NULL ) return; + + int cnt = m_Items.size(); + for( int i=0; iDestroy( m_Items[i].ItemPtr ); + m_Items[i].ItemPtr = NULL; + } + + if( m_Separator != NULL ) + { + m_Menu->Destroy( m_Separator ); + m_Separator = NULL; + } +} + +void RecentIsoList::Repopulate() +{ + int cnt = m_Items.size(); + if( cnt <= 0 ) return; + + m_Separator = m_Menu->AppendSeparator(); + + for( int i=0; iAppendSeparator(); + } + else + { + for( int i=0; iCheck(); + return; + } + } + } + + m_Items.push_back( RecentItem( normalized ) ); + InsertIntoMenu( m_cursel = (m_Items.size()-1) ); + + while( m_Items.size() > m_MaxLength ) + { + m_Items.erase( m_Items.begin() ); + } +} + +void RecentIsoList::InsertIntoMenu( int id ) +{ + if( m_Menu == NULL ) return; + RecentItem& curitem( m_Items[id] ); + curitem.ItemPtr = m_Menu->Append( wxID_ANY, Path::GetFilename(curitem.Filename), curitem.Filename, wxITEM_RADIO ); + + if( m_cursel == id ) + curitem.ItemPtr->Check(); +} + +void RecentIsoList::DoSettingsLoadSave( IniInterface& ini ) +{ + ini.GetConfig().SetRecordDefaults( false ); + + if( ini.IsSaving() ) + { + // Wipe existing recent iso list if we're saving, because our size might have changed + // and that could leave some residual entries in the config. + + ini.GetConfig().DeleteGroup( L"RecentIso" ); + IniScopedGroup groupie( ini, L"RecentIso" ); + + int cnt = m_Items.size(); + for( int i=0; iRecentFileCount; + IniScopedGroup groupie( ini, L"RecentIso" ); + for( uint i=0; iCurrentIso ); + } + + ini.GetConfig().SetRecordDefaults( true ); +} + +void __evt_fastcall RecentIsoList::OnSettingsLoadSave( void* obj, IniInterface& ini ) +{ + if( obj == NULL ) return; + ((RecentIsoList*)obj)->DoSettingsLoadSave( ini ); +} diff --git a/pcsx2/ps2/Iop/IopHwWrite.cpp b/pcsx2/ps2/Iop/IopHwWrite.cpp index 6717b801a0..6898e44707 100644 --- a/pcsx2/ps2/Iop/IopHwWrite.cpp +++ b/pcsx2/ps2/Iop/IopHwWrite.cpp @@ -119,7 +119,7 @@ void __fastcall iopHwWrite8_Page3( u32 addr, mem8_t val ) ( val == '\n' && g_pbufi != 0 ) ) { g_pbuf[g_pbufi] = 0; - Console.WriteLn( ConColor_IOP, g_pbuf ); + Console.WriteLn( ConColor_IOP, "%s", g_pbuf ); g_pbufi = 0; } else if( val != '\n' ) diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 28b55b07a5..2b51e0c2e5 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -1844,6 +1844,10 @@ RelativePath="..\..\gui\Plugins.cpp" > + + diff --git a/plugins/spu2-x/src/spu2freeze.cpp b/plugins/spu2-x/src/spu2freeze.cpp index 87e5865638..7956c62086 100644 --- a/plugins/spu2-x/src/spu2freeze.cpp +++ b/plugins/spu2-x/src/spu2freeze.cpp @@ -31,8 +31,6 @@ namespace Savestate { memset( pcm_cache_data, 0, pcm_BlockCount * sizeof(PcmCacheEntry) ); } - - static s16 old_state_sBuffer[pcm_DecodedSamplesPerBlock] = {0}; } struct Savestate::DataBlock