External Libraries and Modules

Name

gg_module, gg_plugin, ggPlugModule, ggClosePlugin : External Libraries and Modules

Synopsis

#include <ggi/gg-api.h>

struct gg_api;
struct gg_module_state;

struct gg_module {
      const char *name;
      struct gg_version version;
      int klass;
      struct gg_api *api;
      /* the rest is for libgg management */
      struct gg_module_state *state;
};

struct gg_plugin {
      struct gg_module *module;       
      struct gg_channel *channel;
      struct gg_stem *stem;
};

struct gg_plugin *ggPlugModule(struct gg_api *, struct gg_stem *,
                               const char *, const char *, void *);

void ggClosePlugin(struct gg_plugin *);

Description

ggPlugModule asks the API given as first argument to install a plugin, defined by a module, on the stem given as second argument. The three last arguments are the name of the module (well-known contractual name, as found in configuration), a parameter string, and an opaque pointer parameter that will be passed to the internal API plugging function. Calling this function only makes sense if the caller knows enough about the given API to know what it is actually supposed to do and return. See Module management below for further explanation on modules.

ggClosePlugin asks the underlying API to remove and completely frees a plugin. Its address becomes invalid.

Return value

ggPlugModule returns the resulting plugin instance or 'NULL' on failure.

Module management

The term 'module' refers to pluggable code that can be requested at runtime. This code is found in a dynamic library (it is called dynamic but it can also be static) accessed as a gg_scope. Opening a module consists of the following steps:

1) locate the scope for the library where the module is implemented,
2) retrieve the module list from that scope,
4) find the module with the requested name,
3) call the API-specific plug function.

Each API is supposed to know what to do with these modules. They are mostly used to provide the functionality defined by the API. For example, the LibGII inputs are modules that know how to handle a specific device to feed the LibGII event queue. When plugging a module to an input pool, an instance of the source is created, initialized and registered to the input. So the gg_plugin returned by ggPlugModule is really an instance of a module.

Usually, each library will provide one or more API function(s) intended for the user to indirectly open and plug modules. For example the giiOpen(3) call will try to load and add multiple inputs to the current input set. The idea is that the user does not really care about the created plugins themselves. He just wants the functionnality. One call may result in multiple modules being opened behind the scene.

The ggPlugModule is a bit different. It is supposed to open and return one specific plugin, when the caller explicitely wants a reference to the opened plugin for a good reason. For example, a LibGGI target, such as X, will use this call to conveniently add an X input module if LibGII is attached to the stem, without having to depend on libgii at runtime. Schematically:

/*  ... visual initialisation ... */

if ((libgii = ggGetAPIByName(stem, "libgii"))
    && !config->noInput
    && STEM_HAS_API(stem, libgii)) {
       priv->associatedInput = ggPlugModule(libgii, stem, "input-x", "",
                                            priv->relevantResource);
}

/*  ... visual shutdown ... */

ggClosePlugin(priv->associatedInput);

It can also be used by a LibGGI target to open and bind helper modules, providing part of the interface implementation.

Exporting Modules in a Dynamic Library

For libgg, a dynamic library is simply an entry point in a scope. This entry point is a function with the following prototype:

typedef int (ggfunc_dlentry)(int entry, void** entryptr)

It is used to portably retrieve addresses from the scope. The actual name of the function is defined by the relevant API and can be overridden in the configuration file. LibGG defines the reserved entry value 'GG_DLENTRY_MODULES' for retrieving modules in a dynamic library. The code looks like this:

struct gg_module **modules;
void ** pass;

pass = &modules;
if (dlentry(GG_DLENTRY_MODULES, pass) == GGI_OK) {
   /* modules is set and valid */
}

The dlentry function in the dynamic library should look like this:

static struct gg_module *modules[] = {
      &module0,
      &module1,
      NULL
};

int dlentry(int entry, void **entryptr)
{
      struct gg_module ***modulesptr;
      switch(item) {
      case GG_DLENTRY_MODULES:
              modulesptr = (struct gg_module ***)entryptr;
              *modulesptr = modules;
              return GGI_OK;
      default:
              *entryptr = NULL;
      }
      return GGI_ENOTFOUND;
}

See Also