FmModule

## FmModule FmModule — Simple external modules handler. |

## Synopsis

    #define             CHECK_MODULES                       (...)
    #define             FM_DEFINE_MODULE                    (_type_,
                                                             _name_)
    #define             FM_MODULE_DEFINE_TYPE               (_type_,
                                                             _struct_,
                                                             _minver_)
    gboolean            (*FmModuleInitCallback)             (const char *key,
                                                             gpointer init_data,
                                                             int version);
    gboolean            fm_module_is_in_use                 (const char *type,
                                                             const char *name);
    void                fm_module_register_type             (const char *type,
                                                             int minver,
                                                             int maxver,
                                                             FmModuleInitCallback cb);
    void                fm_module_unregister_type           (const char *type);
    gboolean            fm_modules_add_directory            (const char *path);
    void                fm_modules_load                     (void);

## Description

`include`: libfm/fm.h

This implementation allows applications to use external modules and select which ones application wants to use (from none to all).

The naming scheme in examples below is strict. Replace "dummy" part in them with your real name when you trying to use those examples. Those strict example names are:

- FM_MODULE_dummy_VERSION

- fm_module_init_dummy

- fm_module_callback_dummy

- fm_module_register_dummy

To use modules application should make few things. Let say, there is some FmDummyWidget which wants to use "dummy" type of modules. First thing application should do is create a header file which all modules of that type should include:

Example 1. Sample of fm-dummy.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <libfm/fm.h>

    #define FM_MODULE_dummy_VERSION 1

    typedef struct _FmDummyInit {
        int (*get_new)(const char *name);
    } FmDummyInit;

    extern FmDummyInit fm_module_init_dummy;

The FM_MODULE_dummy_VERSION is a number which should be increased each time something in FmDummyInit structure is changed. The FmDummyInit represents an interface to module. It is specific for said module type. The fm_module_init_dummy usage see below.

Second thing application should do is to create implementation of the module handling in your code:

Example 2. Sample of fm-dummy-widget.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include "fm-dummy.h"

    FM_MODULE_DEFINE_TYPE(dummy, FmDummyInit, 1)

    static gboolean fm_module_callback_dummy(const char *name, gpointer init, int ver)
    {
        /* add module callbacks into own data list */
        .......
    }

    .......
    {
        FmDummyInit *module;
        int result = -1;

        CHECK_MODULES();
        module = _find_module("test");
        if (module)
            result = module->get_new("test sample");
        return result;
    }

Third thing application should do is to register module type on the application start, the same way as application calls `fm_init()` on the start:

    1
    fm_module_register_dummy();

On application terminate it is adviced to unregister module type by calling API `fm_module_unregister_type()` the same way as application calls `fm_finalize()` on exit:

    1
    fm_module_unregister_type("dummy");

The module itself will be easy to make. All you should do is to use `FM_DEFINE_MODULE()` macro and implement callbacks for the module interface (see the fm-dummy.h header example above):

Example 3. Sample of module dummy/test

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include "fm-dummy.h"

    FM_DEFINE_MODULE(dummy, test)

    static int fm_dummy_test_get_new(const char *name)
    {
        /* implementation */
    }

    FmDummyInit fm_module_init_dummy = {
        fm_dummy_test_get_new;
    };

The fm_module_init_dummy should be exactly the same structure that is defined in the header file above.

Note that modules are scanned and loaded only once per application run for simplicity and reliability reasons (in fact, deletion of a module that have some code running in another thread may lead to some unpredictable problems). Therefore if you have any module changed you have to restart the application before it see your change.

## Details

### CHECK_MODULES()

    #define CHECK_MODULES(...) if(G_UNLIKELY(!fm_modules_loaded)) fm_modules_load()

### FM_DEFINE_MODULE()

    #define             FM_DEFINE_MODULE(_type_, _name_)

Macro used in module definition. Module should have module specific structure: if `type` is vfs then it should be fm_module_init_vfs. See specific header file for some `extern' definition.

`_type_` : | type of module (e.g. `vfs')
`_name_` : | module type specific key (e.g. `menu')

### FM_MODULE_DEFINE_TYPE()

    #define             FM_MODULE_DEFINE_TYPE(_type_, _struct_, _minver_)

Macro used in module caller. Callback is ran when matched module is found, it should return `TRUE` on success.

`_type_` : | type of module (e.g. `vfs')
`_struct_` : | type of struct with module callbacks
`_minver_` : | minimum version supported

### FmModuleInitCallback ()

    gboolean            (*FmModuleInitCallback)             (const char *key,
                                                             gpointer init_data,
                                                             int version);

This API is used to make callback from the modules loader to the implementation which uses module so the implementation may do required checks and add module to own list of supported data. This callback will be done in default main context.

`key` : | the module name as key value for the type
`init_data` : | module type specific initialization data
`version` : | version of loaded module
Returns : | `TRUE` if module was accepted by implementation.

Since 1.2.0

### fm_module_is_in_use ()

    gboolean            fm_module_is_in_use                 (const char *type,
                                                             const char *name);

Checks if specified module is found and successfully loaded.

`type` : | module type
`name` : | module key. [allow-none]
Returns : | `TRUE` if module is in use.

Since 1.2.0

### fm_module_register_type ()

    void                fm_module_register_type             (const char *type,
                                                             int minver,
                                                             int maxver,
                                                             FmModuleInitCallback cb);

Registers `type` into the modules loader. The modules loader will call `cb` routine when module that supports the `type` was found within the libfm modules directory. The scanning for modules will be done after some timeout after last call to `fm_module_register_type()` so this API should be used at application start before any possible modules usage may appear.

`type` : | module type, unique for the application
`minver` : | minimum supported module version
`maxver` : | maximum supported module version
`cb` : | the callback used to inform about found module

Since 1.2.0

### fm_module_unregister_type ()

    void                fm_module_unregister_type           (const char *type);

Frees any resources that were allocated previously on the call to `fm_module_register_type()` API, including code of the modules. After this call any usage of data from callbacks will be invalid and the most possibly lead to crash so it might be called only on finalizing the application data.

`type` : | module type, unique for the application

Since 1.2.0

### fm_modules_add_directory ()

    gboolean            fm_modules_add_directory            (const char *path);

Adds an application-specific directory `path` to be used later for scanning for modules. The `path` should be absolute UNIX path.

`path` : | absolute path to modules directory
Returns : | `TRUE` if `path` was added successfully.

Since 1.2.0

### fm_modules_load ()

    void                fm_modules_load                     (void);

Forces scanning the libfm modules for existing modules. Any calls to `fm_module_register_type()` after this will have no effect.

Since 1.2.0