Browse Source

Core::Lua Plugin now deletes itself on Core::Shutdown.

Michael Ragazzon 6 years ago
parent
commit
e21b962117

+ 37 - 43
Include/RmlUi/Core/Lua/Interpreter.h

@@ -37,6 +37,9 @@ namespace Rml {
 namespace Core {
 namespace Lua {
 
+class LuaDocumentElementInstancer;
+class LuaEventListenerInstancer;
+
 /**
     This initializes the Lua interpreter, and has functions to load the scripts or
     call functions that exist in Lua.
@@ -46,6 +49,24 @@ namespace Lua {
 class RMLUILUA_API Interpreter : public Plugin
 {
 public:
+	/** Creates the plugin.
+	@remark This is equivilent to calling Initialise(nullptr). */
+	static void Initialise();
+
+	/** Creates the plugin and adds RmlUi to an existing Lua state if one is provided.
+	 @remark If nullptr is passed as an argument, the plugin will automatically create the lua state during initialisation
+	   and close the state during the call to Rml::Core::Shutdown(). Otherwise, if a Lua state is provided, the user is 
+	   responsible for closing the provided Lua state. The state must then be closed after the call to Rml::Core::Shutdown().
+	 @remark The plugin registers the "body" tag to generate a LuaDocument rather than a Rml::Core::ElementDocument. */
+	static void Initialise(lua_State* L);
+
+	/**
+	@return The lua_State that the Interpreter created in Interpreter::Startup()
+	@remark This class lacks a SetLuaState for a reason. If you have to use a seperate Lua binding and want to keep the types
+	from RmlUi, then use this lua_State; it will already have all of the libraries loaded, and all of the types defined.
+	Alternatively, you can call RegisterCoreTypes(lua_State*) with your own Lua state if you need them defined in it. */
+	static lua_State* GetLuaState();
+
     /** This function calls luaL_loadfile and then lua_pcall, reporting the errors (if any)
     @param[in] file Fully qualified file name to execute.
     @remark Somewhat misleading name if you are used to the Lua meaning of "load file". It behaves
@@ -77,53 +98,26 @@ public:
     /** removes 'res' number of items from the stack
     @param[in] res Number of results to remove from the stack.   */
     static void EndCall(int res = 0);
-
-    /** This will populate the global Lua table with all of the Lua core types by calling LuaType<T>::Register
-    @param[in] L The lua_State to use to register the types
-    @remark This is called automatically inside of Interpreter::Startup(), so you do not have to 
-    call this function upon initialization of the Interpreter. If you are using RmlControlsLua, then you
-    \em will need to call Rml::Controls::Lua::RegisterTypes(lua_State*)     */
-    static void RegisterCoreTypes(lua_State* L);
-
-    /** 
-    @return The lua_State that the Interpreter created in Interpreter::Startup()
-    @remark This class lacks a SetLuaState for a reason. If you have to use a seperate Lua binding and want to keep the types
-    from RmlUi, then use this lua_State; it will already have all of the libraries loaded, and all of the types defined.
-    Alternatively, you can call RegisterCoreTypes(lua_State*) with your own Lua state if you need them defined in it. */
-    static lua_State* GetLuaState();
-
-    /** Creates the plugin. 
-	@remark This is equivilent to calling Initialise(nullptr).
-      */
-    static void Initialise();
-    /** Creates the plugin and adds RmlUi to an existing Lua context if one is provided.
-	 @remark Call this function only once, and special care must be taken when destroying the lua_State passed to this method.
-	 Interpreter::Shutdown() calles lua_close on the lua_State pointer provided here, do not call Interpreter::Shutdown if you
-	 must call lua_close yourself or if you need to continue to use the lua_State pointer provided here.  Internally, it calls
-	 Interpreter::Startup() and registers the "body" tag to generate a LuaDocument rather than a Rml::Core::ElementDocument.
-	 If the argument provided is nullptr, a Lua context is created automatically instead. */
-    static void Initialise(lua_State *_L);
-
-    /** Stops the plugin by calling lua_close
-	 @remark Shutdown calls lua_Close on the lua_State associated with the Interpreter.  If a lua_State was provided in the
-	 original call to Initialise, Shutdown should not be called OR you must not call lua_Close from within your code. */
-	static void Shutdown();
     
-    /** @sa Rml::Core::Plugin::GetEventClasses */
-    virtual int GetEventClasses();
-    /** @sa Rml::Core::Plugin::OnInitialise */
-    virtual void OnInitialise();
-    /** Currently does nothing. You must call Interpreter::Shutdown yourself at the appropriate time.
-    @sa Rml::Core::Plugin::OnShutdown    */
-    virtual void OnShutdown();
 private:
-    /** Creates a lua_State for @var _L and calls luaL_openlibs, then calls Interpreter::RegisterCoreTypes(lua_State*)
-    @remark called by Interpreter::Initialise()    */
-    void Startup();
+    int GetEventClasses() override;
+    
+	void OnInitialise() override;
+    
+	void OnShutdown() override;
+
+	/** This will populate the global Lua table with all of the Lua core types by calling LuaType<T>::Register
+	@param[in] L The lua_State to use to register the types
+	@remark This is called automatically inside of Interpreter::Startup(), so you do not have to
+	call this function upon initialization of the Interpreter. If you are using RmlControlsLua, then you
+	\em will need to call Rml::Controls::Lua::RegisterTypes(lua_State*)     */
+	static void RegisterCoreTypes(lua_State* L);
 
-    /** Lua state that Interpreter::Initialise() creates.    */
-    static lua_State* _L;
+	LuaDocumentElementInstancer* lua_document_element_instancer = nullptr;
+	LuaEventListenerInstancer* lua_event_listener_instancer = nullptr;
+	bool owns_lua_state = false;
 };
+
 }
 }
 }

