Logo Search packages:      
Sourcecode: lebiniou version File versions  Download package

plugin.c

/*
 *  Copyright 1994-2011 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  lebiniou is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include "biniou.h"
#include "plugin.h"

/* Note: dlsym prevents us from fully compiling in -pedantic..
 * see http://www.trilithium.com/johan/2004/12/problem-with-dlsym/
 */

#ifdef XDEBUG
#define B_DLSYM(VAR, SYM)                                   \
  (VAR) = (void (*)(struct Context_s *)) dlsym(p->handle, (SYM)); \
  if (libbiniou_verbose && ((VAR) != NULL))                       \
    printf("[p] >> %s has '%s'\n", p->name, (SYM))
#define B_GOTSYM(VAR, SYM) if ((VAR) != NULL)                         \
    printf("[p] >> %s has '%s'\n", p->name, (SYM));
#else
#define B_DLSYM(VAR, SYM)                                   \
  (VAR) = (void (*)(struct Context_s *)) dlsym(p->handle, (SYM))
#define B_GOTSYM(VAR, SYM) { }
#endif


static void
Plugin_load(Plugin_t *p)
{
  const char *error = NULL;
  u_long *_tmp;

  assert(p != NULL);
      
  p->handle = dlopen(p->file, RTLD_NOW);
      
  if (p->handle == NULL) {
    error = dlerror();
    xerror("Failed to load plugin '%s': %s\n",
         p->name, error);
  } else {
    if (libbiniou_verbose)
      printf("[p] Loading plugin '%s'", p->name);
  }
  fflush(stdout);

  _tmp = (u_long *) dlsym(p->handle, "id");
  if (_tmp == NULL) {
    error = dlerror();
    fprintf(stderr, "\n");
    xerror("Plugin MUST define an id (%s)\n", error);
  } else {
    p->id = *_tmp;
    if (libbiniou_verbose)
#ifdef XDEBUG
      printf(" (id= %li)\n", p->id);
#else
      printf("\n");
#endif
  }

  _tmp = (u_long *) dlsym(p->handle, "options");
  if (_tmp == NULL) {
    error = dlerror();
    xerror("Plugin MUST define options (%s)\n", error);
  } else
    p->options = _tmp;

  _tmp = (u_long *) dlsym(p->handle, "mode");
  p->mode = _tmp;

  /* get display name */
  p->dname = (char *) dlsym(p->handle, "dname");
  B_GOTSYM(p->dname, "dname");
  if (p->dname == NULL)
    p->dname = p->name;

  /* get description */
  p->desc = (char *) dlsym(p->handle, "desc");
  B_GOTSYM(p->desc, "desc");

  B_DLSYM(p->create, "create");
  B_DLSYM(p->destroy, "destroy");
  B_DLSYM(p->run, "run");
  B_DLSYM(p->on_switch_on, "on_switch_on");
  B_DLSYM(p->on_switch_off, "on_switch_off");
  p->on_key = (void (*)(u_char)) dlsym(p->handle, "on_key");
  B_GOTSYM(p->on_key, "on_key");

  /* Output plugin stuff */
  /* TODO: remove, use on_key callbacks */
  B_DLSYM(p->set_cmap, "set_cmap");
  p->fullscreen = (void (*)(int)) dlsym(p->handle, "fullscreen");
  B_GOTSYM(p->fullscreen, "fullscreen");
  p->switch_cursor = (void (*)(void)) dlsym(p->handle, "switch_cursor");
  B_GOTSYM(p->switch_cursor, "switch_cursor");
      
  /* Input plugin stuff (? mainly -to check --oliv3) */
  p->jthread = (void *(*)(void *)) dlsym(p->handle, "jthread");
  B_GOTSYM(p->jthread, "jthread");
}


static void
Plugin_unload(Plugin_t *p)
{
  assert (p != NULL);
      
  /* FIXME error checking there, ie if plugin fails to destroy */
  if (p->jthread != NULL) {
    if (libbiniou_verbose) {
      printf("[p] Joining thread from plugin '%s'... ", p->name);
      fflush(stdout);
    }
    pthread_join(p->thread, NULL);
  } else {
    if (libbiniou_verbose) {
      printf("[p] Unloading plugin '%s' (%li call%s)... ", p->name, p->calls,
           ((p->calls == 1) ? "" : "s"));
      fflush(stdout);
    }
  }
    
  if (p->destroy != NULL)
    p->destroy(context);

  dlclose(p->handle);
  if (libbiniou_verbose)
    printf("done.\n");
}


Plugin_t *
Plugin_new(const char *directory, const char *name, const enum PluginType type)
{
  Plugin_t *p = xcalloc(1, sizeof(Plugin_t));

  assert(name != NULL);
  assert(directory != NULL);

  p->name = strdup(name);
  p->calls = 0;

  if (type == PL_INPUT)
    p->file = g_strdup_printf("%s/input/%s/%s.so", directory, name, name);
  else if (type == PL_MAIN)
    p->file = g_strdup_printf("%s/main/%s/%s.so", directory, name, name);
  else if (type == PL_OUTPUT)
    p->file = g_strdup_printf("%s/output/%s/%s.so", directory, name, name);

  Plugin_load(p);

  return p;
}


void
Plugin_delete(Plugin_t *p)
{
  assert(p != NULL);
  Plugin_unload(p);
  xfree(p->name);
  g_free(p->file);
  xfree(p);
}


void
Plugin_reload(Plugin_t *p)
{
  assert(p != NULL);
  Plugin_unload(p);
  Plugin_load(p);
  if (libbiniou_verbose)
    printf("[p] Reloaded plugin '%s'\n", p->name);
}


void
Plugin_init(Plugin_t *p)
{
  assert(p != NULL);

  if (p->create != NULL) {
    if (libbiniou_verbose)
      printf("[+] Initializing plugin %s\n", p->name);
    p->create(context);
  }

  if (p->jthread != NULL) {
    pthread_create(&p->thread, NULL, p->jthread, (void *)context);
    if (libbiniou_verbose)
      printf("[p] Launched thread %s\n", p->name);
  }
}


static char *
Plugin_uppercase(const char *str)
{
  char *tmp;

  assert(str != NULL);
  tmp = strdup(str);

  assert(tmp != NULL);
  assert(tmp[0] != '\0');
  tmp[0] = (char)toupper((int)tmp[0]);

  return tmp;
}


char *
Plugin_name(const Plugin_t *p)
{
  assert(p != NULL);
  return Plugin_uppercase(p->name);
}


char *
Plugin_dname(const Plugin_t *p)
{
  assert(p != NULL);
  return Plugin_uppercase(p->dname);
}


void
Plugin_on_key(const u_long id, const u_char k)
{
  Plugin_t *p = Plugins_find(id);

  if (NULL == p) {
    printf("[!] Plugin id %li not found\n", id);
    return;
  }

  if (NULL == p->on_key) {
    printf("[!] Plugin id %li has no on_key callback\n", id);
    return;
  } else
    p->on_key(k);
}

Generated by  Doxygen 1.6.0   Back to index