Merge pull request #207 from WaywardHeart/memory-leaks

Fix some more memory leaks and improve behavior of disposed objects
This commit is contained in:
Splendide Imaginarius 2024-09-03 01:36:48 +00:00 committed by GitHub
commit fa80e5b24a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 948 additions and 589 deletions

View file

@ -25,17 +25,18 @@
#include "exception.h" #include "exception.h"
#define DEF_PLAY_STOP_POS(entity) \ #define DEF_PLAY_STOP_POS(entity) \
RB_METHOD(audio_##entity##Play) \ RB_METHOD_GUARD(audio_##entity##Play) \
{ \ { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
const char *filename; \ const char *filename; \
int volume = 100; \ int volume = 100; \
int pitch = 100; \ int pitch = 100; \
double pos = 0.0; \ double pos = 0.0; \
rb_get_args(argc, argv, "z|iif", &filename, &volume, &pitch, &pos RB_ARG_END); \ rb_get_args(argc, argv, "z|iif", &filename, &volume, &pitch, &pos RB_ARG_END); \
GUARD_EXC( shState->audio().entity##Play(filename, volume, pitch, pos); ) \ shState->audio().entity##Play(filename, volume, pitch, pos); \
return Qnil; \ return Qnil; \
} \ } \
RB_METHOD_GUARD_END \
RB_METHOD(audio_##entity##Stop) \ RB_METHOD(audio_##entity##Stop) \
{ \ { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
@ -49,16 +50,17 @@
} }
#define DEF_PLAY_STOP(entity) \ #define DEF_PLAY_STOP(entity) \
RB_METHOD(audio_##entity##Play) \ RB_METHOD_GUARD(audio_##entity##Play) \
{ \ { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
const char *filename; \ const char *filename; \
int volume = 100; \ int volume = 100; \
int pitch = 100; \ int pitch = 100; \
rb_get_args(argc, argv, "z|ii", &filename, &volume, &pitch RB_ARG_END); \ 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; \ return Qnil; \
} \ } \
RB_METHOD_GUARD_END \
RB_METHOD(audio_##entity##Stop) \ RB_METHOD(audio_##entity##Stop) \
{ \ { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
@ -87,7 +89,7 @@ RB_METHOD(audio_##entity##Fade) \
#define MAYBE_NIL_TRACK(t) t == Qnil ? -127 : NUM2INT(t) #define MAYBE_NIL_TRACK(t) t == Qnil ? -127 : NUM2INT(t)
RB_METHOD(audio_bgmPlay) RB_METHOD_GUARD(audio_bgmPlay)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
const char *filename; const char *filename;
@ -96,9 +98,10 @@ RB_METHOD(audio_bgmPlay)
double pos = 0.0; double pos = 0.0;
VALUE track = Qnil; VALUE track = Qnil;
rb_get_args(argc, argv, "z|iifo", &filename, &volume, &pitch, &pos, &track RB_ARG_END); 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; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(audio_bgmStop) RB_METHOD(audio_bgmStop)
{ {
@ -117,25 +120,27 @@ RB_METHOD(audio_bgmPos)
return rb_float_new(shState->audio().bgmPos(MAYBE_NIL_TRACK(track))); return rb_float_new(shState->audio().bgmPos(MAYBE_NIL_TRACK(track)));
} }
RB_METHOD(audio_bgmGetVolume) RB_METHOD_GUARD(audio_bgmGetVolume)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE track = Qnil; VALUE track = Qnil;
rb_get_args(argc, argv, "|o", &track RB_ARG_END); rb_get_args(argc, argv, "|o", &track RB_ARG_END);
int ret = 0; 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); return rb_fix_new(ret);
} }
RB_METHOD_GUARD_END
RB_METHOD(audio_bgmSetVolume) RB_METHOD_GUARD(audio_bgmSetVolume)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
int volume; int volume;
VALUE track = Qnil; VALUE track = Qnil;
rb_get_args(argc, argv, "i|o", &volume, &track RB_ARG_END); 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; return Qnil;
} }
RB_METHOD_GUARD_END
DEF_PLAY_STOP_POS( bgs ) DEF_PLAY_STOP_POS( bgs )

View file

@ -315,21 +315,29 @@ static void printP(int argc, VALUE *argv, const char *convMethod,
} }
RB_METHOD(mriPrint) { RB_METHOD_GUARD(mriPrint) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
printP(argc, argv, "to_s", ""); printP(argc, argv, "to_s", "");
shState->checkShutdown();
shState->checkReset();
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(mriP) { RB_METHOD_GUARD(mriP) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
printP(argc, argv, "inspect", "\n"); printP(argc, argv, "inspect", "\n");
shState->checkShutdown();
shState->checkReset();
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(mkxpDelta) { RB_METHOD(mkxpDelta) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -528,14 +536,15 @@ RB_METHOD(mkxpSystemMemory) {
return INT2NUM(SDL_GetSystemRAM()); return INT2NUM(SDL_GetSystemRAM());
} }
RB_METHOD(mkxpReloadPathCache) { RB_METHOD_GUARD(mkxpReloadPathCache) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
GUARD_EXC(shState->fileSystem().reloadPathCache();); shState->fileSystem().reloadPathCache();
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(mkxpAddPath) { RB_METHOD_GUARD(mkxpAddPath) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE path, mountpoint, reload; VALUE path, mountpoint, reload;
@ -545,36 +554,32 @@ RB_METHOD(mkxpAddPath) {
const char *mp = (mountpoint == Qnil) ? 0 : RSTRING_PTR(mountpoint); const char *mp = (mountpoint == Qnil) ? 0 : RSTRING_PTR(mountpoint);
try { bool rl = true;
bool rl = true; if (reload != Qnil)
if (reload != Qnil) rb_bool_arg(reload, &rl);
rb_bool_arg(reload, &rl);
shState->fileSystem().addPath(RSTRING_PTR(path), mp, rl);
shState->fileSystem().addPath(RSTRING_PTR(path), mp, rl);
} catch (Exception &e) {
raiseRbExc(e);
}
return path; return path;
} }
RB_METHOD_GUARD_END
RB_METHOD(mkxpRemovePath) { RB_METHOD_GUARD(mkxpRemovePath) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE path, reload; VALUE path, reload;
rb_scan_args(argc, argv, "11", &path, &reload); rb_scan_args(argc, argv, "11", &path, &reload);
SafeStringValue(path); SafeStringValue(path);
try { bool rl = true;
bool rl = true; if (reload != Qnil)
if (reload != Qnil) rb_bool_arg(reload, &rl);
rb_bool_arg(reload, &rl);
shState->fileSystem().removePath(RSTRING_PTR(path), rl);
shState->fileSystem().removePath(RSTRING_PTR(path), rl);
} catch (Exception &e) {
raiseRbExc(e);
}
return path; return path;
} }
RB_METHOD_GUARD_END
RB_METHOD(mkxpFileExists) { RB_METHOD(mkxpFileExists) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -601,24 +606,25 @@ RB_METHOD(mkxpSetDefaultFontFamily) {
return Qnil; return Qnil;
} }
RB_METHOD(mkxpStringToUTF8) { RB_METHOD_GUARD(mkxpStringToUTF8) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
std::string ret(RSTRING_PTR(self), RSTRING_LEN(self)); 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()); 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_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
std::string ret(RSTRING_PTR(self), RSTRING_LEN(self)); 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()); rb_str_resize(self, ret.length());
memcpy(RSTRING_PTR(self), ret.c_str(), RSTRING_LEN(self)); memcpy(RSTRING_PTR(self), ret.c_str(), RSTRING_LEN(self));
@ -629,6 +635,7 @@ RB_METHOD(mkxpStringToUTF8Bang) {
return self; return self;
} }
RB_METHOD_GUARD_END
#ifdef __APPLE__ #ifdef __APPLE__
#define OPENCMD "open " #define OPENCMD "open "
@ -641,7 +648,7 @@ RB_METHOD(mkxpStringToUTF8Bang) {
#define OPENARGS "" #define OPENARGS ""
#endif #endif
RB_METHOD(mkxpLaunch) { RB_METHOD_GUARD(mkxpLaunch) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE cmdname, args; VALUE cmdname, args;
@ -674,11 +681,12 @@ RB_METHOD(mkxpLaunch) {
} }
if (std::system(command.c_str()) != 0) { 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; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
json5pp::value loadUserSettings() { json5pp::value loadUserSettings() {
json5pp::value ret; json5pp::value ret;
@ -722,7 +730,7 @@ RB_METHOD(mkxpGetJSONSetting) {
} }
RB_METHOD(mkxpSetJSONSetting) { RB_METHOD_GUARD(mkxpSetJSONSetting) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE sname, svalue; VALUE sname, svalue;
@ -736,6 +744,7 @@ RB_METHOD(mkxpSetJSONSetting) {
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(mkxpGetAllJSONSettings) { RB_METHOD(mkxpGetAllJSONSettings) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -756,15 +765,21 @@ static VALUE rgssMainRescue(VALUE arg, VALUE exc) {
return Qnil; return Qnil;
} }
static void processReset() { static bool processReset(bool rubyExc) {
shState->graphics().reset(); const char *str = "Audio.__reset__; Graphics.__reset__;";
shState->audio().reset();
if (rubyExc) {
shState->rtData().rqReset.clear(); rb_eval_string(str);
shState->graphics().repaintWait(shState->rtData().rqResetFinish, false); } else {
int state;
rb_eval_string_protect(str, &state);
return state;
}
return 0;
} }
RB_METHOD(mriRgssMain) { RB_METHOD_GUARD(mriRgssMain) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
while (true) { while (true) {
@ -782,15 +797,16 @@ RB_METHOD(mriRgssMain) {
break; break;
if (rb_obj_class(exc) == getRbData()->exc[Reset]) if (rb_obj_class(exc) == getRbData()->exc[Reset])
processReset(); processReset(true);
else else
rb_exc_raise(exc); rb_exc_raise(exc);
} }
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(mriRgssStop) { RB_METHOD_GUARD(mriRgssStop) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
while (true) while (true)
@ -798,6 +814,7 @@ RB_METHOD(mriRgssStop) {
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(_kernelCaller) { RB_METHOD(_kernelCaller) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -1037,7 +1054,8 @@ static void runRMXPScripts(BacktraceData &btData) {
if (rb_obj_class(exc) != getRbData()->exc[Reset]) if (rb_obj_class(exc) != getRbData()->exc[Reset])
break; break;
processReset(); if (processReset(false))
break;
} }
} }
@ -1246,6 +1264,6 @@ static void mriBindingExecute() {
shState->rtData().rqTermAck.set(); 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, " "); }

View file

@ -50,28 +50,34 @@ RbData::RbData() {
exc[IOError] = rb_eIOError; exc[IOError] = rb_eIOError;
exc[TypeError] = rb_eTypeError; exc[TypeError] = rb_eTypeError;
exc[ArgumentError] = rb_eArgError; exc[ArgumentError] = rb_eArgError;
exc[SystemExit] = rb_eSystemExit;
exc[RuntimeError] = rb_eRuntimeError;
} }
RbData::~RbData() {} RbData::~RbData() {}
/* Indexed with Exception::Type */ /* Indexed with Exception::Type */
static const RbException excToRbExc[] = { const RbException excToRbExc[] = {
RGSS, /* RGSSError */ RGSS, /* RGSSError */
ErrnoENOENT, /* NoFileError */ Reset, /* Reset/RGSSReset */
ErrnoENOENT, /* NoFileError */
IOError, IOError,
TypeError, ArgumentError, TypeError, ArgumentError, SystemExit, RuntimeError,
PHYSFS, /* PHYSFSError */ PHYSFS, /* PHYSFSError */
SDL, /* SDLError */ SDL, /* SDLError */
MKXP /* MKXPError */ MKXP /* MKXPError */
}; };
void raiseRbExc(const Exception &exc) { void raiseRbExc(Exception *exc) {
VALUE str = rb_str_new2(exc->msg.c_str());
RbData *data = getRbData(); 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) { void raiseDisposedAccess(VALUE self) {
@ -89,207 +95,258 @@ void raiseDisposedAccess(VALUE self) {
} }
int rb_get_args(int argc, VALUE *argv, const char *format, ...) { int rb_get_args(int argc, VALUE *argv, const char *format, ...) {
char c; Exception *exc = 0;
VALUE *arg = argv; try{
va_list ap; char c;
bool opt = false; VALUE *arg = argv;
int argI = 0; va_list ap;
bool opt = false;
int argI = 0;
va_start(ap, format); va_start(ap, format);
while ((c = *format++)) { while ((c = *format++)) {
switch (c) { switch (c) {
case '|': case '|':
break; break;
default: default:
// FIXME print num of needed args vs provided // FIXME print num of needed args vs provided
if (argc <= argI && !opt) if (argc <= argI && !opt)
rb_raise(rb_eArgError, "wrong number of arguments"); rb_raise(rb_eArgError, "wrong number of arguments");
break; break;
} }
if (argI >= argc)
break;
switch (c) {
case 'o': {
if (argI >= argc) if (argI >= argc)
break; break;
VALUE *obj = va_arg(ap, VALUE *); switch (c) {
case 'o': {
if (argI >= argc)
break;
*obj = *arg++; VALUE *obj = va_arg(ap, VALUE *);
++argI;
break; *obj = *arg++;
} ++argI;
case 'S': { break;
if (argI >= argc) }
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; break;
VALUE *str = va_arg(ap, VALUE *); default:
VALUE tmp = *arg; rb_raise(rb_eFatal, "invalid argument specifier %c", c);
}
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;
default:
rb_raise(rb_eFatal, "invalid argument specifier %c", c);
}
}
#ifndef NDEBUG #ifndef NDEBUG
/* Pop remaining arg pointers off /* Pop remaining arg pointers off
* the stack to check for RB_ARG_END */ * the stack to check for RB_ARG_END */
format--; format--;
while ((c = *format++)) { while ((c = *format++)) {
switch (c) { switch (c) {
case 'o': case 'o':
case 'S': case 'S':
va_arg(ap, VALUE *); va_arg(ap, VALUE *);
break; break;
case 's': case 's':
va_arg(ap, const char **); va_arg(ap, const char **);
va_arg(ap, int *); va_arg(ap, int *);
break; break;
case 'z': case 'z':
va_arg(ap, const char **); va_arg(ap, const char **);
break; break;
case 'f': case 'f':
va_arg(ap, double *); va_arg(ap, double *);
break; break;
case 'i': case 'i':
va_arg(ap, int *); va_arg(ap, int *);
break; break;
case 'b': case 'b':
va_arg(ap, bool *); va_arg(ap, bool *);
break; break;
}
} }
}
// FIXME print num of needed args vs provided // FIXME print num of needed args vs provided
if (!c && argc > argI) if (!c && argc > argI)
rb_raise(rb_eArgError, "wrong number of arguments"); rb_raise(rb_eArgError, "wrong number of arguments");
/* Verify correct termination */ /* Verify correct termination */
void *argEnd = va_arg(ap, void *); void *argEnd = va_arg(ap, void *);
(void)argEnd; (void)argEnd;
assert(argEnd == RB_ARG_END_VAL); assert(argEnd == RB_ARG_END_VAL);
#endif #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 <ruby/thread.h>
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

View file

@ -55,6 +55,8 @@ enum RbException {
TypeError, TypeError,
ArgumentError, ArgumentError,
SystemExit,
RuntimeError,
RbExceptionsMax RbExceptionsMax
}; };
@ -73,7 +75,12 @@ RbData *getRbData();
struct Exception; 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 #if RAPI_FULL > 187
#define DECL_TYPE(Klass) extern rb_data_type_t Klass##Type #define DECL_TYPE(Klass) extern rb_data_type_t Klass##Type
@ -190,20 +197,50 @@ template <rb_data_type_t *rbType> static VALUE classAllocate(VALUE klass) {
} }
#endif #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 <class C> static void freeInstance(void *inst) { template <class C> static void freeInstance(void *inst) {
delete static_cast<C *>(inst); delete static_cast<C *>(inst);
} }
void raiseDisposedAccess(VALUE self); void raiseDisposedAccess(VALUE self);
template <class C> inline C *getPrivateData(VALUE self) { template <class C> inline C *getPrivateDataNoRaise(VALUE self) {
#if RAPI_FULL > 187 #if RAPI_FULL > 187
C *c = static_cast<C *>(RTYPEDDATA_DATA(self)); return static_cast<C *>(RTYPEDDATA_DATA(self));
#else #else
C *c = static_cast<C *>(DATA_PTR(self)); return static_cast<C *>(DATA_PTR(self));
#endif #endif
}
template <class C> inline C *getPrivateData(VALUE self) {
C *c = getPrivateDataNoRaise<C>(self);
if (!c) { 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; return c;
} }
@ -238,9 +275,28 @@ getPrivateDataCheck(VALUE self, const char *type)
} }
static inline void setPrivateData(VALUE self, void *p) { 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 #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; RTYPEDDATA_DATA(self) = p;
#else #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; DATA_PTR(self) = p;
#endif #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); rb_define_module_function(module, name, RUBY_METHOD_FUNC(func), -1);
} }
#define GUARD_EXC(exp) \ #define GFX_GUARD_EXC(exp) \
{ \ { \
try { \ GFX_LOCK; \
try { \
exp \ exp \
} catch (const Exception &exc) { \ } catch (const Exception &exc) { \
raiseRbExc(exc); \ GFX_UNLOCK; \
} \ throw exc; \
} } \
GFX_UNLOCK; \
#define GFX_GUARD_EXC(exp) \
{\
GFX_LOCK; \
try {\
exp \
} catch (const Exception &exc) {\
GFX_UNLOCK; \
raiseRbExc(exc); \
}\
GFX_UNLOCK;\
} }
@ -338,7 +385,7 @@ static inline VALUE objectLoad(int argc, VALUE *argv, VALUE self) {
C *c = 0; C *c = 0;
GUARD_EXC(c = C::deserialize(data, dataLen);); c = C::deserialize(data, dataLen);
setPrivateData(obj, c); setPrivateData(obj, c);
@ -358,7 +405,7 @@ inline void rb_float_arg(VALUE arg, double *out, int argPos = 0) {
break; break;
default: 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; break;
default: 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; break;
default: 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) { inline void rb_check_argc(int actual, int expected) {
if (actual != expected) if (actual != expected)
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", actual, 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; \ (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) \ #define MARSH_LOAD_FUN(Typ) \
RB_METHOD(Typ##Load) { return objectLoad<Typ>(argc, argv, self); } RB_METHOD_GUARD(Typ##Load) { return objectLoad<Typ>(argc, argv, self); } RB_METHOD_GUARD_END
#define INITCOPY_FUN(Klass) \ #define INITCOPY_FUN(Klass) \
RB_METHOD(Klass##InitializeCopy) { \ RB_METHOD_GUARD(Klass##InitializeCopy) { \
VALUE origObj; \ VALUE origObj; \
rb_get_args(argc, argv, "o", &origObj RB_ARG_END); \ rb_get_args(argc, argv, "o", &origObj RB_ARG_END); \
if (!OBJ_INIT_COPY(self, origObj)) /* When would this fail??*/ \ if (!OBJ_INIT_COPY(self, origObj)) /* When would this fail??*/ \
return self; \ return self; \
Klass *orig = getPrivateData<Klass>(origObj); \ Klass *orig = getPrivateData<Klass>(origObj); \
Klass *k = 0; \ Klass *k = 0; \
GUARD_EXC(k = new Klass(*orig);) \ k = new Klass(*orig); \
setPrivateData(self, k); \ setPrivateData(self, k); \
return self; \ return self; \
} } \
RB_METHOD_GUARD_END
/* Object property which is copied by reference, with allowed NIL /* Object property which is copied by reference, with allowed NIL
* FIXME: Getter assumes prop is disposable, * FIXME: Getter assumes prop is disposable,
@ -461,7 +529,7 @@ RB_METHOD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
@ -471,17 +539,18 @@ if (NIL_P(propObj)) \
prop = 0; \ prop = 0; \
else \ else \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \ prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GUARD_EXC(k->set##PropName(prop);) \ k->set##PropName(prop) \
rb_iv_set(self, prop_iv, propObj); \ rb_iv_set(self, prop_iv, propObj); \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#else #else
#define DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \ #define DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \
RB_METHOD(Klass##Get##PropName) { \ RB_METHOD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
@ -491,10 +560,11 @@ if (NIL_P(propObj)) \
prop = 0; \ prop = 0; \
else \ else \
prop = getPrivateDataCheck<PropKlass>(propObj, #PropKlass); \ prop = getPrivateDataCheck<PropKlass>(propObj, #PropKlass); \
GUARD_EXC(k->set##PropName(prop);) \ k->set##PropName(prop) \
rb_iv_set(self, prop_iv, propObj); \ rb_iv_set(self, prop_iv, propObj); \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#endif #endif
/* Object property which is copied by value, not reference */ /* Object property which is copied by value, not reference */
@ -505,15 +575,16 @@ RB_UNUSED_PARAM; \
checkDisposed<Klass>(self); \ checkDisposed<Klass>(self); \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
VALUE propObj = *argv; \ VALUE propObj = *argv; \
PropKlass *prop; \ PropKlass *prop; \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \ prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GUARD_EXC(k->set##PropName(*prop);) \ k->set##PropName(*prop); \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#else #else
#define DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ #define DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \
RB_METHOD(Klass##Get##PropName) { \ RB_METHOD(Klass##Get##PropName) { \
@ -521,33 +592,36 @@ RB_UNUSED_PARAM; \
checkDisposed<Klass>(self); \ checkDisposed<Klass>(self); \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
VALUE propObj = *argv; \ VALUE propObj = *argv; \
PropKlass *prop; \ PropKlass *prop; \
prop = getPrivateDataCheck<PropKlass>(propObj, #PropKlass); \ prop = getPrivateDataCheck<PropKlass>(propObj, #PropKlass); \
GUARD_EXC(k->set##PropName(*prop);) \ k->set##PropName(*prop); \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#endif #endif
#define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \ #define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \
RB_METHOD(Klass##Get##PropName) { \ RB_METHOD_GUARD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
type value = 0; \ type value = 0; \
GUARD_EXC(value = k->get##PropName();) \ value = k->get##PropName(); \
return value_fun(value); \ return value_fun(value); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD_END \
RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
type value; \ type value; \
rb_##arg_fun##_arg(*argv, &value); \ rb_##arg_fun##_arg(*argv, &value); \
GUARD_EXC(k->set##PropName(value);) \ k->set##PropName(value); \
return *argv; \ return *argv; \
} } \
RB_METHOD_GUARD_END
#define DEF_PROP_I(Klass, PropName) \ #define DEF_PROP_I(Klass, PropName) \
DEF_PROP(Klass, int, PropName, int, rb_fix_new) DEF_PROP(Klass, int, PropName, int, rb_fix_new)
@ -573,7 +647,7 @@ RB_METHOD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
@ -586,7 +660,8 @@ prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GFX_GUARD_EXC(k->set##PropName(prop);) \ GFX_GUARD_EXC(k->set##PropName(prop);) \
rb_iv_set(self, prop_iv, propObj); \ rb_iv_set(self, prop_iv, propObj); \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#else #else
#define DEF_GFX_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \ #define DEF_GFX_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \
DEF_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<Klass>(self); \ checkDisposed<Klass>(self); \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
VALUE propObj = *argv; \ VALUE propObj = *argv; \
@ -608,28 +683,31 @@ PropKlass *prop; \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \ prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GFX_GUARD_EXC(k->set##PropName(*prop);) \ GFX_GUARD_EXC(k->set##PropName(*prop);) \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#else #else
#define DEF_GFX_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ #define DEF_GFX_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \
DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv)
#endif #endif
#define DEF_GFX_PROP(Klass, type, PropName, arg_fun, value_fun) \ #define DEF_GFX_PROP(Klass, type, PropName, arg_fun, value_fun) \
RB_METHOD(Klass##Get##PropName) { \ RB_METHOD_GUARD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
type value = 0; \ type value = 0; \
GUARD_EXC(value = k->get##PropName();) \ value = k->get##PropName(); \
return value_fun(value); \ return value_fun(value); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD_END \
RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
type value; \ type value; \
rb_##arg_fun##_arg(*argv, &value); \ rb_##arg_fun##_arg(*argv, &value); \
GFX_GUARD_EXC(k->set##PropName(value);) \ GFX_GUARD_EXC(k->set##PropName(value);) \
return *argv; \ return *argv; \
} } \
RB_METHOD_GUARD_END
#define DEF_GFX_PROP_I(Klass, PropName) \ #define DEF_GFX_PROP_I(Klass, PropName) \
DEF_GFX_PROP(Klass, int, PropName, int, rb_fix_new) DEF_GFX_PROP(Klass, int, PropName, int, rb_fix_new)

View file

@ -64,7 +64,7 @@ void bitmapInitProps(Bitmap *b, VALUE self) {
b->setInitFont(font); b->setInitFont(font);
} }
RB_METHOD(bitmapInitialize) { RB_METHOD_GUARD(bitmapInitialize) {
Bitmap *b = 0; Bitmap *b = 0;
if (argc == 1) { if (argc == 1) {
@ -84,45 +84,49 @@ RB_METHOD(bitmapInitialize) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapWidth) { RB_METHOD_GUARD(bitmapWidth) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int value = 0; int value = 0;
GUARD_EXC(value = b->width();); value = b->width();
return INT2FIX(value); return INT2FIX(value);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapHeight) { RB_METHOD_GUARD(bitmapHeight) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int value = 0; int value = 0;
GUARD_EXC(value = b->height();); value = b->height();
return INT2FIX(value); return INT2FIX(value);
} }
RB_METHOD_GUARD_END
DEF_GFX_PROP_OBJ_REF(Bitmap, Bitmap, Hires, "hires") DEF_GFX_PROP_OBJ_REF(Bitmap, Bitmap, Hires, "hires")
RB_METHOD(bitmapRect) { RB_METHOD_GUARD(bitmapRect) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
IntRect rect; IntRect rect;
GUARD_EXC(rect = b->rect();); rect = b->rect();
Rect *r = new Rect(rect); Rect *r = new Rect(rect);
return wrapObject(r, RectType); return wrapObject(r, RectType);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapBlt) { RB_METHOD_GUARD(bitmapBlt) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int x, y; int x, y;
@ -137,14 +141,17 @@ RB_METHOD(bitmapBlt) {
&opacity RB_ARG_END); &opacity RB_ARG_END);
src = getPrivateDataCheck<Bitmap>(srcObj, BitmapType); src = getPrivateDataCheck<Bitmap>(srcObj, BitmapType);
srcRect = getPrivateDataCheck<Rect>(srcRectObj, RectType); if (src) {
srcRect = getPrivateDataCheck<Rect>(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; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapStretchBlt) { RB_METHOD_GUARD(bitmapStretchBlt) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
VALUE destRectObj; VALUE destRectObj;
@ -159,16 +166,19 @@ RB_METHOD(bitmapStretchBlt) {
&opacity RB_ARG_END); &opacity RB_ARG_END);
src = getPrivateDataCheck<Bitmap>(srcObj, BitmapType); src = getPrivateDataCheck<Bitmap>(srcObj, BitmapType);
destRect = getPrivateDataCheck<Rect>(destRectObj, RectType); if (src) {
srcRect = getPrivateDataCheck<Rect>(srcRectObj, RectType); destRect = getPrivateDataCheck<Rect>(destRectObj, RectType);
srcRect = getPrivateDataCheck<Rect>(srcRectObj, RectType);
GFX_GUARD_EXC(b->stretchBlt(destRect->toIntRect(), *src, srcRect->toIntRect(),
opacity);); GFX_GUARD_EXC(b->stretchBlt(destRect->toIntRect(), *src, srcRect->toIntRect(),
opacity););
}
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapFillRect) { RB_METHOD_GUARD(bitmapFillRect) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
VALUE colorObj; VALUE colorObj;
@ -197,8 +207,9 @@ RB_METHOD(bitmapFillRect) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapClear) { RB_METHOD_GUARD(bitmapClear) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
@ -207,8 +218,9 @@ RB_METHOD(bitmapClear) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetPixel) { RB_METHOD_GUARD(bitmapGetPixel) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int x, y; int x, y;
@ -216,14 +228,18 @@ RB_METHOD(bitmapGetPixel) {
rb_get_args(argc, argv, "ii", &x, &y RB_ARG_END); rb_get_args(argc, argv, "ii", &x, &y RB_ARG_END);
Color value; 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); Color *color = new Color(value);
return wrapObject(color, ColorType); return wrapObject(color, ColorType);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetPixel) { RB_METHOD_GUARD(bitmapSetPixel) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int x, y; int x, y;
@ -239,8 +255,9 @@ RB_METHOD(bitmapSetPixel) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapHueChange) { RB_METHOD_GUARD(bitmapHueChange) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int hue; int hue;
@ -251,8 +268,9 @@ RB_METHOD(bitmapHueChange) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapDrawText) { RB_METHOD_GUARD(bitmapDrawText) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
const char *str; const char *str;
@ -293,8 +311,9 @@ RB_METHOD(bitmapDrawText) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapTextSize) { RB_METHOD_GUARD(bitmapTextSize) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
const char *str; const char *str;
@ -309,16 +328,50 @@ RB_METHOD(bitmapTextSize) {
} }
IntRect value; IntRect value;
GUARD_EXC(value = b->textSize(str);); value = b->textSize(str);
Rect *rect = new Rect(value); Rect *rect = new Rect(value);
return wrapObject(rect, RectType); return wrapObject(rect, RectType);
} }
RB_METHOD_GUARD_END
DEF_GFX_PROP_OBJ_VAL(Bitmap, Font, Font, "font") RB_METHOD(BitmapGetFont) {
RB_UNUSED_PARAM;
checkDisposed<Bitmap>(self);
return rb_iv_get(self, "font");
}
RB_METHOD_GUARD(BitmapSetFont) {
rb_check_argc(argc, 1);
Bitmap *b = getPrivateData<Bitmap>(self);
VALUE propObj = *argv;
Font *prop = getPrivateDataCheck<Font>(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<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
VALUE color1Obj, color2Obj; VALUE color1Obj, color2Obj;
@ -353,8 +406,9 @@ RB_METHOD(bitmapGradientFillRect) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapClearRect) { RB_METHOD_GUARD(bitmapClearRect) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
if (argc == 1) { if (argc == 1) {
@ -376,33 +430,32 @@ RB_METHOD(bitmapClearRect) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapBlur) { RB_METHOD_GUARD(bitmapBlur) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
GFX_LOCK; GFX_GUARD_EXC( b->blur(); );
b->blur();
GFX_UNLOCK;
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapRadialBlur) { RB_METHOD_GUARD(bitmapRadialBlur) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int angle, divisions; int angle, divisions;
rb_get_args(argc, argv, "ii", &angle, &divisions RB_ARG_END); rb_get_args(argc, argv, "ii", &angle, &divisions RB_ARG_END);
GFX_LOCK; GFX_GUARD_EXC( b->radialBlur(angle, divisions); );
b->radialBlur(angle, divisions);
GFX_UNLOCK;
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetRawData) { RB_METHOD_GUARD(bitmapGetRawData) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
@ -413,8 +466,9 @@ RB_METHOD(bitmapGetRawData) {
return ret; return ret;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetRawData) { RB_METHOD_GUARD(bitmapSetRawData) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE str; VALUE str;
@ -427,8 +481,9 @@ RB_METHOD(bitmapSetRawData) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSaveToFile) { RB_METHOD_GUARD(bitmapSaveToFile) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE str; VALUE str;
@ -441,8 +496,9 @@ RB_METHOD(bitmapSaveToFile) {
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetMega){ RB_METHOD_GUARD(bitmapGetMega){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -455,8 +511,9 @@ RB_METHOD(bitmapGetMega){
return ret; return ret;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetAnimated){ RB_METHOD_GUARD(bitmapGetAnimated){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -469,8 +526,9 @@ RB_METHOD(bitmapGetAnimated){
return ret; return ret;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetPlaying){ RB_METHOD_GUARD(bitmapGetPlaying){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -479,8 +537,9 @@ RB_METHOD(bitmapGetPlaying){
return rb_bool_new(b->isPlaying()); return rb_bool_new(b->isPlaying());
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetPlaying){ RB_METHOD_GUARD(bitmapSetPlaying){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
bool play; bool play;
@ -493,8 +552,9 @@ RB_METHOD(bitmapSetPlaying){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapPlay){ RB_METHOD_GUARD(bitmapPlay){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -504,8 +564,9 @@ RB_METHOD(bitmapPlay){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapStop){ RB_METHOD_GUARD(bitmapStop){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -515,8 +576,9 @@ RB_METHOD(bitmapStop){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGotoStop){ RB_METHOD_GUARD(bitmapGotoStop){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
int frame; int frame;
@ -529,8 +591,9 @@ RB_METHOD(bitmapGotoStop){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGotoPlay){ RB_METHOD_GUARD(bitmapGotoPlay){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
int frame; int frame;
@ -543,8 +606,9 @@ RB_METHOD(bitmapGotoPlay){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapFrames){ RB_METHOD_GUARD(bitmapFrames){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -553,8 +617,9 @@ RB_METHOD(bitmapFrames){
return INT2NUM(b->numFrames()); return INT2NUM(b->numFrames());
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapCurrentFrame){ RB_METHOD_GUARD(bitmapCurrentFrame){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -563,8 +628,9 @@ RB_METHOD(bitmapCurrentFrame){
return INT2NUM(b->currentFrameI()); return INT2NUM(b->currentFrameI());
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapAddFrame){ RB_METHOD_GUARD(bitmapAddFrame){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE srcBitmap; VALUE srcBitmap;
@ -573,6 +639,8 @@ RB_METHOD(bitmapAddFrame){
rb_scan_args(argc, argv, "11", &srcBitmap, &position); rb_scan_args(argc, argv, "11", &srcBitmap, &position);
Bitmap *src = getPrivateDataCheck<Bitmap>(srcBitmap, BitmapType); Bitmap *src = getPrivateDataCheck<Bitmap>(srcBitmap, BitmapType);
if (!src)
raiseDisposedAccess(srcBitmap);
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
@ -588,8 +656,9 @@ RB_METHOD(bitmapAddFrame){
return INT2NUM(ret); return INT2NUM(ret);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapRemoveFrame){ RB_METHOD_GUARD(bitmapRemoveFrame){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE position; VALUE position;
@ -608,8 +677,9 @@ RB_METHOD(bitmapRemoveFrame){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapNextFrame){ RB_METHOD_GUARD(bitmapNextFrame){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -620,8 +690,9 @@ RB_METHOD(bitmapNextFrame){
return INT2NUM(b->currentFrameI()); return INT2NUM(b->currentFrameI());
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapPreviousFrame){ RB_METHOD_GUARD(bitmapPreviousFrame){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -632,8 +703,9 @@ RB_METHOD(bitmapPreviousFrame){
return INT2NUM(b->currentFrameI()); return INT2NUM(b->currentFrameI());
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetFPS){ RB_METHOD_GUARD(bitmapSetFPS){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE fps; VALUE fps;
@ -652,8 +724,9 @@ RB_METHOD(bitmapSetFPS){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetFPS){ RB_METHOD_GUARD(bitmapGetFPS){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -662,12 +735,13 @@ RB_METHOD(bitmapGetFPS){
float ret; float ret;
GUARD_EXC(ret = b->getAnimationFPS();); ret = b->getAnimationFPS();
return rb_float_new(ret); return rb_float_new(ret);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetLooping){ RB_METHOD_GUARD(bitmapSetLooping){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
bool loop; bool loop;
@ -679,8 +753,9 @@ RB_METHOD(bitmapSetLooping){
return rb_bool_new(loop); return rb_bool_new(loop);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetLooping){ RB_METHOD_GUARD(bitmapGetLooping){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -688,12 +763,13 @@ RB_METHOD(bitmapGetLooping){
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
bool ret; bool ret;
GUARD_EXC(ret = b->getLooping();); ret = b->getLooping();
return rb_bool_new(ret); return rb_bool_new(ret);
} }
RB_METHOD_GUARD_END
// Captures the Bitmap's current frame data to a new Bitmap // Captures the Bitmap's current frame data to a new Bitmap
RB_METHOD(bitmapSnapToBitmap) { RB_METHOD_GUARD(bitmapSnapToBitmap) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE position; VALUE position;
@ -713,6 +789,7 @@ RB_METHOD(bitmapSnapToBitmap) {
return ret; return ret;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetMaxSize){ RB_METHOD(bitmapGetMaxSize){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -722,7 +799,7 @@ RB_METHOD(bitmapGetMaxSize){
return INT2NUM(Bitmap::maxSize()); return INT2NUM(Bitmap::maxSize());
} }
RB_METHOD(bitmapInitializeCopy) { RB_METHOD_GUARD(bitmapInitializeCopy) {
rb_check_argc(argc, 1); rb_check_argc(argc, 1);
VALUE origObj = argv[0]; VALUE origObj = argv[0];
@ -740,6 +817,7 @@ RB_METHOD(bitmapInitializeCopy) {
return self; return self;
} }
RB_METHOD_GUARD_END
void bitmapBindingInit() { void bitmapBindingInit() {
VALUE klass = rb_define_class("Bitmap", rb_cObject); VALUE klass = rb_define_class("Bitmap", rb_cObject);

View file

@ -32,7 +32,7 @@
} \ } \
} }
RB_METHOD(CUSLSetStat) { RB_METHOD_GUARD(CUSLSetStat) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE name, stat; VALUE name, stat;
@ -47,11 +47,12 @@ RB_METHOD(CUSLSetStat) {
STEAMSHIM_setStatI(RSTRING_PTR(name), (int)NUM2INT(stat)); STEAMSHIM_setStatI(RSTRING_PTR(name), (int)NUM2INT(stat));
STEAMSHIM_GET_OK(SHIMEVENT_SETSTATI, ret); STEAMSHIM_GET_OK(SHIMEVENT_SETSTATI, ret);
} else { } else {
rb_raise(rb_eTypeError, throw Exception(Exception::TypeError,
"Statistic value must be either an integer or float."); "Statistic value must be either an integer or float.");
} }
return rb_bool_new(ret); return rb_bool_new(ret);
} }
RB_METHOD_GUARD_END
RB_METHOD(CUSLGetStatI) { RB_METHOD(CUSLGetStatI) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;

View file

@ -30,8 +30,8 @@ template<class C>
RB_METHOD(disposableDispose) RB_METHOD(disposableDispose)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
C *d = getPrivateData<C>(self); C *d = getPrivateDataNoRaise<C>(self);
if (!d) if (!d)
return Qnil; return Qnil;
@ -46,7 +46,7 @@ RB_METHOD(disposableIsDisposed)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
C *d = getPrivateData<C>(self); C *d = getPrivateDataNoRaise<C>(self);
if (!d) if (!d)
return Qtrue; return Qtrue;

View file

@ -107,7 +107,13 @@ EQUAL_FUN(Rect)
rb_get_args(argc, argv, param_t_s, &p1, &p2, &p3, &p4 RB_ARG_END); \ rb_get_args(argc, argv, param_t_s, &p1, &p2, &p3, &p4 RB_ARG_END); \
k = new Klass(p1, p2, p3, p4); \ k = new Klass(p1, p2, p3, p4); \
} \ } \
Klass *orig = getPrivateDataNoRaise<Klass>(self); \
if (orig) { \
*orig = *k; \
delete k; \
} else { \
setPrivateData(self, k); \ setPrivateData(self, k); \
} \
return self; \ return self; \
} }
@ -208,11 +214,14 @@ INITCOPY_FUN(Tone)
INITCOPY_FUN(Color) INITCOPY_FUN(Color)
INITCOPY_FUN(Rect) 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) \ #define INIT_BIND(Klass) \
{ \ { \
klass = rb_define_class(#Klass, rb_cObject); \ 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); \ rb_define_class_method(klass, "_load", Klass##Load); \
serializableBindingInit<Klass>(klass); \ serializableBindingInit<Klass>(klass); \
_rb_define_method(klass, "initialize", Klass##Initialize); \ _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, "to_s", Klass##Stringify); \
_rb_define_method(klass, "inspect", 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>(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) \ #define MRB_ATTR_R(Class, attr) \
mrb_define_method(mrb, klass, #attr, Class##Get_##attr, MRB_ARGS_NONE()) mrb_define_method(mrb, klass, #attr, Class##Get_##attr, MRB_ARGS_NONE())

View file

@ -52,6 +52,10 @@ DEF_ALLOCFUNC_CUSTOMFREE(FileInt, fileIntFreeInstance);
#endif #endif
static VALUE fileIntForPath(const char *path, bool rubyExc) { 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(); SDL_RWops *ops = SDL_AllocRW();
try { try {
@ -59,16 +63,9 @@ static VALUE fileIntForPath(const char *path, bool rubyExc) {
} catch (const Exception &e) { } catch (const Exception &e) {
SDL_FreeRW(ops); SDL_FreeRW(ops);
if (rubyExc) throw e;
raiseRbExc(e);
else
throw e;
} }
VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt"));
VALUE obj = rb_obj_alloc(klass);
setPrivateData(obj, ops); setPrivateData(obj, ops);
return obj; return obj;
@ -183,7 +180,7 @@ kernelLoadDataInt(const char *filename, bool rubyExc, bool raw) {
return result; return result;
} }
RB_METHOD(kernelLoadData) { RB_METHOD_GUARD(kernelLoadData) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE filename; VALUE filename;
@ -195,6 +192,7 @@ RB_METHOD(kernelLoadData) {
rb_bool_arg(raw, &rawv); rb_bool_arg(raw, &rawv);
return kernelLoadDataInt(RSTRING_PTR(filename), true, rawv); return kernelLoadDataInt(RSTRING_PTR(filename), true, rawv);
} }
RB_METHOD_GUARD_END
RB_METHOD(kernelSaveData) { RB_METHOD(kernelSaveData) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;

View file

@ -88,7 +88,15 @@ RB_METHOD(fontInitialize) {
* However the same bug/behavior exists in all RM versions. */ * However the same bug/behavior exists in all RM versions. */
rb_iv_set(self, "name", namesObj); rb_iv_set(self, "name", namesObj);
setPrivateData(self, f); Font *orig = getPrivateDataNoRaise<Font>(self);
if (orig)
{
*orig = *f;
delete f;
f = orig;
} else {
setPrivateData(self, f);
}
/* Wrap property objects */ /* Wrap property objects */
f->initDynAttribs(); f->initDynAttribs();

View file

@ -26,10 +26,6 @@
#include "binding-types.h" #include "binding-types.h"
#include "exception.h" #include "exception.h"
#if RAPI_MAJOR >= 2
#include <ruby/thread.h>
#endif
RB_METHOD(graphicsDelta) { RB_METHOD(graphicsDelta) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
GFX_LOCK; GFX_LOCK;
@ -38,14 +34,12 @@ RB_METHOD(graphicsDelta) {
return ret; return ret;
} }
RB_METHOD(graphicsUpdate) RB_METHOD_GUARD(graphicsUpdate)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
#if RAPI_MAJOR >= 2 #if RAPI_MAJOR >= 2
rb_thread_call_without_gvl([](void*) -> void* { drop_gvl_guard([](void*) -> void* {
GFX_LOCK; GFX_GUARD_EXC( shState->graphics().update(); );
shState->graphics().update();
GFX_UNLOCK;
return 0; return 0;
}, 0, 0, 0); }, 0, 0, 0);
#else #else
@ -53,6 +47,7 @@ RB_METHOD(graphicsUpdate)
#endif #endif
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(graphicsAverageFrameRate) RB_METHOD(graphicsAverageFrameRate)
{ {
@ -63,18 +58,30 @@ RB_METHOD(graphicsAverageFrameRate)
return ret; return ret;
} }
RB_METHOD(graphicsFreeze) RB_METHOD_GUARD(graphicsFreeze)
{ {
RB_UNUSED_PARAM; 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(); shState->graphics().freeze();
GFX_UNLOCK; #endif
return Qnil; 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; RB_UNUSED_PARAM;
@ -84,10 +91,24 @@ RB_METHOD(graphicsTransition)
rb_get_args(argc, argv, "|izi", &duration, &filename, &vague RB_ARG_END); 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); ) GFX_GUARD_EXC( shState->graphics().transition(duration, filename, vague); )
#endif
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(graphicsFrameReset) RB_METHOD(graphicsFrameReset)
{ {
@ -179,17 +200,15 @@ RB_METHOD(graphicsDisplayHeight)
return rb_fix_new(shState->graphics().displayHeight()); return rb_fix_new(shState->graphics().displayHeight());
} }
RB_METHOD(graphicsWait) RB_METHOD_GUARD(graphicsWait)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
int duration; int duration;
rb_get_args(argc, argv, "i", &duration RB_ARG_END); rb_get_args(argc, argv, "i", &duration RB_ARG_END);
#if RAPI_MAJOR >= 2 #if RAPI_MAJOR >= 2
rb_thread_call_without_gvl([](void* d) -> void* { drop_gvl_guard([](void* d) -> void* {
GFX_LOCK; GFX_GUARD_EXC( shState->graphics().wait(*(int*)d); );
shState->graphics().wait(*(int*)d);
GFX_UNLOCK;
return 0; return 0;
}, (int*)&duration, 0, 0); }, (int*)&duration, 0, 0);
#else #else
@ -197,38 +216,51 @@ RB_METHOD(graphicsWait)
#endif #endif
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(graphicsFadeout) RB_METHOD_GUARD(graphicsFadeout)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
int duration; int duration;
rb_get_args(argc, argv, "i", &duration RB_ARG_END); 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); shState->graphics().fadeout(duration);
GFX_UNLOCK; #endif
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(graphicsFadein) RB_METHOD_GUARD(graphicsFadein)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
int duration; int duration;
rb_get_args(argc, argv, "i", &duration RB_ARG_END); 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); shState->graphics().fadein(duration);
GFX_UNLOCK; #endif
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
void bitmapInitProps(Bitmap *b, VALUE self); void bitmapInitProps(Bitmap *b, VALUE self);
RB_METHOD(graphicsSnapToBitmap) RB_METHOD_GUARD(graphicsSnapToBitmap)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -241,6 +273,7 @@ RB_METHOD(graphicsSnapToBitmap)
return obj; return obj;
} }
RB_METHOD_GUARD_END
RB_METHOD(graphicsResizeScreen) RB_METHOD(graphicsResizeScreen)
{ {
@ -272,16 +305,15 @@ RB_METHOD(graphicsResizeWindow)
return Qnil; return Qnil;
} }
RB_METHOD(graphicsReset) RB_METHOD_GUARD(graphicsReset)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
GFX_LOCK; GFX_GUARD_EXC( shState->graphics().reset(); );
shState->graphics().reset();
GFX_UNLOCK;
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(graphicsCenter) RB_METHOD(graphicsCenter)
{ {
@ -299,17 +331,17 @@ typedef struct {
void *playMovieInternal(void *args) { void *playMovieInternal(void *args) {
PlayMovieArgs *a = (PlayMovieArgs*)args; PlayMovieArgs *a = (PlayMovieArgs*)args;
GFX_GUARD_EXC( GFX_GUARD_EXC( shState->graphics().playMovie(a->filename, a->volume, a->skippable); );
shState->graphics().playMovie(a->filename, a->volume, a->skippable);
// Signals for shutdown or reset only make playMovie quit early,
// Signals for shutdown or reset only make playMovie quit early, // so check again
// so check again shState->checkShutdown();
shState->graphics().update(); shState->checkReset();
);
return 0; return 0;
} }
RB_METHOD(graphicsPlayMovie) RB_METHOD_GUARD(graphicsPlayMovie)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -327,20 +359,21 @@ RB_METHOD(graphicsPlayMovie)
args.volume = (volumeArg == Qnil) ? 100 : NUM2INT(volumeArg);; args.volume = (volumeArg == Qnil) ? 100 : NUM2INT(volumeArg);;
args.skippable = skip; args.skippable = skip;
#if RAPI_MAJOR >= 2 #if RAPI_MAJOR >= 2
rb_thread_call_without_gvl(playMovieInternal, &args, 0, 0); drop_gvl_guard(playMovieInternal, &args, 0, 0);
#else #else
playMovieInternal(&args); playMovieInternal(&args);
#endif #endif
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
void graphicsScreenshotInternal(const char *filename) void graphicsScreenshotInternal(const char *filename)
{ {
GFX_GUARD_EXC(shState->graphics().screenshot(filename);); GFX_GUARD_EXC(shState->graphics().screenshot(filename););
} }
RB_METHOD(graphicsScreenshot) RB_METHOD_GUARD(graphicsScreenshot)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -349,7 +382,7 @@ RB_METHOD(graphicsScreenshot)
SafeStringValue(filename); SafeStringValue(filename);
#if RAPI_MAJOR >= 2 #if RAPI_MAJOR >= 2
rb_thread_call_without_gvl([](void* fn) -> void* { drop_gvl_guard([](void* fn) -> void* {
graphicsScreenshotInternal((const char*)fn); graphicsScreenshotInternal((const char*)fn);
return 0; return 0;
}, (void*)RSTRING_PTR(filename), 0, 0); }, (void*)RSTRING_PTR(filename), 0, 0);
@ -358,6 +391,7 @@ RB_METHOD(graphicsScreenshot)
#endif #endif
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
DEF_GRA_PROP_I(FrameRate) DEF_GRA_PROP_I(FrameRate)
DEF_GRA_PROP_I(FrameCount) DEF_GRA_PROP_I(FrameCount)

View file

@ -10,10 +10,6 @@
#include "util/json5pp.hpp" #include "util/json5pp.hpp"
#include "binding-util.h" #include "binding-util.h"
#if RAPI_MAJOR >= 2
#include <ruby/thread.h>
#endif
#include "net/net.h" #include "net/net.h"
VALUE stringMap2hash(mkxp_net::StringMap &map) { VALUE stringMap2hash(mkxp_net::StringMap &map) {
@ -78,16 +74,14 @@ VALUE formResponse(mkxp_net::HTTPResponse &res) {
void* httpGetInternal(void *req) { void* httpGetInternal(void *req) {
VALUE ret; VALUE ret;
GUARD_EXC( mkxp_net::HTTPResponse res = ((mkxp_net::HTTPRequest*)req)->get();
mkxp_net::HTTPResponse res = ((mkxp_net::HTTPRequest*)req)->get(); ret = formResponse(res);
ret = formResponse(res);
);
return (void*)ret; return (void*)ret;
} }
#endif #endif
RB_METHOD(httpGet) { RB_METHOD_GUARD(httpGet) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE path, rheaders, redirect; VALUE path, rheaders, redirect;
@ -102,11 +96,12 @@ RB_METHOD(httpGet) {
req.headers().insert(headers.begin(), headers.end()); req.headers().insert(headers.begin(), headers.end());
} }
#if RAPI_MAJOR >= 2 #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 #else
return (VALUE)httpGetInternal(&req); return (VALUE)httpGetInternal(&req);
#endif #endif
} }
RB_METHOD_GUARD_END
#if RAPI_MAJOR >= 2 #if RAPI_MAJOR >= 2
@ -121,16 +116,14 @@ void* httpPostInternal(void *args) {
mkxp_net::HTTPRequest *req = ((httpPostInternalArgs*)args)->req; mkxp_net::HTTPRequest *req = ((httpPostInternalArgs*)args)->req;
mkxp_net::StringMap *postData = ((httpPostInternalArgs*)args)->postData; mkxp_net::StringMap *postData = ((httpPostInternalArgs*)args)->postData;
GUARD_EXC( mkxp_net::HTTPResponse res = req->post(*postData);
mkxp_net::HTTPResponse res = req->post(*postData); ret = formResponse(res);
ret = formResponse(res);
);
return (void*)ret; return (void*)ret;
} }
#endif #endif
RB_METHOD(httpPost) { RB_METHOD_GUARD(httpPost) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE path, postDataHash, rheaders, redirect; VALUE path, postDataHash, rheaders, redirect;
@ -148,11 +141,12 @@ RB_METHOD(httpPost) {
mkxp_net::StringMap postData = hash2StringMap(postDataHash); mkxp_net::StringMap postData = hash2StringMap(postDataHash);
httpPostInternalArgs args {&req, &postData}; httpPostInternalArgs args {&req, &postData};
#if RAPI_MAJOR >= 2 #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 #else
return httpPostInternal(&args); return httpPostInternal(&args);
#endif #endif
} }
RB_METHOD_GUARD_END
#if RAPI_MAJOR >= 2 #if RAPI_MAJOR >= 2
typedef struct { typedef struct {
@ -168,16 +162,14 @@ void* httpPostBodyInternal(void *args) {
const char *reqbody = ((httpPostBodyInternalArgs*)args)->body; const char *reqbody = ((httpPostBodyInternalArgs*)args)->body;
const char *reqctype = ((httpPostBodyInternalArgs*)args)->ctype; const char *reqctype = ((httpPostBodyInternalArgs*)args)->ctype;
GUARD_EXC( mkxp_net::HTTPResponse res = req->post(reqbody, reqctype);
mkxp_net::HTTPResponse res = req->post(reqbody, reqctype); ret = formResponse(res);
ret = formResponse(res);
);
return (void*)ret; return (void*)ret;
} }
#endif #endif
RB_METHOD(httpPostBody) { RB_METHOD_GUARD(httpPostBody) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE path, body, ctype, rheaders; VALUE path, body, ctype, rheaders;
@ -195,11 +187,12 @@ RB_METHOD(httpPostBody) {
httpPostBodyInternalArgs args {&req, RSTRING_PTR(body), RSTRING_PTR(ctype)}; httpPostBodyInternalArgs args {&req, RSTRING_PTR(body), RSTRING_PTR(ctype)};
#if RAPI_MAJOR >= 2 #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 #else
return httpPostBodyInternal(&args); return httpPostBodyInternal(&args);
#endif #endif
} }
RB_METHOD_GUARD_END
VALUE json2rb(json5pp::value const &v) { VALUE json2rb(json5pp::value const &v) {
if (v.is_null()) if (v.is_null())
@ -280,13 +273,13 @@ json5pp::value rb2json(VALUE v) {
return ret_value; 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 // This should be unreachable
return json5pp::value(0); return json5pp::value(0);
} }
RB_METHOD(httpJsonParse) { RB_METHOD_GUARD(httpJsonParse) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE jsonv; VALUE jsonv;
@ -298,13 +291,14 @@ RB_METHOD(httpJsonParse) {
v = json5pp::parse5(RSTRING_PTR(jsonv)); v = json5pp::parse5(RSTRING_PTR(jsonv));
} }
catch (const std::exception &e) { 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); return json2rb(v);
} }
RB_METHOD_GUARD_END
RB_METHOD(httpJsonStringify) { RB_METHOD_GUARD(httpJsonStringify) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE obj; VALUE obj;
@ -313,6 +307,7 @@ RB_METHOD(httpJsonStringify) {
json5pp::value v = rb2json(obj); json5pp::value v = rb2json(obj);
return rb_utf8_str_new_cstr(v.stringify5(json5pp::rule::space_indent<>()).c_str()); return rb_utf8_str_new_cstr(v.stringify5(json5pp::rule::space_indent<>()).c_str());
} }
RB_METHOD_GUARD_END
void httpBindingInit() { void httpBindingInit() {
VALUE mNet = rb_define_module("HTTPLite"); VALUE mNet = rb_define_module("HTTPLite");

View file

@ -37,13 +37,14 @@ RB_METHOD(inputDelta) {
return rb_float_new(shState->input().getDelta()); return rb_float_new(shState->input().getDelta());
} }
RB_METHOD(inputUpdate) { RB_METHOD_GUARD(inputUpdate) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
shState->input().update(); shState->input().update();
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
static int getButtonArg(VALUE *argv) { static int getButtonArg(VALUE *argv) {
int num; int num;
@ -76,7 +77,7 @@ static int getScancodeArg(VALUE *argv) {
try { try {
code = strToScancode[scancode]; code = strToScancode[scancode];
} catch (...) { } 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; return code;
@ -88,7 +89,7 @@ static int getControllerButtonArg(VALUE *argv) {
try { try {
btn = strToGCButton[button]; btn = strToGCButton[button];
} catch (...) { } 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; return btn;
@ -172,7 +173,7 @@ RB_METHOD(inputRepeatTime) {
return rb_float_new(shState->input().repeatTime(num)); return rb_float_new(shState->input().repeatTime(num));
} }
RB_METHOD(inputPressEx) { RB_METHOD_GUARD(inputPressEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -185,8 +186,9 @@ RB_METHOD(inputPressEx) {
return rb_bool_new(shState->input().isPressedEx(NUM2INT(button), 1)); return rb_bool_new(shState->input().isPressedEx(NUM2INT(button), 1));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputTriggerEx) { RB_METHOD_GUARD(inputTriggerEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -199,8 +201,9 @@ RB_METHOD(inputTriggerEx) {
return rb_bool_new(shState->input().isTriggeredEx(NUM2INT(button), 1)); return rb_bool_new(shState->input().isTriggeredEx(NUM2INT(button), 1));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputRepeatEx) { RB_METHOD_GUARD(inputRepeatEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -213,8 +216,9 @@ RB_METHOD(inputRepeatEx) {
return rb_bool_new(shState->input().isRepeatedEx(NUM2INT(button), 1)); return rb_bool_new(shState->input().isRepeatedEx(NUM2INT(button), 1));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputReleaseEx) { RB_METHOD_GUARD(inputReleaseEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -227,8 +231,9 @@ RB_METHOD(inputReleaseEx) {
return rb_bool_new(shState->input().isReleasedEx(NUM2INT(button), 1)); return rb_bool_new(shState->input().isReleasedEx(NUM2INT(button), 1));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputCountEx) { RB_METHOD_GUARD(inputCountEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -241,8 +246,9 @@ RB_METHOD(inputCountEx) {
return UINT2NUM(shState->input().repeatcount(NUM2INT(button), 1)); return UINT2NUM(shState->input().repeatcount(NUM2INT(button), 1));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputRepeatTimeEx) { RB_METHOD_GUARD(inputRepeatTimeEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -255,6 +261,7 @@ RB_METHOD(inputRepeatTimeEx) {
return rb_float_new(shState->input().repeatTimeEx(NUM2INT(button), 1)); return rb_float_new(shState->input().repeatTimeEx(NUM2INT(button), 1));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputDir4) { RB_METHOD(inputDir4) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -370,7 +377,7 @@ AXISFUNC(Trigger, TRIGGERLEFT, TRIGGERRIGHT);
#undef POWERCASE #undef POWERCASE
#undef M_SYMBOL #undef M_SYMBOL
RB_METHOD(inputControllerPressEx) { RB_METHOD_GUARD(inputControllerPressEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -383,8 +390,9 @@ RB_METHOD(inputControllerPressEx) {
return rb_bool_new(shState->input().controllerIsPressedEx(NUM2INT(button))); return rb_bool_new(shState->input().controllerIsPressedEx(NUM2INT(button)));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputControllerTriggerEx) { RB_METHOD_GUARD(inputControllerTriggerEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -397,8 +405,9 @@ RB_METHOD(inputControllerTriggerEx) {
return rb_bool_new(shState->input().controllerIsTriggeredEx(NUM2INT(button))); return rb_bool_new(shState->input().controllerIsTriggeredEx(NUM2INT(button)));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputControllerRepeatEx) { RB_METHOD_GUARD(inputControllerRepeatEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -411,8 +420,9 @@ RB_METHOD(inputControllerRepeatEx) {
return rb_bool_new(shState->input().controllerIsRepeatedEx(NUM2INT(button))); return rb_bool_new(shState->input().controllerIsRepeatedEx(NUM2INT(button)));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputControllerReleaseEx) { RB_METHOD_GUARD(inputControllerReleaseEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -425,8 +435,9 @@ RB_METHOD(inputControllerReleaseEx) {
return rb_bool_new(shState->input().controllerIsReleasedEx(NUM2INT(button))); return rb_bool_new(shState->input().controllerIsReleasedEx(NUM2INT(button)));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputControllerCountEx) { RB_METHOD_GUARD(inputControllerCountEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -439,8 +450,9 @@ RB_METHOD(inputControllerCountEx) {
return rb_bool_new(shState->input().controllerRepeatcount(NUM2INT(button))); return rb_bool_new(shState->input().controllerRepeatcount(NUM2INT(button)));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputControllerRepeatTimeEx) { RB_METHOD_GUARD(inputControllerRepeatTimeEx) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE button; VALUE button;
@ -453,6 +465,7 @@ RB_METHOD(inputControllerRepeatTimeEx) {
return rb_float_new(shState->input().controllerRepeatTimeEx(NUM2INT(button))); return rb_float_new(shState->input().controllerRepeatTimeEx(NUM2INT(button)));
} }
RB_METHOD_GUARD_END
RB_METHOD(inputControllerRawButtonStates) { RB_METHOD(inputControllerRawButtonStates) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -504,18 +517,13 @@ RB_METHOD(inputGets) {
return ret; return ret;
} }
RB_METHOD(inputGetClipboard) { RB_METHOD_GUARD(inputGetClipboard) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE ret; return rb_utf8_str_new_cstr(shState->input().getClipboardText());
try {
ret = rb_utf8_str_new_cstr(shState->input().getClipboardText());
} catch (const Exception &e) {
raiseRbExc(e);
}
return ret;
} }
RB_METHOD_GUARD_END
RB_METHOD(inputSetClipboard) { RB_METHOD_GUARD(inputSetClipboard) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE str; VALUE str;
@ -523,13 +531,11 @@ RB_METHOD(inputSetClipboard) {
SafeStringValue(str); SafeStringValue(str);
try { shState->input().setClipboardText(RSTRING_PTR(str));
shState->input().setClipboardText(RSTRING_PTR(str));
} catch (const Exception &e) {
raiseRbExc(e);
}
return str; return str;
} }
RB_METHOD_GUARD_END
struct { struct {
const char *str; const char *str;

View file

@ -46,7 +46,7 @@ static void *MiniFFI_GetFunctionHandle(void *libhandle, const char *func) {
// MiniFFI.new(library, function[, imports[, exports]]) // MiniFFI.new(library, function[, imports[, exports]])
// Yields itself in blocks // Yields itself in blocks
RB_METHOD(MiniFFI_initialize) { RB_METHOD_GUARD(MiniFFI_initialize) {
VALUE libname, func, imports, exports; VALUE libname, func, imports, exports;
rb_scan_args(argc, argv, "22", &libname, &func, &imports, &exports); rb_scan_args(argc, argv, "22", &libname, &func, &imports, &exports);
SafeStringValue(libname); SafeStringValue(libname);
@ -66,7 +66,7 @@ RB_METHOD(MiniFFI_initialize) {
} }
#endif #endif
if (!hfunc) 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, "_func", MVAL2RB((mffi_value)hfunc));
rb_iv_set(self, "_funcname", func); rb_iv_set(self, "_funcname", func);
@ -138,7 +138,7 @@ RB_METHOD(MiniFFI_initialize) {
} }
if (MINIFFI_MAX_ARGS < RARRAY_LEN(ary_imports)) 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); RARRAY_LEN(ary_imports), MINIFFI_MAX_ARGS);
rb_iv_set(self, "_imports", ary_imports); rb_iv_set(self, "_imports", ary_imports);
@ -181,6 +181,7 @@ RB_METHOD(MiniFFI_initialize) {
rb_yield(self); rb_yield(self);
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
#if RAPI_MAJOR >= 2 #if RAPI_MAJOR >= 2
typedef struct { typedef struct {
@ -195,7 +196,7 @@ void* miniffi_call_cb(void *args) {
} }
#endif #endif
RB_METHOD(MiniFFI_call) { RB_METHOD_GUARD(MiniFFI_call) {
MiniFFIFuncArgs param; MiniFFIFuncArgs param;
#define params param.params #define params param.params
VALUE func = rb_iv_get(self, "_func"); 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 items = rb_scan_args(argc, argv, "0*", &args);
int nimport = RARRAY_LEN(own_imports); int nimport = RARRAY_LEN(own_imports);
if (items != nimport) if (items != nimport)
rb_raise(rb_eRuntimeError, throw Exception(Exception::RuntimeError,
"wrong number of parameters: expected %d, got %d", nimport, items); "wrong number of parameters: expected %d, got %d", nimport, items);
for (int i = 0; i < nimport; i++) { for (int i = 0; i < nimport; i++) {
@ -264,6 +265,7 @@ RB_METHOD(MiniFFI_call) {
return MVAL2RB(0); return MVAL2RB(0);
} }
} }
RB_METHOD_GUARD_END
void MiniFFIBindingInit() { void MiniFFIBindingInit() {
VALUE cMiniFFI = rb_define_class("MiniFFI", rb_cObject); VALUE cMiniFFI = rb_define_class("MiniFFI", rb_cObject);

View file

@ -27,20 +27,21 @@
#include "graphics.h" #include "graphics.h"
template<class C> template<class C>
RB_METHOD(sceneElementGetZ) RB_METHOD_GUARD(sceneElementGetZ)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
SceneElement *se = getPrivateData<C>(self); SceneElement *se = getPrivateData<C>(self);
int value = 0; int value = 0;
GUARD_EXC( value = se->getZ(); ); value = se->getZ();
return rb_fix_new(value); return rb_fix_new(value);
} }
RB_METHOD_GUARD_END
template<class C> template<class C>
RB_METHOD(sceneElementSetZ) RB_METHOD_GUARD(sceneElementSetZ)
{ {
SceneElement *se = getPrivateData<C>(self); SceneElement *se = getPrivateData<C>(self);
@ -51,22 +52,24 @@ RB_METHOD(sceneElementSetZ)
return rb_fix_new(z); return rb_fix_new(z);
} }
RB_METHOD_GUARD_END
template<class C> template<class C>
RB_METHOD(sceneElementGetVisible) RB_METHOD_GUARD(sceneElementGetVisible)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
SceneElement *se = getPrivateData<C>(self); SceneElement *se = getPrivateData<C>(self);
bool value = false; bool value = false;
GUARD_EXC( value = se->getVisible(); ); value = se->getVisible();
return rb_bool_new(value); return rb_bool_new(value);
} }
RB_METHOD_GUARD_END
template<class C> template<class C>
RB_METHOD(sceneElementSetVisible) RB_METHOD_GUARD(sceneElementSetVisible)
{ {
SceneElement *se = getPrivateData<C>(self); SceneElement *se = getPrivateData<C>(self);
@ -75,8 +78,9 @@ RB_METHOD(sceneElementSetVisible)
GFX_GUARD_EXC( se->setVisible(visible); ); GFX_GUARD_EXC( se->setVisible(visible); );
return rb_bool_new(visible); return rb_bool_new(visible);
} }
RB_METHOD_GUARD_END
template<class C> template<class C>
void void

View file

@ -36,7 +36,16 @@ serializableDump(int, VALUE *, VALUE self)
VALUE data = rb_str_new(0, dataSize); 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; return data;
} }

View file

@ -84,27 +84,29 @@ DEF_GFX_PROP_B(Sprite, Mirror)
DEF_GFX_PROP_B(Sprite, PatternTile) DEF_GFX_PROP_B(Sprite, PatternTile)
DEF_GFX_PROP_B(Sprite, Invert) DEF_GFX_PROP_B(Sprite, Invert)
RB_METHOD(spriteWidth) { RB_METHOD_GUARD(spriteWidth) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Sprite *s = getPrivateData<Sprite>(self); Sprite *s = getPrivateData<Sprite>(self);
int value = 0; int value = 0;
GUARD_EXC(value = s->getWidth();) value = s->getWidth();
return rb_fix_new(value); return rb_fix_new(value);
} }
RB_METHOD_GUARD_END
RB_METHOD(spriteHeight) { RB_METHOD_GUARD(spriteHeight) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Sprite *s = getPrivateData<Sprite>(self); Sprite *s = getPrivateData<Sprite>(self);
int value = 0; int value = 0;
GUARD_EXC(value = s->getHeight();) value = s->getHeight();
return rb_fix_new(value); return rb_fix_new(value);
} }
RB_METHOD_GUARD_END
void spriteBindingInit() { void spriteBindingInit() {
VALUE klass = rb_define_class("Sprite", rb_cObject); VALUE klass = rb_define_class("Sprite", rb_cObject);

View file

@ -57,9 +57,14 @@ RB_METHOD(tableInitialize) {
parseArgsTableSizes(argc, argv, &x, &y, &z); parseArgsTableSizes(argc, argv, &x, &y, &z);
Table *t = new Table(x, y, z); Table *t = getPrivateDataNoRaise<Table>(self);
if (t) {
t->resize(x, y, z);
} else {
t = new Table(x, y, z);
setPrivateData(self, t); setPrivateData(self, t);
}
return self; return self;
} }
@ -86,7 +91,7 @@ TABLE_SIZE(x, X)
TABLE_SIZE(y, Y) TABLE_SIZE(y, Y)
TABLE_SIZE(z, Z) TABLE_SIZE(z, Z)
RB_METHOD(tableGetAt) { RB_METHOD_GUARD(tableGetAt) {
Table *t = getPrivateData<Table>(self); Table *t = getPrivateData<Table>(self);
int x, y, z; int x, y, z;
@ -99,7 +104,7 @@ RB_METHOD(tableGetAt) {
z = NUM2INT(argv[2]); z = NUM2INT(argv[2]);
if (argc > 3) 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 || if (x < 0 || x >= t->xSize() || y < 0 || y >= t->ySize() || z < 0 ||
z >= t->zSize()) { z >= t->zSize()) {
@ -110,15 +115,16 @@ RB_METHOD(tableGetAt) {
return INT2FIX(result); /* short always fits in a Fixnum */ return INT2FIX(result); /* short always fits in a Fixnum */
} }
RB_METHOD_GUARD_END
RB_METHOD(tableSetAt) { RB_METHOD_GUARD(tableSetAt) {
Table *t = getPrivateData<Table>(self); Table *t = getPrivateData<Table>(self);
int x, y, z, value; int x, y, z, value;
x = y = z = 0; x = y = z = 0;
if (argc < 2) if (argc < 2)
rb_raise(rb_eArgError, "wrong number of arguments"); throw Exception(Exception::ArgumentError, "wrong number of arguments");
switch (argc) { switch (argc) {
default: default:
@ -146,17 +152,25 @@ RB_METHOD(tableSetAt) {
return argv[argc - 1]; return argv[argc - 1];
} }
RB_METHOD_GUARD_END
MARSH_LOAD_FUN(Table) MARSH_LOAD_FUN(Table)
INITCOPY_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() { void tableBindingInit() {
VALUE klass = rb_define_class("Table", rb_cObject); VALUE klass = rb_define_class("Table", rb_cObject);
#if RAPI_FULL > 187 rb_define_alloc_func(klass, TableAllocatePreInit);
rb_define_alloc_func(klass, classAllocate<&TableType>);
#else
rb_define_alloc_func(klass, TableAllocate);
#endif
serializableBindingInit<Table>(klass); serializableBindingInit<Table>(klass);

View file

@ -35,7 +35,10 @@ DEF_TYPE_CUSTOMFREE(TilemapAutotiles, RUBY_TYPED_NEVER_FREE);
#endif #endif
RB_METHOD(tilemapAutotilesSet) { RB_METHOD(tilemapAutotilesSet) {
Tilemap::Autotiles *a = getPrivateData<Tilemap::Autotiles>(self); Tilemap::Autotiles *a = getPrivateDataNoRaise<Tilemap::Autotiles>(self);
if (!a)
return self;
int i; int i;
VALUE bitmapObj; VALUE bitmapObj;
@ -93,12 +96,18 @@ RB_METHOD(tilemapInitialize) {
t->initDynAttribs(); 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->getAutotiles(), "autotiles", TilemapAutotilesType);
wrapProperty(self, &t->getColor(), "color", ColorType); wrapProperty(self, &t->getColor(), "color", ColorType);
wrapProperty(self, &t->getTone(), "tone", ToneType); 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); VALUE ary = rb_ary_new2(7);
for (int i = 0; i < 7; ++i) for (int i = 0; i < 7; ++i)
@ -117,8 +126,6 @@ RB_METHOD(tilemapInitialize) {
RB_METHOD(tilemapGetAutotiles) { RB_METHOD(tilemapGetAutotiles) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
checkDisposed<Tilemap>(self);
return rb_iv_get(self, "autotiles"); return rb_iv_get(self, "autotiles");
} }

View file

@ -58,10 +58,16 @@ RB_METHOD(tilemapVXInitialize) {
rb_iv_set(self, "viewport", viewportObj); 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, wrapProperty(self, &t->getBitmapArray(), "bitmap_array", BitmapArrayType,
rb_const_get(rb_cObject, rb_intern("Tilemap"))); 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); VALUE ary = rb_ary_new2(9);
for (int i = 0; i < 9; ++i) for (int i = 0; i < 9; ++i)
@ -80,8 +86,6 @@ RB_METHOD(tilemapVXInitialize) {
RB_METHOD(tilemapVXGetBitmapArray) { RB_METHOD(tilemapVXGetBitmapArray) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
checkDisposed<TilemapVX>(self);
return rb_iv_get(self, "bitmap_array"); return rb_iv_get(self, "bitmap_array");
} }
@ -106,7 +110,10 @@ DEF_GFX_PROP_I(TilemapVX, OX)
DEF_GFX_PROP_I(TilemapVX, OY) DEF_GFX_PROP_I(TilemapVX, OY)
RB_METHOD(tilemapVXBitmapsSet) { RB_METHOD(tilemapVXBitmapsSet) {
TilemapVX::BitmapArray *a = getPrivateData<TilemapVX::BitmapArray>(self); TilemapVX::BitmapArray *a = getPrivateDataNoRaise<TilemapVX::BitmapArray>(self);
if (!a)
return self;
int i; int i;
VALUE bitmapObj; VALUE bitmapObj;

View file

@ -42,7 +42,7 @@ RB_METHOD(viewportElementGetViewport)
} }
template<class C> template<class C>
RB_METHOD(viewportElementSetViewport) RB_METHOD_GUARD(viewportElementSetViewport)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -62,6 +62,7 @@ RB_METHOD(viewportElementSetViewport)
return viewportObj; return viewportObj;
} }
RB_METHOD_GUARD_END
template<class C> template<class C>
static C * static C *

View file

@ -44,7 +44,7 @@ RB_METHOD(windowInitialize) {
return self; return self;
} }
RB_METHOD(windowUpdate) { RB_METHOD_GUARD(windowUpdate) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Window *w = getPrivateData<Window>(self); Window *w = getPrivateData<Window>(self);
@ -53,6 +53,7 @@ RB_METHOD(windowUpdate) {
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
DEF_GFX_PROP_OBJ_REF(Window, Bitmap, Windowskin, "windowskin") DEF_GFX_PROP_OBJ_REF(Window, Bitmap, Windowskin, "windowskin")
DEF_GFX_PROP_OBJ_REF(Window, Bitmap, Contents, "contents") DEF_GFX_PROP_OBJ_REF(Window, Bitmap, Contents, "contents")

View file

@ -97,6 +97,7 @@ typedef NSMutableArray<NSNumber*> BindingIndexArray;
-(void)closeWindow { -(void)closeWindow {
[self setNotListening:true]; [self setNotListening:true];
[_window close]; [_window close];
SDL_RaiseWindow(shState->rtData().window);
} }
-(SettingsMenu*)setWindow:(NSWindow*)window { -(SettingsMenu*)setWindow:(NSWindow*)window {

View file

@ -118,7 +118,9 @@ MKXPZTouchBar *_sharedTouchBar;
if (fpsLabel) { if (fpsLabel) {
int targetFrameRate = shState->graphics().getFrameRate(); int targetFrameRate = shState->graphics().getFrameRate();
dispatch_async(dispatch_get_main_queue(), ^{ 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)];
}
}); });
} }
} }

View file

@ -2388,6 +2388,7 @@ int Bitmap::currentFrameI() const
int Bitmap::addFrame(Bitmap &source, int position) int Bitmap::addFrame(Bitmap &source, int position)
{ {
guardDisposed(); guardDisposed();
source.guardDisposed();
GUARD_MEGA; GUARD_MEGA;

View file

@ -1612,6 +1612,13 @@ void Graphics::reset() {
setFrameRate(DEF_FRAMERATE); setFrameRate(DEF_FRAMERATE);
setBrightness(255); 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() { void Graphics::center() {

View file

@ -800,7 +800,9 @@ void EventThread::showMessageBox(const char *body, int flags)
SDL_PushEvent(&event); SDL_PushEvent(&event);
/* Keep repainting screen while box is open */ /* Keep repainting screen while box is open */
shState->graphics().repaintWait(msgBoxDone); try{
shState->graphics().repaintWait(msgBoxDone);
}catch(...){}
/* Prevent endless loops */ /* Prevent endless loops */
resetInputStates(); resetInputStates();
} }

View file

@ -286,7 +286,9 @@ struct RGSSThreadData
scale(scalingFactor), scale(scalingFactor),
config(newconf), config(newconf),
glContext(ctx) glContext(ctx)
{} {
rqResetFinish.set();
}
}; };
#endif // EVENTTHREAD_H #endif // EVENTTHREAD_H

View file

@ -18,43 +18,54 @@
#define NSTOPATH(str) [NSFileManager.defaultManager fileSystemRepresentationWithPath:str] #define NSTOPATH(str) [NSFileManager.defaultManager fileSystemRepresentationWithPath:str]
bool filesystemImpl::fileExists(const char *path) { bool filesystemImpl::fileExists(const char *path) {
BOOL isDir; @autoreleasepool{
return [NSFileManager.defaultManager fileExistsAtPath:PATHTONS(path) isDirectory: &isDir] && !isDir; BOOL isDir;
return [NSFileManager.defaultManager fileExistsAtPath:PATHTONS(path) isDirectory: &isDir] && !isDir;
}
} }
std::string filesystemImpl::contentsOfFileAsString(const char *path) { std::string filesystemImpl::contentsOfFileAsString(const char *path) {
NSString *fileContents = [NSString stringWithContentsOfFile: PATHTONS(path)]; @autoreleasepool {
if (fileContents == nil) NSString *fileContents = [NSString stringWithContentsOfFile: PATHTONS(path)];
throw Exception(Exception::NoFileError, "Failed to read file at %s", path); if (fileContents == nil)
throw Exception(Exception::NoFileError, "Failed to read file at %s", path);
return std::string(fileContents.UTF8String);
return std::string(fileContents.UTF8String);
}
} }
bool filesystemImpl::setCurrentDirectory(const char *path) { bool filesystemImpl::setCurrentDirectory(const char *path) {
return [NSFileManager.defaultManager changeCurrentDirectoryPath: PATHTONS(path)]; @autoreleasepool {
return [NSFileManager.defaultManager changeCurrentDirectoryPath: PATHTONS(path)];
}
} }
std::string filesystemImpl::getCurrentDirectory() { 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) { std::string filesystemImpl::normalizePath(const char *path, bool preferred, bool absolute) {
NSString *nspath = [NSURL fileURLWithPath: PATHTONS(path)].URLByStandardizingPath.path; @autoreleasepool {
NSString *pwd = [NSString stringWithFormat:@"%@/", NSFileManager.defaultManager.currentDirectoryPath]; NSString *nspath = [NSURL fileURLWithPath: PATHTONS(path)].URLByStandardizingPath.path;
if (!absolute) { NSString *pwd = [NSString stringWithFormat:@"%@/", NSFileManager.defaultManager.currentDirectoryPath];
nspath = [nspath stringByReplacingOccurrencesOfString:pwd withString:@""]; 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() { std::string filesystemImpl::getDefaultGameRoot() {
NSString *p = [NSString stringWithFormat: @"%@/%s", NSBundle.mainBundle.bundlePath, "Contents/Game"]; @autoreleasepool {
return std::string(NSTOPATH(p)); NSString *p = [NSString stringWithFormat: @"%@/%s", NSBundle.mainBundle.bundlePath, "Contents/Game"];
return std::string(NSTOPATH(p));
}
} }
NSString *getPathForAsset_internal(const char *baseName, const char *ext) { 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) { std::string filesystemImpl::getPathForAsset(const char *baseName, const char *ext) {
NSString *assetPath = getPathForAsset_internal(baseName, ext); @autoreleasepool {
if (assetPath == nil) NSString *assetPath = getPathForAsset_internal(baseName, ext);
throw Exception(Exception::NoFileError, "Failed to find the asset named %s.%s", 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)));
return std::string(NSTOPATH(getPathForAsset_internal(baseName, ext)));
}
} }
std::string filesystemImpl::contentsOfAssetAsString(const char *baseName, const char *ext) { std::string filesystemImpl::contentsOfAssetAsString(const char *baseName, const char *ext) {
NSString *path = getPathForAsset_internal(baseName, ext); @autoreleasepool {
NSString *fileContents = [NSString stringWithContentsOfFile: path]; NSString *path = getPathForAsset_internal(baseName, ext);
NSString *fileContents = [NSString stringWithContentsOfFile: path];
// This should never fail
if (fileContents == nil) // This should never fail
throw Exception(Exception::MKXPError, "Failed to read file at %s", path.UTF8String); if (fileContents == nil)
throw Exception(Exception::MKXPError, "Failed to read file at %s", path.UTF8String);
return std::string(fileContents.UTF8String);
return std::string(fileContents.UTF8String);
}
} }
std::string filesystemImpl::getResourcePath() { 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) { std::string filesystemImpl::selectPath(SDL_Window *win, const char *msg, const char *prompt) {
NSOpenPanel *panel = [NSOpenPanel openPanel]; @autoreleasepool {
panel.canChooseDirectories = true; NSOpenPanel *panel = [NSOpenPanel openPanel];
panel.canChooseFiles = false; panel.canChooseDirectories = true;
panel.canChooseFiles = false;
if (msg) panel.message = @(msg);
if (prompt) panel.prompt = @(prompt); if (msg) panel.message = @(msg);
//panel.directoryURL = [NSURL fileURLWithPath:NSFileManager.defaultManager.currentDirectoryPath]; if (prompt) panel.prompt = @(prompt);
//panel.directoryURL = [NSURL fileURLWithPath:NSFileManager.defaultManager.currentDirectoryPath];
SDL_SysWMinfo windowinfo{};
SDL_GetWindowWMInfo(win, &windowinfo); SDL_SysWMinfo windowinfo{};
SDL_GetWindowWMInfo(win, &windowinfo);
[panel beginSheetModalForWindow:windowinfo.info.cocoa.window completionHandler:^(NSModalResponse res){
[NSApp stopModalWithCode:res]; [panel beginSheetModalForWindow:windowinfo.info.cocoa.window completionHandler:^(NSModalResponse res){
}]; [NSApp stopModalWithCode:res];
}];
[NSApp runModalForWindow:windowinfo.info.cocoa.window];
[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]; // The window needs to be brought to the front again after the OpenPanel closes
if (panel.URLs.count > 0) [windowinfo.info.cocoa.window makeKeyAndOrderFront:nil];
return std::string(NSTOPATH(panel.URLs[0].path)); if (panel.URLs.count > 0)
return std::string(NSTOPATH(panel.URLs[0].path));
return std::string();
return std::string();
}
} }

View file

@ -13,13 +13,17 @@
#import "SettingsMenuController.h" #import "SettingsMenuController.h"
std::string systemImpl::getSystemLanguage() { std::string systemImpl::getSystemLanguage() {
NSString *languageCode = NSLocale.currentLocale.languageCode; @autoreleasepool {
NSString *countryCode = NSLocale.currentLocale.countryCode; NSString *languageCode = NSLocale.currentLocale.languageCode;
return std::string([NSString stringWithFormat:@"%@_%@", languageCode, countryCode].UTF8String); NSString *countryCode = NSLocale.currentLocale.countryCode;
return std::string([NSString stringWithFormat:@"%@_%@", languageCode, countryCode].UTF8String);
}
} }
std::string systemImpl::getUserName() { std::string systemImpl::getUserName() {
return std::string(NSUserName().UTF8String); @autoreleasepool {
return std::string(NSUserName().UTF8String);
}
} }
int systemImpl::getScalingFactor() { int systemImpl::getScalingFactor() {
@ -64,9 +68,11 @@ bool isMetalSupported() {
} }
std::string getPlistValue(const char *key) { std::string getPlistValue(const char *key) {
NSString *hash = [[NSBundle mainBundle] objectForInfoDictionaryKey:@(key)]; @autoreleasepool {
if (hash != nil) { NSString *hash = [[NSBundle mainBundle] objectForInfoDictionaryKey:@(key)];
return std::string(hash.UTF8String); if (hash != nil) {
return std::string(hash.UTF8String);
}
return "";
} }
return "";
} }

View file

@ -31,12 +31,15 @@ struct Exception
enum Type enum Type
{ {
RGSSError, RGSSError,
Reset,
NoFileError, NoFileError,
IOError, IOError,
/* Already defined by ruby */ /* Already defined by ruby */
TypeError, TypeError,
ArgumentError, ArgumentError,
SystemExit,
RuntimeError,
/* New types introduced in mkxp */ /* New types introduced in mkxp */
PHYSFSError, PHYSFSError,