SF.net SVN: geany:[4115] trunk

ntrel at users.sourceforge.net ntrel at xxxxx
Mon Aug 24 11:35:13 UTC 2009


Revision: 4115
          http://geany.svn.sourceforge.net/geany/?rev=4115&view=rev
Author:   ntrel
Date:     2009-08-24 11:35:13 +0000 (Mon, 24 Aug 2009)

Log Message:
-----------
Update PLUGIN_KEY_GROUP() macro so it doesn't allocate any
GeanyKeyBinding or GeanyKeyGroup structs, so we don't need to break
the ABI when adding fields to them.
Add plugin_set_key_group() for plugins to dynamically set a
keybinding group (e.g. for the Lua script plugin). Used in Split
Window plugin as an example.
Improve keybinding docs a little.

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/doc/pluginsymbols.c
    trunk/plugins/geanyfunctions.h
    trunk/plugins/splitwindow.c
    trunk/src/keybindings.c
    trunk/src/keybindings.h
    trunk/src/plugindata.h
    trunk/src/plugins.c
    trunk/src/pluginutils.c
    trunk/src/pluginutils.h

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2009-08-24 09:41:17 UTC (rev 4114)
+++ trunk/ChangeLog	2009-08-24 11:35:13 UTC (rev 4115)
@@ -1,3 +1,18 @@
+2009-08-24  Nick Treleaven  <nick(dot)treleaven(at)btinternet(dot)com>
+
+ * src/keybindings.c, src/keybindings.h, src/plugindata.h,
+   src/pluginutils.c, src/plugins.c, src/pluginutils.h,
+   doc/pluginsymbols.c, plugins/geanyfunctions.h,
+   plugins/splitwindow.c:
+   Update PLUGIN_KEY_GROUP() macro so it doesn't allocate any
+   GeanyKeyBinding or GeanyKeyGroup structs, so we don't need to break
+   the ABI when adding fields to them.
+   Add plugin_set_key_group() for plugins to dynamically set a
+   keybinding group (e.g. for the Lua script plugin). Used in Split
+   Window plugin as an example.
+   Improve keybinding docs a little.
+
+
 2009-08-20  Nick Treleaven  <nick(dot)treleaven(at)btinternet(dot)com>
 
  * doc/Doxyfile.in, plugins/geanyfunctions.h, plugins/genapi.py:

Modified: trunk/doc/pluginsymbols.c
===================================================================
--- trunk/doc/pluginsymbols.c	2009-08-24 09:41:17 UTC (rev 4114)
+++ trunk/doc/pluginsymbols.c	2009-08-24 11:35:13 UTC (rev 4115)
@@ -70,16 +70,10 @@
  * @see plugin_signal_connect(). */
 PluginCallback plugin_callbacks[];
 
-/** Most plugins should use the PLUGIN_KEY_GROUP() macro to define it. However,
- * its fields are not read until after plugin_init() is called for the plugin, so it
- * is possible to setup a variable number of keybindings, e.g. based on the
- * plugin's configuration file settings.
- * - The @c name field must not be empty or match Geany's default group name.
- * - The @c label field is set by Geany after plugin_init() is called to the name of the
- * plugin.
- * @note This is a single element array for implementation reasons,
- * but you can treat it like a pointer. */
-KeyBindingGroup plugin_key_group[1];
+/** Plugins must use the PLUGIN_KEY_GROUP() macro to define it.
+ * To setup a variable number of keybindings, e.g. based on the
+ * plugin's configuration file settings, use plugin_set_key_group() instead. */
+KeyBindingGroup *plugin_key_group;
 
 
 /** Called before showing the plugin preferences dialog to let the user set some basic

Modified: trunk/plugins/geanyfunctions.h
===================================================================
--- trunk/plugins/geanyfunctions.h	2009-08-24 09:41:17 UTC (rev 4114)
+++ trunk/plugins/geanyfunctions.h	2009-08-24 11:35:13 UTC (rev 4115)
@@ -22,6 +22,8 @@
 	geany_functions->p_plugin->module_make_resident
 #define plugin_signal_connect \
 	geany_functions->p_plugin->signal_connect
+#define plugin_set_key_group \
+	geany_functions->p_plugin->set_key_group
 #define document_new_file \
 	geany_functions->p_document->new_file
 #define document_get_current \

Modified: trunk/plugins/splitwindow.c
===================================================================
--- trunk/plugins/splitwindow.c	2009-08-24 09:41:17 UTC (rev 4114)
+++ trunk/plugins/splitwindow.c	2009-08-24 11:35:13 UTC (rev 4115)
@@ -39,6 +39,7 @@
 
 GeanyData		*geany_data;
 GeanyFunctions	*geany_functions;
+GeanyPlugin		*geany_plugin;
 
 
 /* Keybinding(s) */
