Browse Source

Added love.graphics.isActive. love.graphics function calls (and method calls on objects created via love.graphics) are only guaranteed to work when isActive is true, otherwise bad things might happen (the program crashing, for example.)

It's usually only false when the app is inactive on iOS, and when the window hasn't been created yet.

--HG--
branch : minor
Alex Szpakowski 10 years ago
parent
commit
ac2b03e8a4

+ 27 - 0
src/modules/event/sdl/Event.cpp

@@ -69,6 +69,30 @@ static void normalizedToPixelCoords(double *x, double *y)
 }
 }
 #endif
 #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<graphics::Graphics>(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
 const char *Event::getName() const
 {
 {
 	return "love.event.sdl";
 	return "love.event.sdl";
@@ -78,10 +102,13 @@ Event::Event()
 {
 {
 	if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0)
 	if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0)
 		throw love::Exception("%s", SDL_GetError());
 		throw love::Exception("%s", SDL_GetError());
+
+	SDL_AddEventWatch(watchAppEvents, this);
 }
 }
 
 
 Event::~Event()
 Event::~Event()
 {
 {
+	SDL_DelEventWatch(watchAppEvents, this);
 	SDL_QuitSubSystem(SDL_INIT_EVENTS);
 	SDL_QuitSubSystem(SDL_INIT_EVENTS);
 }
 }
 
 

+ 14 - 0
src/modules/graphics/Graphics.h

@@ -178,6 +178,20 @@ public:
 	 **/
 	 **/
 	virtual void unSetMode() = 0;
 	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(const char *in, DrawMode &out);
 	static bool getConstant(DrawMode in, const char  *&out);
 	static bool getConstant(DrawMode in, const char  *&out);
 
 

+ 21 - 0
src/modules/graphics/opengl/Graphics.cpp

@@ -49,6 +49,7 @@ Graphics::Graphics()
 	: width(0)
 	: width(0)
 	, height(0)
 	, height(0)
 	, created(false)
 	, created(false)
+	, active(true)
 	, writingToStencil(false)
 	, writingToStencil(false)
 {
 {
 	gl = OpenGL();
 	gl = OpenGL();
@@ -322,6 +323,23 @@ void Graphics::unSetMode()
 	created = false;
 	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*/)
 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.
 	// Human-readable strings for the debug info.
@@ -409,6 +427,9 @@ void Graphics::clear(ClearType type)
 
 
 void Graphics::present()
 void Graphics::present()
 {
 {
+	if (!isActive())
+		return;
+
 	// Make sure we don't have a canvas active.
 	// Make sure we don't have a canvas active.
 	std::vector<StrongRef<Canvas>> canvases = states.back().canvases;
 	std::vector<StrongRef<Canvas>> canvases = states.back().canvases;
 	setCanvas();
 	setCanvas();

+ 4 - 0
src/modules/graphics/opengl/Graphics.h

@@ -68,6 +68,9 @@ public:
 	virtual bool setMode(int width, int height, bool &sRGB);
 	virtual bool setMode(int width, int height, bool &sRGB);
 	virtual void unSetMode();
 	virtual void unSetMode();
 
 
+	virtual void setActive(bool active);
+	virtual bool isActive() const;
+
 	void setDebug(bool enable);
 	void setDebug(bool enable);
 
 
 	/**
 	/**
@@ -470,6 +473,7 @@ private:
 	int width;
 	int width;
 	int height;
 	int height;
 	bool created;
 	bool created;
+	bool active;
 
 
 	bool writingToStencil;
 	bool writingToStencil;
 
 

+ 7 - 0
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -69,6 +69,12 @@ int w_isCreated(lua_State *L)
 	return 1;
 	return 1;
 }
 }
 
 
+int w_isActive(lua_State *L)
+{
+	luax_pushboolean(L, instance()->isActive());
+	return 1;
+}
+
 int w_getWidth(lua_State *L)
 int w_getWidth(lua_State *L)
 {
 {
 	lua_pushinteger(L, instance()->getWidth());
 	lua_pushinteger(L, instance()->getWidth());
@@ -1510,6 +1516,7 @@ static const luaL_Reg functions[] =
 	{ "printf", w_printf },
 	{ "printf", w_printf },
 
 
 	{ "isCreated", w_isCreated },
 	{ "isCreated", w_isCreated },
+	{ "isActive", w_isActive },
 	{ "getWidth", w_getWidth },
 	{ "getWidth", w_getWidth },
 	{ "getHeight", w_getHeight },
 	{ "getHeight", w_getHeight },
 	{ "getDimensions", w_getDimensions },
 	{ "getDimensions", w_getDimensions },

+ 1 - 0
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_clear(lua_State *L);
 int w_present(lua_State *L);
 int w_present(lua_State *L);
 int w_isCreated(lua_State *L);
 int w_isCreated(lua_State *L);
+int w_isActive(lua_State *L);
 int w_getWidth(lua_State *L);
 int w_getWidth(lua_State *L);
 int w_getHeight(lua_State *L);
 int w_getHeight(lua_State *L);
 int w_getDimensions(lua_State *L);
 int w_getDimensions(lua_State *L);

+ 1 - 2
src/scripts/boot.lua

@@ -521,7 +521,7 @@ function love.run()
 		-- Call update and draw
 		-- Call update and draw
 		if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
 		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.clear()
 			love.graphics.origin()
 			love.graphics.origin()
 			if love.draw then love.draw() end
 			if love.draw then love.draw() end
@@ -529,7 +529,6 @@ function love.run()
 		end
 		end
 
 
 		if love.timer then love.timer.sleep(0.001) end
 		if love.timer then love.timer.sleep(0.001) end
-
 	end
 	end
 
 
 end
 end

+ 3 - 4
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, 
 	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, 
 	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,
 	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, 
 	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,
 	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, 
 	0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6f,