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.
This commit is contained in:
Thomas Martitz 2014-08-22 06:35:47 +02:00
parent b8a99752f0
commit 1d08d3db4a
3 changed files with 69 additions and 39 deletions

View File

@ -194,6 +194,8 @@ GeanyKeyBinding *keybindings_set_item(GeanyKeyGroup *group, gsize key_id,
kb->default_key = key; kb->default_key = key;
kb->default_mods = mod; kb->default_mods = mod;
kb->callback = callback; kb->callback = callback;
kb->cb_func = NULL;
kb->cb_data = NULL;
kb->menu_item = menu_item; kb->menu_item = menu_item;
kb->id = key_id; kb->id = key_id;
return kb; return kb;
@ -208,6 +210,8 @@ static void add_kb_group(GeanyKeyGroup *group,
group->name = name; group->name = name;
group->label = label; group->label = label;
group->callback = callback; group->callback = callback;
group->cb_func = NULL;
group->cb_data = NULL;
group->plugin = plugin; group->plugin = plugin;
group->key_items = g_ptr_array_new(); 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 */ /* 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) 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) if (keyval == kb->key && state == kb->mods)
{ {
/* call the corresponding callback function for this shortcut */ if (run_kb(kb, group))
if (kb->callback)
{
kb->callback(kb->id);
return TRUE; 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) void keybindings_send_command(guint group_id, guint key_id)
{ {
GeanyKeyBinding *kb; GeanyKeyBinding *kb;
GeanyKeyGroup *group;
kb = keybindings_lookup_item(group_id, key_id); kb = keybindings_lookup_item(group_id, key_id);
if (kb) group = keybindings_get_core_group(group_id);
{ if (kb && group)
if (kb->callback) run_kb(kb, group);
kb->callback(key_id);
else
{
GeanyKeyGroup *group = keybindings_get_core_group(group_id);
if (group->callback)
group->callback(key_id);
}
}
} }

View File

@ -37,12 +37,42 @@ G_BEGIN_DECLS
#define GEANY_PRIMARY_MOD_MASK GDK_CONTROL_MASK #define GEANY_PRIMARY_MOD_MASK GDK_CONTROL_MASK
#endif #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. */ /** Function pointer type used for keybinding callbacks. */
typedef void (*GeanyKeyCallback) (guint key_id); 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. /** Represents a single keybinding action.
*
* Use keybindings_set_item() to set. */ * 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 */ 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 */ GdkModifierType mods; /**< Modifier keys, such as @c GDK_CONTROL_MASK or 0 */
@ -57,19 +87,9 @@ typedef struct GeanyKeyBinding
guint id; guint id;
guint default_key; guint default_key;
GdkModifierType default_mods; GdkModifierType default_mods;
} GeanyKeyBindingFunc cb_func;
GeanyKeyBinding; gpointer cb_data;
};
/** 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;
/* Note: we don't need to break the plugin ABI when appending keybinding or keygroup IDs, /* 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 * just make sure to insert immediately before the _COUNT item, so

View File

@ -38,6 +38,8 @@ struct GeanyKeyGroup
GPtrArray *key_items; /* pointers to GeanyKeyBinding structs */ GPtrArray *key_items; /* pointers to GeanyKeyBinding structs */
gsize plugin_key_count; /* number of keybindings the group holds */ gsize plugin_key_count; /* number of keybindings the group holds */
GeanyKeyBinding *plugin_keys; /* array of GeanyKeyBinding structs */ GeanyKeyBinding *plugin_keys; /* array of GeanyKeyBinding structs */
GeanyKeyGroupFunc cb_func; /* use this or individual keybinding callbacks (new style) */
gpointer cb_data;
}; };
G_END_DECLS G_END_DECLS