Minimal Module: Gwyddion Module Library Reference Manual

## Minimal Module Minimal Module — Dissection of a minimal Gwyddion data processing module |

## Module Overview

In this section we will describe a minimal Gwyddion data-processing module. It provides a function to invert values in a channel about zero. The complete module code is:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    #include <libgwyddion/gwymacros.h>
    #include <libprocess/datafield.h>
    #include <libgwymodule/gwymodule-process.h>
    #include <libgwydgets/gwystock.h>
    #include <app/gwyapp.h>

    #define INVERT_VALUE_RUN_MODES GWY_RUN_IMMEDIATE

    static gboolean module_register(void);
    static void     my_invert_value(GwyContainer *data,
                                    GwyRunType run);

    static GwyModuleInfo module_info = {
        GWY_MODULE_ABI_VERSION,
        &module_register,
        N_("Inverts data value."),
        "J. Random Hacker <hacker.jr@example.org>",
        "1.0",
        "Bit Rot Inc.",
        "2006",
    };

    GWY_MODULE_QUERY(module_info)

    static gboolean
    module_register(void)
    {
        gwy_process_func_register("my_invert_value",
                                  (GwyProcessFunc)&my_invert_value,
                                  N_("/_Test/_Invert Value"),
                                  GWY_STOCK_VALUE_INVERT,
                                  INVERT_VALUE_RUN_MODES,
                                  GWY_MENU_FLAG_DATA,
                                  N_("Invert data value about origin"));

        return TRUE;
    }

    static void
    my_invert_value(GwyContainer *data,
                    GwyRunType run)
    {
        GwyDataField *dfield;
        GQuark quark;
        gint id;

        g_return_if_fail(run & INVERT_VALUE_RUN_MODES);
        gwy_app_data_browser_get_current(GWY_APP_DATA_FIELD, &dfield,
                                         GWY_APP_DATA_FIELD_KEY, &quark,
                                         GWY_APP_DATA_FIELD_ID, &id,
                                         0);
        gwy_app_undo_qcheckpointv(data, 1, &quark);
        gwy_data_field_multiply(dfield, -1.0);
        gwy_data_field_data_changed(dfield);
        gwy_app_channel_log_add_proc(data, id, id);
    }

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.

## Boilerplate

First of all, of course, some header files.

    1
    2
    3
    4
    5
    #include <libgwyddion/gwymacros.h>
    #include <libprocess/datafield.h>
    #include <libgwymodule/gwymodule-process.h>
    #include <libgwydgets/gwystock.h>
    #include <app/gwyapp.h>

These four are essential, for a complex modules you may need additional headers. `gwymacros.h` contains some basic macros, `datafield.h` declares basic GwyDataField methods, `gwystock.h` contains stock icon definitions, `gwymodule-process.h` declares functions essential for registering the module and its data processing functions, and `gwyapp.h` includes everything necessary for interfacing with the application.

## Function Prototypes

Function prototypes of our functions.

    1
    2
    3
    static gboolean module_register(void);
    static void     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.

An attentive reader has probably noticed we omitted the line

    1
    #define INVERT_VALUE_RUN_MODES GWY_RUN_IMMEDIATE

where so-called run mode is defined. We will describe run modes in detail in the section about data processing modules. At this point it suffices to say `GWY_RUN_IMMEDIATE` means the function is non-interactive, executed immediately.

## The Module Info Structure

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 in Gwyddion in the module browser.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    static GwyModuleInfo module_info = {
        GWY_MODULE_ABI_VERSION,
        &module_register,
        N_("Inverts data value."),
        "J. Random Hacker <hacker.jr@example.org>",
        "1.0",
        "Bit Rot Inc.",
        "2006",
    };

The first item is always `GWY_MODULE_ABI_VERSION`. The ABI version compiled to the module is checked by the loader on load-time and modules with wrong ABI version are rejected.

The second item is a pointer to module registration function, by convention called `module_register`. It is described in details below.

The fourth item is module description. It will appear as Description in the module browser. This is a short text (up to a paragraph or two) informing curious humans what the module contains and/or does.

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 the module copyright and date. The copyright field may be the same as authors field (except without the e-mail address), it may be an organization, or whoever owns the copyright.

## The Module Query Function

A Gwyddion module is loaded in two stages. First, it is queried, the module responds with its module info, Gwyddion then performs some basic sanity checks (e.g., whether module ABI version matches). If it looks all right, Gwyddion continues with the 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):

    1
    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.

## Module Feature Registration

The module registration function is called in the second registration stage and is responsible for registering particular module functions, each in one turn. Our sample 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.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    static gboolean
    module_register(void)
    {
        gwy_process_func_register("my_invert_value",
                                  (GwyProcessFunc)&my_invert_value,
                                  N_("/_Test/_Invert Value"),
                                  GWY_STOCK_VALUE_INVERT,
                                  INVERT_VALUE_RUN_MODES,
                                  GWY_MENU_FLAG_DATA,
                                  N_("Invert data value about origin"));

        return TRUE;
    }

The registration function normally returns `TRUE`. Returning `FALSE` means the registration failed, and Gwyddion then attempts to unregister all its already registered functions, unload the module and proceed as if it didn't exist.

## Executive

Now let's do some actuall data processing:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    static void
    my_invert_value(GwyContainer *data,
                    GwyRunType run)
    {
        GwyDataField *dfield;
        GQuark quark;
        gint id;

        g_return_if_fail(run & INVERT_VALUE_RUN_MODES);
        gwy_app_data_browser_get_current(GWY_APP_DATA_FIELD, &dfield,
                                         GWY_APP_DATA_FIELD_KEY, &quark,
                                         GWY_APP_DATA_FIELD_ID, &id,
                                         0);
        gwy_app_undo_qcheckpointv(data, 1, &quark);
        gwy_data_field_multiply(dfield, -1.0);
        gwy_data_field_data_changed(dfield);
        gwy_app_channel_log_add_proc(data, id, id);
    }

A few things can be seen here. First, we check the run mode we were executed in. More sofisticated modules can in principle do different things based on the run mode, but we just check whether it looks sane.

Next, we get the data field to operate on. The notion of current object is maintained by the application data browser therefore we us a data browser method (beside the current data field, we also ask for its key that will be useful for undo later).

GwyDataField is the basic data object representing a two-dimensional array of values (typically a height field). Quite a few datafield manipulating functions already exist in libprocess, we will use one of them to perform the value inversion.

Function `gwy_app_undo_qcheckpointv()` creates a point in the undo history we can return to later. It is necessary to call it before we start modifying the data. Its first argument is the data container the objects we will change reside in. Then we pass the number of changed items (1) and an array of their indentifiers in the data container.

Then we finally invert the value with `gwy_data_field_multiply()` and we are done – almost. To notify views displaying our data field that its data has changed we call `gwy_data_field_data_changed()`. This function should be called once on each changed data field after all processing is done.

When we perform a data modification, it should be logged to the data operation log. A new log entry can be added with `gwy_app_channel_log_add_proc()`, where `id` is the numeric identifier of the data field in the container. If the source and target of the operation is the same, we just pass the same identifier twice. If new data are created the two identifier can differ, as described in the logging documentation.