DevelopingPlugins
Contents |
About this page
This page is written for C developers that want to create a plugin for Bluefish. It gives a couple of pointers where to look for functions that should be used by plugins. I assume you know about gtk programming.
Other documents to look at
- bluefish.h defines struct Tdocument (for each opened document), struct Tbfwin (for each bluefish window), struct Tmain (one for all bluefish windows)
- document.h has many useful functions that handle on a single document, many are document-content related
- bfwin.h has many useful functions that handle a single bluefish window, many are GUI related
Creating the plugin itself
Create a file that defines a TBluefishPlugin struct (from plugins.h) that defines the plugin functions. All functions may be NULL except for the plugin_init() function, and define the function getplugin() that returns this struct:
static TBluefishPlugin bfplugin = {
"plugin name",
BFPLUGIN_VERSION, /* plugin API version, from plugin.h */
GTK_MAJOR_VERSION, /* gtk major version, gtom gtk.h */
sizeof(Tdocument), /* from bluefish.h */
sizeof(Tsessionvars), /* from bluefish.h */
sizeof(Tglobalsession), /* from bluefish.h */
sizeof(Tbfwin), /* from bluefish.h */
sizeof(Tproject), /* from bluefish.h */
sizeof(Tmain), /* from bluefish.h */
sizeof(Tproperties), /* from bluefish.h */
BFPLUGIN_PRIORITY_DEFAULT, /* the order in which the init functions of the plugins will be called */
1, /* whether or not this plugin is enabled by default */
NULL, /* private */
plugin_init, /* init the plugin, only called once during the lifetime */
plugin_initgui, /* optional, init the gui, called once for every bluefish window */
plugin_enforce_session, /* optional, called when the session for a window changes (after project load/unload)*/
plugin_cleanup, /* optional, called once on bluefish shutdown */
plugin_cleanup_gui, /* optional, called once for every window that is closed */
plugin_register_globses_config, /* optional, register variables that should be stored in the global session */
plugin_register_session_config, /* optional, register variables that should be stored in the active session (project specific) */
plugin_session_cleanup, /* optional, called after a session is closed (during project close */
NULL, /* for future binary compatibility */
NULL, /* for future binary compatibility */
NULL /* for future binary compatibility */
};
G_MODULE_EXPORT TBluefishPlugin *
getplugin(void) {
return &bfplugin;
}
plugin_init
void plugin_init(void)
plugin_initgui
void plugin_initgui(Tbfwin * bfwin)
plugin_enforce_session
void plugin_enforce_session(Tbfwin * bfwin)
plugin_cleanup
void plugin_cleanup(void)
plugin_cleanup_gui
void plugin_cleanup_gui(Tbfwin * bfwin)
plugin_register_globses_config, plugin_register_session_config
GHashTable *plugin_register_globses_config(GHashTable * configlist) GHashTable *plugin_register_session_config(GHashTable * configlist, Tsessionvars * session)
in this function you can call make_config_list_item() from rcfile.h to register a configuration variable that will be either stored in the global session or the per-project session.
for example to register an integer variable, that will be default set to 0:
static GHashTable *plugin_register_globses_config(GHashTable * configlist) {
return make_config_list_item(configlist, &some_plugin_integer, 'i', "myplugin_variable", 0);
}
plugin_session_cleanup
void plugin_session_cleanup(Tsessionvars * session)
Callbacks you can register
Callbacks registered in bluefish.h
in struct Tmain in bluefish.h are a couple of lists in which function pointers can be registered that will be called on certain events:
doc_view_populate_popup_cbs
plugins can register functions here that need to be called when the right-click menu in the document is populated, for an example see the Edit tag and Edit color menu entry that is handled by the htmlbar plugin.
void callback(GtkTextView * textview, GtkMenu * menu, Tdocument * doc)
you can use gtk_menu_shell_prepend() to add items to the menu.
If you want to do something based on the position of the popup in the text, retrieve the last click offset like this:
if (main_v->bevent_doc == doc) {
offset = main_v->bevent_charoffset;
}
doc_view_button_press_cbs
plugins can register functions here that are called on a button press in a document.
void mycallback(GtkWidget * widget, GdkEventButton * bevent, Tdocument * doc)
sidepanel_initgui
plugins can register a function here that is called when the side pane GUI is initialized. Note that pressing F9 or pressing apply in the preferences might call this function.
void callback(Tbfwin *bfwin);
add such a function like this:
main_v->sidepanel_initgui = g_slist_prepend(main_v->sidepanel_initgui,myplugin_sidepanel_initgui);
usually if you use this function you want to add a page to the notebook in the sidebar. Assuming your widgets are inside a GtkVBox in variable vbox, and you have a GtkImage in variable image:
gtk_notebook_insert_page_menu(GTK_NOTEBOOK(bfwin->leftpanel_notebook),vbox,image,gtk_label_new(_("My Plugin")),2);
sidepanel_destroygui
plugins can register a function here that is called when the side pane is destroyed. Note that pressing F9 or pressing apply in the preferences might call this function.
void callback(Tbfwin *bfwin);
Callbacks from bfwin.h
CurdocChangedCallback
In bfwin.h there is an API to register a function PER WINDOW that will be called when the current document changes:
void bfwin_current_document_change_register(Tbfwin *bfwin, CurdocChangedCallback func, gpointer data); void bfwin_current_document_change_remove_by_data(Tbfwin *bfwin, gpointer data);
The callback should look like:
void my_callback(Tbfwin *bfwin, Tdocument *olddoc, Tdocument *newdoc, gpointer data)
DocInsertTextCallback
In bfwin.h there is an API to register a function PER WINDOW that will be called when text is inserted:
void bfwin_document_insert_text_register(Tbfwin *bfwin, DocInsertTextCallback func, gpointer data); void bfwin_document_insert_text_remove_by_data(Tbfwin *bfwin, gpointer data);
The callback should look like:
void my_callback(Tdocument *doc, const gchar *string, GtkTextIter * iter, gint pos, gint len, gint clen, gpointer data)
DocDeleteRangeCallback
In bfwin.h there is an API to register a function PER WINDOW that will be called when text is deleted:
void bfwin_document_delete_range_register(Tbfwin *bfwin, DocDeleteRangeCallback func, gpointer data); void bfwin_document_delete_range_remove_by_data(Tbfwin *bfwin, gpointer data);
The callback should look like:
void my_callback(Tdocument *doc, GtkTextIter * itstart, gint start, GtkTextIter * itend, gint end, const gchar *string, gpointer data)
DocDestroyCallback
In bfwin.h there is an API to register a function PER WINDOW that will be called when a document is destroyed:
void bfwin_document_destroy_register(Tbfwin *bfwin, DocDestroyCallback func, gpointer data); void bfwin_document_destroy_remove_by_data(Tbfwin *bfwin, gpointer data);
The callback should look like:
void my_callback(Tdocument *doc, gpointer data)
Your initgui() function might look like this:
static void
myplugin_initgui(Tbfwin * bfwin) {
static const gchar *myplugin_plugin_ui =
"<ui>"
"<menubar name='MainMenu'>"
"<menu action='ToolsMenu'>"
"<menuitem action='MyMagic'/>"
"</menu>"
"</menubar>"
"</ui>";
GtkActionGroup *action_group;
GError *error = NULL;
static const GtkActionEntry myplugin_actions[] = {
{"MyMagic", NULL, N_("Do my magic"), "<shift><ctrl>\",N_("Do my magic at cursor"), G_CALLBACK(do_magic_cb)},
}
action_group = gtk_action_group_new("mypluginActions");
gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE "_plugin_myplugin");
gtk_action_group_add_actions(action_group, myplugin_actions, G_N_ELEMENTS(myplugin_actions), bfwin);
gtk_ui_manager_insert_action_group(bfwin->uimanager, action_group, 0);
g_object_unref(action_group);
gtk_ui_manager_add_ui_from_string(bfwin->uimanager, myplugin_plugin_ui, -1, &error);
if (error != NULL) {
g_warning("building myplugin plugin menu failed: %s", error->message);
g_error_free(error);
}
}