+ 0 - 5
Samples/luainvaders/src/main.cpp

@@ -129,11 +129,6 @@ int main(int, char**)
 
 	Shell::EventLoop(GameLoop);	
 
-	Rml::Core::RemoveContext(context->GetName());
-
-	// Shutdown Lua before we shut down RmlUi.
-	Rml::Core::Lua::Interpreter::Shutdown();
-
 	// Shut down the game singletons.
 	HighScores::Shutdown();
 

+ 3 - 3
Source/Core/Element.cpp

@@ -1269,10 +1269,10 @@ bool Element::Focus()
 
 	// Update the focus chain up the hierarchy.
 	Element* element = this;
-	while (element->GetParentNode())
+	while (Element* parent = element->GetParentNode())
 	{
-		element->GetParentNode()->focus = element;
-		element = element->GetParentNode();
+		parent->focus = element;
+		element = parent;
 	}
 
 	return true;

+ 90 - 87
Source/Core/Lua/Interpreter.cpp

@@ -60,50 +60,29 @@
 namespace Rml {
 namespace Core {
 namespace Lua {
-lua_State* Interpreter::_L = nullptr;
+
+static lua_State* g_L = nullptr;
+
 //typedefs for nicer Lua names
 typedef Rml::Core::ElementDocument Document;
 
-void Interpreter::Startup()
+
+void Interpreter::Initialise()
 {
-	if(_L == nullptr)
-	{
-		Log::Message(Log::LT_INFO, "Loading Lua interpreter");
-		_L = luaL_newstate();
-		luaL_openlibs(_L);
-	}
-    RegisterCoreTypes(_L);
+	Rml::Core::Lua::Interpreter::Initialise(nullptr);
 }
 
-
-void Interpreter::RegisterCoreTypes(lua_State* L)
+void Interpreter::Initialise(lua_State* luaStatePointer)
 {
-    LuaType<Vector2i>::Register(L);
-    LuaType<Vector2f>::Register(L);
-    LuaType<Colourf>::Register(L);
-    LuaType<Colourb>::Register(L);
-    LuaType<Log>::Register(L);
-    LuaType<ElementStyleProxy>::Register(L);
-    LuaType<Element>::Register(L);
-        //things that inherit from Element
-        LuaType<Document>::Register(L);
-        LuaType<ElementText>::Register(L);
-    LuaType<ElementPtr>::Register(L);
-    LuaType<Event>::Register(L);
-    LuaType<Context>::Register(L);
-    LuaType<LuaRmlUi>::Register(L);
-    LuaType<ElementInstancer>::Register(L);
-    //Proxy tables
-    LuaType<ContextDocumentsProxy>::Register(L);
-    LuaType<EventParametersProxy>::Register(L);
-    LuaType<ElementAttributesProxy>::Register(L);
-    LuaType<ElementChildNodesProxy>::Register(L);
-    LuaType<RmlUiContextsProxy>::Register(L);
-    OverrideLuaGlobalFunctions(L);
-    //push the global variable "rmlui" to use the "RmlUi" methods
-    LuaRmlUiPushrmluiGlobal(L);
+	RMLUI_ASSERT(g_L == nullptr);
+	g_L = luaStatePointer;
+	Rml::Core::RegisterPlugin(new Interpreter());
 }
 
+lua_State* Interpreter::GetLuaState() 
+{
+	return g_L;
+}
 
 
 void Interpreter::LoadFile(const String& file)
@@ -112,27 +91,27 @@ void Interpreter::LoadFile(const String& file)
     Rml::Core::FileInterface* file_interface = Rml::Core::GetFileInterface();
     Rml::Core::FileHandle handle = file_interface->Open(file);
     if(handle == 0) {
-        lua_pushfstring(_L, "LoadFile: Unable to open file: %s", file.c_str());
-        Report(_L);
+        lua_pushfstring(g_L, "LoadFile: Unable to open file: %s", file.c_str());
+        Report(g_L);
         return;
     }
 
     size_t size = file_interface->Length(handle);
     if(size == 0) {
-        lua_pushfstring(_L, "LoadFile: File is 0 bytes in size: %s", file.c_str());
-        Report(_L);
+        lua_pushfstring(g_L, "LoadFile: File is 0 bytes in size: %s", file.c_str());
+        Report(g_L);
         return;
     }
     char* file_contents = new char[size];
     file_interface->Read(file_contents,size,handle);
     file_interface->Close(handle);
 
-    if(luaL_loadbuffer(_L,file_contents,size,file.c_str()) != 0)
-        Report(_L); 
+    if(luaL_loadbuffer(g_L,file_contents,size,file.c_str()) != 0)
+        Report(g_L); 
     else //if there were no errors loading, then the compiled function is on the top of the stack
     {
-        if(lua_pcall(_L,0,0,0) != 0)
-            Report(_L);
+        if(lua_pcall(g_L,0,0,0) != 0)
+            Report(g_L);
     }
 
     delete[] file_contents;
@@ -141,34 +120,34 @@ void Interpreter::LoadFile(const String& file)
 
 void Interpreter::DoString(const Rml::Core::String& code, const Rml::Core::String& name)
 {
-    if(luaL_loadbuffer(_L,code.c_str(),code.length(), name.c_str()) != 0)
-        Report(_L);
+    if(luaL_loadbuffer(g_L,code.c_str(),code.length(), name.c_str()) != 0)
+        Report(g_L);
     else
     {
-        if(lua_pcall(_L,0,0,0) != 0)
-            Report(_L);
+        if(lua_pcall(g_L,0,0,0) != 0)
+            Report(g_L);
     }
 }
 
 void Interpreter::LoadString(const Rml::Core::String& code, const Rml::Core::String& name)
 {
-    if(luaL_loadbuffer(_L,code.c_str(),code.length(), name.c_str()) != 0)
-        Report(_L);
+    if(luaL_loadbuffer(g_L,code.c_str(),code.length(), name.c_str()) != 0)
+        Report(g_L);
 }
 
 
 void Interpreter::BeginCall(int funRef)
 {
-    lua_settop(_L,0); //empty stack
-    //lua_getref(_L,funRef);
-    lua_rawgeti(_L, LUA_REGISTRYINDEX, (int)funRef);
+    lua_settop(g_L,0); //empty stack
+    //lua_getref(g_L,funRef);
+    lua_rawgeti(g_L, LUA_REGISTRYINDEX, (int)funRef);
 }
 
 bool Interpreter::ExecuteCall(int params, int res)
 {
     bool ret = true;
-    int top = lua_gettop(_L);
-    if(lua_type(_L,top-params) != LUA_TFUNCTION)
+    int top = lua_gettop(g_L);
+    if(lua_type(g_L,top-params) != LUA_TFUNCTION)
     {
         ret = false;
         //stack cleanup
@@ -176,16 +155,16 @@ bool Interpreter::ExecuteCall(int params, int res)
         {
             for(int i = top; i >= (top-params); i--)
             {
-                if(!lua_isnone(_L,i))
-                    lua_remove(_L,i);
+                if(!lua_isnone(g_L,i))
+                    lua_remove(g_L,i);
             }
         }
     }
     else
     {
-        if(lua_pcall(_L,params,res,0) != 0)
+        if(lua_pcall(g_L,params,res,0) != 0)
         {
-            Report(_L);
+            Report(g_L);
             ret = false;
         }
     }
@@ -197,13 +176,11 @@ void Interpreter::EndCall(int res)
     //stack cleanup
     for(int i = res; i > 0; i--)
     {
-        if(!lua_isnone(_L,res))
-            lua_remove(_L,res);
+        if(!lua_isnone(g_L,res))
+            lua_remove(g_L,res);
     }
 }
 
-lua_State* Interpreter::GetLuaState() { return _L; }
-
 
 //From Plugin
 int Interpreter::GetEventClasses()
@@ -211,46 +188,72 @@ int Interpreter::GetEventClasses()
     return EVT_BASIC;
 }
 
-static LuaDocumentElementInstancer* g_lua_document_element_instancer = nullptr;
-static LuaEventListenerInstancer* g_lua_event_listener_instancer = nullptr;
-
 void Interpreter::OnInitialise()
 {
-    Startup();
-	g_lua_document_element_instancer = new LuaDocumentElementInstancer();
-	g_lua_event_listener_instancer = new LuaEventListenerInstancer();
-    Factory::RegisterElementInstancer("body", g_lua_document_element_instancer);
-	Factory::RegisterEventListenerInstancer(g_lua_event_listener_instancer);
+	if (g_L == nullptr)
+	{
+		Log::Message(Log::LT_INFO, "Loading Lua interpreter");
+		g_L = luaL_newstate();
+		luaL_openlibs(g_L);
+		owns_lua_state = true;
+	}
+	else
+	{
+		owns_lua_state = false;
+	}
+	RegisterCoreTypes(g_L);
+
+	lua_document_element_instancer = new LuaDocumentElementInstancer();
+	lua_event_listener_instancer = new LuaEventListenerInstancer();
+    Factory::RegisterElementInstancer("body", lua_document_element_instancer);
+	Factory::RegisterEventListenerInstancer(lua_event_listener_instancer);
 }
 
 void Interpreter::OnShutdown()
 {
-	delete g_lua_document_element_instancer;
-	delete g_lua_event_listener_instancer;
-	g_lua_document_element_instancer = nullptr;
-	g_lua_event_listener_instancer = nullptr;
-}
+	delete lua_document_element_instancer;
+	delete lua_event_listener_instancer;
+	lua_document_element_instancer = nullptr;
+	lua_event_listener_instancer = nullptr;
 
-void Interpreter::Initialise()
-{
-    Rml::Core::Lua::Interpreter::Initialise(nullptr);
-}
+	if (owns_lua_state)
+		lua_close(g_L);
+	
+	g_L = nullptr;
 
-void Interpreter::Initialise(lua_State *luaStatePointer)
-{
-	Interpreter *iPtr = new Interpreter();
-	iPtr->_L = luaStatePointer;
-	Rml::Core::RegisterPlugin(iPtr);
+	delete this;
 }
 
-void Interpreter::Shutdown()
+void Interpreter::RegisterCoreTypes(lua_State* L)
 {
-	lua_close(_L);
+	LuaType<Vector2i>::Register(L);
+	LuaType<Vector2f>::Register(L);
+	LuaType<Colourf>::Register(L);
+	LuaType<Colourb>::Register(L);
+	LuaType<Log>::Register(L);
+	LuaType<ElementStyleProxy>::Register(L);
+	LuaType<Element>::Register(L);
+	//things that inherit from Element
+	LuaType<Document>::Register(L);
+	LuaType<ElementText>::Register(L);
+	LuaType<ElementPtr>::Register(L);
+	LuaType<Event>::Register(L);
+	LuaType<Context>::Register(L);
+	LuaType<LuaRmlUi>::Register(L);
+	LuaType<ElementInstancer>::Register(L);
+	//Proxy tables
+	LuaType<ContextDocumentsProxy>::Register(L);
+	LuaType<EventParametersProxy>::Register(L);
+	LuaType<ElementAttributesProxy>::Register(L);
+	LuaType<ElementChildNodesProxy>::Register(L);
+	LuaType<RmlUiContextsProxy>::Register(L);
+	OverrideLuaGlobalFunctions(L);
+	//push the global variable "rmlui" to use the "RmlUi" methods
+	LuaRmlUiPushrmluiGlobal(L);
 }
 
 
 
-
 }
 }
 }