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.