From 64cb37d4a91967261b649fd2fe43a41d003a9410 Mon Sep 17 00:00:00 2001 From: Andreas Butti Date: Sun, 17 Feb 2019 22:06:40 +0100 Subject: [PATCH] Lua Plugin --- .cproject | 2 + plugins/Example/main.lua | 9 +- src/control/Control.cpp | 16 +-- src/control/Control.h | 22 ++-- src/plugin/Plugin.cpp | 186 ++++++++++++++++++++++++++++++-- src/plugin/Plugin.h | 68 +++++++++++- src/plugin/PluginController.cpp | 21 +++- src/plugin/PluginController.h | 5 + 8 files changed, 292 insertions(+), 37 deletions(-) diff --git a/.cproject b/.cproject index bba09fbb1388..f7b987ad4ea2 100644 --- a/.cproject +++ b/.cproject @@ -35,6 +35,7 @@ + @@ -48,6 +49,7 @@ + diff --git a/plugins/Example/main.lua b/plugins/Example/main.lua index e83919320619..f1a19dac7dd1 100644 --- a/plugins/Example/main.lua +++ b/plugins/Example/main.lua @@ -1,3 +1,10 @@ -- This is an example Xournal++ Plugin - copy this to get started -print("test123\n"); +print("Hello from Lua Plugin\n"); + +-- Register all Toolbar actions and intialize all UI stuff +function initUi() + print("Plugin initUi called\n"); +end + + diff --git a/src/control/Control.cpp b/src/control/Control.cpp index 7603ab71b559..5ecbd851a894 100644 --- a/src/control/Control.cpp +++ b/src/control/Control.cpp @@ -70,7 +70,6 @@ Control::Control(GladeSearchpath* gladeSearchPath) { XOJ_INIT_TYPE(Control); - this->win = NULL; this->recent = new RecentManager(); this->undoRedo = new UndoRedoHandler(this); this->recent->addListener(this); @@ -97,22 +96,12 @@ Control::Control(GladeSearchpath* gladeSearchPath) this->pageTypes = new PageTypeHandler(gladeSearchPath); this->newPageType = new PageTypeMenu(this->pageTypes, settings, true, true); - this->sidebar = NULL; - this->searchBar = NULL; - this->audioController = new AudioController(this->settings,this); this->scrollHandler = new ScrollHandler(this); this->scheduler = new XournalScheduler(); - this->autosaveTimeout = 0; - - this->statusbar = NULL; - this->lbState = NULL; - this->pgState = NULL; - this->maxState = 0; - this->doc = new Document(this); // for crashhandling @@ -129,10 +118,6 @@ Control::Control(GladeSearchpath* gladeSearchPath) */ this->changeTimout = g_timeout_add_seconds(5, (GSourceFunc) checkChangedDocument, this); - this->clipboardHandler = NULL; - - this->dragDropHandler = NULL; - this->pageBackgroundChangeController = new PageBackgroundChangeController(this); this->layerController = new LayerController(this); @@ -141,6 +126,7 @@ Control::Control(GladeSearchpath* gladeSearchPath) this->fullscreenHandler = new FullscreenHandler(settings); this->pluginController = new PluginController(this); + this->pluginController->registerToolbar(); } Control::~Control() diff --git a/src/control/Control.h b/src/control/Control.h index 24f387b47603..416241e0c32c 100644 --- a/src/control/Control.h +++ b/src/control/Control.h @@ -304,12 +304,12 @@ class Control : ZoomControl* zoom; Settings* settings; - MainWindow* win; + MainWindow* win = NULL; - Document* doc; + Document* doc = NULL; - Sidebar* sidebar; - SearchBar* searchBar; + Sidebar* sidebar = NULL; + SearchBar* searchBar = NULL; ToolHandler* toolHandler; @@ -321,7 +321,7 @@ class Control : AudioController* audioController; - ToolbarDragDropHandler* dragDropHandler; + ToolbarDragDropHandler* dragDropHandler = NULL; /** * The cursor handler @@ -341,12 +341,12 @@ class Control : /** * Our clipboard abstraction */ - ClipboardHandler* clipboardHandler; + ClipboardHandler* clipboardHandler = NULL; /** * The autosave handler ID */ - int autosaveTimeout; + int autosaveTimeout = 0; Path lastAutosaveFilename; XournalScheduler* scheduler; @@ -354,10 +354,10 @@ class Control : /** * State / Blocking attributes */ - GtkWidget* statusbar; - GtkLabel* lbState; - GtkProgressBar* pgState; - int maxState; + GtkWidget* statusbar = NULL; + GtkLabel* lbState = NULL; + GtkProgressBar* pgState = NULL; + int maxState = 0; bool isBlocking; GladeSearchpath* gladeSearchPath; diff --git a/src/plugin/Plugin.cpp b/src/plugin/Plugin.cpp index 0a2ae415da1b..2377760e7bfa 100644 --- a/src/plugin/Plugin.cpp +++ b/src/plugin/Plugin.cpp @@ -1,27 +1,197 @@ #include "Plugin.h" -#include +#include #ifdef ENABLE_PLUGINS -Plugin::Plugin(string path) - : path(path) +#include +#include +#include + +#define LOAD_FROM_INI(target, group, key) \ + { \ + char* value = g_key_file_get_string(config, group, key, NULL); \ + if (value != NULL) \ + { \ + target = value; \ + g_free(value); \ + } \ + } + + +Plugin::Plugin(string name, string path) + : name(name), + path(path) { XOJ_INIT_TYPE(Plugin); - + loadIni(); + loadScript(); } Plugin::~Plugin() { XOJ_CHECK_TYPE(Plugin); + + if (lua) + { + // Clean up, free the Lua state var + lua_close(lua); + lua = NULL; + } + XOJ_RELEASE_TYPE(Plugin); } -//void Plugin::aaaaaa() -//{ -// XOJ_CHECK_TYPE(Plugin); -//} + +/** + * Register toolbar item and all other UI stuff + */ +void Plugin::registerToolbar() +{ + XOJ_CHECK_TYPE(Plugin); + + if (!this->valid) + { + return; + } + + // lua_register + // lua_atpanic + // luaL_ref LUA_REGISTRYINDEX +/* + * + + lua_getfield(luaState, LUA_REGISTRYINDEX, "SciTE_InitialState"); + if (lua_istable(luaState, -1)) { + clear_table(luaState, LUA_GLOBALSINDEX, true); + merge_table(luaState, LUA_GLOBALSINDEX, -1, true); + lua_pop(luaState, 1); + + + * + * + * + * */ + + if (callFunction("initUi")) + { + g_message("Plugin «%s» UI initialized", name.c_str()); + } + else + { + g_message("Plugin «%s» has no UI init", name.c_str()); + } +} + +/** + * Load ini file + */ +void Plugin::loadIni() +{ + XOJ_CHECK_TYPE(Plugin); + + GKeyFile* config = g_key_file_new(); + g_key_file_set_list_separator(config, ','); + + string filename = path + "/plugin.ini"; + if (!g_key_file_load_from_file(config, filename.c_str(), G_KEY_FILE_NONE, NULL)) + { + g_key_file_free(config); + return; + } + + LOAD_FROM_INI(author, "about", "author"); + LOAD_FROM_INI(version, "about", "version"); + + if (version == "") + { + version = PROJECT_VERSION; + } + + LOAD_FROM_INI(mainfile, "plugin", "mainfile"); + + g_key_file_free(config); + + this->valid = true; +} + +/** + * Load the plugin script + */ +void Plugin::loadScript() +{ + XOJ_CHECK_TYPE(Plugin); + + if (mainfile == "") + { + this->valid = false; + return; + } + + if (mainfile.find("..") != std::string::npos) + { + g_warning("Plugin «%s» contains unsupported path «%s»", name.c_str(), mainfile.c_str()); + this->valid = false; + return; + } + + // Create Lua state variable + lua = luaL_newstate(); + + // Load Lua libraries + luaL_openlibs(lua); + + // Load but don't run the Lua script + string luafile = path + "/" + mainfile; + if (luaL_loadfile(lua, luafile.c_str())) + { + // Error out if file can't be read + g_warning("Could not run plugin Lua file: «%s»", luafile.c_str()); + this->valid = false; + return; + } + + // Register Plugin object to Lua instance + lua_pushnil(luaState); + lua_setfield(lua, LUA_REGISTRYINDEX, "Xournalpp_Plugin"); + + + // Run the loaded Lua script + if (lua_pcall(lua, 0, 0, 0)) + { + g_warning("Could not run plugin Lua file: «%s», error.", luafile.c_str()); + this->valid = false; + return; + } +} + +/** + * Execute lua function + */ +bool Plugin::callFunction(string fnc) +{ + lua_getglobal(lua, fnc.c_str()); + + // Run the function + if (lua_pcall(lua, 0, 0, 0)) + { + // Failed + return false; + } + + return true; +} + +/** + * Check if this plugin is valid + */ +bool Plugin::isValid() +{ + XOJ_CHECK_TYPE(Plugin); + + return valid; +} #endif diff --git a/src/plugin/Plugin.h b/src/plugin/Plugin.h index 2e7636dd5611..62c4da3a777f 100644 --- a/src/plugin/Plugin.h +++ b/src/plugin/Plugin.h @@ -13,12 +13,45 @@ #include +#include + +#ifdef ENABLE_PLUGINS +#include + + class Plugin { public: - Plugin(string path); + Plugin(string name, string path); virtual ~Plugin(); +public: + /** + * Check if this plugin is valid + */ + bool isValid(); + + /** + * Register toolbar item and all other UI stuff + */ + void registerToolbar(); + +private: + /** + * Load ini file + */ + void loadIni(); + + /** + * Load the plugin script + */ + void loadScript(); + + /** + * Execute lua function + */ + bool callFunction(string fnc); + private: XOJ_TYPE_ATTRIB; @@ -26,4 +59,37 @@ class Plugin * Plugin root path */ string path; + + /** + * Plugin name + */ + string name; + + /** + * Author of the plugin + */ + string author; + + /** + * Plugin version + */ + string version; + + /** + * Main plugin script + */ + string mainfile; + + /** + * Lua engine + */ + lua_State* lua = NULL; + + /** + * Flag if the plugin is valid / correct loaded + */ + bool valid = false; }; + +#endif + diff --git a/src/plugin/PluginController.cpp b/src/plugin/PluginController.cpp index 8de2bdd75739..3fbbb7f31d2a 100644 --- a/src/plugin/PluginController.cpp +++ b/src/plugin/PluginController.cpp @@ -20,6 +20,7 @@ PluginController::PluginController(Control* control) PluginController::~PluginController() { XOJ_CHECK_TYPE(PluginController); +#ifdef ENABLE_PLUGINS for (Plugin* p : this->plugins) { @@ -28,6 +29,7 @@ PluginController::~PluginController() this->plugins.clear(); +#endif XOJ_RELEASE_TYPE(PluginController); } @@ -57,9 +59,10 @@ void PluginController::loadPluginsFrom(string path) pluginFolder += "/"; pluginFolder += file; - Plugin* p = new Plugin(pluginFolder); + Plugin* p = new Plugin(file, pluginFolder); if (!p->isValid()) { + g_warning("Error loading plugin «%s»", file); delete p; continue; } @@ -70,3 +73,19 @@ void PluginController::loadPluginsFrom(string path) #endif } +/** + * Register toolbar item and all other UI stuff + */ +void PluginController::registerToolbar() +{ + XOJ_CHECK_TYPE(PluginController); + +#ifdef ENABLE_PLUGINS + for (Plugin* p : this->plugins) + { + p->registerToolbar(); + } +#endif +} + + diff --git a/src/plugin/PluginController.h b/src/plugin/PluginController.h index d47bf01d2777..744db24f7702 100644 --- a/src/plugin/PluginController.h +++ b/src/plugin/PluginController.h @@ -30,6 +30,11 @@ class PluginController */ void loadPluginsFrom(string path); + /** + * Register toolbar item and all other UI stuff + */ + void registerToolbar(); + private: XOJ_TYPE_ATTRIB;