/[pcsx2_0.9.7]/branch/debug/0.X/0.9.X/0.9.7/ramdump-lateset/pcsx2/gui/Panels/PluginSelectorPanel.cpp
ViewVC logotype

Contents of /branch/debug/0.X/0.9.X/0.9.7/ramdump-lateset/pcsx2/gui/Panels/PluginSelectorPanel.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 330 - (show annotations) (download)
Tue Dec 28 04:24:23 2010 UTC (9 years, 9 months ago) by william
File size: 26759 byte(s)
merged upstream r4154-r4160
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "PrecompiledHeader.h"
17
18 #include <wx/dynlib.h>
19 #include <wx/dir.h>
20
21 #include "App.h"
22 #include "AppSaveStates.h"
23 #include "Plugins.h"
24 #include "ConfigurationPanels.h"
25
26 #include "Dialogs/ModalPopups.h"
27
28 #include "Utilities/ThreadingDialogs.h"
29 #include "Utilities/SafeArray.inl"
30
31 // Allows us to force-disable threading for debugging/troubleshooting
32 static const bool DisableThreading =
33 #ifdef __LINUX__
34 true; // linux appears to have threading issues with loadlibrary.
35 #else
36 false;
37 #endif
38
39 using namespace pxSizerFlags;
40 using namespace Threading;
41
42 BEGIN_DECLARE_EVENT_TYPES()
43 DECLARE_EVENT_TYPE(pxEvt_EnumeratedNext, -1)
44 DECLARE_EVENT_TYPE(pxEvt_EnumerationFinished, -1)
45 DECLARE_EVENT_TYPE(pxEVT_ShowStatusBar, -1)
46 END_DECLARE_EVENT_TYPES()
47
48 DEFINE_EVENT_TYPE(pxEvt_EnumeratedNext);
49 DEFINE_EVENT_TYPE(pxEvt_EnumerationFinished);
50 DEFINE_EVENT_TYPE(pxEVT_ShowStatusBar);
51
52 typedef s32 (CALLBACK* TestFnptr)();
53 typedef void (CALLBACK* ConfigureFnptr)();
54
55 static const wxString failed_separator( L"-------- Unsupported Plugins --------" );
56
57 namespace Exception
58 {
59 class NotEnumerablePlugin : public BadStream
60 {
61 public:
62 DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream );
63
64 wxString FormatDiagnosticMessage() const
65 {
66 FastFormatUnicode retval;
67 retval.Write("File is not a PCSX2 plugin");
68 _formatDiagMsg(retval);
69 return retval;
70 }
71 };
72 }
73
74 // --------------------------------------------------------------------------------------
75 // PluginEnumerator class
76 // --------------------------------------------------------------------------------------
77 class PluginEnumerator
78 {
79 protected:
80 wxString m_plugpath;
81 wxDynamicLibrary m_plugin;
82
83 _PS2EgetLibType m_GetLibType;
84 _PS2EgetLibName m_GetLibName;
85 _PS2EgetLibVersion2 m_GetLibVersion2;
86
87 u32 m_type;
88
89 public:
90
91 // Constructor!
92 //
93 // Possible Exceptions:
94 // BadStream - thrown if the provided file is simply not a loadable DLL.
95 // NotEnumerablePlugin - thrown if the DLL is not a PCSX2 plugin, or if it's of an unsupported version.
96 //
97 PluginEnumerator( const wxString& plugpath )
98 : m_plugpath( plugpath )
99 {
100 if( !m_plugin.Load( m_plugpath ) )
101 throw Exception::BadStream( m_plugpath ).SetBothMsgs(L"File is not a valid dynamic library.");
102
103 wxDoNotLogInThisScope please;
104 m_GetLibType = (_PS2EgetLibType)m_plugin.GetSymbol( L"PS2EgetLibType" );
105 m_GetLibName = (_PS2EgetLibName)m_plugin.GetSymbol( L"PS2EgetLibName" );
106 m_GetLibVersion2 = (_PS2EgetLibVersion2)m_plugin.GetSymbol( L"PS2EgetLibVersion2" );
107
108 if( m_GetLibType == NULL || m_GetLibName == NULL || m_GetLibVersion2 == NULL)
109 throw Exception::NotEnumerablePlugin( m_plugpath );
110
111 m_type = m_GetLibType();
112 }
113
114 bool CheckVersion( PluginsEnum_t pluginTypeIndex ) const
115 {
116 const PluginInfo& info( tbl_PluginInfo[pluginTypeIndex] );
117 if( m_type & info.typemask )
118 {
119 int version = m_GetLibVersion2( info.typemask );
120 if ( ((version >> 16)&0xff) == tbl_PluginInfo[pluginTypeIndex].version )
121 return true;
122
123 Console.Warning("%s Plugin %s: Version %x != %x", info.shortname, m_plugpath.c_str(), 0xff&(version >> 16), info.version);
124 }
125 return false;
126 }
127
128 bool Test( int pluginTypeIndex ) const
129 {
130 // all test functions use the same parameterless API, so just pick one arbitrarily (I pick PAD!)
131 TestFnptr testfunc = (TestFnptr)m_plugin.GetSymbol( fromUTF8( tbl_PluginInfo[pluginTypeIndex].shortname ) + L"test" );
132 if( testfunc == NULL ) return false;
133 return (testfunc() == 0);
134 }
135
136 wxString GetName() const
137 {
138 pxAssert( m_GetLibName != NULL );
139 return fromUTF8(m_GetLibName());
140 }
141
142 void GetVersionString( wxString& dest, int pluginTypeIndex ) const
143 {
144 const PluginInfo& info( tbl_PluginInfo[pluginTypeIndex] );
145 int version = m_GetLibVersion2( info.typemask );
146 dest.Printf( L"%d.%d.%d", (version>>8)&0xff, version&0xff, (version>>24)&0xff );
147 }
148 };
149
150 // --------------------------------------------------------------------------------------
151 // ApplyPluginsDialog
152 // --------------------------------------------------------------------------------------
153 class ApplyPluginsDialog : public WaitForTaskDialog
154 {
155 DECLARE_DYNAMIC_CLASS_NO_COPY(ApplyPluginsDialog)
156
157 typedef wxDialogWithHelpers _parent;
158
159 protected:
160 BaseApplicableConfigPanel* m_panel;
161
162 public:
163 ApplyPluginsDialog( BaseApplicableConfigPanel* panel=NULL );
164 virtual ~ApplyPluginsDialog() throw() {}
165
166 BaseApplicableConfigPanel* GetApplicableConfigPanel() const { return m_panel; }
167 };
168
169
170 // --------------------------------------------------------------------------------------
171 // ApplyOverValidStateEvent
172 // --------------------------------------------------------------------------------------
173 class ApplyOverValidStateEvent : public pxActionEvent
174 {
175 //DeclareNoncopyableObject( ApplyOverValidStateEvent );
176 typedef pxActionEvent _parent;
177
178 protected:
179 ApplyPluginsDialog* m_owner;
180
181 public:
182 ApplyOverValidStateEvent( ApplyPluginsDialog* owner=NULL )
183 {
184 m_owner = owner;
185 }
186
187 virtual ~ApplyOverValidStateEvent() throw() { }
188 virtual ApplyOverValidStateEvent *Clone() const { return new ApplyOverValidStateEvent(*this); }
189
190 protected:
191 void InvokeEvent();
192 };
193
194
195 // --------------------------------------------------------------------------------------
196 // SysExecEvent_ApplyPlugins
197 // --------------------------------------------------------------------------------------
198 class SysExecEvent_ApplyPlugins : public SysExecEvent
199 {
200 typedef SysExecEvent _parent;
201
202 protected:
203 ApplyPluginsDialog* m_dialog;
204
205 public:
206 wxString GetEventName() const { return L"PluginSelectorPanel::ApplyPlugins"; }
207
208 virtual ~SysExecEvent_ApplyPlugins() throw() {}
209 SysExecEvent_ApplyPlugins* Clone() const { return new SysExecEvent_ApplyPlugins( *this ); }
210
211 SysExecEvent_ApplyPlugins( ApplyPluginsDialog* parent, SynchronousActionState& sync )
212 : SysExecEvent( &sync )
213 {
214 m_dialog = parent;
215 }
216
217 protected:
218 void InvokeEvent();
219 void CleanupEvent();
220
221 void PostFinishToDialog();
222 };
223
224 // --------------------------------------------------------------------------------------
225 // ApplyPluginsDialog Implementations
226 // --------------------------------------------------------------------------------------
227 IMPLEMENT_DYNAMIC_CLASS(ApplyPluginsDialog, WaitForTaskDialog)
228
229 ApplyPluginsDialog::ApplyPluginsDialog( BaseApplicableConfigPanel* panel )
230 : WaitForTaskDialog( _("Applying settings...") )
231 {
232 GetSysExecutorThread().PostEvent( new SysExecEvent_ApplyPlugins( this, m_sync ) );
233 }
234
235 // --------------------------------------------------------------------------------------
236 // ApplyOverValidStateEvent Implementations
237 // --------------------------------------------------------------------------------------
238 void ApplyOverValidStateEvent::InvokeEvent()
239 {
240 wxDialogWithHelpers dialog( m_owner, _("Shutdown PS2 virtual machine?") );
241
242 dialog += dialog.Heading( pxE( "!Notice:PluginSelector:ConfirmShutdown",
243 L"Warning! Changing plugins requires a complete shutdown and reset of the PS2 virtual machine. "
244 L"PCSX2 will attempt to save and restore the state, but if the newly selected plugins are "
245 L"incompatible the recovery may fail, and current progress will be lost."
246 L"\n\n"
247 L"Are you sure you want to apply settings now?"
248 ) );
249
250 int result = pxIssueConfirmation( dialog, MsgButtons().OK().Cancel(), L"PluginSelector.ConfirmShutdown" );
251
252 if( result == wxID_CANCEL )
253 throw Exception::CannotApplySettings( m_owner->GetApplicableConfigPanel() ).Quiet()
254 .SetDiagMsg(L"Cannot apply settings: canceled by user because plugins changed while the emulation state was active.");
255 }
256
257 // --------------------------------------------------------------------------------------
258 // SysExecEvent_ApplyPlugins Implementations
259 // --------------------------------------------------------------------------------------
260 void SysExecEvent_ApplyPlugins::InvokeEvent()
261 {
262 ScopedCoreThreadPause paused_core;
263
264 ScopedPtr< VmStateBuffer > buffer;
265
266 if( SysHasValidState() )
267 {
268 paused_core.AllowResume();
269 ApplyOverValidStateEvent aEvt( m_dialog );
270 wxGetApp().ProcessEvent( aEvt );
271 paused_core.DisallowResume();
272
273 // FIXME : We only actually have to save plugins here, except the recovery code
274 // in SysCoreThread isn't quite set up yet to handle that (I think...) --air
275
276 memSavingState saveme( *(buffer.Reassign(new VmStateBuffer(L"StateBuffer_ApplyNewPlugins"))) );
277
278 saveme.FreezeAll();
279 }
280
281 ScopedCoreThreadClose closed_core;
282
283 CorePlugins.Shutdown();
284 CorePlugins.Unload();
285 LoadPluginsImmediate();
286 CorePlugins.Init();
287
288 if( buffer ) CoreThread.UploadStateCopy( *buffer );
289
290 PostFinishToDialog();
291
292 closed_core.AllowResume();
293 paused_core.AllowResume();
294 }
295
296 void SysExecEvent_ApplyPlugins::PostFinishToDialog()
297 {
298 if( !m_dialog ) return;
299 wxCommandEvent tevt( pxEvt_ThreadedTaskComplete );
300 m_dialog->GetEventHandler()->AddPendingEvent( tevt );
301 m_dialog = NULL;
302 }
303
304 void SysExecEvent_ApplyPlugins::CleanupEvent()
305 {
306 PostFinishToDialog();
307 _parent::CleanupEvent();
308 }
309
310 // --------------------------------------------------------------------------------------
311 // PluginSelectorPanel::StatusPanel implementations
312 // --------------------------------------------------------------------------------------
313
314 Panels::PluginSelectorPanel::StatusPanel::StatusPanel( wxWindow* parent )
315 : wxPanelWithHelpers( parent, wxVERTICAL )
316 , m_gauge( *new wxGauge( this, wxID_ANY, 10 ) )
317 , m_label( *new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE | wxST_NO_AUTORESIZE ) )
318 {
319 m_progress = 0;
320
321 m_gauge.SetToolTip( _("I'm givin' her all she's got, Captain!") );
322
323 *this += Heading(_( "Enumerating available plugins..." )).Bold() | StdExpand();
324 *this += m_gauge | pxExpand.Border( wxLEFT | wxRIGHT, 32 );
325 *this += m_label | StdExpand();
326
327 Fit();
328 }
329
330 void Panels::PluginSelectorPanel::StatusPanel::SetGaugeLength( int len )
331 {
332 m_gauge.SetRange( len );
333 }
334
335 void Panels::PluginSelectorPanel::StatusPanel::AdvanceProgress( const wxString& msg )
336 {
337 m_label.SetLabel( msg );
338 m_gauge.SetValue( ++m_progress );
339 }
340
341 void Panels::PluginSelectorPanel::StatusPanel::Reset()
342 {
343 m_gauge.SetValue( m_progress = 0 );
344 m_label.SetLabel( wxEmptyString );
345 }
346
347 // Id for all Configure buttons (any non-negative arbitrary integer will do)
348 static const int ButtonId_Configure = 51;
349
350 // --------------------------------------------------------------------------------------
351 // PluginSelectorPanel::ComboBoxPanel implementations
352 // --------------------------------------------------------------------------------------
353 Panels::PluginSelectorPanel::ComboBoxPanel::ComboBoxPanel( PluginSelectorPanel* parent )
354 : wxPanelWithHelpers( parent, wxVERTICAL )
355 , m_FolderPicker( *new DirPickerPanel( this, FolderId_Plugins,
356 _("Plugins Search Path:"),
357 _("Select a folder with PCSX2 plugins") )
358 )
359 {
360 wxFlexGridSizer& s_plugin( *new wxFlexGridSizer( PluginId_Count, 3, 16, 10 ) );
361 s_plugin.SetFlexibleDirection( wxHORIZONTAL );
362 s_plugin.AddGrowableCol( 1 ); // expands combo boxes to full width.
363
364 const PluginInfo* pi = tbl_PluginInfo; do
365 {
366 const PluginsEnum_t pid = pi->id;
367
368 m_combobox[pid] = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY );
369
370 m_configbutton[pid] = new wxButton( this, ButtonId_Configure, L"Configure..." );
371 m_configbutton[pid]->SetClientData( (void*)(int)pid );
372
373 s_plugin += Label( pi->GetShortname() ) | pxBorder( wxTOP | wxLEFT, 2 );
374 s_plugin += m_combobox[pid] | pxExpand;
375 s_plugin += m_configbutton[pid];
376 } while( ++pi, pi->shortname != NULL );
377
378 m_FolderPicker.SetStaticDesc( _("Click the Browse button to select a different folder for PCSX2 plugins.") );
379
380 *this += s_plugin | pxExpand;
381 *this += 6;
382 *this += m_FolderPicker | StdExpand();
383 }
384
385 void Panels::PluginSelectorPanel::ComboBoxPanel::Reset()
386 {
387 for( int i=0; i<PluginId_Count; ++i )
388 {
389 m_combobox[i]->Clear();
390 m_combobox[i]->SetSelection( wxNOT_FOUND );
391 m_combobox[i]->SetValue( wxEmptyString );
392
393 m_configbutton[i]->Disable();
394 }
395 }
396
397 void Panels::PluginSelectorPanel::DispatchEvent( const PluginEventType& evt )
398 {
399 if( (evt != CorePlugins_Loaded) && (evt != CorePlugins_Unloaded) ) return; // everything else we don't care about
400
401 if( IsBeingDeleted() ) return;
402
403 const PluginInfo* pi = tbl_PluginInfo; do
404 {
405 wxComboBox& box( m_ComponentBoxes->Get(pi->id) );
406 int sel = box.GetSelection();
407 if( sel == wxNOT_FOUND ) continue;
408
409 m_ComponentBoxes->GetConfigButton(pi->id).Enable(
410 (m_FileList==NULL || m_FileList->Count() == 0) ? false :
411 g_Conf->FullpathMatchTest( pi->id,(*m_FileList)[((int)box.GetClientData(sel))] )
412 );
413 } while( ++pi, pi->shortname != NULL );
414
415 }
416
417 Panels::PluginSelectorPanel::PluginSelectorPanel( wxWindow* parent )
418 : BaseSelectorPanel( parent )
419 {
420 m_StatusPanel = new StatusPanel( this );
421 m_ComponentBoxes = new ComboBoxPanel( this );
422
423 // note: the status panel is a floating window, so that it can be positioned in the
424 // center of the dialog after it's been fitted to the contents.
425
426 *this += m_ComponentBoxes | StdExpand().ReserveSpaceEvenIfHidden();
427
428 m_StatusPanel->Hide();
429 m_ComponentBoxes->Hide();
430
431 // refresh button used for diagnostics... (don't think there's a point to having one otherwise) --air
432 //wxButton* refresh = new wxButton( this, wxID_ANY, L"Refresh" );
433 //s_main.Add( refresh );
434 //Connect( refresh->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PluginSelectorPanel::OnRefresh ) );
435
436 Connect( pxEvt_EnumeratedNext, wxCommandEventHandler( PluginSelectorPanel::OnProgress ) );
437 Connect( pxEvt_EnumerationFinished, wxCommandEventHandler( PluginSelectorPanel::OnEnumComplete ) );
438 Connect( pxEVT_ShowStatusBar, wxCommandEventHandler( PluginSelectorPanel::OnShowStatusBar ) );
439 Connect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( PluginSelectorPanel::OnPluginSelected ) );
440
441 Connect( ButtonId_Configure, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PluginSelectorPanel::OnConfigure_Clicked ) );
442
443 AppStatusEvent_OnSettingsApplied();
444 }
445
446 Panels::PluginSelectorPanel::~PluginSelectorPanel() throw()
447 {
448 CancelRefresh(); // in case the enumeration thread is currently refreshing...
449 }
450
451 void Panels::PluginSelectorPanel::AppStatusEvent_OnSettingsApplied()
452 {
453 m_ComponentBoxes->GetDirPicker().Reset();
454 }
455
456 static wxString GetApplyFailedMsg()
457 {
458 return wxsFormat( pxE( "!Notice:PluginSelector:ApplyFailed",
459 L"All plugins must have valid selections for %s to run. If you are unable to make "
460 L"a valid selection due to missing plugins or an incomplete install of %s, then "
461 L"press cancel to close the Configuration panel."
462 ), pxGetAppName().c_str(), pxGetAppName().c_str() );
463 }
464
465 void Panels::PluginSelectorPanel::Apply()
466 {
467 // user never entered plugins panel? Skip application since combo boxes are invalid/uninitialized.
468 if( !m_FileList ) return;
469
470 AppConfig curconf( *g_Conf );
471
472 const PluginInfo* pi = tbl_PluginInfo; do
473 {
474 const PluginsEnum_t pid = pi->id;
475 int sel = m_ComponentBoxes->Get(pid).GetSelection();
476 if( sel == wxNOT_FOUND )
477 {
478 wxString plugname( pi->GetShortname() );
479
480 throw Exception::CannotApplySettings( this )
481 .SetDiagMsg(pxsFmt( L"PluginSelectorPanel: Invalid or missing selection for the %s plugin.", plugname.c_str()) )
482 .SetUserMsg(pxsFmt( L"Please select a valid plugin for the %s.", plugname.c_str() ) + L"\n\n" + GetApplyFailedMsg() );
483 }
484
485 g_Conf->BaseFilenames.Plugins[pid] = GetFilename((int)m_ComponentBoxes->Get(pid).GetClientData(sel));
486 } while( ++pi, pi->shortname != NULL );
487
488 // ----------------------------------------------------------------------------
489 // Make sure folders are up to date, and try to load/reload plugins if needed...
490
491 g_Conf->Folders.ApplyDefaults();
492
493 // Need to unload the current emulation state if the user changed plugins, because
494 // the whole plugin system needs to be re-loaded.
495
496 pi = tbl_PluginInfo; do {
497 if( g_Conf->FullpathTo( pi->id ) != curconf.FullpathTo( pi->id ) )
498 break;
499 } while( ++pi, pi->shortname != NULL );
500
501 if( pi->shortname == NULL ) return; // no plugins changed? nothing left to do!
502
503 // ----------------------------------------------------------------------------
504 // Plugin names are not up-to-date -- RELOAD!
505
506 try
507 {
508 if( wxID_CANCEL == ApplyPluginsDialog( this ).ShowModal() )
509 throw Exception::CannotApplySettings( this ).Quiet().SetDiagMsg(L"User canceled plugin load process.");
510 }
511 catch( Exception::PluginError& ex )
512 {
513 // Rethrow PluginLoadErrors as a failure to Apply...
514
515 wxString plugname( tbl_PluginInfo[ex.PluginId].GetShortname() );
516
517 throw Exception::CannotApplySettings( this )
518 .SetDiagMsg(ex.FormatDiagnosticMessage())
519 .SetUserMsg(pxsFmt(
520 _("The selected %s plugin failed to load.\n\nReason: %s\n\n"),
521 plugname.c_str(), ex.FormatDisplayMessage().c_str()
522 ) + GetApplyFailedMsg());
523 }
524 }
525
526 void Panels::PluginSelectorPanel::CancelRefresh()
527 {
528 }
529
530 // This method is a callback from the BaseSelectorPanel. It is called when the page is shown
531 // and the page's enumerated selections are valid (meaning we should start our enumeration
532 // thread!)
533 void Panels::PluginSelectorPanel::DoRefresh()
534 {
535 m_ComponentBoxes->Reset();
536 if( !m_FileList )
537 {
538 wxCommandEvent evt;
539 OnEnumComplete( evt );
540 return;
541 }
542
543 // Disable all controls until enumeration is complete
544 m_ComponentBoxes->Hide();
545
546 // (including next button if it's a Wizard)
547 wxWindow* forwardButton = GetGrandParent()->FindWindow( wxID_FORWARD );
548 if( forwardButton != NULL )
549 forwardButton->Disable();
550
551 // Show status bar for plugin enumeration. Use a pending event so that
552 // the window's size can get initialized properly before trying to custom-
553 // fit the status panel to it.
554 wxCommandEvent evt( pxEVT_ShowStatusBar );
555 GetEventHandler()->AddPendingEvent( evt );
556
557 m_EnumeratorThread.Delete() = new EnumThread( *this );
558
559 if( DisableThreading )
560 m_EnumeratorThread->DoNextPlugin( 0 );
561 else
562 m_EnumeratorThread->Start();
563 }
564
565 bool Panels::PluginSelectorPanel::ValidateEnumerationStatus()
566 {
567 if( m_EnumeratorThread ) return true; // Cant reset file lists while we're busy enumerating...
568
569 bool validated = true;
570
571 // re-enumerate plugins, and if anything changed then we need to wipe
572 // the contents of the combo boxes and re-enumerate everything.
573
574 // Impl Note: ScopedPtr used so that resources get cleaned up if an exception
575 // occurs during file enumeration.
576 ScopedPtr<wxArrayString> pluginlist( new wxArrayString() );
577
578 int pluggers = EnumeratePluginsInFolder( m_ComponentBoxes->GetPluginsPath(), pluginlist );
579
580 if( !m_FileList || (*pluginlist != *m_FileList) )
581 validated = false;
582
583 if( pluggers == 0 )
584 {
585 m_FileList = NULL;
586 return validated;
587 }
588
589 m_FileList.SwapPtr( pluginlist );
590
591 // set the gague length a little shorter than the plugin count. 2 reasons:
592 // * some of the plugins might be duds.
593 // * on high end machines and Win7, the statusbar lags a lot and never gets to 100% before being hidden.
594
595 m_StatusPanel->SetGaugeLength( std::max( 1, (pluggers-1) - (pluggers/8) ) );
596
597 return validated;
598 }
599
600 void Panels::PluginSelectorPanel::OnPluginSelected( wxCommandEvent& evt )
601 {
602 if( IsBeingDeleted() || m_ComponentBoxes->IsBeingDeleted() ) return;
603
604 const PluginInfo* pi = tbl_PluginInfo; do
605 {
606 wxComboBox& box( m_ComponentBoxes->Get(pi->id) );
607 if( box.GetId() == evt.GetId() )
608 {
609 // Button is enabled if:
610 // (a) plugins aren't even loaded yet.
611 // (b) current selection matches exactly the currently configured/loaded plugin.
612
613 bool isSame = (!CorePlugins.AreLoaded()) || g_Conf->FullpathMatchTest( pi->id, (*m_FileList)[(int)box.GetClientData(box.GetSelection())] );
614 m_ComponentBoxes->GetConfigButton( pi->id ).Enable( isSame );
615
616 if( !isSame ) evt.Skip(); // enabled Apply button! :D
617 return;
618 }
619 } while( ++pi, pi->shortname != NULL );
620 }
621
622 void Panels::PluginSelectorPanel::OnConfigure_Clicked( wxCommandEvent& evt )
623 {
624 if( IsBeingDeleted() ) return;
625
626 PluginsEnum_t pid = (PluginsEnum_t)(int)((wxEvtHandler*)evt.GetEventObject())->GetClientData();
627
628 int sel = m_ComponentBoxes->Get(pid).GetSelection();
629 if( sel == wxNOT_FOUND ) return;
630
631 // Only allow configuration if the selected plugin matches exactly our currently loaded one.
632 // Otherwise who knows what sort of funny business could happen configuring a plugin while
633 // another instance/version is running. >_<
634
635 const wxString filename( (*m_FileList)[(int)m_ComponentBoxes->Get(pid).GetClientData(sel)] );
636
637 if( CorePlugins.AreLoaded() && !g_Conf->FullpathMatchTest( pid, filename ) )
638 {
639 Console.Warning( "(PluginSelector) Plugin name mismatch, configuration request ignored." );
640 return;
641 }
642
643 wxDynamicLibrary dynlib( filename );
644
645 if( ConfigureFnptr configfunc = (ConfigureFnptr)dynlib.GetSymbol( tbl_PluginInfo[pid].GetShortname() + L"configure" ) )
646 {
647
648 wxWindowDisabler disabler;
649 ScopedCoreThreadPause paused_core( new SysExecEvent_SaveSinglePlugin(pid) );
650 if (!CorePlugins.AreLoaded())
651 {
652 typedef void (CALLBACK* SetDirFnptr)( const char* dir );
653
654 if( SetDirFnptr func = (SetDirFnptr)dynlib.GetSymbol( tbl_PluginInfo[pid].GetShortname() + L"setSettingsDir" ) )
655 {
656 func( GetSettingsFolder().ToUTF8() );
657 }
658
659 if( SetDirFnptr func = (SetDirFnptr)dynlib.GetSymbol( tbl_PluginInfo[pid].GetShortname() + L"setLogDir" ) )
660 {
661 func( GetLogFolder().ToUTF8() );
662 }
663 }
664
665 configfunc();
666 }
667 }
668
669 void Panels::PluginSelectorPanel::OnShowStatusBar( wxCommandEvent& evt )
670 {
671 m_StatusPanel->SetSize( m_ComponentBoxes->GetSize().GetWidth() - 8, wxDefaultCoord );
672 m_StatusPanel->CentreOnParent();
673 m_StatusPanel->Show();
674 }
675
676 void Panels::PluginSelectorPanel::OnEnumComplete( wxCommandEvent& evt )
677 {
678 m_EnumeratorThread = NULL;
679
680 // fixme: Default plugins should be picked based on the timestamp of the DLL or something?
681 // (for now we just force it to selection zero if nothing's selected)
682
683 int emptyBoxes = 0;
684 const PluginInfo* pi = tbl_PluginInfo; do
685 {
686 const PluginsEnum_t pid = pi->id;
687 if( m_ComponentBoxes->Get(pid).GetCount() <= 0 )
688 emptyBoxes++;
689
690 else if( m_ComponentBoxes->Get(pid).GetSelection() == wxNOT_FOUND )
691 {
692 m_ComponentBoxes->Get(pid).SetSelection( 0 );
693 m_ComponentBoxes->GetConfigButton(pid).Enable( !CorePlugins.AreLoaded() );
694 }
695 } while( ++pi, pi->shortname != NULL );
696
697 m_ComponentBoxes->Show();
698 m_StatusPanel->Hide();
699 m_StatusPanel->Reset();
700
701 wxWindow* forwardButton = GetGrandParent()->FindWindow( wxID_FORWARD );
702 if( forwardButton != NULL )
703 forwardButton->Enable();
704 }
705
706
707 void Panels::PluginSelectorPanel::OnProgress( wxCommandEvent& evt )
708 {
709 if( !m_FileList ) return;
710
711 // The thread can get canceled and replaced with a new thread, which means all
712 // pending messages should be ignored.
713 if( m_EnumeratorThread != (EnumThread*)evt.GetClientData() ) return;
714
715 const size_t evtidx = evt.GetExtraLong();
716
717 if( DisableThreading )
718 {
719 const int nextidx = evtidx+1;
720 if( nextidx == m_FileList->Count() )
721 {
722 wxCommandEvent done( pxEvt_EnumerationFinished );
723 GetEventHandler()->AddPendingEvent( done );
724 }
725 else
726 m_EnumeratorThread->DoNextPlugin( nextidx );
727 }
728
729 m_StatusPanel->AdvanceProgress( (evtidx < m_FileList->Count()-1) ?
730 (*m_FileList)[evtidx + 1] : wxString(_("Completing tasks..."))
731 );
732
733 EnumeratedPluginInfo& result( m_EnumeratorThread->Results[evtidx] );
734
735 if( result.TypeMask == 0 )
736 {
737 Console.Error( L"Some kinda plugin failure: " + (*m_FileList)[evtidx] );
738 }
739
740 const PluginInfo* pi = tbl_PluginInfo; do
741 {
742 const PluginsEnum_t pid = pi->id;
743 if( result.TypeMask & pi->typemask )
744 {
745 if( result.PassedTest & pi->typemask )
746 {
747 int sel = m_ComponentBoxes->Get(pid).Append( wxsFormat( L"%s %s [%s]",
748 result.Name.c_str(), result.Version[pid].c_str(), Path::GetFilenameWithoutExt( (*m_FileList)[evtidx] ).c_str() ),
749 (void*)evtidx
750 );
751
752 if( g_Conf->FullpathMatchTest( pid, (*m_FileList)[evtidx] ) )
753 {
754 m_ComponentBoxes->Get(pid).SetSelection( sel );
755 m_ComponentBoxes->GetConfigButton(pid).Enable();
756 }
757 }
758 }
759 } while( ++pi, pi->shortname != NULL );
760 }
761
762
763 // --------------------------------------------------------------------------------------
764 // EnumThread method implementations
765 // --------------------------------------------------------------------------------------
766
767 Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master )
768 : pxThread()
769 , Results( master.FileCount(), L"PluginSelectorResults" )
770 , m_master( master )
771 , m_hourglass( Cursor_KindaBusy )
772 {
773 Results.MatchLengthToAllocatedSize();
774 }
775
776 void Panels::PluginSelectorPanel::EnumThread::DoNextPlugin( int curidx )
777 {
778 DbgCon.Indent().WriteLn( L"Plugin: " + m_master.GetFilename( curidx ) );
779
780 try
781 {
782 EnumeratedPluginInfo& result( Results[curidx] );
783 result.TypeMask = 0;
784
785 PluginEnumerator penum( m_master.GetFilename( curidx ) );
786
787 result.Name = penum.GetName();
788 const PluginInfo* pi = tbl_PluginInfo; do
789 {
790 const PluginsEnum_t pid = pi->id;
791 result.TypeMask |= pi->typemask;
792 if( penum.CheckVersion( pid ) )
793 {
794 result.PassedTest |= tbl_PluginInfo[pid].typemask;
795 penum.GetVersionString( result.Version[pid], pid );
796 }
797 } while( ++pi, pi->shortname != NULL );
798 }
799 catch( Exception::BadStream& ex )
800 {
801 Console.Warning( ex.FormatDiagnosticMessage() );
802 }
803
804 wxCommandEvent yay( pxEvt_EnumeratedNext );
805 yay.SetClientData( this );
806 yay.SetExtraLong( curidx );
807 m_master.GetEventHandler()->AddPendingEvent( yay );
808 }
809
810 void Panels::PluginSelectorPanel::EnumThread::ExecuteTaskInThread()
811 {
812 DevCon.WriteLn( "Plugin Enumeration Thread started..." );
813
814 wxGetApp().Ping();
815 Sleep( 2 );
816
817 for( int curidx=0; curidx < m_master.FileCount(); ++curidx )
818 {
819 DoNextPlugin( curidx );
820
821 // speed isn't critical here, but the pretty status bar sure is. Sleep off
822 // some brief cycles to give the status bar time to refresh.
823
824 Sleep( 5 );
825 //Sleep(150); // uncomment this to slow down the selector, for debugging threading.
826 }
827
828 wxCommandEvent done( pxEvt_EnumerationFinished );
829 done.SetClientData( this );
830 m_master.GetEventHandler()->AddPendingEvent( done );
831
832 DevCon.WriteLn( "Plugin Enumeration Thread complete!" );
833 }

  ViewVC Help
Powered by ViewVC 1.1.22