forked from mia/Aegisub
Add a generic function for invoking functions on the GUI thread
This commit is contained in:
parent
1d020b851e
commit
947dc537d1
5 changed files with 46 additions and 58 deletions
|
@ -223,9 +223,6 @@ namespace Automation4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProgressSink
|
// ProgressSink
|
||||||
wxDEFINE_EVENT(EVT_SHOW_DIALOG, wxThreadEvent);
|
|
||||||
wxDEFINE_EVENT(EVT_SHOW_SCRIPT_DIALOG, wxThreadEvent);
|
|
||||||
|
|
||||||
ProgressSink::ProgressSink(agi::ProgressSink *impl, BackgroundScriptRunner *bsr)
|
ProgressSink::ProgressSink(agi::ProgressSink *impl, BackgroundScriptRunner *bsr)
|
||||||
: impl(impl)
|
: impl(impl)
|
||||||
, bsr(bsr)
|
, bsr(bsr)
|
||||||
|
@ -235,74 +232,35 @@ namespace Automation4 {
|
||||||
|
|
||||||
void ProgressSink::ShowDialog(ScriptDialog *config_dialog)
|
void ProgressSink::ShowDialog(ScriptDialog *config_dialog)
|
||||||
{
|
{
|
||||||
wxSemaphore sema(0, 1);
|
InvokeOnMainThread([=] {
|
||||||
wxThreadEvent *evt = new wxThreadEvent(EVT_SHOW_SCRIPT_DIALOG);
|
wxDialog w; // container dialog box
|
||||||
evt->SetPayload(std::make_pair(config_dialog, &sema));
|
w.SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
|
||||||
bsr->QueueEvent(evt);
|
w.Create(bsr->GetParentWindow(), -1, bsr->GetTitle());
|
||||||
sema.Wait();
|
wxBoxSizer *s = new wxBoxSizer(wxHORIZONTAL); // sizer for putting contents in
|
||||||
|
wxWindow *ww = config_dialog->CreateWindow(&w); // generate actual dialog contents
|
||||||
|
s->Add(ww, 0, wxALL, 5); // add contents to dialog
|
||||||
|
w.SetSizerAndFit(s);
|
||||||
|
w.CenterOnParent();
|
||||||
|
w.ShowModal();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int ProgressSink::ShowDialog(wxDialog *dialog)
|
int ProgressSink::ShowDialog(wxDialog *dialog)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
wxSemaphore sema(0, 1);
|
InvokeOnMainThread([&] { ret = dialog->ShowModal(); });
|
||||||
wxThreadEvent *evt = new wxThreadEvent(EVT_SHOW_DIALOG);
|
|
||||||
evt->SetPayload(std::make_tuple(dialog, &sema, &ret));
|
|
||||||
bsr->QueueEvent(evt);
|
|
||||||
sema.Wait();
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
BackgroundScriptRunner::BackgroundScriptRunner(wxWindow *parent, wxString const& title)
|
BackgroundScriptRunner::BackgroundScriptRunner(wxWindow *parent, wxString const& title)
|
||||||
: impl(new DialogProgress(parent, title))
|
: impl(new DialogProgress(parent, title))
|
||||||
{
|
{
|
||||||
impl->Bind(EVT_SHOW_DIALOG, &BackgroundScriptRunner::OnDialog, this);
|
|
||||||
impl->Bind(EVT_SHOW_SCRIPT_DIALOG, &BackgroundScriptRunner::OnScriptDialog, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BackgroundScriptRunner::~BackgroundScriptRunner()
|
BackgroundScriptRunner::~BackgroundScriptRunner()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundScriptRunner::OnScriptDialog(wxThreadEvent &evt)
|
|
||||||
{
|
|
||||||
std::pair<ScriptDialog*, wxSemaphore*> payload = evt.GetPayload<std::pair<ScriptDialog*, wxSemaphore*> >();
|
|
||||||
|
|
||||||
wxDialog w; // container dialog box
|
|
||||||
w.SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
|
|
||||||
w.Create(impl.get(), -1, impl->GetTitle());
|
|
||||||
wxBoxSizer *s = new wxBoxSizer(wxHORIZONTAL); // sizer for putting contents in
|
|
||||||
wxWindow *ww = payload.first->CreateWindow(&w); // generate actual dialog contents
|
|
||||||
s->Add(ww, 0, wxALL, 5); // add contents to dialog
|
|
||||||
w.SetSizerAndFit(s);
|
|
||||||
w.CenterOnParent();
|
|
||||||
w.ShowModal();
|
|
||||||
|
|
||||||
// Tell the calling thread it can wake up now
|
|
||||||
payload.second->Post();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackgroundScriptRunner::OnDialog(wxThreadEvent &evt)
|
|
||||||
{
|
|
||||||
using namespace std;
|
|
||||||
tuple<wxDialog*, wxSemaphore*, int*> payload = evt.GetPayload<tuple<wxDialog*, wxSemaphore*, int*> >();
|
|
||||||
*get<2>(payload) = get<0>(payload)->ShowModal();
|
|
||||||
get<1>(payload)->Post();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackgroundScriptRunner::QueueEvent(wxEvent *evt)
|
|
||||||
{
|
|
||||||
wxQueueEvent(impl.get(), evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a function taking an Automation4::ProgressSink to one taking an
|
|
||||||
// agi::ProgressSink so that we can pass it to an agi::BackgroundWorker
|
|
||||||
static void progress_sink_wrapper(std::function<void (ProgressSink*)> task, agi::ProgressSink *ps, BackgroundScriptRunner *bsr)
|
|
||||||
{
|
|
||||||
ProgressSink aps(ps, bsr);
|
|
||||||
task(&aps);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackgroundScriptRunner::Run(std::function<void (ProgressSink*)> task)
|
void BackgroundScriptRunner::Run(std::function<void (ProgressSink*)> task)
|
||||||
{
|
{
|
||||||
int prio = OPT_GET("Automation/Thread Priority")->GetInt();
|
int prio = OPT_GET("Automation/Thread Priority")->GetInt();
|
||||||
|
@ -311,7 +269,10 @@ namespace Automation4 {
|
||||||
else if (prio == 2) prio = 10; // lowest
|
else if (prio == 2) prio = 10; // lowest
|
||||||
else prio = 50; // fallback normal
|
else prio = 50; // fallback normal
|
||||||
|
|
||||||
impl->Run(bind(progress_sink_wrapper, task, std::placeholders::_1, this), prio);
|
impl->Run([&](agi::ProgressSink *ps) {
|
||||||
|
ProgressSink aps(ps, this);
|
||||||
|
task(&aps);
|
||||||
|
}, prio);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxWindow *BackgroundScriptRunner::GetParentWindow() const
|
wxWindow *BackgroundScriptRunner::GetParentWindow() const
|
||||||
|
@ -319,6 +280,11 @@ namespace Automation4 {
|
||||||
return impl.get();
|
return impl.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxString BackgroundScriptRunner::GetTitle() const
|
||||||
|
{
|
||||||
|
return impl->GetTitle();
|
||||||
|
}
|
||||||
|
|
||||||
// Script
|
// Script
|
||||||
Script::Script(wxString const& filename)
|
Script::Script(wxString const& filename)
|
||||||
: filename(filename)
|
: filename(filename)
|
||||||
|
|
|
@ -124,11 +124,9 @@ namespace Automation4 {
|
||||||
class BackgroundScriptRunner {
|
class BackgroundScriptRunner {
|
||||||
agi::scoped_ptr<DialogProgress> impl;
|
agi::scoped_ptr<DialogProgress> impl;
|
||||||
|
|
||||||
void OnDialog(wxThreadEvent &evt);
|
|
||||||
void OnScriptDialog(wxThreadEvent &evt);
|
|
||||||
public:
|
public:
|
||||||
void QueueEvent(wxEvent *evt);
|
|
||||||
wxWindow *GetParentWindow() const;
|
wxWindow *GetParentWindow() const;
|
||||||
|
wxString GetTitle() const;
|
||||||
|
|
||||||
void Run(std::function<void(ProgressSink*)> task);
|
void Run(std::function<void(ProgressSink*)> task);
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,10 @@ bool AegisubApp::OnInit() {
|
||||||
SetAppName("aegisub");
|
SetAppName("aegisub");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Bind(EVT_CALL_THUNK, [](wxThreadEvent &evt) {
|
||||||
|
evt.GetPayload<std::function<void()>>()();
|
||||||
|
});
|
||||||
|
|
||||||
// logging.
|
// logging.
|
||||||
agi::log::log = new agi::log::LogSink;
|
agi::log::log = new agi::log::LogSink;
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,8 @@
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
wxDEFINE_EVENT(EVT_CALL_THUNK, wxThreadEvent);
|
||||||
|
|
||||||
wxString MakeRelativePath(wxString _path, wxString reference) {
|
wxString MakeRelativePath(wxString _path, wxString reference) {
|
||||||
if (_path.empty() || _path[0] == '?') return _path;
|
if (_path.empty() || _path[0] == '?') return _path;
|
||||||
wxFileName path(_path);
|
wxFileName path(_path);
|
||||||
|
|
|
@ -39,9 +39,11 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <wx/app.h>
|
||||||
#include <wx/icon.h>
|
#include <wx/icon.h>
|
||||||
#include <wx/thread.h>
|
#include <wx/thread.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -182,3 +184,19 @@ struct cast {
|
||||||
return dynamic_cast<Out>(&in);
|
return dynamic_cast<Out>(&in);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
wxDECLARE_EVENT(EVT_CALL_THUNK, wxThreadEvent);
|
||||||
|
|
||||||
|
template<typename Function>
|
||||||
|
void InvokeOnMainThreadAsync(Function const& f) {
|
||||||
|
wxThreadEvent *evt = new wxThreadEvent(EVT_CALL_THUNK);
|
||||||
|
evt->SetPayload<std::function<void()>>(f);
|
||||||
|
wxTheApp->QueueEvent(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Function>
|
||||||
|
void InvokeOnMainThread(Function const& f) {
|
||||||
|
wxSemaphore sema(0, 1);
|
||||||
|
InvokeOnMainThreadAsync([&] { f(); sema.Post(); });
|
||||||
|
sema.Wait();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue