diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index a515a1df2..faf2150b4 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -69,6 +69,30 @@ static void normalizedToPixelCoords(double *x, double *y) } #endif +// SDL's event watch callbacks trigger when the event is actually posted inside +// SDL, unlike with SDL_PollEvents. This is useful for some events which require +// handling inside the function which triggered them on some backends. +static int SDLCALL watchAppEvents(void * /*udata*/, SDL_Event *event) +{ + graphics::Graphics *gfx = Module::getInstance(Module::M_GRAPHICS); + + switch (event->type) + { + // On iOS, calling any OpenGL ES function after the function which triggers + // SDL_APP_DIDENTERBACKGROUND is called will kill the app, so we handle it + // with an event watch callback, which will be called inside that function. + case SDL_APP_DIDENTERBACKGROUND: + case SDL_APP_WILLENTERFOREGROUND: + if (gfx) + gfx->setActive(event->type == SDL_APP_WILLENTERFOREGROUND); + break; + default: + break; + } + + return 1; +} + const char *Event::getName() const { return "love.event.sdl"; @@ -78,10 +102,13 @@ Event::Event() { if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) throw love::Exception("%s", SDL_GetError()); + + SDL_AddEventWatch(watchAppEvents, this); } Event::~Event() { + SDL_DelEventWatch(watchAppEvents, this); SDL_QuitSubSystem(SDL_INIT_EVENTS); } diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 04bce98ad..93a27ed49 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -178,6 +178,20 @@ public: **/ virtual void unSetMode() = 0; + /** + * Sets whether the module is active (internal use only.) + **/ + virtual void setActive(bool active) = 0; + + /** + * Gets whether the module is active. Graphics module methods are only + * guaranteed to work when it is active. Calling them otherwise may cause + * the program to crash (or worse.) + * Normally the module will always be active as long as a window exists, it + * may be different on some platforms (especially mobile ones.) + **/ + virtual bool isActive() const = 0; + static bool getConstant(const char *in, DrawMode &out); static bool getConstant(DrawMode in, const char *&out); diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 16a6d73af..0172ce4c6 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -49,6 +49,7 @@ Graphics::Graphics() : width(0) , height(0) , created(false) + , active(true) , writingToStencil(false) { gl = OpenGL(); @@ -322,6 +323,23 @@ void Graphics::unSetMode() created = false; } +void Graphics::setActive(bool enable) +{ + // Make sure all pending OpenGL commands have fully executed before + // returning, if we're going from active to inactive. + if (isCreated() && this->active && !enable) + glFinish(); + + active = enable; +} + +bool Graphics::isActive() const +{ + // The graphics module is only completely 'active' if there's a window, a + // context, and the active variable is set. + return active && isCreated() && currentWindow && currentWindow->isCreated(); +} + static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, const GLvoid* /*usr*/) { // Human-readable strings for the debug info. @@ -409,6 +427,9 @@ void Graphics::clear(ClearType type) void Graphics::present() { + if (!isActive()) + return; + // Make sure we don't have a canvas active. std::vector> canvases = states.back().canvases; setCanvas(); diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 95958b85f..80ae4d4fb 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -68,6 +68,9 @@ public: virtual bool setMode(int width, int height, bool &sRGB); virtual void unSetMode(); + virtual void setActive(bool active); + virtual bool isActive() const; + void setDebug(bool enable); /** @@ -470,6 +473,7 @@ private: int width; int height; bool created; + bool active; bool writingToStencil; diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 32a631178..fd50702a9 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -69,6 +69,12 @@ int w_isCreated(lua_State *L) return 1; } +int w_isActive(lua_State *L) +{ + luax_pushboolean(L, instance()->isActive()); + return 1; +} + int w_getWidth(lua_State *L) { lua_pushinteger(L, instance()->getWidth()); @@ -1510,6 +1516,7 @@ static const luaL_Reg functions[] = { "printf", w_printf }, { "isCreated", w_isCreated }, + { "isActive", w_isActive }, { "getWidth", w_getWidth }, { "getHeight", w_getHeight }, { "getDimensions", w_getDimensions }, diff --git a/src/modules/graphics/opengl/wrap_Graphics.h b/src/modules/graphics/opengl/wrap_Graphics.h index e995f4512..5270cdb89 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.h +++ b/src/modules/graphics/opengl/wrap_Graphics.h @@ -44,6 +44,7 @@ int w_reset(lua_State *L); int w_clear(lua_State *L); int w_present(lua_State *L); int w_isCreated(lua_State *L); +int w_isActive(lua_State *L); int w_getWidth(lua_State *L); int w_getHeight(lua_State *L); int w_getDimensions(lua_State *L); diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index 725d6ca88..a21f3349e 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -521,7 +521,7 @@ function love.run() -- Call update and draw if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled - if love.window and love.graphics and love.window.isCreated() then + if love.graphics and love.graphics.isActive() then love.graphics.clear() love.graphics.origin() if love.draw then love.draw() end @@ -529,7 +529,6 @@ function love.run() end if love.timer then love.timer.sleep(0.001) end - end end diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index d75a22111..4183035af 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -939,10 +939,9 @@ const unsigned char boot_lua[] = 0x29, 0x20, 0x65, 0x6e, 0x64, 0x20, 0x2d, 0x2d, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x70, 0x61, 0x73, 0x73, 0x20, 0x30, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x61, - 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x61, - 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x69, 0x73, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, + 0x2e, 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x28, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6f,