Hook example code

From Second Life Wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
#include "lldarray.h"
// data1 and data2 may be used for any arbitrary user data.
// from_plugin should be set to FALSE if the function is being called due to a user's action,
// and TRUE if it is being called from another plugin.  (The idea is to avoid event loops, but
// maybe there is a better way.
// If function pointer returns FALSE, and this is one of a series of callbacks for a hook, 
// the function should terminate without passing control to any further plugins or to the
// rest of the viewer function.  (This is to allow hook functions to "swallow" events by return FALSE.)
typedef bool (*func_ptr)(void *data1, void *data2);

class hook {
public:
        const char * name;
        LLDynamicArray<func_ptr> *hook_ptrs;
        hook() {}
        hook(const char *n) {name = n; hook_ptrs = new (LLDynamicArray<func_ptr>)();}
};

class viewer_func  {
public:
        const char * name;
        func_ptr ptr;
        viewer_func() {}
        viewer_func(const char * n, func_ptr p) { name=n; ptr=p;}
};

class plugin_interface {
private:
        hook * get_hook_by_name(const char *name);
        viewer_func * get_viewer_func_by_name(const char *name);
public:
        LLDynamicArray<hook> hooks;
        LLDynamicArray<viewer_func> viewer_funcs;
        
        void add_hook(const char *name, const func_ptr ptr);  

       void add_viewer_func(const char *name, func_ptr ptr);
       char ** get_viewer_func_list();
       char ** get_hook_list();
       
       const char * get_interface_version();
       void * call_viewer_func(const char *name, void *data1, void *data2);
       bool call_hooks(const char *name, void *data1, void *data2);
       void init();
       //plugin_interface();   
       
};

#define PLUGIN_HOOK(name, data1, data2) fprintf(stderr, "PLUGIN_HOOK(%s)\n", name); if(!gPluginInterface.call_hooks(name, (void *)(data1), (void *)(data2))) return; 

extern plugin_interface gPluginInterface;


void plugin_interface::add_hook(const char *name, const func_ptr ptr) {
       /* This function adds a named hook definition with nothing to call to the list.
         It should be called once for each hooked function upon instantiation of 
         the plugin interface; the hook_ptrs lists will be filled in, if necessary,
         by plugin init functions.  We need a list of hook names (function names)
         so that plugins can ask the interface what hooks it will export. */
       fprintf(stderr, "add_hook(%s = %p)\n", name, ptr);
       if(ptr) {
               hook * myhook = get_hook_by_name(name);
               if (myhook == NULL) {
                       fprintf(stderr, "ERROR: tried to add function to unknown hook %s\n", name);
                       return;
               } 
               myhook->hook_ptrs->put(ptr);
       } else
               hooks.put(*(new hook(name)));
}
hook * plugin_interface::get_hook_by_name(const char *name) {
       // this should really be a hash table lookup
       for(int i=0; i < hooks.count() ; i++) 
               if (!strcasecmp(name, hooks[i].name)) 
                       return &hooks[i];
       return NULL;
}
bool plugin_interface::call_hooks(const char *name, void *data1, void *data2) {
       hook * func = get_hook_by_name(name);
       if (func) {
               for (int i=0; i < func->hook_ptrs->count(); i++) {
                       LLDynamicArray<func_ptr> *fptr_array=func->hook_ptrs;
                       func_ptr fptr=(*fptr_array)[i];
                       if (!(fptr)(data1, data2)) return FALSE;
               }
               return TRUE;
       } else return FALSE;
}