diff --git a/binding/audio-binding.cpp b/binding/audio-binding.cpp index aaa56bb5..1e6d1777 100644 --- a/binding/audio-binding.cpp +++ b/binding/audio-binding.cpp @@ -25,17 +25,18 @@ #include "exception.h" #define DEF_PLAY_STOP_POS(entity) \ - RB_METHOD(audio_##entity##Play) \ + RB_METHOD_GUARD(audio_##entity##Play) \ { \ RB_UNUSED_PARAM; \ const char *filename; \ int volume = 100; \ int pitch = 100; \ double pos = 0.0; \ - rb_get_args(argc, argv, "z|iif", &filename, &volume, &pitch, &pos RB_ARG_END); \ - GUARD_EXC( shState->audio().entity##Play(filename, volume, pitch, pos); ) \ + rb_get_args(argc, argv, "z|iif", &filename, &volume, &pitch, &pos RB_ARG_END); \ + shState->audio().entity##Play(filename, volume, pitch, pos); \ return Qnil; \ } \ + RB_METHOD_GUARD_END \ RB_METHOD(audio_##entity##Stop) \ { \ RB_UNUSED_PARAM; \ @@ -49,16 +50,17 @@ } #define DEF_PLAY_STOP(entity) \ - RB_METHOD(audio_##entity##Play) \ + RB_METHOD_GUARD(audio_##entity##Play) \ { \ RB_UNUSED_PARAM; \ const char *filename; \ int volume = 100; \ int pitch = 100; \ rb_get_args(argc, argv, "z|ii", &filename, &volume, &pitch RB_ARG_END); \ - GUARD_EXC( shState->audio().entity##Play(filename, volume, pitch); ) \ + shState->audio().entity##Play(filename, volume, pitch); \ return Qnil; \ } \ + RB_METHOD_GUARD_END \ RB_METHOD(audio_##entity##Stop) \ { \ RB_UNUSED_PARAM; \ @@ -87,7 +89,7 @@ RB_METHOD(audio_##entity##Fade) \ #define MAYBE_NIL_TRACK(t) t == Qnil ? -127 : NUM2INT(t) -RB_METHOD(audio_bgmPlay) +RB_METHOD_GUARD(audio_bgmPlay) { RB_UNUSED_PARAM; const char *filename; @@ -96,9 +98,10 @@ RB_METHOD(audio_bgmPlay) double pos = 0.0; VALUE track = Qnil; rb_get_args(argc, argv, "z|iifo", &filename, &volume, &pitch, &pos, &track RB_ARG_END); - GUARD_EXC( shState->audio().bgmPlay(filename, volume, pitch, pos, MAYBE_NIL_TRACK(track)); ) + shState->audio().bgmPlay(filename, volume, pitch, pos, MAYBE_NIL_TRACK(track)); return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(audio_bgmStop) { @@ -117,25 +120,27 @@ RB_METHOD(audio_bgmPos) return rb_float_new(shState->audio().bgmPos(MAYBE_NIL_TRACK(track))); } -RB_METHOD(audio_bgmGetVolume) +RB_METHOD_GUARD(audio_bgmGetVolume) { RB_UNUSED_PARAM; VALUE track = Qnil; rb_get_args(argc, argv, "|o", &track RB_ARG_END); int ret = 0; - GUARD_EXC( ret = shState->audio().bgmGetVolume(MAYBE_NIL_TRACK(track)); ) + ret = shState->audio().bgmGetVolume(MAYBE_NIL_TRACK(track)); return rb_fix_new(ret); } +RB_METHOD_GUARD_END -RB_METHOD(audio_bgmSetVolume) +RB_METHOD_GUARD(audio_bgmSetVolume) { RB_UNUSED_PARAM; int volume; VALUE track = Qnil; rb_get_args(argc, argv, "i|o", &volume, &track RB_ARG_END); - GUARD_EXC( shState->audio().bgmSetVolume(volume, MAYBE_NIL_TRACK(track)); ) + shState->audio().bgmSetVolume(volume, MAYBE_NIL_TRACK(track)); return Qnil; } +RB_METHOD_GUARD_END DEF_PLAY_STOP_POS( bgs ) diff --git a/binding/binding-mri.cpp b/binding/binding-mri.cpp index 35289bc0..39d62d21 100644 --- a/binding/binding-mri.cpp +++ b/binding/binding-mri.cpp @@ -315,21 +315,29 @@ static void printP(int argc, VALUE *argv, const char *convMethod, } -RB_METHOD(mriPrint) { +RB_METHOD_GUARD(mriPrint) { RB_UNUSED_PARAM; printP(argc, argv, "to_s", ""); + shState->checkShutdown(); + shState->checkReset(); + return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(mriP) { +RB_METHOD_GUARD(mriP) { RB_UNUSED_PARAM; printP(argc, argv, "inspect", "\n"); + shState->checkShutdown(); + shState->checkReset(); + return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(mkxpDelta) { RB_UNUSED_PARAM; @@ -528,14 +536,15 @@ RB_METHOD(mkxpSystemMemory) { return INT2NUM(SDL_GetSystemRAM()); } -RB_METHOD(mkxpReloadPathCache) { +RB_METHOD_GUARD(mkxpReloadPathCache) { RB_UNUSED_PARAM; - GUARD_EXC(shState->fileSystem().reloadPathCache();); + shState->fileSystem().reloadPathCache(); return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(mkxpAddPath) { +RB_METHOD_GUARD(mkxpAddPath) { RB_UNUSED_PARAM; VALUE path, mountpoint, reload; @@ -545,36 +554,32 @@ RB_METHOD(mkxpAddPath) { const char *mp = (mountpoint == Qnil) ? 0 : RSTRING_PTR(mountpoint); - try { - bool rl = true; - if (reload != Qnil) - rb_bool_arg(reload, &rl); - - shState->fileSystem().addPath(RSTRING_PTR(path), mp, rl); - } catch (Exception &e) { - raiseRbExc(e); - } + bool rl = true; + if (reload != Qnil) + rb_bool_arg(reload, &rl); + + shState->fileSystem().addPath(RSTRING_PTR(path), mp, rl); + return path; } +RB_METHOD_GUARD_END -RB_METHOD(mkxpRemovePath) { +RB_METHOD_GUARD(mkxpRemovePath) { RB_UNUSED_PARAM; VALUE path, reload; rb_scan_args(argc, argv, "11", &path, &reload); SafeStringValue(path); - try { - bool rl = true; - if (reload != Qnil) - rb_bool_arg(reload, &rl); - - shState->fileSystem().removePath(RSTRING_PTR(path), rl); - } catch (Exception &e) { - raiseRbExc(e); - } + bool rl = true; + if (reload != Qnil) + rb_bool_arg(reload, &rl); + + shState->fileSystem().removePath(RSTRING_PTR(path), rl); + return path; } +RB_METHOD_GUARD_END RB_METHOD(mkxpFileExists) { RB_UNUSED_PARAM; @@ -601,24 +606,25 @@ RB_METHOD(mkxpSetDefaultFontFamily) { return Qnil; } -RB_METHOD(mkxpStringToUTF8) { +RB_METHOD_GUARD(mkxpStringToUTF8) { RB_UNUSED_PARAM; rb_check_argc(argc, 0); std::string ret(RSTRING_PTR(self), RSTRING_LEN(self)); - GUARD_EXC(ret = Encoding::convertString(ret); ); + ret = Encoding::convertString(ret); return rb_utf8_str_new(ret.c_str(), ret.length()); } +RB_METHOD_GUARD_END -RB_METHOD(mkxpStringToUTF8Bang) { +RB_METHOD_GUARD(mkxpStringToUTF8Bang) { RB_UNUSED_PARAM; rb_check_argc(argc, 0); std::string ret(RSTRING_PTR(self), RSTRING_LEN(self)); - GUARD_EXC(ret = Encoding::convertString(ret); ); + ret = Encoding::convertString(ret); rb_str_resize(self, ret.length()); memcpy(RSTRING_PTR(self), ret.c_str(), RSTRING_LEN(self)); @@ -629,6 +635,7 @@ RB_METHOD(mkxpStringToUTF8Bang) { return self; } +RB_METHOD_GUARD_END #ifdef __APPLE__ #define OPENCMD "open " @@ -641,7 +648,7 @@ RB_METHOD(mkxpStringToUTF8Bang) { #define OPENARGS "" #endif -RB_METHOD(mkxpLaunch) { +RB_METHOD_GUARD(mkxpLaunch) { RB_UNUSED_PARAM; VALUE cmdname, args; @@ -674,11 +681,12 @@ RB_METHOD(mkxpLaunch) { } if (std::system(command.c_str()) != 0) { - raiseRbExc(Exception(Exception::MKXPError, "Failed to launch \"%s\"", RSTRING_PTR(cmdname))); + throw Exception(Exception::MKXPError, "Failed to launch \"%s\"", RSTRING_PTR(cmdname)); } return RUBY_Qnil; } +RB_METHOD_GUARD_END json5pp::value loadUserSettings() { json5pp::value ret; @@ -722,7 +730,7 @@ RB_METHOD(mkxpGetJSONSetting) { } -RB_METHOD(mkxpSetJSONSetting) { +RB_METHOD_GUARD(mkxpSetJSONSetting) { RB_UNUSED_PARAM; VALUE sname, svalue; @@ -736,6 +744,7 @@ RB_METHOD(mkxpSetJSONSetting) { return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(mkxpGetAllJSONSettings) { RB_UNUSED_PARAM; @@ -756,15 +765,21 @@ static VALUE rgssMainRescue(VALUE arg, VALUE exc) { return Qnil; } -static void processReset() { - shState->graphics().reset(); - shState->audio().reset(); - - shState->rtData().rqReset.clear(); - shState->graphics().repaintWait(shState->rtData().rqResetFinish, false); +static bool processReset(bool rubyExc) { + const char *str = "Audio.__reset__; Graphics.__reset__;"; + + if (rubyExc) { + rb_eval_string(str); + } else { + int state; + rb_eval_string_protect(str, &state); + return state; + } + + return 0; } -RB_METHOD(mriRgssMain) { +RB_METHOD_GUARD(mriRgssMain) { RB_UNUSED_PARAM; while (true) { @@ -782,15 +797,16 @@ RB_METHOD(mriRgssMain) { break; if (rb_obj_class(exc) == getRbData()->exc[Reset]) - processReset(); + processReset(true); else rb_exc_raise(exc); } return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(mriRgssStop) { +RB_METHOD_GUARD(mriRgssStop) { RB_UNUSED_PARAM; while (true) @@ -798,6 +814,7 @@ RB_METHOD(mriRgssStop) { return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(_kernelCaller) { RB_UNUSED_PARAM; @@ -1037,7 +1054,8 @@ static void runRMXPScripts(BacktraceData &btData) { if (rb_obj_class(exc) != getRbData()->exc[Reset]) break; - processReset(); + if (processReset(false)) + break; } } @@ -1246,6 +1264,6 @@ static void mriBindingExecute() { shState->rtData().rqTermAck.set(); } -static void mriBindingTerminate() { rb_raise(rb_eSystemExit, " "); } +static void mriBindingTerminate() { throw Exception(Exception::SystemExit, " "); } -static void mriBindingReset() { rb_raise(getRbData()->exc[Reset], " "); } +static void mriBindingReset() { throw Exception(Exception::Reset, " "); } diff --git a/binding/binding-util.cpp b/binding/binding-util.cpp index 5a097239..9349f197 100644 --- a/binding/binding-util.cpp +++ b/binding/binding-util.cpp @@ -50,28 +50,34 @@ RbData::RbData() { exc[IOError] = rb_eIOError; exc[TypeError] = rb_eTypeError; exc[ArgumentError] = rb_eArgError; + exc[SystemExit] = rb_eSystemExit; + exc[RuntimeError] = rb_eRuntimeError; } RbData::~RbData() {} /* Indexed with Exception::Type */ -static const RbException excToRbExc[] = { - RGSS, /* RGSSError */ - ErrnoENOENT, /* NoFileError */ +const RbException excToRbExc[] = { + RGSS, /* RGSSError */ + Reset, /* Reset/RGSSReset */ + ErrnoENOENT, /* NoFileError */ IOError, - TypeError, ArgumentError, + TypeError, ArgumentError, SystemExit, RuntimeError, PHYSFS, /* PHYSFSError */ SDL, /* SDLError */ MKXP /* MKXPError */ }; -void raiseRbExc(const Exception &exc) { +void raiseRbExc(Exception *exc) { + VALUE str = rb_str_new2(exc->msg.c_str()); RbData *data = getRbData(); - VALUE excClass = data->exc[excToRbExc[exc.type]]; + VALUE excClass = data->exc[excToRbExc[exc->type]]; - rb_raise(excClass, "%s", exc.msg.c_str()); + delete exc; + + rb_exc_raise(rb_class_new_instance(1, &str, excClass)); } void raiseDisposedAccess(VALUE self) { @@ -89,207 +95,258 @@ void raiseDisposedAccess(VALUE self) { } int rb_get_args(int argc, VALUE *argv, const char *format, ...) { - char c; - VALUE *arg = argv; - va_list ap; - bool opt = false; - int argI = 0; + Exception *exc = 0; + try{ + char c; + VALUE *arg = argv; + va_list ap; + bool opt = false; + int argI = 0; - va_start(ap, format); + va_start(ap, format); - while ((c = *format++)) { - switch (c) { - case '|': - break; - default: - // FIXME print num of needed args vs provided - if (argc <= argI && !opt) - rb_raise(rb_eArgError, "wrong number of arguments"); + while ((c = *format++)) { + switch (c) { + case '|': + break; + default: + // FIXME print num of needed args vs provided + if (argc <= argI && !opt) + rb_raise(rb_eArgError, "wrong number of arguments"); - break; - } + break; + } - if (argI >= argc) - break; - - switch (c) { - case 'o': { if (argI >= argc) break; - VALUE *obj = va_arg(ap, VALUE *); + switch (c) { + case 'o': { + if (argI >= argc) + break; - *obj = *arg++; - ++argI; + VALUE *obj = va_arg(ap, VALUE *); - break; - } + *obj = *arg++; + ++argI; - case 'S': { - if (argI >= argc) + break; + } + + case 'S': { + if (argI >= argc) + break; + + VALUE *str = va_arg(ap, VALUE *); + VALUE tmp = *arg; + + if (!RB_TYPE_P(tmp, RUBY_T_STRING)) + rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); + + *str = tmp; + ++argI; + + break; + } + + case 's': { + if (argI >= argc) + break; + + const char **s = va_arg(ap, const char **); + int *len = va_arg(ap, int *); + + VALUE tmp = *arg; + + if (!RB_TYPE_P(tmp, RUBY_T_STRING)) + rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); + + *s = RSTRING_PTR(tmp); + *len = RSTRING_LEN(tmp); + ++argI; + + break; + } + + case 'z': { + if (argI >= argc) + break; + + const char **s = va_arg(ap, const char **); + + VALUE tmp = *arg++; + + if (!RB_TYPE_P(tmp, RUBY_T_STRING)) + rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); + + *s = RSTRING_PTR(tmp); + ++argI; + + break; + } + + case 'f': { + if (argI >= argc) + break; + + double *f = va_arg(ap, double *); + VALUE fVal = *arg++; + + rb_float_arg(fVal, f, argI); + + ++argI; + break; + } + + case 'i': { + if (argI >= argc) + break; + + int *i = va_arg(ap, int *); + VALUE iVal = *arg++; + + rb_int_arg(iVal, i, argI); + + ++argI; + break; + } + + case 'b': { + if (argI >= argc) + break; + + bool *b = va_arg(ap, bool *); + VALUE bVal = *arg++; + + rb_bool_arg(bVal, b, argI); + + ++argI; + break; + } + + case 'n': { + if (argI >= argc) + break; + + ID *sym = va_arg(ap, ID *); + + VALUE symVal = *arg++; + + if (!SYMBOL_P(symVal)) + rb_raise(rb_eTypeError, "Argument %d: Expected symbol", argI); + + *sym = SYM2ID(symVal); + ++argI; + + break; + } + + case '|': + opt = true; break; - VALUE *str = va_arg(ap, VALUE *); - VALUE tmp = *arg; - - if (!RB_TYPE_P(tmp, RUBY_T_STRING)) - rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); - - *str = tmp; - ++argI; - - break; + default: + rb_raise(rb_eFatal, "invalid argument specifier %c", c); + } } - case 's': { - if (argI >= argc) - break; - - const char **s = va_arg(ap, const char **); - int *len = va_arg(ap, int *); - - VALUE tmp = *arg; - - if (!RB_TYPE_P(tmp, RUBY_T_STRING)) - rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); - - *s = RSTRING_PTR(tmp); - *len = RSTRING_LEN(tmp); - ++argI; - - break; - } - - case 'z': { - if (argI >= argc) - break; - - const char **s = va_arg(ap, const char **); - - VALUE tmp = *arg++; - - if (!RB_TYPE_P(tmp, RUBY_T_STRING)) - rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); - - *s = RSTRING_PTR(tmp); - ++argI; - - break; - } - - case 'f': { - if (argI >= argc) - break; - - double *f = va_arg(ap, double *); - VALUE fVal = *arg++; - - rb_float_arg(fVal, f, argI); - - ++argI; - break; - } - - case 'i': { - if (argI >= argc) - break; - - int *i = va_arg(ap, int *); - VALUE iVal = *arg++; - - rb_int_arg(iVal, i, argI); - - ++argI; - break; - } - - case 'b': { - if (argI >= argc) - break; - - bool *b = va_arg(ap, bool *); - VALUE bVal = *arg++; - - rb_bool_arg(bVal, b, argI); - - ++argI; - break; - } - - case 'n': { - if (argI >= argc) - break; - - ID *sym = va_arg(ap, ID *); - - VALUE symVal = *arg++; - - if (!SYMBOL_P(symVal)) - rb_raise(rb_eTypeError, "Argument %d: Expected symbol", argI); - - *sym = SYM2ID(symVal); - ++argI; - - break; - } - - case '|': - opt = true; - break; - - default: - rb_raise(rb_eFatal, "invalid argument specifier %c", c); - } - } - #ifndef NDEBUG - /* Pop remaining arg pointers off - * the stack to check for RB_ARG_END */ - format--; + /* Pop remaining arg pointers off + * the stack to check for RB_ARG_END */ + format--; - while ((c = *format++)) { - switch (c) { - case 'o': - case 'S': - va_arg(ap, VALUE *); - break; + while ((c = *format++)) { + switch (c) { + case 'o': + case 'S': + va_arg(ap, VALUE *); + break; - case 's': - va_arg(ap, const char **); - va_arg(ap, int *); - break; + case 's': + va_arg(ap, const char **); + va_arg(ap, int *); + break; - case 'z': - va_arg(ap, const char **); - break; + case 'z': + va_arg(ap, const char **); + break; - case 'f': - va_arg(ap, double *); - break; + case 'f': + va_arg(ap, double *); + break; - case 'i': - va_arg(ap, int *); - break; + case 'i': + va_arg(ap, int *); + break; - case 'b': - va_arg(ap, bool *); - break; + case 'b': + va_arg(ap, bool *); + break; + } } - } - // FIXME print num of needed args vs provided - if (!c && argc > argI) - rb_raise(rb_eArgError, "wrong number of arguments"); + // FIXME print num of needed args vs provided + if (!c && argc > argI) + rb_raise(rb_eArgError, "wrong number of arguments"); - /* Verify correct termination */ - void *argEnd = va_arg(ap, void *); - (void)argEnd; - assert(argEnd == RB_ARG_END_VAL); + /* Verify correct termination */ + void *argEnd = va_arg(ap, void *); + (void)argEnd; + assert(argEnd == RB_ARG_END_VAL); #endif - va_end(ap); + va_end(ap); - return argI; + return argI; + } catch (const Exception &e) { + exc = new Exception(e); + } + + /* This should always be true if we reach here */ + if (exc) { + /* Raising here is probably fine, right? + * If any methods allocate something with a destructor before + * calling this then they can probably be fixed to not do that. */ + raiseRbExc(exc); + } + + return 0; } + +#if RAPI_MAJOR >= 2 +#include + +typedef struct gvl_guard_args { + Exception *exc; + void *(*func)(void *); + void *args; +} gvl_guard_args; + +static void *gvl_guard(void *args) { + gvl_guard_args *gvl_args = (gvl_guard_args*)args; + try{ + return gvl_args->func(gvl_args->args); + } catch (const Exception &e) { + gvl_args->exc = new Exception(e); + } + return 0; +} + +void *drop_gvl_guard(void *(*func)(void *), void *args, + rb_unblock_function_t *ubf, void *data2) { + gvl_guard_args gvl_args = {0, func, args}; + + void *ret = rb_thread_call_without_gvl(&gvl_guard, &gvl_args, ubf, data2); + + Exception *&exc = gvl_args.exc; + if (exc){ + Exception e(*exc); + delete exc; + throw e; + } + return ret; +} + +#endif diff --git a/binding/binding-util.h b/binding/binding-util.h index da6e59ab..1cb6bc2f 100644 --- a/binding/binding-util.h +++ b/binding/binding-util.h @@ -55,6 +55,8 @@ enum RbException { TypeError, ArgumentError, + SystemExit, + RuntimeError, RbExceptionsMax }; @@ -73,7 +75,12 @@ RbData *getRbData(); struct Exception; -void raiseRbExc(const Exception &exc); +void raiseRbExc(Exception *exc); + +#if RAPI_MAJOR >= 2 +void *drop_gvl_guard(void *(*func)(void *), void *args, + rb_unblock_function_t *ubf, void *data2); +#endif #if RAPI_FULL > 187 #define DECL_TYPE(Klass) extern rb_data_type_t Klass##Type @@ -190,20 +197,50 @@ template static VALUE classAllocate(VALUE klass) { } #endif +#if RAPI_FULL > 187 +#define CLASS_ALLOCATE_PRE_INIT(Name, initializeFunc) \ +static VALUE Name##AllocatePreInit(VALUE klass) { \ + VALUE ret = classAllocate<& Name##Type>(klass); \ + \ + initializeFunc(0, 0, ret); \ + \ + return ret; \ +} +#else +#define CLASS_ALLOCATE_PRE_INIT(Name, initializeFunc) \ +static VALUE Name##AllocatePreInit(VALUE klass) { \ + VALUE ret = Name##Allocate(klass); \ + \ + initializeFunc(0, 0, ret); \ + \ + return ret; \ +} +#endif + template static void freeInstance(void *inst) { delete static_cast(inst); } void raiseDisposedAccess(VALUE self); -template inline C *getPrivateData(VALUE self) { +template inline C *getPrivateDataNoRaise(VALUE self) { #if RAPI_FULL > 187 - C *c = static_cast(RTYPEDDATA_DATA(self)); + return static_cast(RTYPEDDATA_DATA(self)); #else - C *c = static_cast(DATA_PTR(self)); + return static_cast(DATA_PTR(self)); #endif +} + +template inline C *getPrivateData(VALUE self) { + C *c = getPrivateDataNoRaise(self); + if (!c) { - raiseRbExc(Exception(Exception::MKXPError, "No instance data for variable (missing call to super?)")); + //raiseRbExc(Exception(Exception::MKXPError, "No instance data for variable (missing call to super?)")); + + /* FIXME: MiniFFI and FileInt don't have default allocations + * despite not being disposables. Should they be fixed, + * or just left with a misleading error message? */ + raiseDisposedAccess(self); } return c; } @@ -238,9 +275,28 @@ getPrivateDataCheck(VALUE self, const char *type) } static inline void setPrivateData(VALUE self, void *p) { + /* RGSS's behavior is to just leak memory if a disposable is reinitialized, + * with the original disposable being left permanently instantiated, + * but that's (1) bad, and (2) would currently cause memory access issues + * when things like a sprite's src_rect inevitably get GC'd, so we're not + * copying that. */ #if RAPI_FULL > 187 + // Free the old value if it already exists (initialize called twice?) + if (RTYPEDDATA_DATA(self) && (RTYPEDDATA_DATA(self) != p)) { + /* RUBY_TYPED_NEVER_FREE == 0, and we don't use + * RUBY_TYPED_DEFAULT_FREE for our stuff, so just + * checking if it's truthy should be fine */ + if (RTYPEDDATA_TYPE(self)->function.dfree) + (*RTYPEDDATA_TYPE(self)->function.dfree)(RTYPEDDATA_DATA(self)); + } RTYPEDDATA_DATA(self) = p; #else + // Free the old value if it already exists (initialize called twice?) + if (DATA_PTR(self) && (DATA_PTR(self) != p)) { + /* As above, just check if it's truthy */ + if (RDATA(self)->dfree) + (*RDATA(self)->dfree)(DATA_PTR(self)); + } DATA_PTR(self) = p; #endif } @@ -306,25 +362,16 @@ static inline void _rb_define_module_function(VALUE module, const char *name, rb_define_module_function(module, name, RUBY_METHOD_FUNC(func), -1); } -#define GUARD_EXC(exp) \ -{ \ -try { \ +#define GFX_GUARD_EXC(exp) \ +{ \ +GFX_LOCK; \ +try { \ exp \ -} catch (const Exception &exc) { \ -raiseRbExc(exc); \ -} \ -} - -#define GFX_GUARD_EXC(exp) \ -{\ -GFX_LOCK; \ -try {\ -exp \ -} catch (const Exception &exc) {\ -GFX_UNLOCK; \ -raiseRbExc(exc); \ -}\ -GFX_UNLOCK;\ +} catch (const Exception &exc) { \ +GFX_UNLOCK; \ +throw exc; \ +} \ +GFX_UNLOCK; \ } @@ -338,7 +385,7 @@ static inline VALUE objectLoad(int argc, VALUE *argv, VALUE self) { C *c = 0; - GUARD_EXC(c = C::deserialize(data, dataLen);); + c = C::deserialize(data, dataLen); setPrivateData(obj, c); @@ -358,7 +405,7 @@ inline void rb_float_arg(VALUE arg, double *out, int argPos = 0) { break; default: - rb_raise(rb_eTypeError, "Argument %d: Expected float", argPos); + throw Exception(Exception::TypeError, "Argument %d: Expected float", argPos); } } @@ -374,7 +421,7 @@ inline void rb_int_arg(VALUE arg, int *out, int argPos = 0) { break; default: - rb_raise(rb_eTypeError, "Argument %d: Expected fixnum", argPos); + throw Exception(Exception::TypeError, "Argument %d: Expected fixnum", argPos); } } @@ -390,10 +437,13 @@ inline void rb_bool_arg(VALUE arg, bool *out, int argPos = 0) { break; default: - rb_raise(rb_eTypeError, "Argument %d: Expected bool", argPos); + throw Exception(Exception::TypeError, "Argument %d: Expected bool", argPos); } } +/* rb_check_argc and rb_error_arity are both + * consistently called before any C++ objects are allocated, + * so we can just call rb_raise directly in them */ inline void rb_check_argc(int actual, int expected) { if (actual != expected) rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", actual, @@ -431,21 +481,39 @@ static inline VALUE rb_file_open_str(VALUE filename, const char *mode) { (void)self; \ } +/* Calling rb_raise inside the catch block + * leaks memory even if we catch by value */ +#define RB_METHOD_GUARD(name) RB_METHOD(name) \ +{ \ + Exception *exc = 0; \ + try{ \ + +#define RB_METHOD_GUARD_END \ + } catch (const Exception &e) { \ + exc = new Exception(e); \ + } \ + if (exc) { \ + raiseRbExc(exc); \ + } \ + return Qnil; \ +} + #define MARSH_LOAD_FUN(Typ) \ -RB_METHOD(Typ##Load) { return objectLoad(argc, argv, self); } +RB_METHOD_GUARD(Typ##Load) { return objectLoad(argc, argv, self); } RB_METHOD_GUARD_END #define INITCOPY_FUN(Klass) \ -RB_METHOD(Klass##InitializeCopy) { \ +RB_METHOD_GUARD(Klass##InitializeCopy) { \ VALUE origObj; \ rb_get_args(argc, argv, "o", &origObj RB_ARG_END); \ if (!OBJ_INIT_COPY(self, origObj)) /* When would this fail??*/ \ return self; \ Klass *orig = getPrivateData(origObj); \ Klass *k = 0; \ -GUARD_EXC(k = new Klass(*orig);) \ +k = new Klass(*orig); \ setPrivateData(self, k); \ return self; \ -} +} \ +RB_METHOD_GUARD_END /* Object property which is copied by reference, with allowed NIL * FIXME: Getter assumes prop is disposable, @@ -461,7 +529,7 @@ RB_METHOD(Klass##Get##PropName) { \ RB_UNUSED_PARAM; \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ RB_UNUSED_PARAM; \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ @@ -471,17 +539,18 @@ if (NIL_P(propObj)) \ prop = 0; \ else \ prop = getPrivateDataCheck(propObj, PropKlass##Type); \ -GUARD_EXC(k->set##PropName(prop);) \ +k->set##PropName(prop) \ rb_iv_set(self, prop_iv, propObj); \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #else #define DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \ RB_METHOD(Klass##Get##PropName) { \ RB_UNUSED_PARAM; \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ RB_UNUSED_PARAM; \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ @@ -491,10 +560,11 @@ if (NIL_P(propObj)) \ prop = 0; \ else \ prop = getPrivateDataCheck(propObj, #PropKlass); \ -GUARD_EXC(k->set##PropName(prop);) \ +k->set##PropName(prop) \ rb_iv_set(self, prop_iv, propObj); \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #endif /* Object property which is copied by value, not reference */ @@ -505,15 +575,16 @@ RB_UNUSED_PARAM; \ checkDisposed(self); \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ VALUE propObj = *argv; \ PropKlass *prop; \ prop = getPrivateDataCheck(propObj, PropKlass##Type); \ -GUARD_EXC(k->set##PropName(*prop);) \ +k->set##PropName(*prop); \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #else #define DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ RB_METHOD(Klass##Get##PropName) { \ @@ -521,33 +592,36 @@ RB_UNUSED_PARAM; \ checkDisposed(self); \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ VALUE propObj = *argv; \ PropKlass *prop; \ prop = getPrivateDataCheck(propObj, #PropKlass); \ -GUARD_EXC(k->set##PropName(*prop);) \ +k->set##PropName(*prop); \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #endif -#define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \ -RB_METHOD(Klass##Get##PropName) { \ +#define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \ +RB_METHOD_GUARD(Klass##Get##PropName) { \ RB_UNUSED_PARAM; \ Klass *k = getPrivateData(self); \ type value = 0; \ -GUARD_EXC(value = k->get##PropName();) \ +value = k->get##PropName(); \ return value_fun(value); \ -} \ -RB_METHOD(Klass##Set##PropName) { \ +} \ +RB_METHOD_GUARD_END \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ type value; \ rb_##arg_fun##_arg(*argv, &value); \ -GUARD_EXC(k->set##PropName(value);) \ +k->set##PropName(value); \ return *argv; \ -} +} \ +RB_METHOD_GUARD_END #define DEF_PROP_I(Klass, PropName) \ DEF_PROP(Klass, int, PropName, int, rb_fix_new) @@ -573,7 +647,7 @@ RB_METHOD(Klass##Get##PropName) { \ RB_UNUSED_PARAM; \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ RB_UNUSED_PARAM; \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ @@ -586,7 +660,8 @@ prop = getPrivateDataCheck(propObj, PropKlass##Type); \ GFX_GUARD_EXC(k->set##PropName(prop);) \ rb_iv_set(self, prop_iv, propObj); \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #else #define DEF_GFX_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \ DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) @@ -600,7 +675,7 @@ RB_UNUSED_PARAM; \ checkDisposed(self); \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ VALUE propObj = *argv; \ @@ -608,28 +683,31 @@ PropKlass *prop; \ prop = getPrivateDataCheck(propObj, PropKlass##Type); \ GFX_GUARD_EXC(k->set##PropName(*prop);) \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #else #define DEF_GFX_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) #endif -#define DEF_GFX_PROP(Klass, type, PropName, arg_fun, value_fun) \ -RB_METHOD(Klass##Get##PropName) { \ +#define DEF_GFX_PROP(Klass, type, PropName, arg_fun, value_fun) \ +RB_METHOD_GUARD(Klass##Get##PropName) { \ RB_UNUSED_PARAM; \ Klass *k = getPrivateData(self); \ type value = 0; \ -GUARD_EXC(value = k->get##PropName();) \ +value = k->get##PropName(); \ return value_fun(value); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD_END \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ type value; \ rb_##arg_fun##_arg(*argv, &value); \ GFX_GUARD_EXC(k->set##PropName(value);) \ return *argv; \ -} +} \ +RB_METHOD_GUARD_END #define DEF_GFX_PROP_I(Klass, PropName) \ DEF_GFX_PROP(Klass, int, PropName, int, rb_fix_new) diff --git a/binding/bitmap-binding.cpp b/binding/bitmap-binding.cpp index 442b285c..b38614e5 100644 --- a/binding/bitmap-binding.cpp +++ b/binding/bitmap-binding.cpp @@ -64,7 +64,7 @@ void bitmapInitProps(Bitmap *b, VALUE self) { b->setInitFont(font); } -RB_METHOD(bitmapInitialize) { +RB_METHOD_GUARD(bitmapInitialize) { Bitmap *b = 0; if (argc == 1) { @@ -84,45 +84,49 @@ RB_METHOD(bitmapInitialize) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapWidth) { +RB_METHOD_GUARD(bitmapWidth) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); int value = 0; - GUARD_EXC(value = b->width();); + value = b->width(); return INT2FIX(value); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapHeight) { +RB_METHOD_GUARD(bitmapHeight) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); int value = 0; - GUARD_EXC(value = b->height();); + value = b->height(); return INT2FIX(value); } +RB_METHOD_GUARD_END DEF_GFX_PROP_OBJ_REF(Bitmap, Bitmap, Hires, "hires") -RB_METHOD(bitmapRect) { +RB_METHOD_GUARD(bitmapRect) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); IntRect rect; - GUARD_EXC(rect = b->rect();); + rect = b->rect(); Rect *r = new Rect(rect); return wrapObject(r, RectType); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapBlt) { +RB_METHOD_GUARD(bitmapBlt) { Bitmap *b = getPrivateData(self); int x, y; @@ -137,14 +141,17 @@ RB_METHOD(bitmapBlt) { &opacity RB_ARG_END); src = getPrivateDataCheck(srcObj, BitmapType); - srcRect = getPrivateDataCheck(srcRectObj, RectType); + if (src) { + srcRect = getPrivateDataCheck(srcRectObj, RectType); - GFX_GUARD_EXC(b->blt(x, y, *src, srcRect->toIntRect(), opacity);); + GFX_GUARD_EXC(b->blt(x, y, *src, srcRect->toIntRect(), opacity);); + } return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapStretchBlt) { +RB_METHOD_GUARD(bitmapStretchBlt) { Bitmap *b = getPrivateData(self); VALUE destRectObj; @@ -159,16 +166,19 @@ RB_METHOD(bitmapStretchBlt) { &opacity RB_ARG_END); src = getPrivateDataCheck(srcObj, BitmapType); - destRect = getPrivateDataCheck(destRectObj, RectType); - srcRect = getPrivateDataCheck(srcRectObj, RectType); - - GFX_GUARD_EXC(b->stretchBlt(destRect->toIntRect(), *src, srcRect->toIntRect(), - opacity);); + if (src) { + destRect = getPrivateDataCheck(destRectObj, RectType); + srcRect = getPrivateDataCheck(srcRectObj, RectType); + + GFX_GUARD_EXC(b->stretchBlt(destRect->toIntRect(), *src, srcRect->toIntRect(), + opacity);); + } return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapFillRect) { +RB_METHOD_GUARD(bitmapFillRect) { Bitmap *b = getPrivateData(self); VALUE colorObj; @@ -197,8 +207,9 @@ RB_METHOD(bitmapFillRect) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapClear) { +RB_METHOD_GUARD(bitmapClear) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); @@ -207,8 +218,9 @@ RB_METHOD(bitmapClear) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetPixel) { +RB_METHOD_GUARD(bitmapGetPixel) { Bitmap *b = getPrivateData(self); int x, y; @@ -216,14 +228,18 @@ RB_METHOD(bitmapGetPixel) { rb_get_args(argc, argv, "ii", &x, &y RB_ARG_END); Color value; - GUARD_EXC(value = b->getPixel(x, y);); + if (b->surface() || b->megaSurface()) + value = b->getPixel(x, y); + else + GFX_GUARD_EXC(value = b->getPixel(x, y);); Color *color = new Color(value); return wrapObject(color, ColorType); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSetPixel) { +RB_METHOD_GUARD(bitmapSetPixel) { Bitmap *b = getPrivateData(self); int x, y; @@ -239,8 +255,9 @@ RB_METHOD(bitmapSetPixel) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapHueChange) { +RB_METHOD_GUARD(bitmapHueChange) { Bitmap *b = getPrivateData(self); int hue; @@ -251,8 +268,9 @@ RB_METHOD(bitmapHueChange) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapDrawText) { +RB_METHOD_GUARD(bitmapDrawText) { Bitmap *b = getPrivateData(self); const char *str; @@ -293,8 +311,9 @@ RB_METHOD(bitmapDrawText) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapTextSize) { +RB_METHOD_GUARD(bitmapTextSize) { Bitmap *b = getPrivateData(self); const char *str; @@ -309,16 +328,50 @@ RB_METHOD(bitmapTextSize) { } IntRect value; - GUARD_EXC(value = b->textSize(str);); + value = b->textSize(str); Rect *rect = new Rect(value); return wrapObject(rect, RectType); } +RB_METHOD_GUARD_END -DEF_GFX_PROP_OBJ_VAL(Bitmap, Font, Font, "font") +RB_METHOD(BitmapGetFont) { + RB_UNUSED_PARAM; + checkDisposed(self); + return rb_iv_get(self, "font"); +} +RB_METHOD_GUARD(BitmapSetFont) { + rb_check_argc(argc, 1); + Bitmap *b = getPrivateData(self); + VALUE propObj = *argv; + + Font *prop = getPrivateDataCheck(propObj, FontType); + if (prop) { + GFX_GUARD_EXC(b->setFont(*prop);) + + VALUE f = rb_iv_get(self, "font"); + if (f) { + rb_iv_set(f, "name", rb_iv_get(propObj, "name")); + rb_iv_set(f, "size", rb_iv_get(propObj, "size")); + rb_iv_set(f, "bold", rb_iv_get(propObj, "bold")); + rb_iv_set(f, "italic", rb_iv_get(propObj, "italic")); -RB_METHOD(bitmapGradientFillRect) { + if (rgssVer >= 2) { + rb_iv_set(f, "shadow", rb_iv_get(propObj, "shadow")); + } + + if (rgssVer >= 3) { + rb_iv_set(f, "outline", rb_iv_get(propObj, "outline")); + } + } + } + + return propObj; +} +RB_METHOD_GUARD_END + +RB_METHOD_GUARD(bitmapGradientFillRect) { Bitmap *b = getPrivateData(self); VALUE color1Obj, color2Obj; @@ -353,8 +406,9 @@ RB_METHOD(bitmapGradientFillRect) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapClearRect) { +RB_METHOD_GUARD(bitmapClearRect) { Bitmap *b = getPrivateData(self); if (argc == 1) { @@ -376,33 +430,32 @@ RB_METHOD(bitmapClearRect) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapBlur) { +RB_METHOD_GUARD(bitmapBlur) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); - GFX_LOCK; - b->blur(); - GFX_UNLOCK; + GFX_GUARD_EXC( b->blur(); ); return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapRadialBlur) { +RB_METHOD_GUARD(bitmapRadialBlur) { Bitmap *b = getPrivateData(self); int angle, divisions; rb_get_args(argc, argv, "ii", &angle, &divisions RB_ARG_END); - GFX_LOCK; - b->radialBlur(angle, divisions); - GFX_UNLOCK; + GFX_GUARD_EXC( b->radialBlur(angle, divisions); ); return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetRawData) { +RB_METHOD_GUARD(bitmapGetRawData) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); @@ -413,8 +466,9 @@ RB_METHOD(bitmapGetRawData) { return ret; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSetRawData) { +RB_METHOD_GUARD(bitmapSetRawData) { RB_UNUSED_PARAM; VALUE str; @@ -427,8 +481,9 @@ RB_METHOD(bitmapSetRawData) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSaveToFile) { +RB_METHOD_GUARD(bitmapSaveToFile) { RB_UNUSED_PARAM; VALUE str; @@ -441,8 +496,9 @@ RB_METHOD(bitmapSaveToFile) { return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetMega){ +RB_METHOD_GUARD(bitmapGetMega){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -455,8 +511,9 @@ RB_METHOD(bitmapGetMega){ return ret; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetAnimated){ +RB_METHOD_GUARD(bitmapGetAnimated){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -469,8 +526,9 @@ RB_METHOD(bitmapGetAnimated){ return ret; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetPlaying){ +RB_METHOD_GUARD(bitmapGetPlaying){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -479,8 +537,9 @@ RB_METHOD(bitmapGetPlaying){ return rb_bool_new(b->isPlaying()); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSetPlaying){ +RB_METHOD_GUARD(bitmapSetPlaying){ RB_UNUSED_PARAM; bool play; @@ -493,8 +552,9 @@ RB_METHOD(bitmapSetPlaying){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapPlay){ +RB_METHOD_GUARD(bitmapPlay){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -504,8 +564,9 @@ RB_METHOD(bitmapPlay){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapStop){ +RB_METHOD_GUARD(bitmapStop){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -515,8 +576,9 @@ RB_METHOD(bitmapStop){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGotoStop){ +RB_METHOD_GUARD(bitmapGotoStop){ RB_UNUSED_PARAM; int frame; @@ -529,8 +591,9 @@ RB_METHOD(bitmapGotoStop){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGotoPlay){ +RB_METHOD_GUARD(bitmapGotoPlay){ RB_UNUSED_PARAM; int frame; @@ -543,8 +606,9 @@ RB_METHOD(bitmapGotoPlay){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapFrames){ +RB_METHOD_GUARD(bitmapFrames){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -553,8 +617,9 @@ RB_METHOD(bitmapFrames){ return INT2NUM(b->numFrames()); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapCurrentFrame){ +RB_METHOD_GUARD(bitmapCurrentFrame){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -563,8 +628,9 @@ RB_METHOD(bitmapCurrentFrame){ return INT2NUM(b->currentFrameI()); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapAddFrame){ +RB_METHOD_GUARD(bitmapAddFrame){ RB_UNUSED_PARAM; VALUE srcBitmap; @@ -573,6 +639,8 @@ RB_METHOD(bitmapAddFrame){ rb_scan_args(argc, argv, "11", &srcBitmap, &position); Bitmap *src = getPrivateDataCheck(srcBitmap, BitmapType); + if (!src) + raiseDisposedAccess(srcBitmap); Bitmap *b = getPrivateData(self); @@ -588,8 +656,9 @@ RB_METHOD(bitmapAddFrame){ return INT2NUM(ret); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapRemoveFrame){ +RB_METHOD_GUARD(bitmapRemoveFrame){ RB_UNUSED_PARAM; VALUE position; @@ -608,8 +677,9 @@ RB_METHOD(bitmapRemoveFrame){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapNextFrame){ +RB_METHOD_GUARD(bitmapNextFrame){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -620,8 +690,9 @@ RB_METHOD(bitmapNextFrame){ return INT2NUM(b->currentFrameI()); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapPreviousFrame){ +RB_METHOD_GUARD(bitmapPreviousFrame){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -632,8 +703,9 @@ RB_METHOD(bitmapPreviousFrame){ return INT2NUM(b->currentFrameI()); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSetFPS){ +RB_METHOD_GUARD(bitmapSetFPS){ RB_UNUSED_PARAM; VALUE fps; @@ -652,8 +724,9 @@ RB_METHOD(bitmapSetFPS){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetFPS){ +RB_METHOD_GUARD(bitmapGetFPS){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -662,12 +735,13 @@ RB_METHOD(bitmapGetFPS){ float ret; - GUARD_EXC(ret = b->getAnimationFPS();); + ret = b->getAnimationFPS(); return rb_float_new(ret); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSetLooping){ +RB_METHOD_GUARD(bitmapSetLooping){ RB_UNUSED_PARAM; bool loop; @@ -679,8 +753,9 @@ RB_METHOD(bitmapSetLooping){ return rb_bool_new(loop); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetLooping){ +RB_METHOD_GUARD(bitmapGetLooping){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -688,12 +763,13 @@ RB_METHOD(bitmapGetLooping){ Bitmap *b = getPrivateData(self); bool ret; - GUARD_EXC(ret = b->getLooping();); + ret = b->getLooping(); return rb_bool_new(ret); } +RB_METHOD_GUARD_END // Captures the Bitmap's current frame data to a new Bitmap -RB_METHOD(bitmapSnapToBitmap) { +RB_METHOD_GUARD(bitmapSnapToBitmap) { RB_UNUSED_PARAM; VALUE position; @@ -713,6 +789,7 @@ RB_METHOD(bitmapSnapToBitmap) { return ret; } +RB_METHOD_GUARD_END RB_METHOD(bitmapGetMaxSize){ RB_UNUSED_PARAM; @@ -722,7 +799,7 @@ RB_METHOD(bitmapGetMaxSize){ return INT2NUM(Bitmap::maxSize()); } -RB_METHOD(bitmapInitializeCopy) { +RB_METHOD_GUARD(bitmapInitializeCopy) { rb_check_argc(argc, 1); VALUE origObj = argv[0]; @@ -740,6 +817,7 @@ RB_METHOD(bitmapInitializeCopy) { return self; } +RB_METHOD_GUARD_END void bitmapBindingInit() { VALUE klass = rb_define_class("Bitmap", rb_cObject); diff --git a/binding/cusl-binding.cpp b/binding/cusl-binding.cpp index f280032c..8fe795ef 100644 --- a/binding/cusl-binding.cpp +++ b/binding/cusl-binding.cpp @@ -32,7 +32,7 @@ } \ } -RB_METHOD(CUSLSetStat) { +RB_METHOD_GUARD(CUSLSetStat) { RB_UNUSED_PARAM; VALUE name, stat; @@ -47,11 +47,12 @@ RB_METHOD(CUSLSetStat) { STEAMSHIM_setStatI(RSTRING_PTR(name), (int)NUM2INT(stat)); STEAMSHIM_GET_OK(SHIMEVENT_SETSTATI, ret); } else { - rb_raise(rb_eTypeError, + throw Exception(Exception::TypeError, "Statistic value must be either an integer or float."); } return rb_bool_new(ret); } +RB_METHOD_GUARD_END RB_METHOD(CUSLGetStatI) { RB_UNUSED_PARAM; diff --git a/binding/disposable-binding.h b/binding/disposable-binding.h index 1f531991..69fac862 100644 --- a/binding/disposable-binding.h +++ b/binding/disposable-binding.h @@ -30,8 +30,8 @@ template RB_METHOD(disposableDispose) { RB_UNUSED_PARAM; - - C *d = getPrivateData(self); + + C *d = getPrivateDataNoRaise(self); if (!d) return Qnil; @@ -46,7 +46,7 @@ RB_METHOD(disposableIsDisposed) { RB_UNUSED_PARAM; - C *d = getPrivateData(self); + C *d = getPrivateDataNoRaise(self); if (!d) return Qtrue; diff --git a/binding/etc-binding.cpp b/binding/etc-binding.cpp index ba4458a8..130bbc3e 100644 --- a/binding/etc-binding.cpp +++ b/binding/etc-binding.cpp @@ -107,7 +107,13 @@ EQUAL_FUN(Rect) rb_get_args(argc, argv, param_t_s, &p1, &p2, &p3, &p4 RB_ARG_END); \ k = new Klass(p1, p2, p3, p4); \ } \ + Klass *orig = getPrivateDataNoRaise(self); \ + if (orig) { \ + *orig = *k; \ + delete k; \ + } else { \ setPrivateData(self, k); \ + } \ return self; \ } @@ -208,11 +214,14 @@ INITCOPY_FUN(Tone) INITCOPY_FUN(Color) INITCOPY_FUN(Rect) -#if RAPI_FULL > 187 +CLASS_ALLOCATE_PRE_INIT(Tone, ToneInitialize); +CLASS_ALLOCATE_PRE_INIT(Color, ColorInitialize); +CLASS_ALLOCATE_PRE_INIT(Rect, RectInitialize); + #define INIT_BIND(Klass) \ { \ klass = rb_define_class(#Klass, rb_cObject); \ - rb_define_alloc_func(klass, classAllocate<&Klass##Type>); \ + rb_define_alloc_func(klass, Klass##AllocatePreInit); \ rb_define_class_method(klass, "_load", Klass##Load); \ serializableBindingInit(klass); \ _rb_define_method(klass, "initialize", Klass##Initialize); \ @@ -224,23 +233,6 @@ INITCOPY_FUN(Rect) _rb_define_method(klass, "to_s", Klass##Stringify); \ _rb_define_method(klass, "inspect", Klass##Stringify); \ } -#else -#define INIT_BIND(Klass) \ - { \ - klass = rb_define_class(#Klass, rb_cObject); \ - rb_define_alloc_func(klass, Klass##Allocate); \ - rb_define_class_method(klass, "_load", Klass##Load); \ - serializableBindingInit(klass); \ - _rb_define_method(klass, "initialize", Klass##Initialize); \ - _rb_define_method(klass, "initialize_copy", Klass##InitializeCopy); \ - _rb_define_method(klass, "set", Klass##Set); \ - _rb_define_method(klass, "==", Klass##Equal); \ - _rb_define_method(klass, "===", Klass##Equal); \ - _rb_define_method(klass, "eql?", Klass##Equal); \ - _rb_define_method(klass, "to_s", Klass##Stringify); \ - _rb_define_method(klass, "inspect", Klass##Stringify); \ - } -#endif #define MRB_ATTR_R(Class, attr) \ mrb_define_method(mrb, klass, #attr, Class##Get_##attr, MRB_ARGS_NONE()) diff --git a/binding/filesystem-binding.cpp b/binding/filesystem-binding.cpp index b0c41a76..9c479a00 100644 --- a/binding/filesystem-binding.cpp +++ b/binding/filesystem-binding.cpp @@ -52,6 +52,10 @@ DEF_ALLOCFUNC_CUSTOMFREE(FileInt, fileIntFreeInstance); #endif static VALUE fileIntForPath(const char *path, bool rubyExc) { + VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt")); + + VALUE obj = rb_obj_alloc(klass); + SDL_RWops *ops = SDL_AllocRW(); try { @@ -59,16 +63,9 @@ static VALUE fileIntForPath(const char *path, bool rubyExc) { } catch (const Exception &e) { SDL_FreeRW(ops); - if (rubyExc) - raiseRbExc(e); - else - throw e; + throw e; } - VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt")); - - VALUE obj = rb_obj_alloc(klass); - setPrivateData(obj, ops); return obj; @@ -183,7 +180,7 @@ kernelLoadDataInt(const char *filename, bool rubyExc, bool raw) { return result; } -RB_METHOD(kernelLoadData) { +RB_METHOD_GUARD(kernelLoadData) { RB_UNUSED_PARAM; VALUE filename; @@ -195,6 +192,7 @@ RB_METHOD(kernelLoadData) { rb_bool_arg(raw, &rawv); return kernelLoadDataInt(RSTRING_PTR(filename), true, rawv); } +RB_METHOD_GUARD_END RB_METHOD(kernelSaveData) { RB_UNUSED_PARAM; diff --git a/binding/font-binding.cpp b/binding/font-binding.cpp index 664806a6..6c944940 100644 --- a/binding/font-binding.cpp +++ b/binding/font-binding.cpp @@ -88,7 +88,15 @@ RB_METHOD(fontInitialize) { * However the same bug/behavior exists in all RM versions. */ rb_iv_set(self, "name", namesObj); - setPrivateData(self, f); + Font *orig = getPrivateDataNoRaise(self); + if (orig) + { + *orig = *f; + delete f; + f = orig; + } else { + setPrivateData(self, f); + } /* Wrap property objects */ f->initDynAttribs(); diff --git a/binding/graphics-binding.cpp b/binding/graphics-binding.cpp index d28521fc..894163b6 100644 --- a/binding/graphics-binding.cpp +++ b/binding/graphics-binding.cpp @@ -26,10 +26,6 @@ #include "binding-types.h" #include "exception.h" -#if RAPI_MAJOR >= 2 -#include -#endif - RB_METHOD(graphicsDelta) { RB_UNUSED_PARAM; GFX_LOCK; @@ -38,14 +34,12 @@ RB_METHOD(graphicsDelta) { return ret; } -RB_METHOD(graphicsUpdate) +RB_METHOD_GUARD(graphicsUpdate) { RB_UNUSED_PARAM; #if RAPI_MAJOR >= 2 - rb_thread_call_without_gvl([](void*) -> void* { - GFX_LOCK; - shState->graphics().update(); - GFX_UNLOCK; + drop_gvl_guard([](void*) -> void* { + GFX_GUARD_EXC( shState->graphics().update(); ); return 0; }, 0, 0, 0); #else @@ -53,6 +47,7 @@ RB_METHOD(graphicsUpdate) #endif return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(graphicsAverageFrameRate) { @@ -63,18 +58,30 @@ RB_METHOD(graphicsAverageFrameRate) return ret; } -RB_METHOD(graphicsFreeze) +RB_METHOD_GUARD(graphicsFreeze) { RB_UNUSED_PARAM; - GFX_LOCK; +#if RAPI_MAJOR >= 2 + drop_gvl_guard([](void*) -> void* { + GFX_GUARD_EXC( shState->graphics().freeze(); ); + return 0; + }, 0, 0, 0); +#else shState->graphics().freeze(); - GFX_UNLOCK; +#endif return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(graphicsTransition) +typedef struct { + int duration; + const char *filename; + int vague; +} TransitionArgs; + +RB_METHOD_GUARD(graphicsTransition) { RB_UNUSED_PARAM; @@ -84,10 +91,24 @@ RB_METHOD(graphicsTransition) rb_get_args(argc, argv, "|izi", &duration, &filename, &vague RB_ARG_END); + TransitionArgs args = {duration, filename, vague}; + +#if RAPI_MAJOR >= 2 + drop_gvl_guard([](void *args) -> void* { + TransitionArgs &a = *((TransitionArgs*)args); + GFX_GUARD_EXC( shState->graphics().transition(a.duration, + a.filename, + a.vague + ); ); + return 0; + }, &args, 0, 0); +#else GFX_GUARD_EXC( shState->graphics().transition(duration, filename, vague); ) +#endif return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(graphicsFrameReset) { @@ -179,17 +200,15 @@ RB_METHOD(graphicsDisplayHeight) return rb_fix_new(shState->graphics().displayHeight()); } -RB_METHOD(graphicsWait) +RB_METHOD_GUARD(graphicsWait) { RB_UNUSED_PARAM; int duration; rb_get_args(argc, argv, "i", &duration RB_ARG_END); #if RAPI_MAJOR >= 2 - rb_thread_call_without_gvl([](void* d) -> void* { - GFX_LOCK; - shState->graphics().wait(*(int*)d); - GFX_UNLOCK; + drop_gvl_guard([](void* d) -> void* { + GFX_GUARD_EXC( shState->graphics().wait(*(int*)d); ); return 0; }, (int*)&duration, 0, 0); #else @@ -197,38 +216,51 @@ RB_METHOD(graphicsWait) #endif return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(graphicsFadeout) +RB_METHOD_GUARD(graphicsFadeout) { RB_UNUSED_PARAM; int duration; rb_get_args(argc, argv, "i", &duration RB_ARG_END); - GFX_LOCK; +#if RAPI_MAJOR >= 2 + drop_gvl_guard([](void* d) -> void* { + GFX_GUARD_EXC( shState->graphics().fadeout(*(int*)d); ); + return 0; + }, (int*)&duration, 0, 0); +#else shState->graphics().fadeout(duration); - GFX_UNLOCK; +#endif return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(graphicsFadein) +RB_METHOD_GUARD(graphicsFadein) { RB_UNUSED_PARAM; int duration; rb_get_args(argc, argv, "i", &duration RB_ARG_END); - GFX_LOCK; +#if RAPI_MAJOR >= 2 + drop_gvl_guard([](void* d) -> void* { + GFX_GUARD_EXC( shState->graphics().fadein(*(int*)d); ); + return 0; + }, (int*)&duration, 0, 0); +#else shState->graphics().fadein(duration); - GFX_UNLOCK; +#endif return Qnil; } +RB_METHOD_GUARD_END void bitmapInitProps(Bitmap *b, VALUE self); -RB_METHOD(graphicsSnapToBitmap) +RB_METHOD_GUARD(graphicsSnapToBitmap) { RB_UNUSED_PARAM; @@ -241,6 +273,7 @@ RB_METHOD(graphicsSnapToBitmap) return obj; } +RB_METHOD_GUARD_END RB_METHOD(graphicsResizeScreen) { @@ -272,16 +305,15 @@ RB_METHOD(graphicsResizeWindow) return Qnil; } -RB_METHOD(graphicsReset) +RB_METHOD_GUARD(graphicsReset) { RB_UNUSED_PARAM; - GFX_LOCK; - shState->graphics().reset(); - GFX_UNLOCK; + GFX_GUARD_EXC( shState->graphics().reset(); ); return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(graphicsCenter) { @@ -299,17 +331,17 @@ typedef struct { void *playMovieInternal(void *args) { PlayMovieArgs *a = (PlayMovieArgs*)args; - GFX_GUARD_EXC( - shState->graphics().playMovie(a->filename, a->volume, a->skippable); - - // Signals for shutdown or reset only make playMovie quit early, - // so check again - shState->graphics().update(); - ); + GFX_GUARD_EXC( shState->graphics().playMovie(a->filename, a->volume, a->skippable); ); + + // Signals for shutdown or reset only make playMovie quit early, + // so check again + shState->checkShutdown(); + shState->checkReset(); + return 0; } -RB_METHOD(graphicsPlayMovie) +RB_METHOD_GUARD(graphicsPlayMovie) { RB_UNUSED_PARAM; @@ -327,20 +359,21 @@ RB_METHOD(graphicsPlayMovie) args.volume = (volumeArg == Qnil) ? 100 : NUM2INT(volumeArg);; args.skippable = skip; #if RAPI_MAJOR >= 2 - rb_thread_call_without_gvl(playMovieInternal, &args, 0, 0); + drop_gvl_guard(playMovieInternal, &args, 0, 0); #else playMovieInternal(&args); #endif return Qnil; } +RB_METHOD_GUARD_END void graphicsScreenshotInternal(const char *filename) { GFX_GUARD_EXC(shState->graphics().screenshot(filename);); } -RB_METHOD(graphicsScreenshot) +RB_METHOD_GUARD(graphicsScreenshot) { RB_UNUSED_PARAM; @@ -349,7 +382,7 @@ RB_METHOD(graphicsScreenshot) SafeStringValue(filename); #if RAPI_MAJOR >= 2 - rb_thread_call_without_gvl([](void* fn) -> void* { + drop_gvl_guard([](void* fn) -> void* { graphicsScreenshotInternal((const char*)fn); return 0; }, (void*)RSTRING_PTR(filename), 0, 0); @@ -358,6 +391,7 @@ RB_METHOD(graphicsScreenshot) #endif return Qnil; } +RB_METHOD_GUARD_END DEF_GRA_PROP_I(FrameRate) DEF_GRA_PROP_I(FrameCount) diff --git a/binding/http-binding.cpp b/binding/http-binding.cpp index f6debeb4..61678021 100644 --- a/binding/http-binding.cpp +++ b/binding/http-binding.cpp @@ -10,10 +10,6 @@ #include "util/json5pp.hpp" #include "binding-util.h" -#if RAPI_MAJOR >= 2 -#include -#endif - #include "net/net.h" VALUE stringMap2hash(mkxp_net::StringMap &map) { @@ -78,16 +74,14 @@ VALUE formResponse(mkxp_net::HTTPResponse &res) { void* httpGetInternal(void *req) { VALUE ret; - GUARD_EXC( - mkxp_net::HTTPResponse res = ((mkxp_net::HTTPRequest*)req)->get(); - ret = formResponse(res); - ); + mkxp_net::HTTPResponse res = ((mkxp_net::HTTPRequest*)req)->get(); + ret = formResponse(res); return (void*)ret; } #endif -RB_METHOD(httpGet) { +RB_METHOD_GUARD(httpGet) { RB_UNUSED_PARAM; VALUE path, rheaders, redirect; @@ -102,11 +96,12 @@ RB_METHOD(httpGet) { req.headers().insert(headers.begin(), headers.end()); } #if RAPI_MAJOR >= 2 - return (VALUE)rb_thread_call_without_gvl(httpGetInternal, &req, 0, 0); + return (VALUE)drop_gvl_guard(httpGetInternal, &req, 0, 0); #else return (VALUE)httpGetInternal(&req); #endif } +RB_METHOD_GUARD_END #if RAPI_MAJOR >= 2 @@ -121,16 +116,14 @@ void* httpPostInternal(void *args) { mkxp_net::HTTPRequest *req = ((httpPostInternalArgs*)args)->req; mkxp_net::StringMap *postData = ((httpPostInternalArgs*)args)->postData; - GUARD_EXC( - mkxp_net::HTTPResponse res = req->post(*postData); - ret = formResponse(res); - ); + mkxp_net::HTTPResponse res = req->post(*postData); + ret = formResponse(res); return (void*)ret; } #endif -RB_METHOD(httpPost) { +RB_METHOD_GUARD(httpPost) { RB_UNUSED_PARAM; VALUE path, postDataHash, rheaders, redirect; @@ -148,11 +141,12 @@ RB_METHOD(httpPost) { mkxp_net::StringMap postData = hash2StringMap(postDataHash); httpPostInternalArgs args {&req, &postData}; #if RAPI_MAJOR >= 2 - return (VALUE)rb_thread_call_without_gvl(httpPostInternal, &args, 0, 0); + return (VALUE)drop_gvl_guard(httpPostInternal, &args, 0, 0); #else return httpPostInternal(&args); #endif } +RB_METHOD_GUARD_END #if RAPI_MAJOR >= 2 typedef struct { @@ -168,16 +162,14 @@ void* httpPostBodyInternal(void *args) { const char *reqbody = ((httpPostBodyInternalArgs*)args)->body; const char *reqctype = ((httpPostBodyInternalArgs*)args)->ctype; - GUARD_EXC( - mkxp_net::HTTPResponse res = req->post(reqbody, reqctype); - ret = formResponse(res); - ); + mkxp_net::HTTPResponse res = req->post(reqbody, reqctype); + ret = formResponse(res); return (void*)ret; } #endif -RB_METHOD(httpPostBody) { +RB_METHOD_GUARD(httpPostBody) { RB_UNUSED_PARAM; VALUE path, body, ctype, rheaders; @@ -195,11 +187,12 @@ RB_METHOD(httpPostBody) { httpPostBodyInternalArgs args {&req, RSTRING_PTR(body), RSTRING_PTR(ctype)}; #if RAPI_MAJOR >= 2 - return (VALUE)rb_thread_call_without_gvl(httpPostBodyInternal, &args, 0, 0); + return (VALUE)drop_gvl_guard(httpPostBodyInternal, &args, 0, 0); #else return httpPostBodyInternal(&args); #endif } +RB_METHOD_GUARD_END VALUE json2rb(json5pp::value const &v) { if (v.is_null()) @@ -280,13 +273,13 @@ json5pp::value rb2json(VALUE v) { return ret_value; } - raiseRbExc(Exception(Exception::MKXPError, "Invalid value for JSON: %s", RSTRING_PTR(rb_inspect(v)))); + throw Exception(Exception::MKXPError, "Invalid value for JSON: %s", RSTRING_PTR(rb_inspect(v))); // This should be unreachable return json5pp::value(0); } -RB_METHOD(httpJsonParse) { +RB_METHOD_GUARD(httpJsonParse) { RB_UNUSED_PARAM; VALUE jsonv; @@ -298,13 +291,14 @@ RB_METHOD(httpJsonParse) { v = json5pp::parse5(RSTRING_PTR(jsonv)); } catch (const std::exception &e) { - raiseRbExc(Exception(Exception::MKXPError, "Failed to parse JSON: %s", e.what())); + throw Exception(Exception::MKXPError, "Failed to parse JSON: %s", e.what()); } return json2rb(v); } +RB_METHOD_GUARD_END -RB_METHOD(httpJsonStringify) { +RB_METHOD_GUARD(httpJsonStringify) { RB_UNUSED_PARAM; VALUE obj; @@ -313,6 +307,7 @@ RB_METHOD(httpJsonStringify) { json5pp::value v = rb2json(obj); return rb_utf8_str_new_cstr(v.stringify5(json5pp::rule::space_indent<>()).c_str()); } +RB_METHOD_GUARD_END void httpBindingInit() { VALUE mNet = rb_define_module("HTTPLite"); diff --git a/binding/input-binding.cpp b/binding/input-binding.cpp index bbe55502..3e20428b 100644 --- a/binding/input-binding.cpp +++ b/binding/input-binding.cpp @@ -37,13 +37,14 @@ RB_METHOD(inputDelta) { return rb_float_new(shState->input().getDelta()); } -RB_METHOD(inputUpdate) { +RB_METHOD_GUARD(inputUpdate) { RB_UNUSED_PARAM; shState->input().update(); return Qnil; } +RB_METHOD_GUARD_END static int getButtonArg(VALUE *argv) { int num; @@ -76,7 +77,7 @@ static int getScancodeArg(VALUE *argv) { try { code = strToScancode[scancode]; } catch (...) { - rb_raise(rb_eRuntimeError, "%s is not a valid name of an SDL scancode.", scancode); + throw Exception(Exception::RuntimeError, "%s is not a valid name of an SDL scancode.", scancode); } return code; @@ -88,7 +89,7 @@ static int getControllerButtonArg(VALUE *argv) { try { btn = strToGCButton[button]; } catch (...) { - rb_raise(rb_eRuntimeError, "%s is not a valid name of an SDL Controller button.", button); + throw Exception(Exception::RuntimeError, "%s is not a valid name of an SDL Controller button.", button); } return btn; @@ -172,7 +173,7 @@ RB_METHOD(inputRepeatTime) { return rb_float_new(shState->input().repeatTime(num)); } -RB_METHOD(inputPressEx) { +RB_METHOD_GUARD(inputPressEx) { RB_UNUSED_PARAM; VALUE button; @@ -185,8 +186,9 @@ RB_METHOD(inputPressEx) { return rb_bool_new(shState->input().isPressedEx(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END -RB_METHOD(inputTriggerEx) { +RB_METHOD_GUARD(inputTriggerEx) { RB_UNUSED_PARAM; VALUE button; @@ -199,8 +201,9 @@ RB_METHOD(inputTriggerEx) { return rb_bool_new(shState->input().isTriggeredEx(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END -RB_METHOD(inputRepeatEx) { +RB_METHOD_GUARD(inputRepeatEx) { RB_UNUSED_PARAM; VALUE button; @@ -213,8 +216,9 @@ RB_METHOD(inputRepeatEx) { return rb_bool_new(shState->input().isRepeatedEx(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END -RB_METHOD(inputReleaseEx) { +RB_METHOD_GUARD(inputReleaseEx) { RB_UNUSED_PARAM; VALUE button; @@ -227,8 +231,9 @@ RB_METHOD(inputReleaseEx) { return rb_bool_new(shState->input().isReleasedEx(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END -RB_METHOD(inputCountEx) { +RB_METHOD_GUARD(inputCountEx) { RB_UNUSED_PARAM; VALUE button; @@ -241,8 +246,9 @@ RB_METHOD(inputCountEx) { return UINT2NUM(shState->input().repeatcount(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END -RB_METHOD(inputRepeatTimeEx) { +RB_METHOD_GUARD(inputRepeatTimeEx) { RB_UNUSED_PARAM; VALUE button; @@ -255,6 +261,7 @@ RB_METHOD(inputRepeatTimeEx) { return rb_float_new(shState->input().repeatTimeEx(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END RB_METHOD(inputDir4) { RB_UNUSED_PARAM; @@ -370,7 +377,7 @@ AXISFUNC(Trigger, TRIGGERLEFT, TRIGGERRIGHT); #undef POWERCASE #undef M_SYMBOL -RB_METHOD(inputControllerPressEx) { +RB_METHOD_GUARD(inputControllerPressEx) { RB_UNUSED_PARAM; VALUE button; @@ -383,8 +390,9 @@ RB_METHOD(inputControllerPressEx) { return rb_bool_new(shState->input().controllerIsPressedEx(NUM2INT(button))); } +RB_METHOD_GUARD_END -RB_METHOD(inputControllerTriggerEx) { +RB_METHOD_GUARD(inputControllerTriggerEx) { RB_UNUSED_PARAM; VALUE button; @@ -397,8 +405,9 @@ RB_METHOD(inputControllerTriggerEx) { return rb_bool_new(shState->input().controllerIsTriggeredEx(NUM2INT(button))); } +RB_METHOD_GUARD_END -RB_METHOD(inputControllerRepeatEx) { +RB_METHOD_GUARD(inputControllerRepeatEx) { RB_UNUSED_PARAM; VALUE button; @@ -411,8 +420,9 @@ RB_METHOD(inputControllerRepeatEx) { return rb_bool_new(shState->input().controllerIsRepeatedEx(NUM2INT(button))); } +RB_METHOD_GUARD_END -RB_METHOD(inputControllerReleaseEx) { +RB_METHOD_GUARD(inputControllerReleaseEx) { RB_UNUSED_PARAM; VALUE button; @@ -425,8 +435,9 @@ RB_METHOD(inputControllerReleaseEx) { return rb_bool_new(shState->input().controllerIsReleasedEx(NUM2INT(button))); } +RB_METHOD_GUARD_END -RB_METHOD(inputControllerCountEx) { +RB_METHOD_GUARD(inputControllerCountEx) { RB_UNUSED_PARAM; VALUE button; @@ -439,8 +450,9 @@ RB_METHOD(inputControllerCountEx) { return rb_bool_new(shState->input().controllerRepeatcount(NUM2INT(button))); } +RB_METHOD_GUARD_END -RB_METHOD(inputControllerRepeatTimeEx) { +RB_METHOD_GUARD(inputControllerRepeatTimeEx) { RB_UNUSED_PARAM; VALUE button; @@ -453,6 +465,7 @@ RB_METHOD(inputControllerRepeatTimeEx) { return rb_float_new(shState->input().controllerRepeatTimeEx(NUM2INT(button))); } +RB_METHOD_GUARD_END RB_METHOD(inputControllerRawButtonStates) { RB_UNUSED_PARAM; @@ -504,18 +517,13 @@ RB_METHOD(inputGets) { return ret; } -RB_METHOD(inputGetClipboard) { +RB_METHOD_GUARD(inputGetClipboard) { RB_UNUSED_PARAM; - VALUE ret; - try { - ret = rb_utf8_str_new_cstr(shState->input().getClipboardText()); - } catch (const Exception &e) { - raiseRbExc(e); - } - return ret; + return rb_utf8_str_new_cstr(shState->input().getClipboardText()); } +RB_METHOD_GUARD_END -RB_METHOD(inputSetClipboard) { +RB_METHOD_GUARD(inputSetClipboard) { RB_UNUSED_PARAM; VALUE str; @@ -523,13 +531,11 @@ RB_METHOD(inputSetClipboard) { SafeStringValue(str); - try { - shState->input().setClipboardText(RSTRING_PTR(str)); - } catch (const Exception &e) { - raiseRbExc(e); - } + shState->input().setClipboardText(RSTRING_PTR(str)); + return str; } +RB_METHOD_GUARD_END struct { const char *str; diff --git a/binding/miniffi-binding.cpp b/binding/miniffi-binding.cpp index 3c24c3f9..8a539558 100644 --- a/binding/miniffi-binding.cpp +++ b/binding/miniffi-binding.cpp @@ -46,7 +46,7 @@ static void *MiniFFI_GetFunctionHandle(void *libhandle, const char *func) { // MiniFFI.new(library, function[, imports[, exports]]) // Yields itself in blocks -RB_METHOD(MiniFFI_initialize) { +RB_METHOD_GUARD(MiniFFI_initialize) { VALUE libname, func, imports, exports; rb_scan_args(argc, argv, "22", &libname, &func, &imports, &exports); SafeStringValue(libname); @@ -66,7 +66,7 @@ RB_METHOD(MiniFFI_initialize) { } #endif if (!hfunc) - rb_raise(rb_eRuntimeError, "%s", SDL_GetError()); + throw Exception(Exception::RuntimeError, "%s", SDL_GetError()); rb_iv_set(self, "_func", MVAL2RB((mffi_value)hfunc)); rb_iv_set(self, "_funcname", func); @@ -138,7 +138,7 @@ RB_METHOD(MiniFFI_initialize) { } if (MINIFFI_MAX_ARGS < RARRAY_LEN(ary_imports)) - rb_raise(rb_eRuntimeError, "too many parameters: %ld/%ld\n", + throw Exception(Exception::RuntimeError, "too many parameters: %ld/%ld\n", RARRAY_LEN(ary_imports), MINIFFI_MAX_ARGS); rb_iv_set(self, "_imports", ary_imports); @@ -181,6 +181,7 @@ RB_METHOD(MiniFFI_initialize) { rb_yield(self); return Qnil; } +RB_METHOD_GUARD_END #if RAPI_MAJOR >= 2 typedef struct { @@ -195,7 +196,7 @@ void* miniffi_call_cb(void *args) { } #endif -RB_METHOD(MiniFFI_call) { +RB_METHOD_GUARD(MiniFFI_call) { MiniFFIFuncArgs param; #define params param.params VALUE func = rb_iv_get(self, "_func"); @@ -206,7 +207,7 @@ RB_METHOD(MiniFFI_call) { int items = rb_scan_args(argc, argv, "0*", &args); int nimport = RARRAY_LEN(own_imports); if (items != nimport) - rb_raise(rb_eRuntimeError, + throw Exception(Exception::RuntimeError, "wrong number of parameters: expected %d, got %d", nimport, items); for (int i = 0; i < nimport; i++) { @@ -264,6 +265,7 @@ RB_METHOD(MiniFFI_call) { return MVAL2RB(0); } } +RB_METHOD_GUARD_END void MiniFFIBindingInit() { VALUE cMiniFFI = rb_define_class("MiniFFI", rb_cObject); diff --git a/binding/sceneelement-binding.h b/binding/sceneelement-binding.h index 270cdb07..b49abf79 100644 --- a/binding/sceneelement-binding.h +++ b/binding/sceneelement-binding.h @@ -27,20 +27,21 @@ #include "graphics.h" template -RB_METHOD(sceneElementGetZ) +RB_METHOD_GUARD(sceneElementGetZ) { RB_UNUSED_PARAM; SceneElement *se = getPrivateData(self); int value = 0; - GUARD_EXC( value = se->getZ(); ); + value = se->getZ(); return rb_fix_new(value); } +RB_METHOD_GUARD_END template -RB_METHOD(sceneElementSetZ) +RB_METHOD_GUARD(sceneElementSetZ) { SceneElement *se = getPrivateData(self); @@ -51,22 +52,24 @@ RB_METHOD(sceneElementSetZ) return rb_fix_new(z); } +RB_METHOD_GUARD_END template -RB_METHOD(sceneElementGetVisible) +RB_METHOD_GUARD(sceneElementGetVisible) { RB_UNUSED_PARAM; SceneElement *se = getPrivateData(self); bool value = false; - GUARD_EXC( value = se->getVisible(); ); + value = se->getVisible(); return rb_bool_new(value); } +RB_METHOD_GUARD_END template -RB_METHOD(sceneElementSetVisible) +RB_METHOD_GUARD(sceneElementSetVisible) { SceneElement *se = getPrivateData(self); @@ -75,8 +78,9 @@ RB_METHOD(sceneElementSetVisible) GFX_GUARD_EXC( se->setVisible(visible); ); - return rb_bool_new(visible); + return rb_bool_new(visible); } +RB_METHOD_GUARD_END template void diff --git a/binding/serializable-binding.h b/binding/serializable-binding.h index 12e897bd..d6f42bea 100644 --- a/binding/serializable-binding.h +++ b/binding/serializable-binding.h @@ -36,7 +36,16 @@ serializableDump(int, VALUE *, VALUE self) VALUE data = rb_str_new(0, dataSize); - GUARD_EXC( s->serialize(RSTRING_PTR(data)); ); + Exception *exc = 0; + try{ + s->serialize(RSTRING_PTR(data)); + } catch (const Exception &e) { + exc = new Exception(e); + } + + if (exc) { + raiseRbExc(exc); + } return data; } diff --git a/binding/sprite-binding.cpp b/binding/sprite-binding.cpp index 77da2ee8..096464e4 100644 --- a/binding/sprite-binding.cpp +++ b/binding/sprite-binding.cpp @@ -84,27 +84,29 @@ DEF_GFX_PROP_B(Sprite, Mirror) DEF_GFX_PROP_B(Sprite, PatternTile) DEF_GFX_PROP_B(Sprite, Invert) -RB_METHOD(spriteWidth) { +RB_METHOD_GUARD(spriteWidth) { RB_UNUSED_PARAM; Sprite *s = getPrivateData(self); int value = 0; - GUARD_EXC(value = s->getWidth();) + value = s->getWidth(); return rb_fix_new(value); } +RB_METHOD_GUARD_END -RB_METHOD(spriteHeight) { +RB_METHOD_GUARD(spriteHeight) { RB_UNUSED_PARAM; Sprite *s = getPrivateData(self); int value = 0; - GUARD_EXC(value = s->getHeight();) + value = s->getHeight(); return rb_fix_new(value); } +RB_METHOD_GUARD_END void spriteBindingInit() { VALUE klass = rb_define_class("Sprite", rb_cObject); diff --git a/binding/table-binding.cpp b/binding/table-binding.cpp index 65452d6e..770514a3 100644 --- a/binding/table-binding.cpp +++ b/binding/table-binding.cpp @@ -57,9 +57,14 @@ RB_METHOD(tableInitialize) { parseArgsTableSizes(argc, argv, &x, &y, &z); - Table *t = new Table(x, y, z); + Table *t = getPrivateDataNoRaise(self); + if (t) { + t->resize(x, y, z); + } else { + t = new Table(x, y, z); - setPrivateData(self, t); + setPrivateData(self, t); + } return self; } @@ -86,7 +91,7 @@ TABLE_SIZE(x, X) TABLE_SIZE(y, Y) TABLE_SIZE(z, Z) -RB_METHOD(tableGetAt) { +RB_METHOD_GUARD(tableGetAt) { Table *t = getPrivateData
(self); int x, y, z; @@ -99,7 +104,7 @@ RB_METHOD(tableGetAt) { z = NUM2INT(argv[2]); if (argc > 3) - rb_raise(rb_eArgError, "wrong number of arguments"); + throw Exception(Exception::ArgumentError, "wrong number of arguments"); if (x < 0 || x >= t->xSize() || y < 0 || y >= t->ySize() || z < 0 || z >= t->zSize()) { @@ -110,15 +115,16 @@ RB_METHOD(tableGetAt) { return INT2FIX(result); /* short always fits in a Fixnum */ } +RB_METHOD_GUARD_END -RB_METHOD(tableSetAt) { +RB_METHOD_GUARD(tableSetAt) { Table *t = getPrivateData
(self); int x, y, z, value; x = y = z = 0; if (argc < 2) - rb_raise(rb_eArgError, "wrong number of arguments"); + throw Exception(Exception::ArgumentError, "wrong number of arguments"); switch (argc) { default: @@ -146,17 +152,25 @@ RB_METHOD(tableSetAt) { return argv[argc - 1]; } +RB_METHOD_GUARD_END MARSH_LOAD_FUN(Table) INITCOPY_FUN(Table) + +RB_METHOD(tableInitializeDefault) { + Table *t = new Table(0, 0, 0); + + setPrivateData(self, t); + + return self; +} + +CLASS_ALLOCATE_PRE_INIT(Table, tableInitializeDefault); + void tableBindingInit() { VALUE klass = rb_define_class("Table", rb_cObject); -#if RAPI_FULL > 187 - rb_define_alloc_func(klass, classAllocate<&TableType>); -#else - rb_define_alloc_func(klass, TableAllocate); -#endif + rb_define_alloc_func(klass, TableAllocatePreInit); serializableBindingInit
(klass); diff --git a/binding/tilemap-binding.cpp b/binding/tilemap-binding.cpp index d2c5a754..8180c5b4 100644 --- a/binding/tilemap-binding.cpp +++ b/binding/tilemap-binding.cpp @@ -35,7 +35,10 @@ DEF_TYPE_CUSTOMFREE(TilemapAutotiles, RUBY_TYPED_NEVER_FREE); #endif RB_METHOD(tilemapAutotilesSet) { - Tilemap::Autotiles *a = getPrivateData(self); + Tilemap::Autotiles *a = getPrivateDataNoRaise(self); + + if (!a) + return self; int i; VALUE bitmapObj; @@ -93,12 +96,18 @@ RB_METHOD(tilemapInitialize) { t->initDynAttribs(); + /* Dispose the old autotiles if we're reinitializing. + * See the comment in setPrivateData for more info. */ + VALUE autotilesObj = rb_iv_get(self, "autotiles"); + if (autotilesObj != Qnil) + setPrivateData(autotilesObj, 0); + wrapProperty(self, &t->getAutotiles(), "autotiles", TilemapAutotilesType); wrapProperty(self, &t->getColor(), "color", ColorType); wrapProperty(self, &t->getTone(), "tone", ToneType); - VALUE autotilesObj = rb_iv_get(self, "autotiles"); + autotilesObj = rb_iv_get(self, "autotiles"); VALUE ary = rb_ary_new2(7); for (int i = 0; i < 7; ++i) @@ -117,8 +126,6 @@ RB_METHOD(tilemapInitialize) { RB_METHOD(tilemapGetAutotiles) { RB_UNUSED_PARAM; - checkDisposed(self); - return rb_iv_get(self, "autotiles"); } diff --git a/binding/tilemapvx-binding.cpp b/binding/tilemapvx-binding.cpp index 3e616571..18261c07 100644 --- a/binding/tilemapvx-binding.cpp +++ b/binding/tilemapvx-binding.cpp @@ -58,10 +58,16 @@ RB_METHOD(tilemapVXInitialize) { rb_iv_set(self, "viewport", viewportObj); + /* Dispose the old bitmap array if we're reinitializing. + * See the comment in setPrivateData for more info. */ + VALUE autotilesObj = rb_iv_get(self, "bitmap_array"); + if (autotilesObj != Qnil) + setPrivateData(autotilesObj, 0); + wrapProperty(self, &t->getBitmapArray(), "bitmap_array", BitmapArrayType, rb_const_get(rb_cObject, rb_intern("Tilemap"))); - VALUE autotilesObj = rb_iv_get(self, "bitmap_array"); + autotilesObj = rb_iv_get(self, "bitmap_array"); VALUE ary = rb_ary_new2(9); for (int i = 0; i < 9; ++i) @@ -80,8 +86,6 @@ RB_METHOD(tilemapVXInitialize) { RB_METHOD(tilemapVXGetBitmapArray) { RB_UNUSED_PARAM; - checkDisposed(self); - return rb_iv_get(self, "bitmap_array"); } @@ -106,7 +110,10 @@ DEF_GFX_PROP_I(TilemapVX, OX) DEF_GFX_PROP_I(TilemapVX, OY) RB_METHOD(tilemapVXBitmapsSet) { - TilemapVX::BitmapArray *a = getPrivateData(self); + TilemapVX::BitmapArray *a = getPrivateDataNoRaise(self); + + if (!a) + return self; int i; VALUE bitmapObj; diff --git a/binding/viewportelement-binding.h b/binding/viewportelement-binding.h index 209bc7da..fb9e916e 100644 --- a/binding/viewportelement-binding.h +++ b/binding/viewportelement-binding.h @@ -42,7 +42,7 @@ RB_METHOD(viewportElementGetViewport) } template -RB_METHOD(viewportElementSetViewport) +RB_METHOD_GUARD(viewportElementSetViewport) { RB_UNUSED_PARAM; @@ -62,6 +62,7 @@ RB_METHOD(viewportElementSetViewport) return viewportObj; } +RB_METHOD_GUARD_END template static C * diff --git a/binding/window-binding.cpp b/binding/window-binding.cpp index 2ba55207..601fef3d 100644 --- a/binding/window-binding.cpp +++ b/binding/window-binding.cpp @@ -44,7 +44,7 @@ RB_METHOD(windowInitialize) { return self; } -RB_METHOD(windowUpdate) { +RB_METHOD_GUARD(windowUpdate) { RB_UNUSED_PARAM; Window *w = getPrivateData(self); @@ -53,6 +53,7 @@ RB_METHOD(windowUpdate) { return Qnil; } +RB_METHOD_GUARD_END DEF_GFX_PROP_OBJ_REF(Window, Bitmap, Windowskin, "windowskin") DEF_GFX_PROP_OBJ_REF(Window, Bitmap, Contents, "contents") diff --git a/macos/views/SettingsMenuController.mm b/macos/views/SettingsMenuController.mm index 8900971d..2932aa1a 100644 --- a/macos/views/SettingsMenuController.mm +++ b/macos/views/SettingsMenuController.mm @@ -97,6 +97,7 @@ typedef NSMutableArray BindingIndexArray; -(void)closeWindow { [self setNotListening:true]; [_window close]; + SDL_RaiseWindow(shState->rtData().window); } -(SettingsMenu*)setWindow:(NSWindow*)window { diff --git a/macos/views/TouchBar.mm b/macos/views/TouchBar.mm index a92a9e13..bdff3a94 100644 --- a/macos/views/TouchBar.mm +++ b/macos/views/TouchBar.mm @@ -118,7 +118,9 @@ MKXPZTouchBar *_sharedTouchBar; if (fpsLabel) { int targetFrameRate = shState->graphics().getFrameRate(); dispatch_async(dispatch_get_main_queue(), ^{ - self->fpsLabel.stringValue = [NSString stringWithFormat:@"%@\n%i FPS (%i%%)", self.gameTitle, value, (int)((float)value / (float)targetFrameRate * 100)]; + @autoreleasepool { + self->fpsLabel.stringValue = [NSString stringWithFormat:@"%@\n%i FPS (%i%%)", self.gameTitle, value, (int)((float)value / (float)targetFrameRate * 100)]; + } }); } } diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index b2ca66c1..62ad9df5 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -2388,6 +2388,7 @@ int Bitmap::currentFrameI() const int Bitmap::addFrame(Bitmap &source, int position) { guardDisposed(); + source.guardDisposed(); GUARD_MEGA; diff --git a/src/display/graphics.cpp b/src/display/graphics.cpp index 204ae0d7..0f3c880e 100644 --- a/src/display/graphics.cpp +++ b/src/display/graphics.cpp @@ -1612,6 +1612,13 @@ void Graphics::reset() { setFrameRate(DEF_FRAMERATE); setBrightness(255); + + // Always update at least once to clear the screen + if (p->threadData->rqResetFinish) + update(); + else + repaintWait(p->threadData->rqResetFinish, false); + p->threadData->rqReset.clear(); } void Graphics::center() { diff --git a/src/eventthread.cpp b/src/eventthread.cpp index 18dc1128..2bd3b808 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -800,7 +800,9 @@ void EventThread::showMessageBox(const char *body, int flags) SDL_PushEvent(&event); /* Keep repainting screen while box is open */ - shState->graphics().repaintWait(msgBoxDone); + try{ + shState->graphics().repaintWait(msgBoxDone); + }catch(...){} /* Prevent endless loops */ resetInputStates(); } diff --git a/src/eventthread.h b/src/eventthread.h index 6879af99..1d746bdb 100644 --- a/src/eventthread.h +++ b/src/eventthread.h @@ -286,7 +286,9 @@ struct RGSSThreadData scale(scalingFactor), config(newconf), glContext(ctx) - {} + { + rqResetFinish.set(); + } }; #endif // EVENTTHREAD_H diff --git a/src/filesystem/filesystemImplApple.mm b/src/filesystem/filesystemImplApple.mm index 63141e29..f854922a 100644 --- a/src/filesystem/filesystemImplApple.mm +++ b/src/filesystem/filesystemImplApple.mm @@ -18,43 +18,54 @@ #define NSTOPATH(str) [NSFileManager.defaultManager fileSystemRepresentationWithPath:str] bool filesystemImpl::fileExists(const char *path) { - BOOL isDir; - return [NSFileManager.defaultManager fileExistsAtPath:PATHTONS(path) isDirectory: &isDir] && !isDir; + @autoreleasepool{ + BOOL isDir; + return [NSFileManager.defaultManager fileExistsAtPath:PATHTONS(path) isDirectory: &isDir] && !isDir; + } } std::string filesystemImpl::contentsOfFileAsString(const char *path) { - NSString *fileContents = [NSString stringWithContentsOfFile: PATHTONS(path)]; - if (fileContents == nil) - throw Exception(Exception::NoFileError, "Failed to read file at %s", path); - - return std::string(fileContents.UTF8String); - + @autoreleasepool { + NSString *fileContents = [NSString stringWithContentsOfFile: PATHTONS(path)]; + if (fileContents == nil) + throw Exception(Exception::NoFileError, "Failed to read file at %s", path); + + return std::string(fileContents.UTF8String); + } } bool filesystemImpl::setCurrentDirectory(const char *path) { - return [NSFileManager.defaultManager changeCurrentDirectoryPath: PATHTONS(path)]; + @autoreleasepool { + return [NSFileManager.defaultManager changeCurrentDirectoryPath: PATHTONS(path)]; + } } std::string filesystemImpl::getCurrentDirectory() { - return std::string(NSTOPATH(NSFileManager.defaultManager.currentDirectoryPath)); + @autoreleasepool { + return std::string(NSTOPATH(NSFileManager.defaultManager.currentDirectoryPath)); + } } std::string filesystemImpl::normalizePath(const char *path, bool preferred, bool absolute) { - NSString *nspath = [NSURL fileURLWithPath: PATHTONS(path)].URLByStandardizingPath.path; - NSString *pwd = [NSString stringWithFormat:@"%@/", NSFileManager.defaultManager.currentDirectoryPath]; - if (!absolute) { - nspath = [nspath stringByReplacingOccurrencesOfString:pwd withString:@""]; + @autoreleasepool { + NSString *nspath = [NSURL fileURLWithPath: PATHTONS(path)].URLByStandardizingPath.path; + NSString *pwd = [NSString stringWithFormat:@"%@/", NSFileManager.defaultManager.currentDirectoryPath]; + if (!absolute) { + nspath = [nspath stringByReplacingOccurrencesOfString:pwd withString:@""]; + } + nspath = [nspath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; + return std::string(NSTOPATH(nspath)); } - nspath = [nspath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; - return std::string(NSTOPATH(nspath)); } std::string filesystemImpl::getDefaultGameRoot() { - NSString *p = [NSString stringWithFormat: @"%@/%s", NSBundle.mainBundle.bundlePath, "Contents/Game"]; - return std::string(NSTOPATH(p)); + @autoreleasepool { + NSString *p = [NSString stringWithFormat: @"%@/%s", NSBundle.mainBundle.bundlePath, "Contents/Game"]; + return std::string(NSTOPATH(p)); + } } NSString *getPathForAsset_internal(const char *baseName, const char *ext) { @@ -73,51 +84,58 @@ NSString *getPathForAsset_internal(const char *baseName, const char *ext) { } std::string filesystemImpl::getPathForAsset(const char *baseName, const char *ext) { - NSString *assetPath = getPathForAsset_internal(baseName, ext); - if (assetPath == nil) - throw Exception(Exception::NoFileError, "Failed to find the asset named %s.%s", baseName, ext); - - return std::string(NSTOPATH(getPathForAsset_internal(baseName, ext))); + @autoreleasepool { + NSString *assetPath = getPathForAsset_internal(baseName, ext); + if (assetPath == nil) + throw Exception(Exception::NoFileError, "Failed to find the asset named %s.%s", baseName, ext); + + return std::string(NSTOPATH(getPathForAsset_internal(baseName, ext))); + } } std::string filesystemImpl::contentsOfAssetAsString(const char *baseName, const char *ext) { - NSString *path = getPathForAsset_internal(baseName, ext); - NSString *fileContents = [NSString stringWithContentsOfFile: path]; - - // This should never fail - if (fileContents == nil) - throw Exception(Exception::MKXPError, "Failed to read file at %s", path.UTF8String); - - return std::string(fileContents.UTF8String); - + @autoreleasepool { + NSString *path = getPathForAsset_internal(baseName, ext); + NSString *fileContents = [NSString stringWithContentsOfFile: path]; + + // This should never fail + if (fileContents == nil) + throw Exception(Exception::MKXPError, "Failed to read file at %s", path.UTF8String); + + return std::string(fileContents.UTF8String); + } } std::string filesystemImpl::getResourcePath() { - return std::string(NSTOPATH(NSBundle.mainBundle.resourcePath)); + @autoreleasepool { + return std::string(NSTOPATH(NSBundle.mainBundle.resourcePath)); + } } std::string filesystemImpl::selectPath(SDL_Window *win, const char *msg, const char *prompt) { - NSOpenPanel *panel = [NSOpenPanel openPanel]; - panel.canChooseDirectories = true; - panel.canChooseFiles = false; - - if (msg) panel.message = @(msg); - if (prompt) panel.prompt = @(prompt); - //panel.directoryURL = [NSURL fileURLWithPath:NSFileManager.defaultManager.currentDirectoryPath]; - - SDL_SysWMinfo windowinfo{}; - SDL_GetWindowWMInfo(win, &windowinfo); - - [panel beginSheetModalForWindow:windowinfo.info.cocoa.window completionHandler:^(NSModalResponse res){ - [NSApp stopModalWithCode:res]; - }]; - - [NSApp runModalForWindow:windowinfo.info.cocoa.window]; - - // The window needs to be brought to the front again after the OpenPanel closes - [windowinfo.info.cocoa.window makeKeyAndOrderFront:nil]; - if (panel.URLs.count > 0) - return std::string(NSTOPATH(panel.URLs[0].path)); - - return std::string(); + @autoreleasepool { + NSOpenPanel *panel = [NSOpenPanel openPanel]; + panel.canChooseDirectories = true; + panel.canChooseFiles = false; + + if (msg) panel.message = @(msg); + if (prompt) panel.prompt = @(prompt); + //panel.directoryURL = [NSURL fileURLWithPath:NSFileManager.defaultManager.currentDirectoryPath]; + + SDL_SysWMinfo windowinfo{}; + SDL_GetWindowWMInfo(win, &windowinfo); + + [panel beginSheetModalForWindow:windowinfo.info.cocoa.window completionHandler:^(NSModalResponse res){ + [NSApp stopModalWithCode:res]; + }]; + + [NSApp runModalForWindow:windowinfo.info.cocoa.window]; + + // The window needs to be brought to the front again after the OpenPanel closes + [windowinfo.info.cocoa.window makeKeyAndOrderFront:nil]; + if (panel.URLs.count > 0) + return std::string(NSTOPATH(panel.URLs[0].path)); + + return std::string(); + } } diff --git a/src/system/systemImplApple.mm b/src/system/systemImplApple.mm index bfbc98ba..f8316720 100644 --- a/src/system/systemImplApple.mm +++ b/src/system/systemImplApple.mm @@ -13,13 +13,17 @@ #import "SettingsMenuController.h" std::string systemImpl::getSystemLanguage() { - NSString *languageCode = NSLocale.currentLocale.languageCode; - NSString *countryCode = NSLocale.currentLocale.countryCode; - return std::string([NSString stringWithFormat:@"%@_%@", languageCode, countryCode].UTF8String); + @autoreleasepool { + NSString *languageCode = NSLocale.currentLocale.languageCode; + NSString *countryCode = NSLocale.currentLocale.countryCode; + return std::string([NSString stringWithFormat:@"%@_%@", languageCode, countryCode].UTF8String); + } } std::string systemImpl::getUserName() { - return std::string(NSUserName().UTF8String); + @autoreleasepool { + return std::string(NSUserName().UTF8String); + } } int systemImpl::getScalingFactor() { @@ -64,9 +68,11 @@ bool isMetalSupported() { } std::string getPlistValue(const char *key) { - NSString *hash = [[NSBundle mainBundle] objectForInfoDictionaryKey:@(key)]; - if (hash != nil) { - return std::string(hash.UTF8String); + @autoreleasepool { + NSString *hash = [[NSBundle mainBundle] objectForInfoDictionaryKey:@(key)]; + if (hash != nil) { + return std::string(hash.UTF8String); + } + return ""; } - return ""; } diff --git a/src/util/exception.h b/src/util/exception.h index 6f95b604..ae956000 100644 --- a/src/util/exception.h +++ b/src/util/exception.h @@ -31,12 +31,15 @@ struct Exception enum Type { RGSSError, + Reset, NoFileError, IOError, /* Already defined by ruby */ TypeError, ArgumentError, + SystemExit, + RuntimeError, /* New types introduced in mkxp */ PHYSFSError,