Writing a gedit Plugin with Genie

Introduction

Genie is a great language to write a plugin for gedit. Genie can produce a binary shared object file that maintains the C ABI (Application Binary Interface). So no loading of a language runtime and no runtime parsing of language files are needed. This provides quick start up times for the plugin. Genie also has excellent bindings for the GTK+ 3 graphical user interface stack and this makes it easier to implement user interface details.

The Minimum Needed for a Plugin

The first step is to create the files that allow gedit to find the plugin and display it in the list of plugins. This section of the tutorial covers the basics of how gedit uses libpeas for plugins. It shows:

  • the definition of a peas_register_types () function in the Genie file

  • the .plugin key file used to describe the plugin

  • the valac options to produce a shared object

  • the location to install local plugins for gedit

The Genie File

Save the following Genie code as a file called src/genie-gedit-plugin-tutorial.gs:

uses
	Peas

def peas_register_types( module:ObjectModule )
	print( module.module_name )

The libpeas .plugin File

A plugin needs a .plugin file in GLib's key file format. The file gives details to libpeas about the plugin. Save the following plugin file as genie-gedit-plugin-tutorial.plugin in the top level of the project directory:

[Plugin]
Module=genie-gedit-plugin-tutorial.so
Loader=C
IAge=3
Name=Genie gedit Plugin Tutorial
Description=A gedit plugin written in Genie\nThis plugin demonstrates how to write a gedit plugin using the Genie programming language
Authors=A.N. Other <another@myemail>
Copyright=Copyright © 2016 A.N.Other
Website=https://wiki.gnome.org/Projects/Genie/geditPlugin

Details of other keys that can be present in a .plugin file are given in the GNOME Developer documentation for PeasPluginInfo.

Confirming the Plugin is Working

01_gedit_preferences.png

02_gedit_plugins_list.png

03_gedit_plugin_about.png

A Makefile for the Tutorial

The tutorial aims to provide explanation and examples of writing a useful plugin for gedit. To make the building and installing of the plugin easier the following make file can be used. This is for GNU make and gives a number targets for various stages of the build process.

First copy the following makefile in to a text editor and save it as Makefile in an empty directory:

# Variables
PLUGIN = genie-gedit-plugin-tutorial
SOURCES = src/$(PLUGIN).gs
LIBRARIES = --pkg libpeas-1.0

LIBDIR := $(shell pkg-config --variable=libdir gedit)
MAKEFLAGS += --silent
VALAC = valac

# Targets
.PHONY: all
all: create-build-directory build-shared-object
	echo "$(PLUGIN) built"

.PHONY: clean
clean:
	rm build -rf
	echo "$(PLUGIN) project directory cleaned"

.PHONY: install
install:
	cp \
		build/lib$(PLUGIN).so \
		$(PLUGIN).plugin \
		$(DESTDIR)$(LIBDIR)/gedit/plugins/
	echo "$(PLUGIN) installed"

.PHONY: uninstall
uninstall:
	rm \
		$(DESTDIR)$(LIBDIR)/gedit/plugins/{lib$(PLUGIN).so,$(PLUGIN).plugin}
		echo "$(PLUGIN) uninstalled"

.PHONY: install-local
install-local:
	mkdir --parents $(HOME)/.local/share/gedit/plugins
	cp \
		build/lib$(PLUGIN).so \
		$(PLUGIN).plugin \
		$(HOME)/.local/share/gedit/plugins/
	echo "$(PLUGIN) installed to home .local directory"

.PHONY: uninstall-local
uninstall-local:
	rm \
		$(HOME)/.local/share/gedit/plugins/{lib$(PLUGIN).so,$(PLUGIN).plugin}
	echo "$(PLUGIN) uninstalled from home .local directory"

