From 1d08d3db4a0c7f6dc91309f3986d232b26cffb08 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Fri, 22 Aug 2014 06:35:47 +0200 Subject: [PATCH] plugin api: introduce GeanyKeyGroupFunc and GeanyKeyBindingFunc These are new keybinding callback functions that take a few more parameters. Most importantly they have pdata pointer which allows plugins to store context information. This is especially useful for future plugins in OOP languages to store an instance pointer there, or interpreted ones to store interpreter context. --- src/keybindings.c | 58 +++++++++++++++++++++++----------------- src/keybindings.h | 48 +++++++++++++++++++++++---------- src/keybindingsprivate.h | 2 ++ 3 files changed, 69 insertions(+), 39 deletions(-) diff --git a/src/keybindings.c b/src/keybindings.c index 5dcfabcc..f5f5652b 100644 --- a/src/keybindings.c +++ b/src/keybindings.c @@ -194,6 +194,8 @@ GeanyKeyBinding *keybindings_set_item(GeanyKeyGroup *group, gsize key_id, kb->default_key = key; kb->default_mods = mod; kb->callback = callback; + kb->cb_func = NULL; + kb->cb_data = NULL; kb->menu_item = menu_item; kb->id = key_id; return kb; @@ -208,6 +210,8 @@ static void add_kb_group(GeanyKeyGroup *group, group->name = name; group->label = label; group->callback = callback; + group->cb_func = NULL; + group->cb_data = NULL; group->plugin = plugin; group->key_items = g_ptr_array_new(); } @@ -1207,6 +1211,30 @@ gboolean keybindings_check_event(GdkEventKey *ev, GeanyKeyBinding *kb) } +static gboolean run_kb(GeanyKeyBinding *kb, GeanyKeyGroup *group) +{ + gboolean handled = TRUE; + /* call the corresponding handler/callback functions for this shortcut. + * Check the individual keybindings first (handler first, callback second) and + * group second (again handler first, callback second) */ + if (kb->cb_func) + handled = kb->cb_func(kb, kb->id, kb->cb_data); + else if (kb->callback) + kb->callback(kb->id); + else if (group->cb_func) + handled = group->cb_func(group, kb->id, group->cb_data); + else if (group->callback) + handled = group->callback(kb->id); + else + { + g_warning("No callback or handler for keybinding %s: %s!", group->name, kb->name); + return FALSE; + } + + return handled; +} + + /* central keypress event handler, almost all keypress events go to this function */ static gboolean on_key_press_event(GtkWidget *widget, GdkEventKey *ev, gpointer user_data) { @@ -1249,20 +1277,8 @@ static gboolean on_key_press_event(GtkWidget *widget, GdkEventKey *ev, gpointer { if (keyval == kb->key && state == kb->mods) { - /* call the corresponding callback function for this shortcut */ - if (kb->callback) - { - kb->callback(kb->id); + if (run_kb(kb, group)) return TRUE; - } - else if (group->callback) - { - if (group->callback(kb->id)) - return TRUE; - else - continue; /* not handled */ - } - g_warning("No callback for keybinding %s: %s!", group->name, kb->name); } } } @@ -1296,20 +1312,12 @@ GEANY_API_SYMBOL void keybindings_send_command(guint group_id, guint key_id) { GeanyKeyBinding *kb; + GeanyKeyGroup *group; kb = keybindings_lookup_item(group_id, key_id); - if (kb) - { - if (kb->callback) - kb->callback(key_id); - else - { - GeanyKeyGroup *group = keybindings_get_core_group(group_id); - - if (group->callback) - group->callback(key_id); - } - } + group = keybindings_get_core_group(group_id); + if (kb && group) + run_kb(kb, group); } diff --git a/src/keybindings.h b/src/keybindings.h index 06480100..bbe081fd 100644 --- a/src/keybindings.h +++ b/src/keybindings.h @@ -37,12 +37,42 @@ G_BEGIN_DECLS #define GEANY_PRIMARY_MOD_MASK GDK_CONTROL_MASK #endif +/** A collection of keybindings grouped together. */ +typedef struct GeanyKeyGroup GeanyKeyGroup; +typedef struct GeanyKeyBinding GeanyKeyBinding; + +/** Function pointer type used for keybinding group callbacks. + * + * You should return @c TRUE to indicate handling the callback. (Occasionally, if the keybinding + * cannot apply in the current situation, it is useful to return @c FALSE to allow a later keybinding + * with the same key combination to handle it). */ +typedef gboolean (*GeanyKeyGroupCallback) (guint key_id); + +/** Function pointer type used for keybinding group callbacks, with userdata for passing context. + * + * You should return @c TRUE to indicate handling the callback. (Occasionally, if the keybinding + * cannot apply in the current situation, it is useful to return @c FALSE to allow a later keybinding + * with the same key combination to handle it). + * + * @since 1.26 (API 226) */ +typedef gboolean (*GeanyKeyGroupFunc)(GeanyKeyGroup *group, guint key_id, gpointer pdata); + /** Function pointer type used for keybinding callbacks. */ typedef void (*GeanyKeyCallback) (guint key_id); +/** Function pointer type used for keybinding callbacks, with userdata for passing context + * + * You should return @c TRUE to indicate handling the callback. (Occasionally, if the keybinding + * cannot apply in the current situation, it is useful to return @c FALSE to allow a later keybinding + * with the same key combination to handle it). + * + * @since 1.26 (API 226) */ +typedef gboolean (*GeanyKeyBindingFunc)(GeanyKeyBinding *key, guint key_id, gpointer pdata); + /** Represents a single keybinding action. + * * Use keybindings_set_item() to set. */ -typedef struct GeanyKeyBinding +struct GeanyKeyBinding { 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 */ @@ -57,19 +87,9 @@ typedef struct GeanyKeyBinding guint id; guint default_key; GdkModifierType default_mods; -} -GeanyKeyBinding; - - -/** Function pointer type used for keybinding group callbacks. - * You should return @c TRUE to indicate handling the callback. (Occasionally, if the keybinding - * cannot apply in the current situation, it is useful to return @c FALSE to allow a later keybinding - * with the same key combination to handle it). */ -typedef gboolean (*GeanyKeyGroupCallback) (guint key_id); - -/** A collection of keybindings grouped together. */ -typedef struct GeanyKeyGroup GeanyKeyGroup; - + GeanyKeyBindingFunc cb_func; + gpointer cb_data; +}; /* Note: we don't need to break the plugin ABI when appending keybinding or keygroup IDs, * just make sure to insert immediately before the _COUNT item, so diff --git a/src/keybindingsprivate.h b/src/keybindingsprivate.h index d963b4c2..5eb17603 100644 --- a/src/keybindingsprivate.h +++ b/src/keybindingsprivate.h @@ -38,6 +38,8 @@ struct GeanyKeyGroup GPtrArray *key_items; /* pointers to GeanyKeyBinding structs */ gsize plugin_key_count; /* number of keybindings the group holds */ GeanyKeyBinding *plugin_keys; /* array of GeanyKeyBinding structs */ + GeanyKeyGroupFunc cb_func; /* use this or individual keybinding callbacks (new style) */ + gpointer cb_data; }; G_END_DECLS