forked from mia/Aegisub
Ruby: scripts run in a separate thread
Originally committed to SVN as r921.
This commit is contained in:
parent
6da6f1bc57
commit
2f52b36910
5 changed files with 102 additions and 43 deletions
|
@ -366,9 +366,7 @@ namespace Automation4 {
|
|||
|
||||
if (script_finished) {
|
||||
if (!debug_visible) {
|
||||
if(IsModal())
|
||||
EndModal(0);
|
||||
else Show(false);
|
||||
EndModal(0);
|
||||
} else {
|
||||
cancel_button->Enable(true);
|
||||
cancel_button->SetLabel(_("Close"));
|
||||
|
@ -452,10 +450,7 @@ namespace Automation4 {
|
|||
cancelled = true;
|
||||
cancel_button->Enable(false);
|
||||
} else {
|
||||
if(this->IsModal())
|
||||
EndModal(0);
|
||||
else
|
||||
Show(false);
|
||||
EndModal(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -232,6 +232,7 @@ namespace Automation4 {
|
|||
void OnIdle(wxIdleEvent &evt);
|
||||
void OnConfigDialog(ShowConfigDialogEvent &evt);
|
||||
|
||||
void DoUpdateDisplay();
|
||||
|
||||
protected:
|
||||
volatile bool cancelled;
|
||||
|
@ -241,7 +242,6 @@ namespace Automation4 {
|
|||
virtual ~ProgressSink();
|
||||
|
||||
public:
|
||||
void DoUpdateDisplay();
|
||||
void SetProgress(float _progress);
|
||||
void SetTask(const wxString &_task);
|
||||
void SetTitle(const wxString &_title);
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace Automation4 {
|
|||
RubyScript * RubyScript::inst = NULL; // current Ruby Script
|
||||
RubyProgressSink* RubyProgressSink::inst = NULL;
|
||||
VALUE RubyScript::RubyAegisub;
|
||||
RubyAssFile *RubyAssFile::raf = NULL;
|
||||
// RubyAssFile *RubyAssFile::raf = NULL;
|
||||
|
||||
// RubyScriptReader
|
||||
RubyScriptReader::RubyScriptReader(const wxString &filename)
|
||||
|
@ -137,7 +137,8 @@ namespace Automation4 {
|
|||
rb_protect(rbLoadWrapper, rb_str_new2(t), &status);
|
||||
if(status > 0) // something bad happened (probably parsing error)
|
||||
{
|
||||
//throw StringValueCStr(ruby_errinfo);
|
||||
VALUE err = rb_errinfo();
|
||||
throw StringValueCStr(err);
|
||||
}
|
||||
|
||||
VALUE global_var = rb_gv_get("$script_name");
|
||||
|
@ -281,11 +282,20 @@ namespace Automation4 {
|
|||
return true;
|
||||
|
||||
try {
|
||||
RubyProgressSink::inst = NULL;
|
||||
RubyAssFile *subsobj = new RubyAssFile(subs, true, true);
|
||||
VALUE sel = CreateIntegerArray(selected); // selected items
|
||||
RubyObjects::Get()->Register(sel);
|
||||
VALUE result = rbFunCall(rb_mKernel, rb_to_id(validation_fun), 3, subsobj->rbAssFile, sel, rb_int2inum(active));
|
||||
RubyObjects::Get()->Unregister(sel);
|
||||
VALUE *argv = ALLOCA_N(VALUE, 3);
|
||||
argv[0] = subsobj->rbAssFile;
|
||||
argv[1] = CreateIntegerArray(selected); // selected items;
|
||||
argv[2] = INT2FIX(active);
|
||||
RubyCallArguments arg(rb_mKernel, rb_to_id(validation_fun), 3, argv);
|
||||
VALUE result;
|
||||
RubyThreadedCall call(&arg, &result);
|
||||
wxThread::ExitCode code = call.Wait();
|
||||
if(code)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(result != Qnil && result != Qfalse)
|
||||
return true;
|
||||
}catch (const char* e) {
|
||||
|
@ -302,26 +312,67 @@ namespace Automation4 {
|
|||
delete RubyProgressSink::inst;
|
||||
RubyProgressSink::inst = new RubyProgressSink(progress_parent, false);
|
||||
RubyProgressSink::inst->SetTitle(GetName());
|
||||
RubyProgressSink::inst->Show(true);
|
||||
|
||||
// do call
|
||||
RubyAssFile *subsobj = new RubyAssFile(subs, true, true);
|
||||
VALUE sel = CreateIntegerArray(selected); // selected items
|
||||
RubyObjects::Get()->Register(sel);
|
||||
VALUE result = rbFunCall(rb_mKernel, rb_to_id(macro_fun), 3, subsobj->rbAssFile, sel, rb_int2inum(active));
|
||||
RubyObjects::Get()->Unregister(sel);
|
||||
if(result != Qnil && result != Qfalse)
|
||||
VALUE *argv = ALLOCA_N(VALUE, 3);
|
||||
argv[0] = subsobj->rbAssFile;
|
||||
argv[1] = CreateIntegerArray(selected); // selected items;
|
||||
argv[2] = INT2FIX(active);
|
||||
RubyCallArguments arg(rb_mKernel, rb_to_id(macro_fun), 3, argv);
|
||||
VALUE result;
|
||||
RubyThreadedCall call(&arg, &result);
|
||||
RubyProgressSink::inst->ShowModal();
|
||||
wxThread::ExitCode code = call.Wait();
|
||||
RubyProgressSink::inst = NULL;
|
||||
if(code)
|
||||
{
|
||||
if(TYPE(result) == T_STRING)
|
||||
throw StringValueCStr(result);
|
||||
else throw "Unknown Error";
|
||||
}
|
||||
else if(result != Qnil && result != Qfalse)
|
||||
{
|
||||
subsobj->RubyUpdateAssFile(result);
|
||||
}
|
||||
delete subsobj;
|
||||
} catch (const char* e) {
|
||||
wxString *err = new wxString(e, wxConvUTF8);
|
||||
wxMessageBox(*err, _T("Error running macro"),wxICON_ERROR | wxOK);
|
||||
}
|
||||
RubyProgressSink::inst->script_finished = true;
|
||||
}
|
||||
|
||||
|
||||
RubyThreadedCall::RubyThreadedCall(RubyCallArguments *a, VALUE *res)
|
||||
: wxThread(wxTHREAD_JOINABLE)
|
||||
,args(a), result(res)
|
||||
{
|
||||
int prio = Options.AsInt(_T("Automation Thread Priority"));
|
||||
if (prio == 0) prio = 50; // normal
|
||||
else if (prio == 1) prio = 30; // below normal
|
||||
else if (prio == 2) prio = 10; // lowest
|
||||
else prio = 50; // fallback normal
|
||||
Create();
|
||||
SetPriority(prio);
|
||||
Run();
|
||||
}
|
||||
|
||||
wxThread::ExitCode RubyThreadedCall::Entry()
|
||||
{
|
||||
int error = 0;
|
||||
*result = rb_protect(rbCallWrapper, reinterpret_cast<VALUE>(args), &error);
|
||||
if(RubyProgressSink::inst)
|
||||
{
|
||||
RubyProgressSink::inst->script_finished = true;
|
||||
wxWakeUpIdle();
|
||||
}
|
||||
if(error) {
|
||||
*result = rb_errinfo();
|
||||
return (wxThread::ExitCode)1;
|
||||
}
|
||||
return (wxThread::ExitCode)0;
|
||||
}
|
||||
|
||||
// RubyFeatureFilter
|
||||
RubyFeatureFilter::RubyFeatureFilter(const wxString &_name, const wxString &_description,
|
||||
int merit, VALUE _filter_fun, VALUE _dialog_fun)
|
||||
|
@ -363,19 +414,32 @@ namespace Automation4 {
|
|||
delete RubyProgressSink::inst;
|
||||
RubyProgressSink::inst = new RubyProgressSink(export_dialog, false);
|
||||
RubyProgressSink::inst->SetTitle(GetName());
|
||||
RubyProgressSink::inst->Show(true);
|
||||
|
||||
RubyAssFile *subsobj = new RubyAssFile(subs, true/*modify*/, false/*undo*/);
|
||||
VALUE result = rbFunCall(rb_mKernel, rb_to_id(filter_fun), 2, subsobj->rbAssFile, Qnil /* config */);
|
||||
if(result != Qnil && result != Qfalse)
|
||||
VALUE *argv = ALLOCA_N(VALUE, 2);
|
||||
argv[0] = subsobj->rbAssFile;
|
||||
argv[1] = Qnil; // config
|
||||
RubyCallArguments arg(rb_mKernel, rb_to_id(filter_fun), 2, argv);
|
||||
VALUE result;
|
||||
RubyThreadedCall call(&arg, &result);
|
||||
RubyProgressSink::inst->ShowModal();
|
||||
wxThread::ExitCode code = call.Wait();
|
||||
RubyProgressSink::inst = NULL;
|
||||
if(code)
|
||||
{
|
||||
if(TYPE(result) == T_STRING)
|
||||
throw StringValueCStr(result);
|
||||
else throw "Unknown Error";
|
||||
}
|
||||
else if(result != Qnil && result != Qfalse)
|
||||
{
|
||||
subsobj->RubyUpdateAssFile(result);
|
||||
}
|
||||
delete subsobj;
|
||||
} catch (const char* e) {
|
||||
wxString *err = new wxString(e, wxConvUTF8);
|
||||
wxMessageBox(*err, _T("Error running filter"),wxICON_ERROR | wxOK);
|
||||
wxMessageBox(*err, _T("Error running filter"),wxICON_ERROR | wxOK);
|
||||
}
|
||||
RubyProgressSink::inst->script_finished = true;
|
||||
}
|
||||
|
||||
ScriptConfigDialog* RubyFeatureFilter::GenerateConfigDialog(wxWindow *parent)
|
||||
|
@ -422,8 +486,6 @@ namespace Automation4 {
|
|||
{
|
||||
float _progr = rb_num2dbl(progress);
|
||||
RubyProgressSink::inst->SetProgress(_progr);
|
||||
RubyProgressSink::inst->DoUpdateDisplay();
|
||||
wxSafeYield(RubyProgressSink::inst);
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
|
@ -431,7 +493,6 @@ namespace Automation4 {
|
|||
{
|
||||
wxString _t(StringValueCStr(task), wxConvUTF8);
|
||||
RubyProgressSink::inst->SetTask(_t);
|
||||
RubyProgressSink::inst->DoUpdateDisplay();
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
|
@ -439,8 +500,6 @@ namespace Automation4 {
|
|||
{
|
||||
wxString _t(StringValueCStr(title), wxConvUTF8);
|
||||
RubyProgressSink::inst->SetTitle(_t);
|
||||
//wxSafeYield(RubyProgressSink::inst);
|
||||
RubyProgressSink::inst->DoUpdateDisplay();
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
|
@ -461,8 +520,6 @@ namespace Automation4 {
|
|||
else args[1] = args[0];
|
||||
wxString _m(StringValueCStr(args[1]), wxConvUTF8);
|
||||
RubyProgressSink::inst->AddDebugOutput(_m);
|
||||
RubyProgressSink::inst->DoUpdateDisplay();
|
||||
wxSafeYield(RubyProgressSink::inst);
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
|
@ -564,7 +621,8 @@ namespace Automation4 {
|
|||
VALUE result;
|
||||
result = rb_protect(rbCallWrapper, reinterpret_cast<VALUE>(&arg), &error);
|
||||
if(error) {
|
||||
//throw StringValueCStr(ruby_errinfo);
|
||||
VALUE err = rb_errinfo();
|
||||
throw StringValueCStr(err);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -76,12 +76,12 @@ namespace Automation4 {
|
|||
static int RubyUnparseTagData();
|
||||
static int RubySetUndoPoint();
|
||||
|
||||
~RubyAssFile();
|
||||
public:
|
||||
void RubyUpdateAssFile(VALUE subtitles);
|
||||
static VALUE AssEntryToRuby(AssEntry *e); // makes a Ruby representation of AssEntry
|
||||
static AssEntry *RubyToAssEntry(VALUE ass_entry); // creates an AssEntry object from a Ruby representation
|
||||
RubyAssFile(AssFile *_ass, bool _can_modify, bool _can_set_undo);
|
||||
~RubyAssFile();
|
||||
|
||||
static RubyAssFile *raf;
|
||||
VALUE rbAssFile;
|
||||
|
@ -245,6 +245,17 @@ namespace Automation4 {
|
|||
RubyCallArguments(VALUE _recv, ID _id, int _n, VALUE *_argv);
|
||||
};
|
||||
|
||||
// A single call to a Ruby function, run inside a separate thread.
|
||||
// This object should be created on the stack in the function that does the call.
|
||||
class RubyThreadedCall : public wxThread {
|
||||
private:
|
||||
RubyCallArguments *args;
|
||||
VALUE *result;
|
||||
public:
|
||||
RubyThreadedCall(RubyCallArguments *args, VALUE *result);
|
||||
virtual ExitCode Entry();
|
||||
};
|
||||
|
||||
VALUE rbCallWrapper(VALUE arg);
|
||||
VALUE rbExecWrapper(VALUE arg);
|
||||
VALUE rbLoadWrapper(VALUE arg);
|
||||
|
|
|
@ -337,8 +337,8 @@ namespace Automation4 {
|
|||
// If the first line is dialogue we leave header from the original (styles, info, etc)
|
||||
void RubyAssFile::RubyUpdateAssFile(VALUE subtitles)
|
||||
{
|
||||
RubyObjects::Get()->Register(subtitles);
|
||||
int size = rb_num2long(rb_funcall(subtitles, rb_to_id(rb_str_new2("size")), 0));
|
||||
//RubyObjects::Get()->Register(subtitles);
|
||||
int size = RARRAY(subtitles)->len;
|
||||
|
||||
if(size <= 0) return; // empty - leave the original
|
||||
|
||||
|
@ -378,7 +378,7 @@ namespace Automation4 {
|
|||
rb_set_errinfo(Qnil);
|
||||
}
|
||||
}
|
||||
RubyObjects::Get()->Unregister(subtitles);
|
||||
//RubyObjects::Get()->Unregister(subtitles);
|
||||
}
|
||||
|
||||
int RubyAssFile::RubyParseTagData()
|
||||
|
@ -401,7 +401,6 @@ namespace Automation4 {
|
|||
|
||||
RubyAssFile::~RubyAssFile()
|
||||
{
|
||||
RubyObjects::Get()->Unregister(rbAssFile);
|
||||
}
|
||||
|
||||
RubyAssFile::RubyAssFile(AssFile *_ass, bool _can_modify, bool _can_set_undo)
|
||||
|
@ -409,12 +408,8 @@ namespace Automation4 {
|
|||
, can_modify(_can_modify)
|
||||
, can_set_undo(_can_set_undo)
|
||||
{
|
||||
if(RubyAssFile::raf)
|
||||
delete RubyAssFile::raf; // delete previous if there is one
|
||||
RubyAssFile::raf = this; // set pointer to this obj
|
||||
|
||||
rbAssFile = rb_ary_new2(ass->Line.size());
|
||||
RubyObjects::Get()->Register(rbAssFile);
|
||||
|
||||
std::list<AssEntry*>::iterator entry;
|
||||
int status;
|
||||
|
|
Loading…
Reference in a new issue