![]() |
![]() |
![]() |
Gwyddion Module Library Reference Manual | ![]() |
---|
A Minimal ModuleA Minimal Module — Dissection of a minimal Gwyddion data processing module. |
A minimal Gwyddion data-processing module could look like this:
#include <libgwyddion/gwymacros.h> #include <libgwymodule/gwymodule.h> #include <libprocess/datafield.h> #include <app/gwyapp.h> #define INVERT_VALUE_RUN_MODES \ (GWY_RUN_NONINTERACTIVE | GWY_RUN_WITH_DEFAULTS) static gboolean module_register (const gchar *name); static gboolean my_invert_value (GwyContainer *data, GwyRunType run); static GwyModuleInfo module_info = { GWY_MODULE_ABI_VERSION, &module_register, "value_invert", "Inverts data value.", "J. Random Hacker <hacker.jr@example.org>", "1.0", "J. Random Hacker", "2004", }; GWY_MODULE_QUERY(module_info) static gboolean module_register(const gchar *name) { static GwyProcessFuncInfo my_invert_value_func_info = { "my_invert_value", "/_Test/_Invert Value", (GwyProcessFunc)&my_invert_value, INVERT_VALUE_RUN_MODES, 0, }; gwy_process_func_register(name, &my_invert_value_func_info); return TRUE; } static gboolean my_invert_value(GwyContainer *data, GwyRunType run) { GwyDataField *dfield; g_return_val_if_fail(run & INVERT_VALUE_RUN_MODES, FALSE); dfield = GWY_DATA_FIELD(gwy_container_get_object_by_name(data, "/0/data")); gwy_app_undo_checkpoint(data, "/0/data", NULL); gwy_data_field_invert(dfield, FALSE, FALSE, TRUE); return TRUE; }
Now, we should be able to compile this code (see below), make a dynamically linked library (*.so, *.dll, depending on the operating system) and put it to your Gwyddion modules directory (e. g. /lib/gwyddion/modules/process/, however depending on your actual installation and operating system). After Gwyddion starts, the module is found and menu entry Test/Invert Value will appear in the main menu. Clicking on this menu item will invert the actual data. As this is the minimal module it even does not have graphical user interface to change parameters of data processing. However, for its purpose – data inversion – it is sufficient.
Though the above example is minimal it still constis of quite a bit of code. We will analyse it piece-by-piece in the following paragraphs.
First of all, of course, some header files.
#include <libgwyddion/gwymacros.h> #include <libgwymodule/gwymodule.h> #include <libprocess/datafield.h> #include <app/gwyapp.h>
These four are essential, for a complex modules you may need additional
headers.
gwymacros.h
contains some basic macros (none of them is actually used here),
gwymodule.h
declares functions essential for registering the module and its features,
datafield.h
declared basic GwyDataField functions
(like value inversion we will use in the module later), and
gwyapp.h
declares undo/redo functions and other main application related
stuff.
Now we declare the run modes our module supports.
#define INVERT_VALUE_RUN_MODES \ (GWY_RUN_NONINTERACTIVE | GWY_RUN_WITH_DEFAULTS)
This is just a convenience macro, so we don't have to type them several times manually.
There are four run modes total,
though GWY_RUN_MODAL
and
GWY_RUN_INTERACTIVE
are useful only for modules
with a graphical user interface.
GWY_RUN_NONINTERACTIVE
is the right
run mode for a noninteractive module like our example.
GWY_RUN_WITH_DEFAULT
is currently
unused in Gwyddion, but it's a good idea (and easy) to support it too.
Function prototypes of our functions.
static gboolean module_register (const gchar *name); static gboolean my_invert_value (GwyContainer *data, GwyRunType run);
Note all
functions and global variables should be declared
static
, the module should export no symbol
except GWY_MODULE_QUERY
described below.
Here the interesting part starts. The GwyModuleInfo structure contains overall information about the module, most of it is presented in a more-or-less human-readable form Gwyddion in the module browser.
static GwyModuleInfo module_info = { GWY_MODULE_ABI_VERSION, &module_register, "value_invert", "Inverts data value.", "J. Random Hacker <hacker.jr@example.org>", "1.0", "J. Random Hacker", "2004",
The first item is always
GWY_MODULE_ABI_VERSION.
The second one is a pointer to module registration function, by
convention called module_register
, it is described
in details below.
The third item ("value_invert"
) is the module name.
It will appear as Module in the browser.
A module is uniquely identified by its name, so module name have to be
unique, Gwyddion refuses to load more modules of the same name. Otherwise
it is a free-form string, though by convention, it is usually kept
the same as file name of the module.
The fourth item is module description. It will appear as Description in the browser. This is a short text (up to a paragraph or two) informing curious humans what the module is about.
The next item is the module author(s). Under normal circumstances this should be a name of a person (or more people). Including a contact e-mail address here it's a good idea because it will appear in the browser as Authors, so people don't need to look to the module sources to find out how to contact you.
The next item is the module version, a free-form string that will appear as Version in the browser. Though it is free-form, using a versioning scheme with alorithmically comparable versions is preferable.
The last but one and last items are module copyright and date. The copyright field may be the same as authors field (except without the eventual e-mail address), it may be an organization, or even someone else than the author.
A Gwyddion module is loaded in two stages. First, it is queried, the module responds with its module info, Gwyddion checks whether it looks good (e.g., whether module ABI version matches). If it is OK, Gwyddion continues with registration of particular module features.
The query function should be always constructed using the GWY_MODULE_QUERY macro as follows (note there is no semicolon after the right parenthesis):
GWY_MODULE_QUERY(module_info)
The module_info
parameter is the module info
described above. If you change its name for any reason, change it here
too.
The module registration function is called in the second registration
stage and is responsible for registering particular module functions.
Our module registeres only a one function,
my_invert_value
.
Each function type has its own registration function, our function is a data processing one, so it's registered with gwy_process_func_register(). File loading and/or saving functions are registered with gwy_file_func_register(), etc. (at the time of writing this there exist four module function types).
The registration itself is carried out by filling a function info
structure and calling gwy_*_func_register()
with
the info. Note the function info has to be persistent (static), because
Gwyddion doesn't make a copy of it. It must not be freed or changed
after the registration.
static gboolean module_register(const gchar *name) { static GwyProcessFuncInfo my_invert_value_func_info = { "my_invert_value", "/_Test/My _Invert Value", (GwyProcessFunc)&my_invert_value, INVERT_VALUE_RUN_MODES, 0, }; gwy_process_func_register(name, &my_invert_value_func_info); return TRUE; }
The registration function should always return TRUE
.
Returning FALSE
means the registration failed, and
Gwyddion then tries to unregister all its already registered functions
and unload the module. Normally there is hardly any reason why the
registration could fail.
The name
argument has to be passed as the first
argument of all function registration calls
(gwy_process_func_register()
here).
Now it is identical to module name specified in module info, but
don't count on it.
Each function type has a different function info structure, though some
fields are present in all of them. Data processing function info
GwyProcessFuncInfo consits
of function name (again, this has to be an unique identifier, among
the functions of the same type), path where it should be placed into
the Data Process menu, a pointer to the function itself
(my_invert_value
), and run modes it supports (we
cleverly defined the INVERT_VALUE_RUN_MODES
macro
for them).
Now, let's do the actuall data processing:
static gboolean my_invert_value(GwyContainer *data, GwyRunType run) { GwyDataField *dfield; g_return_val_if_fail(run & INVERT_VALUE_RUN_MODES, FALSE); dfield = GWY_DATA_FIELD(gwy_container_get_object_by_name(data, "/0/data")); gwy_app_undo_checkpoint(data, "/0/data", NULL); gwy_data_field_invert(dfield, FALSE, FALSE, TRUE); return TRUE; }
A few things can be seen here. First, we check the run mode. More sofisticated modules with a GUI and their own settings can do different things based on the run mode, but we just check whether it looks sane.
Next, we get a datafield from some container. The GwyDataField object is the basic data object representing two-dimensional array of values (height field). Quite a few datafield manipulating functions already exist in libprocess, we use one of them (gwy_data_field_invert()) to perform the value inversion too.
The obscure part is getting the datafield out from some container that
was passed to our function. Just take it as a fact the data are
called "/0/data"
, it is probably equally good name
as anything else. There are other strange things in the container
but you'd rather not want to know about them (at least not now, some
more exotic container inhabitants are described in the
Beyond Minimal Module
section).
The
gwy_app_undo_checkpoint()
creates a point in the undo history we can return to later, call it
just before you start modifying the data. Its second argument is
what is to be saved, so "/0/data"
follows us here
too. The NULL
just terminates the argument list.
Then we finally invert the value with
gwy_data_field_invert()
and return TRUE
since we modified the data. If we
didn't modify them, we would have returned FALSE
.