.PHONY: create-build-directory
create-build-directory:
	mkdir --parents build/
	rm build/* -rf

.PHONY: build-shared-object
build-shared-object:
	$(VALAC) \
		$(SOURCES) \
		$(LIBRARIES) \
		-X -fPIC \
		-X -shared \
		--library $(PLUGIN) \
		--hide-internal \
		--directory build/ \
		--vapi $(PLUGIN).vapi \
		--output lib$(PLUGIN).so

Embedding Resources

User interface templates, image files, CSS files and other resources can be embedded in the plugin using GLib's GResource. This section of the tutorial covers:

  • using the [GtkTemplate] and [GtkCallback] attributes in a Genie class

  • writing a GtkBuilder template to embed in the plugin

  • writing a GResource XML file to include the template
  • compiling the GResource XML file and the template to a single C file
  • compiling the project and C file to make a single plugin binary file

The Genie File

Save the following Genie file as src/color-dialog.gs:

namespace UserInterface

	[GtkTemplate( ui = "/widgets/color-picker.ui" )]
	class private ColorDialog:Gtk.ColorChooserDialog
		[GtkCallback]
		def private close_handler( widget:int )
			this.destroy()

This Genie code makes use of the [GtkTemplate] attribute to generate code to handle a GtkBuilder template. The template is identified by the GResource file name /widgets/color-picker.ui.

The Genie code also adds a Gtk+ signal handler called close_handler. Again an attribute is used to generate the extra code needed. The attribute is [GtkCallback].

The dialog will be called when gedit starts. Change the Genie file src/genie-gedit-plugin-tutorial.gs to:

uses
	Peas

def peas_register_types( module:ObjectModule )
	new ColorDialog().show_all()

Writing a GtkBuilder Template

Save the following GtkBuilder template as src/resources/color-picker.ui:

<interface>
<template class="UserInterfaceColorDialog" parent="GtkColorChooserDialog">
<property name="title">Genie gedit Plugin Tutorial Color Chooser</property>
<signal name="response" handler="close_handler" />
</template>
</interface>

GtkBuilder enables Gtk+3 user interfaces to be defined in XML files. This makes it easier to edit the definitions and to use tools such as Glade user interface designer. There is a schema for the XML user interface definitions.

The above user interface definition creates a template based on GtkColorChooserDialog. The class attribute defines the Genie class that will use the template. The Genie code is later in this section, but for now it should be noted the class is actually UserInterface.ColorDialog because it is in a namespace. The template does not allow for namespaces or sub-namespaces in the class name so the names are concatenated without the dot.

The definition also sets the title property of the GtkColorChooserDialog to "Genie gedit Plugin Tutorial Color Chooser". By having the property in the XML definition it is easier to change. The definition also defines a handler for the response signal from GtkColorChooserDialog. The handler is the close_handler method in the Genie UserInterface.ColorDialog class. In the Genie code earlier in this section this method is written to just close the dialog.

Writing a GResource XML File

Save the following GResource XML file as src/resources/resources.gresource.xml:

<?xml version="1.0" encoding="UTF-8"?>
<gresources>
  <gresource prefix="/widgets">
    <file>color-picker.ui</file>
  </gresource>
</gresources>

Compiling the GResource to a C File

GResources are compiled to a single C file using the glib-compile-resources command.

Add the following target to the end of the Makefile:

.PHONY: compile-resources
compile-resources:
        mkdir build/src/resources --parents
        glib-compile-resources \
                --sourcedir src/resources \
                --generate-source \
                --target build/src/resources/resources.c \
                src/resources/resources.gresource.xml

and then add the compile-resources target as a dependency of make all:

all: create-build-directory compile-resources build-shared-object

The command options to glib-compile-resources identify the directory where the resources are held; that a C source file should be generated; the name of the C file to be generated; and the GResource XML file that lists the resources to be included.

To add further resources just save the resource in the src/resources directory and add it to the list in the XML file. The build instructions to glib-compile-resources do not need to be changed.

Compiling the gedit Plugin

Add the GResources C file and the Genie color-dialog file to the list of source files in the Makefile:

SOURCES = src/$(PLUGIN).gs \
        build/src/resources/resources.c \
        src/color-dialog.gs

Two extra options need to be added to the target that calls valac. Change the build-shared-object target in the Makefile to:

.PHONY: build-shared-object
build-shared-object:
        $(VALAC) \
                $(SOURCES) \
                $(LIBRARIES) \
                --target-glib 2.38 \
                --gresources src/resources/resources.gresource.xml \
                -X -fPIC \
                -X -shared \
                --library $(PLUGIN) \
                --hide-internal \
                --directory build/ \
                --vapi $(PLUGIN).vapi \
                --output lib$(PLUGIN).so

The Vala code generation routines for GtkBuilder require features that are present in GLib 2.38+, so --target-glib 2.38 is added. The use of the [GtkBuilder] attribute does some type checking of the GResource file, so --gresources src/resources/resources.gresource.xml passes the GResource file to Vala to check. Usually this is not required when using a GResource file with Genie.

Confirming the Plugin is Working

Build the plugin and install locally:

make all
make install-local

Now when the plugin starts the following color dialog should appear:

04_compiled_resource.png

Projects/Genie/geditPlugin (last edited 2018-02-22 19:28:42 by AlThomas)