@@ -50,9 +51,6 @@
 	KB_COUNT
 };
 
-PLUGIN_KEY_GROUP(split_window, KB_COUNT);
-
-
 enum State
 {
 	STATE_SPLIT_HORIZONTAL,
@@ -396,6 +394,7 @@
 void plugin_init(GeanyData *data)
 {
 	GtkWidget *item, *menu;
+	GeanyKeyGroup *key_group;
 
 	menu_items.main = item = gtk_menu_item_new_with_mnemonic(_("_Split Window"));
 	gtk_menu_shell_append(GTK_MENU_SHELL(geany_data->main_widgets->tools_menu), item);
@@ -424,11 +423,12 @@
 	set_state(STATE_UNSPLIT);
 
 	/* setup keybindings */
-	keybindings_set_item(plugin_key_group, KB_SPLIT_HORIZONTAL, kb_activate,
+	key_group = plugin_set_key_group(geany_plugin, "split_window", KB_COUNT, NULL);
+	keybindings_set_item(key_group, KB_SPLIT_HORIZONTAL, kb_activate,
 		0, 0, "split_horizontal", _("Split Horizontally"), menu_items.horizontal);
-	keybindings_set_item(plugin_key_group, KB_SPLIT_VERTICAL, kb_activate,
+	keybindings_set_item(key_group, KB_SPLIT_VERTICAL, kb_activate,
 		0, 0, "split_vertical", _("Split Vertically"), menu_items.vertical);
-	keybindings_set_item(plugin_key_group, KB_SPLIT_UNSPLIT, kb_activate,
+	keybindings_set_item(key_group, KB_SPLIT_UNSPLIT, kb_activate,
 		0, 0, "split_unsplit", _("Unsplit"), menu_items.unsplit);
 }
 

Modified: trunk/src/keybindings.c
===================================================================
--- trunk/src/keybindings.c	2009-08-24 09:41:17 UTC (rev 4114)
+++ trunk/src/keybindings.c	2009-08-24 11:35:13 UTC (rev 4115)
@@ -114,11 +114,11 @@
 /** Simple convenience function to fill a GeanyKeyBinding struct item.
  * @param group Group.
  * @param key_id Keybinding index for the group.
- * @param callback Function to call when activated.
+ * @param callback Function to call when activated, or @c NULL.
  * @param key (Lower case) default key, e.g. @c GDK_j, but usually 0 for unset.
  * @param mod Default modifier, e.g. @c GDK_CONTROL_MASK, but usually 0 for unset.
- * @param name Not duplicated - use a static string.
- * @param label Currently not duplicated - use a static or heap-allocated (e.g. translated) string.
+ * @param name Key name for the configuration file, such as @c "menu_new".
+ * @param label Label used in the preferences dialog keybindings tab.
  * @param menu_item Optional widget to set an accelerator for, or @c NULL. */
 void keybindings_set_item(GeanyKeyGroup *group, gsize key_id,
 		GeanyKeyCallback callback, guint key, GdkModifierType mod,

Modified: trunk/src/keybindings.h
===================================================================
--- trunk/src/keybindings.h	2009-08-24 09:41:17 UTC (rev 4114)
+++ trunk/src/keybindings.h	2009-08-24 11:35:13 UTC (rev 4115)
@@ -31,30 +31,30 @@
 #define GEANY_KEYBINDINGS_H 1
 
 
-/** Function pointer type used for keybinding callbacks */
+/** Function pointer type used for keybinding callbacks. */
 typedef void (*GeanyKeyCallback) (guint key_id);
 
-/** Represents a single keybinding action */
+/** Represents a single keybinding action. */
 /* Note: name and label are not const strings so plugins can set them to malloc'd strings
  * and free them in cleanup(). */
 typedef struct GeanyKeyBinding
 {
-	guint key;				/**< Key value in lower-case, such as @c GDK_a */
-	GdkModifierType mods;	/**< Modifier keys, such as @c GDK_CONTROL_MASK */
+	guint key;				/**< Key value in lower-case, such as @c GDK_a or 0 */
+	GdkModifierType mods;	/**< Modifier keys, such as @c GDK_CONTROL_MASK or 0 */
 	gchar *name;			/**< Key name for the configuration file, such as @c "menu_new" */
 	gchar *label;			/**< Label used in the preferences dialog keybindings tab */
-	GeanyKeyCallback callback;	/**< Callback function called when the key combination is pressed */
-	GtkWidget *menu_item;	/**< Menu item widget for setting the menu accelerator */
+	GeanyKeyCallback callback;	/**< Function called when the key combination is pressed, or @c NULL */
+	GtkWidget *menu_item;	/**< Optional widget to set an accelerator for, or @c NULL */
 } GeanyKeyBinding;
 
 
-/** A collection of keybindings grouped together. */
+/** A collection of keybindings grouped together. Plugins should not set these fields. */
 typedef struct GeanyKeyGroup
 {
 	const gchar *name;		/**< Group name used in the configuration file, such as @c "html_chars" */
-	const gchar *label;		/**< Group label used in the preferences dialog keybindings tab */
-	gsize count;			/**< Count of GeanyKeyBinding structs in @c keys */
-	GeanyKeyBinding *keys;	/**< Fixed array of GeanyKeyBinding structs */
+	const gchar *label;		/* Group label used in the preferences dialog keybindings tab */
+	gsize count;			/**< The number of keybindings the group holds */
+	GeanyKeyBinding *keys;	/* array of GeanyKeyBinding structs */
 }
 GeanyKeyGroup;
 

Modified: trunk/src/plugindata.h
===================================================================
--- trunk/src/plugindata.h	2009-08-24 09:41:17 UTC (rev 4114)
+++ trunk/src/plugindata.h	2009-08-24 11:35:13 UTC (rev 4115)
@@ -50,13 +50,13 @@
 enum {
 	/** The Application Programming Interface (API) version, incremented
 	 * whenever any plugin data types are modified or appended to. */
-	GEANY_API_VERSION = 150,
+	GEANY_API_VERSION = 151,
 
 	/** The Application Binary Interface (ABI) version, incremented whenever
 	 * existing fields in the plugin data types have to be changed or reordered. */
 	/* This should usually stay the same if fields are only appended, assuming only pointers to
 	 * structs and not structs themselves are declared by plugins. */
-	GEANY_ABI_VERSION = 63
+	GEANY_ABI_VERSION = 64
 };
 
 /** Check the plugin can be loaded by Geany.
@@ -119,23 +119,32 @@
 	}
 
 
+/** @see PLUGIN_KEY_GROUP() macro. */
+typedef struct GeanyKeyGroupInfo
+{
+	const gchar *name;		/**< Group name used in the configuration file, such as @c "html_chars" */
+	gsize count;			/**< The number of keybindings the group will hold */
+}
+GeanyKeyGroupInfo;
+
 /** Declare and initialise a keybinding group.
- * @code GeanyKeyGroup plugin_key_group[1]; @endcode
- * You must then set the @c plugin_key_group::keys[] entries for the group in plugin_init().
+ * @code GeanyKeyGroup *plugin_key_group; @endcode
+ * You must then set the @c plugin_key_group::keys[] entries for the group in plugin_init(),
+ * normally using keybindings_set_item().
  * The @c plugin_key_group::label field is set by Geany after @c plugin_init()
  * is called, to the name of the plugin.
  * @param group_name A unique group name (without quotes) to be used in the
  * configuration file, such as @c html_chars.
- * @param key_count	The number of keybindings the group will hold. */
+ * @param key_count	The number of keybindings the group will hold.
+ * @see plugin_set_key_group() to set the group size dynamically. */
 #define PLUGIN_KEY_GROUP(group_name, key_count) \
-	static GeanyKeyBinding plugin_keys[key_count]; \
-	\
-	/* We have to declare plugin_key_group as a single element array.
+	/* We have to declare this as a single element array.
 	 * Declaring as a pointer to a struct doesn't work with g_module_symbol(). */ \
-	GeanyKeyGroup plugin_key_group[1] = \
+	GeanyKeyGroupInfo plugin_key_group_info[1] = \
 	{ \
-		{G_STRINGIFY(group_name), NULL, key_count, plugin_keys} \
-	};
+		{G_STRINGIFY(group_name), key_count} \
+	};\
+	GeanyKeyGroup *plugin_key_group = NULL;
 
 
 /** Callback array entry type used with the @ref plugin_callbacks symbol. */
@@ -225,7 +234,7 @@
 	struct NavQueueFuncs        *p_navqueue;		/**< See navqueue.h */
 	struct EditorFuncs        	*p_editor;			/**< See editor.h */
 	struct MainFuncs        	*p_main;			/**< See main.h */
-	struct PluginFuncs        	*p_plugin;			/**< See plugins.c */
+	struct PluginFuncs        	*p_plugin;			/**< See pluginutils.c */
 	struct ScintillaFuncs		*p_scintilla;		/**< See ScintillaFuncs */
 	struct MsgWinFuncs			*p_msgwin;			/**< See msgwindow.h */
 }
@@ -541,7 +550,10 @@
 EditorFuncs;
 
 
-/* See plugins.c */
+/* avoid including keybindings.h */
+typedef gboolean (*_GeanyKeyGroupCallback) (guint key_id);
+
+/* See pluginutils.c */
 typedef struct PluginFuncs
 {
 	void	(*add_toolbar_item)(GeanyPlugin *plugin, GtkToolItem *item);
@@ -549,6 +561,8 @@
 	void	(*signal_connect) (GeanyPlugin *plugin,
 		GObject *object, gchar *signal_name, gboolean after,
 		GCallback callback, gpointer user_data);
+	struct GeanyKeyGroup* (*set_key_group)(GeanyPlugin *plugin,
+		const gchar *section_name, gsize count, _GeanyKeyGroupCallback callback);
 }
 PluginFuncs;
 
@@ -556,7 +570,8 @@
 /* Deprecated aliases */
 #ifndef GEANY_DISABLE_DEPRECATED
 
-/** @c NULL-safe way to get the index of @a doc_ptr in the documents array. */
+/** @deprecated - copy into your plugin code if needed.
+ * @c NULL-safe way to get the index of @a doc_ptr in the documents array. */
 #define DOC_IDX(doc_ptr) \
 	(doc_ptr ? doc_ptr->index : -1)
 #define DOC_IDX_VALID(doc_idx) \

Modified: trunk/src/plugins.c
===================================================================
--- trunk/src/plugins.c	2009-08-24 09:41:17 UTC (rev 4114)
+++ trunk/src/plugins.c	2009-08-24 11:35:13 UTC (rev 4115)
@@ -82,7 +82,8 @@
 static PluginFuncs plugin_funcs = {
 	&plugin_add_toolbar_item,
 	&plugin_module_make_resident,
-	&plugin_signal_connect
+	&plugin_signal_connect,
+	&plugin_set_key_group
 };
 
 static DocumentFuncs doc_funcs = {
@@ -447,42 +448,36 @@
 }
 
 
-static void
-add_kb_group(Plugin *plugin)
+static void read_key_group(Plugin *plugin)
 {
-	guint i;
+	GeanyKeyGroupInfo *p_key_info;
+	GeanyKeyGroup **p_key_group;
 
-	if (!NZV(plugin->key_group->name))
+	g_module_symbol(plugin->module, "plugin_key_group_info", (void *) &p_key_info);
+	g_module_symbol(plugin->module, "plugin_key_group", (void *) &p_key_group);
+	if (p_key_info && p_key_group)
 	{
-		geany_debug("Plugin \"%s\" has not set a name for its keybinding group"
-			" - ignoring all keybindings!",
-			plugin->info.name);
-		return;
-	}
-	g_return_if_fail(! g_str_equal(plugin->key_group->name, keybindings_keyfile_group_name));
+		GeanyKeyGroupInfo *key_info = p_key_info;
 
-	for (i = 0; i < plugin->key_group->count; i++)
-	{
-		GeanyKeyBinding *kb = &plugin->key_group->keys[i];
-
-		if (!NZV(kb->name))
+		if (*p_key_group)
+			geany_debug("Ignoring plugin_key_group symbol for plugin '%s' - "
+				"use plugin_set_key_group() instead to allocate keybindings dynamically.",
+				plugin->info.name);
+		else
 		{
-			geany_debug("Plugin \"%s\" has not set a name for keybinding %d"
-				" - ignoring all keybindings!",
-				plugin->info.name, i);
-			plugin->key_group->count = 0;
-			break;
+			if (key_info->count)
+			{
+				GeanyKeyGroup *key_group =
+					plugin_set_key_group(&plugin->public, key_info->name, key_info->count, NULL);
+				if (key_group)
+					*p_key_group = key_group;
+			}
+			else
+				geany_debug("Ignoring plugin_key_group_info symbol for plugin '%s' - "
+					"count field is zero. Maybe use plugin_set_key_group() instead?",
+					plugin->info.name);
 		}
 	}
-	if (plugin->key_group->count == 0)
-	{
-		plugin->key_group = NULL;	/* Ignore the group (maybe the plugin has optional KB) */
-		return;
-	}
-
-	plugin->key_group->label = plugin->info.name;
-
-	g_ptr_array_add(keybinding_groups, plugin->key_group);
 }
 
 
@@ -512,6 +507,7 @@
 	g_module_symbol(plugin->module, "plugin_fields", (void *) &plugin_fields);
 	if (plugin_fields)
 		*plugin_fields = &plugin->fields;
+	read_key_group(plugin);
 
 	/* start the plugin */
 	g_return_if_fail(plugin->init);
@@ -539,10 +535,6 @@
 	if (callbacks)
 		add_callbacks(plugin, callbacks);
 
-	g_module_symbol(plugin->module, "plugin_key_group", (void *) &plugin->key_group);
-	if (plugin->key_group)
-		add_kb_group(plugin);
-
 	/* remember which plugins are active */
 	active_plugin_list = g_list_append(active_plugin_list, plugin);
 
@@ -692,8 +684,11 @@
 	remove_callbacks(plugin);
 
 	if (plugin->key_group)
+	{
+		g_free(plugin->key_group->keys);
 		g_ptr_array_remove_fast(keybinding_groups, plugin->key_group);
-
+		setptr(plugin->key_group, NULL);
+	}
 	widget = plugin->toolbar_separator.widget;
 	if (widget)
 		gtk_widget_destroy(widget);

Modified: trunk/src/pluginutils.c
===================================================================
--- trunk/src/pluginutils.c	2009-08-24 09:41:17 UTC (rev 4114)
+++ trunk/src/pluginutils.c	2009-08-24 11:35:13 UTC (rev 4115)
@@ -27,11 +27,15 @@
  * These functions all take the @ref geany_plugin symbol as their first argument. */
 
 #include "geany.h"
+
+#include <string.h>
+
 #include "pluginutils.h"
 #include "pluginprivate.h"
 
 #include "ui_utils.h"
 #include "toolbar.h"
+#include "utils.h"
 
 
 /** Insert a toolbar item before the Quit button, or after the previous plugin toolbar item.
@@ -125,3 +129,51 @@
 }
 
 
+/** Setup or resize a keybinding group for the plugin.
+ * You should then call keybindings_set_item() for each keybinding in the group.
+ * @param plugin Must be @ref geany_plugin.
+ * @param section_name Name used in the configuration file, such as @c "html_chars".
+ * @param count Number of keybindings for the group.
+ * @param callback Unused, must be @c NULL.
+ * @return The plugin's keybinding group.
+ * @since 0.19. */
+GeanyKeyGroup *plugin_set_key_group(GeanyPlugin *plugin,
+		const gchar *section_name, gsize count, GeanyKeyGroupCallback callback)
+{
+	GeanyKeyGroup *group;
+	GeanyPluginPrivate *priv = plugin->priv;
+
+	g_return_val_if_fail(section_name, NULL);
+	g_return_val_if_fail(count, NULL);
+	g_return_val_if_fail(!callback, NULL);
+
+	if (!priv->key_group)
+		priv->key_group = g_new0(GeanyKeyGroup, 1);
+	group = priv->key_group;
+
+	group->name = section_name;
+
+	if (!group->keys || count > group->count)
+	{
+		group->keys = g_renew(GeanyKeyBinding, group->keys, count);
+		memset(group->keys + group->count, 0, (count - group->count) * sizeof(GeanyKeyBinding));
+	}
+	group->count = count;
+
+	if (!NZV(group->name))
+	{
+		geany_debug("Plugin \"%s\" has not set the name field for its keybinding group"
+			" - ignoring all keybindings!",
+			priv->info.name);
+		return NULL;
+	}
+	/* prevent conflict with core bindings */
+	g_return_val_if_fail(! g_str_equal(group->name, keybindings_keyfile_group_name), NULL);
+
+	group->label = priv->info.name;
+
+	g_ptr_array_add(keybinding_groups, group);
+	return group;
+}
+
+

Modified: trunk/src/pluginutils.h
===================================================================
--- trunk/src/pluginutils.h	2009-08-24 09:41:17 UTC (rev 4114)
+++ trunk/src/pluginutils.h	2009-08-24 11:35:13 UTC (rev 4115)
@@ -26,7 +26,7 @@
 #ifndef PLUGINUTILS_H
 #define PLUGINUTILS_H
 
-#include "plugindata.h"
+#include "plugindata.h"	/* GeanyPlugin */
 
 void plugin_add_toolbar_item(GeanyPlugin *plugin, GtkToolItem *item);
 
@@ -36,4 +36,11 @@
 		GObject *object, gchar *signal_name, gboolean after,
 		GCallback callback, gpointer user_data);
 
+
+/** Function pointer type used for keybinding group callbacks. */
+typedef gboolean (*GeanyKeyGroupCallback) (guint key_id);
+
+struct GeanyKeyGroup *plugin_set_key_group(GeanyPlugin *plugin,
+		const gchar *section_name, gsize count, GeanyKeyGroupCallback callback);
+
 #endif /* PLUGINUTILS_H */


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the Commits mailing list