DevelopingPlugins

From Bluefish Wiki
Jump to: navigation, search

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)

Connecting to the menu

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);
}
}
Personal tools