Revision: 1643 http://svn.sourceforge.net/geany/?rev=1643&view=rev Author: ntrel Date: 2007-06-26 09:17:16 -0700 (Tue, 26 Jun 2007)
Log Message: ----------- Added very basic plugin support - any plugins found in /lib/geany are loaded at startup. Windows support will be added later. Added Demo plugin (currently installed by default), which adds an item in the Tools menu.
Modified Paths: -------------- trunk/ChangeLog trunk/HACKING trunk/Makefile.am trunk/configure.in trunk/po/POTFILES.in trunk/src/Makefile.am trunk/src/main.c trunk/src/makefile.win32 trunk/win32-config.h
Added Paths: ----------- trunk/plugins/ trunk/plugins/Makefile.am trunk/plugins/demoplugin.c trunk/src/plugindata.h trunk/src/plugins.c trunk/src/plugins.h
Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2007-06-26 15:42:55 UTC (rev 1642) +++ trunk/ChangeLog 2007-06-26 16:17:16 UTC (rev 1643) @@ -1,3 +1,16 @@ +2007-06-26 Nick Treleaven nick.treleaven@btinternet.com + + * plugins/demoplugin.c, plugins/Makefile.am, configure.in, + src/makefile.win32, src/plugindata.h, src/plugins.c, src/main.c, + src/plugins.h, src/Makefile.am, win32-config.h, HACKING, Makefile.am, + po/POTFILES.in: + Added very basic plugin support - any plugins found in + $prefix/lib/geany are loaded at startup. Windows support will be + added later. + Added Demo plugin (currently installed by default), which adds an + item in the Tools menu. + + 2007-06-26 Enrico Tröger enrico.troeger@uvena.de
* geany.glade, src/document.c, src/editor.h, src/interface.c, @@ -43,7 +56,7 @@ 2007-06-20 Nick Treleaven nick.treleaven@btinternet.com
* src/callbacks.c: - Prevent segfault when using goto tag from an untitled file. + Prevent segfault when using Goto Tag from an untitled file.
2007-06-19 Nick Treleaven nick.treleaven@btinternet.com
Modified: trunk/HACKING =================================================================== --- trunk/HACKING 2007-06-26 15:42:55 UTC (rev 1642) +++ trunk/HACKING 2007-06-26 16:17:16 UTC (rev 1643) @@ -102,3 +102,37 @@ In symbols.c: Update init_tag_list() for foo, listing the tm_tag_* types corresponding to the s_tag_type_names strings used in foo.c for FooKinds. + + +PLUGINS +======= + +See plugins/demoplugin.c for a very basic example plugin. +src/plugindata.h contains the plugin API data types. +src/plugins.c loads and unloads plugins. + +Loading a plugin from GDB +------------------------- +This is useful so you can load plugins without installing them first. +Alternatively you can use a symlink to $prefix/lib/geany/myplugin.so, (where +$prefix is /usr/local by default). + +The gdb session below was run from the toplevel Geany source directory. +Start normally with e.g. "gdb src/geany". +Type 'r' to run. +Press Ctrl-C from the gdb window to interrupt program execution. + +Program received signal SIGINT, Interrupt. +0x00d16402 in __kernel_vsyscall () +(gdb) call plugin_new("./plugins/.libs/demoplugin.so") +** INFO: Loaded: ./plugins/.libs/demoplugin.so (Demo) +$1 = (Plugin *) 0x905a890 +(gdb) c +Continuing. + +Program received signal SIGINT, Interrupt. +0x00d16402 in __kernel_vsyscall () +(gdb) call plugin_free(0x905a890) +** INFO: Unloaded: ./plugins/.libs/demoplugin.so +(gdb) c +Continuing.
Modified: trunk/Makefile.am =================================================================== --- trunk/Makefile.am 2007-06-26 15:42:55 UTC (rev 1642) +++ trunk/Makefile.am 2007-06-26 16:17:16 UTC (rev 1643) @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in
-SUBDIRS = tagmanager scintilla src po doc +SUBDIRS = tagmanager scintilla src plugins po doc
WIN32_BUILD_FILES = \ geany_private.rc \
Modified: trunk/configure.in =================================================================== --- trunk/configure.in 2007-06-26 15:42:55 UTC (rev 1642) +++ trunk/configure.in 2007-06-26 16:17:16 UTC (rev 1643) @@ -18,6 +18,11 @@ AC_PROG_LN_S AC_PROG_MAKE_SET
+# for plugins +AC_DISABLE_STATIC +AM_PROG_LIBTOOL +LIBTOOL="$LIBTOOL --silent" + # autoscan start
# Checks for header files. @@ -95,6 +100,16 @@ # [AC_MSG_ERROR([VTE support enabled, but VTE not found])], []) # fi
+# Plugins support +AC_ARG_ENABLE(plugins, [AC_HELP_STRING([--disable-plugins], [compile without plugin support])], , enable_plugins=yes) + +if test "x$enable_plugins" = "xyes" ; then + AC_DEFINE(HAVE_PLUGINS, 1, [Define if plugins are enabled.]) + AM_CONDITIONAL(PLUGINS, true) +else + AM_CONDITIONAL(PLUGINS, false) +fi + # Check for random number paths (skip when cross compiling) if test "x$build" = "x$target"; then AC_CHECK_FILE([/dev/urandom], AC_DEFINE([HAVE_DEVURANDOM], [1], [Define that you found /dev/urandom])) @@ -159,6 +174,7 @@ scintilla/Makefile scintilla/include/Makefile src/Makefile +plugins/Makefile po/Makefile.in doc/Makefile doc/geany.1 @@ -174,6 +190,7 @@ echo "Building Geany for : ${target}" fi echo "Using GTK version : ${GTK_VERSION}" +echo "Build with plugin support : ${enable_plugins}" echo "Use virtual terminal support : ${want_vte}" echo "Use (UNIX domain) socket support : ${want_socket}" if test "${REVISION}" != "-1"
Added: trunk/plugins/Makefile.am =================================================================== --- trunk/plugins/Makefile.am (rev 0) +++ trunk/plugins/Makefile.am 2007-06-26 16:17:16 UTC (rev 1643) @@ -0,0 +1,46 @@ +# Adapted from Pidgin's plugins/Makefile.am, thanks + +#EXTRA_DIST = \ + #makefile.win32 + +AM_CFLAGS = -Wall + +plugindir = $(libdir)/geany + +demoplugin_la_LDFLAGS = -module -avoid-version + +if PLUGINS + +# Plugins to be installed +plugin_LTLIBRARIES = \ + demoplugin.la + +# Plugins not to be installed +#noinst_LTLIBRARIES = \ + #demoplugin.la + +demoplugin_la_SOURCES = demoplugin.c + +demoplugin_la_LIBADD = $(PACKAGE_LIBS) + +endif # PLUGINS + +AM_CPPFLAGS = \ + -DDATADIR="$(datadir)" \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/tagmanager/include \ + -I$(top_srcdir)/scintilla/include \ + $(PACKAGE_CFLAGS) \ + $(PLUGIN_CFLAGS) + +# +# This part allows people to build their own plugins in here. +# Yes, it's a mess. +# +SUFFIXES = .c .so +.c.so: + $(LIBTOOL) --mode=compile $(CC) -DHAVE_CONFIG_H -I$(top_srcdir) $(AM_CPPFLAGS) $(CFLAGS) -c $< -o tmp$@.lo $(PLUGIN_CFLAGS) + $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o libtmp$@.la -rpath $(plugindir) tmp$@.lo $(LIBS) $(LDFLAGS) -module -avoid-version $(PLUGIN_LIBS) + @rm -f tmp$@.lo tmp$@.o libtmp$@.la + @cp .libs/libtmp$@.so* $@ + @rm -f .libs/libtmp$@.*
Property changes on: trunk/plugins/Makefile.am ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native
Added: trunk/plugins/demoplugin.c =================================================================== --- trunk/plugins/demoplugin.c (rev 0) +++ trunk/plugins/demoplugin.c 2007-06-26 16:17:16 UTC (rev 1643) @@ -0,0 +1,83 @@ +/* + * demoplugin.c - this file is part of Geany, a fast and lightweight IDE + * + * Copyright 2007 Enrico Tröger enrico.troeger@uvena.de + * Copyright 2007 Nick Treleaven nick.treleaven@btinternet.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id$ + */ + +/* Demo plugin. */ + +#include "geany.h" +#include "support.h" +#include "plugindata.h" + + +static PluginData *my_data; + +static struct +{ + GtkWidget *menu_item; +} +local_data; + + +/* This performs runtime checks that try to ensure: + * 1. Geany ABI data types are compatible with this plugin. + * 2. Geany sources provide the required API for this plugin. */ +VERSION_CHECK(1) + + +static void +item_activate(GtkMenuItem *menuitem, gpointer gdata) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new( + GTK_WINDOW(my_data->app->window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + _("Hello World!")); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), + _("(From the %s plugin)"), my_data->name); + + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + + +void init(PluginData *data) +{ + my_data = data; + my_data->name = g_strdup("Demo"); + + local_data.menu_item = gtk_menu_item_new_with_mnemonic(_("_Demo Plugin")); + gtk_widget_show(local_data.menu_item); + gtk_container_add(GTK_CONTAINER(my_data->tools_menu), local_data.menu_item); + g_signal_connect(G_OBJECT(local_data.menu_item), "activate", G_CALLBACK(item_activate), NULL); +} + + +void cleanup() +{ + gtk_widget_destroy(local_data.menu_item); + + g_free(my_data->name); +}
Property changes on: trunk/plugins/demoplugin.c ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native
Modified: trunk/po/POTFILES.in =================================================================== --- trunk/po/POTFILES.in 2007-06-26 15:42:55 UTC (rev 1642) +++ trunk/po/POTFILES.in 2007-06-26 16:17:16 UTC (rev 1643) @@ -5,6 +5,7 @@ src/callbacks.c src/dialogs.c src/document.c +src/editor.c src/encodings.c src/filetypes.c src/geany.h @@ -17,9 +18,9 @@ src/msgwindow.c src/navqueue.c src/notebook.c +src/plugins.c src/prefs.c src/project.c -src/editor.c src/sciwrappers.c src/search.c src/socket.c
Modified: trunk/src/Makefile.am =================================================================== --- trunk/src/Makefile.am 2007-06-26 15:42:55 UTC (rev 1642) +++ trunk/src/Makefile.am 2007-06-26 16:17:16 UTC (rev 1643) @@ -2,7 +2,7 @@ # $Id$
-EXTRA_DIST = images.c gb.c win32.c win32.h +EXTRA_DIST = images.c gb.c win32.c win32.h plugindata.h
bin_PROGRAMS = geany
@@ -12,6 +12,7 @@ callbacks.c callbacks.h \ dialogs.c dialogs.h \ document.c document.h \ + editor.c editor.h \ encodings.c encodings.h \ filetypes.c filetypes.h \ highlighting.c highlighting.h \ @@ -22,9 +23,9 @@ msgwindow.c msgwindow.h \ navqueue.c navqueue.h \ notebook.c notebook.h \ + plugins.c plugins.h \ prefs.c prefs.h \ project.c project.h \ - editor.c editor.h \ sciwrappers.c sciwrappers.h \ search.c search.h \ socket.c socket.h \
Modified: trunk/src/main.c =================================================================== --- trunk/src/main.c 2007-06-26 15:42:55 UTC (rev 1642) +++ trunk/src/main.c 2007-06-26 16:17:16 UTC (rev 1643) @@ -64,6 +64,7 @@ #include "project.h" #include "tools.h" #include "navqueue.h" +#include "plugins.h"
#ifdef HAVE_SOCKET # include "socket.h" @@ -769,6 +770,11 @@ } #endif
+#ifdef HAVE_PLUGINS + // load any enabled plugins just before we draw the main window + plugins_init(); +#endif + // finally realize the window to show the user what we have done gtk_widget_show(app->window); app->main_window_realized = TRUE; @@ -799,6 +805,9 @@ socket_finalize(); #endif
+#ifdef HAVE_PLUGINS + plugins_free(); +#endif navqueue_free(); keybindings_free(); filetypes_save_commands();
Modified: trunk/src/makefile.win32 =================================================================== --- trunk/src/makefile.win32 2007-06-26 15:42:55 UTC (rev 1642) +++ trunk/src/makefile.win32 2007-06-26 16:17:16 UTC (rev 1643) @@ -47,7 +47,7 @@ OBJS = treeviews.o templates.o encodings.o about.o prefs.o win32.o build.o msgwindow.o dialogs.o \ filetypes.o interface.o main.o support.o callbacks.o utils.o ui_utils.o socket.o \ highlighting.o editor.o document.o sciwrappers.o keyfile.o keybindings.o search.o notebook.o \ - symbols.o tools.o project.o navqueue.o + symbols.o tools.o project.o navqueue.o plugins.o
.c.o: $(CC) $(CCFLAGS) -c $<
Added: trunk/src/plugindata.h =================================================================== --- trunk/src/plugindata.h (rev 0) +++ trunk/src/plugindata.h 2007-06-26 16:17:16 UTC (rev 1643) @@ -0,0 +1,64 @@ +/* + * plugindata.h - this file is part of Geany, a fast and lightweight IDE + * + * Copyright 2007 Enrico Tröger enrico.troeger@uvena.de + * Copyright 2007 Nick Treleaven nick.treleaven@btinternet.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +/* The API version should be incremented whenever any plugin data types below are + * modified. */ +static const gint api_version = 1; + +/* The ABI version should be incremented whenever existing fields in the plugin + * data types below have to be changed or reordered. It should stay the same if fields + * are only appended, as this doesn't affect existing fields. */ +static const gint abi_version = 1; + + +/* TODO: if possible, the API version should be checked at compile time, not runtime. */ +#define VERSION_CHECK(api_required) \ + gint version_check(gint abi_ver) \ + { \ + if (abi_ver != abi_version) \ + return -1; \ + if (api_version < (api_required)) \ + return (api_required); \ + else return 0; \ + } + + +typedef struct PluginData PluginData; + +struct PluginData +{ + gchar *name; // name of plugin + gchar *description; // description of plugin + + MyApp *app; // Geany application data fields + + /* Almost all plugins should add menu items to the Tools menu only */ + GtkWidget *tools_menu; +}; + + +#endif
Property changes on: trunk/src/plugindata.h ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native
Added: trunk/src/plugins.c =================================================================== --- trunk/src/plugins.c (rev 0) +++ trunk/src/plugins.c 2007-06-26 16:17:16 UTC (rev 1643) @@ -0,0 +1,210 @@ +/* + * plugins.c - this file is part of Geany, a fast and lightweight IDE + * + * Copyright 2007 Enrico Tröger enrico.troeger@uvena.de + * Copyright 2007 Nick Treleaven nick.treleaven@btinternet.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id$ + */ + +/* Code to manage, load and unload plugins. */ + +#include "geany.h" + +#ifdef HAVE_PLUGINS + +#include "plugins.h" +#include "plugindata.h" +#include "support.h" +#include "utils.h" + + +typedef struct Plugin Plugin; + +struct Plugin +{ + GModule *module; + gchar *filename; // plugin filename (/path/libname.so) + PluginData data; + + void (*init) (PluginData *data); /* Called when the plugin is enabled */ + void (*cleanup) (); /* Called when the plugin is disabled or when Geany exits */ +}; + + +static GList *plugin_list = NULL; + +/* Prevent the same plugin filename being loaded more than once. + * Note: g_module_name always returns the .so name, even when Plugin::filename + * is an .la file. */ +static gboolean +plugin_loaded(GModule *module) +{ + const gchar *fname = g_module_name(module); + GList *item; + + for (item = plugin_list; item != NULL; item = g_list_next(item)) + { + Plugin *p = item->data; + + if (utils_str_equal(fname, g_module_name(p->module))) + return TRUE; + } + return FALSE; +} + + +static gboolean +plugin_check_version(GModule *module) +{ + gint (*version_check)(gint) = NULL; + gint result; + + g_module_symbol(module, "version_check", (void *) &version_check); + + if (version_check) + { + result = version_check(abi_version); + if (result < 0) + { + geany_debug("Plugin "%s" is not binary compatible with this " + "release of Geany - recompile it.", g_module_name(module)); + return FALSE; + } + if (result > 0) + { + geany_debug("Plugin "%s" requires a newer version of Geany (API >= v%d).", + g_module_name(module), result); + return FALSE; + } + } + return TRUE; +} + + +static Plugin* +plugin_new(const gchar *fname) +{ + Plugin *plugin; + GModule *module; + + g_return_val_if_fail(fname, NULL); + g_return_val_if_fail(g_module_supported(), NULL); + + module = g_module_open(fname, G_MODULE_BIND_LAZY); + if (! module) + { + g_warning("%s", g_module_error()); + return NULL; + } + + if (plugin_loaded(module)) + { + geany_debug("Plugin "%s" already loaded.", fname); + + if (! g_module_close(module)) + g_warning("%s: %s", fname, g_module_error()); + return NULL; + } + + if (! plugin_check_version(module)) + { + if (! g_module_close(module)) + g_warning("%s: %s", fname, g_module_error()); + return NULL; + } + + plugin = g_new0(Plugin, 1); + plugin->filename = g_strdup(fname); + plugin->module = module; + + plugin->data.app = app; + plugin->data.tools_menu = lookup_widget(app->window, "tools1_menu"); + + g_module_symbol(module, "init", (void *) &plugin->init); + g_module_symbol(module, "cleanup", (void *) &plugin->cleanup); + + if (plugin->init) + plugin->init(&plugin->data); + + geany_debug("Loaded: %s (%s)", fname, + NVL(plugin->data.name, "<Unknown>")); + return plugin; +} + + +static void +plugin_free(Plugin *plugin) +{ + g_return_if_fail(plugin); + g_return_if_fail(plugin->module); + + if (plugin->cleanup) + plugin->cleanup(); + + if (! g_module_close(plugin->module)) + g_warning("%s: %s", plugin->filename, g_module_error()); + else + geany_debug("Unloaded: %s", plugin->filename); + + g_free(plugin->filename); + g_free(plugin); +} + + +// TODO: Pass -DLIBDIR="$(libdir)/geany" in Makefile.am +#define LIBDIR \ + PACKAGE_DATA_DIR G_DIR_SEPARATOR_S ".." G_DIR_SEPARATOR_S "lib" \ + G_DIR_SEPARATOR_S PACKAGE + +void plugins_init() +{ + const gchar *path = LIBDIR; + GSList *list, *item; + + list = utils_get_file_list(path, NULL, NULL); + + for (item = list; item != NULL; item = g_slist_next(item)) + { + gchar *fname = g_strconcat(path, G_DIR_SEPARATOR_S, item->data, NULL); + Plugin *plugin; + + plugin = plugin_new(fname); + if (plugin != NULL) + { + plugin_list = g_list_append(plugin_list, plugin); + } + g_free(fname); + } + + g_slist_foreach(list, (GFunc) g_free, NULL); + g_slist_free(list); +} + + +void plugins_free() +{ + if (plugin_list != NULL) + { + g_list_foreach(plugin_list, (GFunc) plugin_free, NULL); + g_list_free(plugin_list); + } +} + + +#endif
Property changes on: trunk/src/plugins.c ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native
Added: trunk/src/plugins.h =================================================================== --- trunk/src/plugins.h (rev 0) +++ trunk/src/plugins.h 2007-06-26 16:17:16 UTC (rev 1643) @@ -0,0 +1,37 @@ +/* + * plugins.h - this file is part of Geany, a fast and lightweight IDE + * + * Copyright 2007 Enrico Tröger enrico.troeger@uvena.de + * Copyright 2007 Nick Treleaven nick.treleaven@btinternet.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id$ + */ + + +#ifndef PLUGINS_H +#define PLUGINS_H + +#ifdef HAVE_PLUGINS + +void plugins_init(); + +void plugins_free(); + +#endif + +#endif
Property changes on: trunk/src/plugins.h ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native
Modified: trunk/win32-config.h =================================================================== --- trunk/win32-config.h 2007-06-26 15:42:55 UTC (rev 1642) +++ trunk/win32-config.h 2007-06-26 16:17:16 UTC (rev 1643) @@ -137,6 +137,9 @@ /* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */
+/* Define if plugins are enabled. */ +//#define HAVE_PLUGINS 1 + /* Define to 1 if you have the `putenv' function. */ #define HAVE_PUTENV 1
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.