Logo Search packages:      
Sourcecode: vertex version File versions

vpi.c

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <math.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#ifdef HAVE_IMLIB
# include <Imlib.h>
#endif

#include "../include/string.h"
#include "../include/fio.h"
#include "../include/disk.h"
#include "../include/prochandle.h"

#include "guiutils.h"
#include "cdialog.h"
#include "fb.h"
#include "progressdialog.h"

#include "view.h"

#include "editor.h"
#include "editorlist.h"
#include "editorviewcb.h"

#include "vpi.h"
#include "vpiinternal.h"
#include "vmacfg.h"
#include "vmacfglist.h"
#include "vma.h"
#include "vmautils.h"
#include "config.h"
#include "compiletimeinfo.h"

#include "images/icon_import_32x32.xpm"
#include "images/icon_export_32x32.xpm"
#include "images/icon_render_32x32.xpm"
#include "images/icon_options_32x32.xpm"


/* Local utilities. */
static vma_core_struct *VPIGetCoreFromID(vpi_id *id);
static ma_editor_struct *VPIGetEditorFromID(vpi_id *id, int editor_id);


/* Client data set/get. */
void VPISetClientData(vpi_id *id, void *client_data);
void *VPIGetClientData(vpi_id *id);

/* Version setting. */
int VPISetPluginVersion(
        vpi_id *id, int version_major, int version_minor
);

/* Data type allocation & deallocation. */
vpi_ftype_struct *VPIFTypeNew(void);
void VPIFTypeDelete(vpi_ftype_struct *buf);
vpi_color_struct *VPIColorNew(void);
void VPIColorDelete(vpi_color_struct *buf);
vpi_camera_struct *VPICameraNew(void);
void VPICameraDelete(vpi_camera_struct *buf);
vpi_light_struct *VPILightNew(void);
void VPILightDelete(vpi_light_struct *buf);

/* Messages and user response io. */
void VPIMessage(
      vpi_id *id, int editor_id,
      const char *title,
      const char *message,
      const char *details,
      int type          /* One of VPI_MESSAGE_*. */
);
int VPIQuestion(
        vpi_id *id, int editor_id,  /* Can be NULL and -1. */
        const char *title,
        const char *message,
        const char *details,
        int type,             /* One of VPI_MESSAGE_*. */
        vpi_flag response_flags,    /* Any or'ed set of VPI_RESPONSE_FLAG_*. */
        vpi_flag default_response   /* One of VPI_RESPONSE_FLAG_*. */
);
int VPIQuestionSimple(
        vpi_id *id, int editor_id,  /* Can be NULL and -1. */
        const char *message
);
int VPIProgress(
      vpi_id *id, int editor_id,
      const char *title,      /* Title of progress. */
        const char *message,  /* Message. */
      const char *stop_label, /* Stop button label. */
        int type,               /* One of VPI_MESSAGE_*. */
      double progress,  /* 0.0 to 1.0 (or -1.0). */
      unsigned int nblocks    /* 0 for continuous. */
);
void VPIProgressDone(vpi_id *id, int editor_id);
int VPIFileSelect(
      vpi_id *id, int editor_id,
      const char *title,
      const char *ok_label, const char *cancel_label,
      const char *path,
      vpi_ftype_struct **ftype, int total_ftypes,
      char ***path_rtn, int *total_path_rtns,
      vpi_ftype_struct **ftype_rtn
);
char *VPIFileSelectSimple(
        vpi_id *id, int editor_id,
        const char *path
);

void *VPIGetEditorToplevel(vpi_id *id, int editor_id);


/* Value fetching abstraction layer. */
int VPIGetP(vpi_id *id, int code, void **p);
int VPIGetS(vpi_id *id, int code, char **s);
int VPIGetI(vpi_id *id, int code, int *i);
int VPIGetUI(vpi_id *id, int code, unsigned int *i); 
int VPIGetL(vpi_id *id, vpi_code_t code, long *l);
int VPIGetUL(vpi_id *id, vpi_code_t code, unsigned long *ul);
int VPIGetF(vpi_id *id, int code, float *f);
int VPIGetD(vpi_id *id, int code, double *d);


/* Plug-in basic operation support setting. */
int VPIQuery(vpi_id *id, int op_code);
int VPISetOperationCB(
        vpi_id *id,
      int op_code,                  /* One of VPI_OP_*. */
        void *func_ptr,                 /* Can be NULL to disable. */
        void *client_data
);
void VPIUnsetOperationCB(
        vpi_id *id,
      int op_code             /* One of VPI_OP_*. */
);

/* Extended operation features: Import. */
int VPIImportSetFileType(vpi_id *id, vpi_ftype_struct *ftype);
void VPIImportClearFileTypes(vpi_id *id);
int VPIImportSetFCheckFunc(
        vpi_id *id,
      int (*import_fcheck)(vpi_id *, const char *, const char *, void *),
      void *client_data
);

/* Extended operation features: Export. */
int VPIExportSetFileType(vpi_id *id, vpi_ftype_struct *ftype);
void VPIExportClearFileTypes(vpi_id *id);

/* Extended operation features: Export. */
void VPIRenderSetLabel(
        vpi_id *id,
        const char *label
);


/* Plug-in listing appearance on Vertex setting. */
static void VPIUpdateXPMData(
      u_int8_t ***tar_buf, int *tar_buf_lines,
      const u_int8_t **src_buf
);
vpi_appearance_struct *VPIAppearanceNew(void);
void VPIAppearanceDelete(vpi_appearance_struct *v);
void VPIAppearanceSet(vpi_id *id, const vpi_appearance_struct *v);
vpi_appearance_struct *VPIAppearanceGet(vpi_id *id);


/* Disk object stat fetching. */
int VPIStat(vpi_id *id, const char *path, struct stat *stat_buf);
int VPILStat(vpi_id *id, const char *path, struct stat *stat_buf);

/* File IO. */
FILE *VPIFOpen(vpi_id *id, const char *path, const char *mode);
int VPIFGetC(vpi_id *id, FILE *fp);
char *VPIFGetS(vpi_id *id, char *s, int size, FILE *fp);
long VPIFRead(vpi_id *id, void *ptr, long size, long nmemb, FILE *fp);
int VPIFPutC(vpi_id *id, int c, FILE *fp);
int VPIFPutS(vpi_id *id, const char *s, FILE *fp);
long VPIFWrite(vpi_id *id, const void *ptr, long size, long nmemb, FILE *fp);
int VPIFSeek(vpi_id *id, FILE *fp, long offset, int whence);
long VPIFTell(vpi_id *id, FILE *fp);
void VPIRewind(vpi_id *id, FILE *fp);
void VPIFClose(vpi_id *id, FILE *fp);

void VPIFSeekNextLine(vpi_id *id, FILE *fp);
void VPIFSeekPastSpaces(vpi_id *id, FILE *fp);
void VPIFSeekPastChar(vpi_id *id, FILE *fp, char c);
char *VPIFGetString(vpi_id *id, FILE *fp);
char *VPIFGetStringLined(vpi_id *id, FILE *fp);
char *VPIFGetStringLiteral(vpi_id *id, FILE *fp);


/* Vertex editor data IO. */
int VPIEditorGetHeader(
        vpi_id *id, int editor_id,
        const char **filename,
        void ***mh_item, int *total_mh_items
);
int VPIEditorGetModels(
        vpi_id *id, int editor_id,
        v3d_model_struct ***model, int *total_models
);
int VPIEditorGetCamera(
      vpi_id *id, int editor_id, vpi_camera_struct **cam
);
int VPIEditorGetLight(
        vpi_id *id, int editor_id, vpi_light_struct **light, int light_num
);
int VPIEditorGetLights(
        vpi_id *id, int editor_id, vpi_light_struct **light, int *total_lights
);
v3d_model_struct *VPIEditorGetModelByNumber(
        vpi_id *id, int editor_id, int model_num
);
v3d_model_struct *VPIEditorModelNew(
        vpi_id *id, int editor_id,
        int create_position,    /* VPI_POSITION_*. */
        int *model_num,
        int type, const char *name
);
void VPIEditorModelDelete(
        vpi_id *id, int editor_id,
        int model_num
);
void VPIEditorModelSelect(
        vpi_id *id, int editor_id, int model_num
);
v3d_model_struct *VPIEditorModelGetSelected(
      vpi_id *id, int editor_id, int *model_num
);
void VPIEditorPrimitiveSelect(
        vpi_id *id, int editor_id, int pn
);
int *VPIEditorPrimitiveGetSelected(
        vpi_id *id, int editor_id, int *total
);
void VPIEditorRedraw(vpi_id *id, int editor_id, int refresh_lists);
gint VPIEditorGetHasChanges(vpi_id *id, int editor_id);
void VPIEditorSetHasChanges(vpi_id *id, int editor_id, int has_changes);


/* Misc functions. */
const char *VPIErrorString(vpi_id *id, int error_code);
FILE *VPICreateTemporyFile(
        vpi_id *id,
        const char *name_prefix,
        char **new_path_rtn
);
int VPIMove(vpi_id *id, const char *old_path, const char *new_path);
int VPICopy(vpi_id *id, const char *src_path, const char *tar_path);
int VPIMkDir(
        vpi_id *id, const char *path, mode_t m, int make_parents_as_needed
);
int VPIRmDir(vpi_id *id, const char *path);
char **VPIDirEnts(
        vpi_id *id, const char *path, int *nentries_rtn
);

int VPIUnlink(vpi_id *id, const char *path);
int VPISymLink(vpi_id *id, const char *value, const char *path);
int VPILink(vpi_id *id, const char *value, const char *path);
char *VPIGetLink(vpi_id *id, const char *path);
int VPIExec(
        vpi_id *id, const char *command, int block
);
int VPIExecO(
        vpi_id *id, const char *command, int block,
        const char *stdout_file, const char *stderr_file
);
int VPIExecAO(
        vpi_id *id, const char *command, int block,
        const char *stdout_file, const char *stderr_file
);
int VPIIsRunning(vpi_id *id, int pid);
int VPIKill(vpi_id *id, int pid, int s);


/*
 *    Returns the pointer to the core structure.
 */
static vma_core_struct *VPIGetCoreFromID(vpi_id *id)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
      return((pi != NULL) ? (vma_core_struct *)pi->core_ptr : NULL);
}

/*
 *    Returns the pointer to the editor referenced by editor_id.
 */
static ma_editor_struct *VPIGetEditorFromID(vpi_id *id, int editor_id)
{
      int i = editor_id;
      vma_core_struct *core_ptr = VPIGetCoreFromID(id);
      if(core_ptr == NULL)
          return(NULL);

      if((i < 0) || (i >= core_ptr->total_editors))
          return(NULL);

      return(core_ptr->editor[i]);
}

/*
 *    Sets the client data that will be given on the manage and
 *    shutdown functions.
 */
void VPISetClientData(vpi_id *id, void *client_data)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
      if(pi != NULL)
          pi->client_data = client_data;
}

/*
 *    Returns the client data set by VPISetClientData().
 */
void *VPIGetClientData(vpi_id *id)
{
      vma_plugin_struct *pi = VMA_PLUGIN(id);
      return((pi != NULL) ? pi->client_data : NULL);
}

/*
 *    Sets the plug-in version, if the given version is newer than
 *    the version of Vertex then run time issues (if any) will be
 *    taken into consideration.
 *
 *    Returns 0 if the plug-ins version is equal or older than Vertex's
 *    version, and 1 if the plug-in's version is newer than Vertex's.
 *
 *    Can also return -1 on error.
 */
int VPISetPluginVersion(
        vpi_id *id, int version_major, int version_minor
)
{
      vma_plugin_struct *pi = VMA_PLUGIN(id);
      if(pi == NULL)
          return(-1);

      if(version_major > PROG_VERSION_MAJOR)
          return(1);
      if(version_minor > PROG_VERSION_MINOR)
          return(1);

      return(0);
}


/*
 *    Data type allocation and deallocation.
 */
vpi_ftype_struct *VPIFTypeNew(void)
{
      vpi_ftype_struct *buf = (vpi_ftype_struct *)calloc(
            1, sizeof(vpi_ftype_struct)
        );
        return(buf);
}
void VPIFTypeDelete(vpi_ftype_struct *buf)
{
      if(buf != NULL)
        {
          if(buf->flags & VPI_FTYPE_EXT)
            free(buf->ext);
          if(buf->flags & VPI_FTYPE_NAME)
                free(buf->name);

            free(buf);
        }
}

vpi_color_struct *VPIColorNew(void)
{
      vpi_color_struct *buf = (vpi_color_struct *)calloc(
          1, sizeof(vpi_color_struct)
      );
      return(buf);
}
void VPIColorDelete(vpi_color_struct *buf)
{
      if(buf != NULL)
      {
/* No allocated members to delete. */
          free(buf);
      }
}

vpi_camera_struct *VPICameraNew(void)
{
        vpi_camera_struct *buf = (vpi_camera_struct *)calloc(
            1, sizeof(vpi_camera_struct)
        );
        return(buf);
}
void VPICameraDelete(vpi_camera_struct *buf)
{
      if(buf != NULL)
      {
/* No allocated members to delete. */
          free(buf);
      }
}

vpi_light_struct *VPILightNew(void)
{
        vpi_light_struct *buf = (vpi_light_struct *)calloc(
            1, sizeof(vpi_light_struct)
        );
        return(buf);
}
void VPILightDelete(vpi_light_struct *buf)
{
        if(buf != NULL)
        {
/* No allocated members to delete. */
            free(buf);
        }
}


/*
 *      Prints message and blocks calling thread of execution untill user 
 *    response. Note Vertex will still manage its own resources but
 *    plug-in's manage function will not be called during this block.
 *
 *    Given plug-in id and editor id are optional.
 */
void VPIMessage(
        vpi_id *id, int editor_id,
        const char *title,
        const char *message,
        const char *details,
        int type                /* One of VPI_MESSAGE_*. */
)
{
        int icon_code;   
        vma_plugin_struct *pi = VMA_PLUGIN(id);


        switch(type)
        {
          case VPI_MESSAGE_QUESTION:
            icon_code = CDIALOG_ICON_QUESTION;
            break;
          case VPI_MESSAGE_ERROR:
            icon_code = CDIALOG_ICON_ERROR;
            break;
          case VPI_MESSAGE_WARNING:
            icon_code = CDIALOG_ICON_WARNING;   
            break;
          default:
            icon_code = CDIALOG_ICON_INFO;
            break;
        }   

        /* Plug-in pointer not given? */
        if(pi == NULL)
        {
            CDialogSetTransientFor(NULL);
            CDialogGetResponse(
                title,
                message,
                details,
                icon_code,  
                CDIALOG_BTNFLAG_OK |
                ((details != NULL) ? CDIALOG_BTNFLAG_HELP : 0),
                CDIALOG_BTNFLAG_OK
            );
        }
        else
        {
            ma_editor_struct *editor = VPIGetEditorFromID(id, editor_id);
            if((editor != NULL) ?
                (editor->initialized && !editor->processing) : FALSE
            )
                CDialogSetTransientFor(editor->toplevel);
            else
                CDialogSetTransientFor(NULL);

            CDialogGetResponse(
                title,
                message,
                details,
                icon_code,
                CDIALOG_BTNFLAG_OK |
                ((details == NULL) ? 0 : CDIALOG_BTNFLAG_HELP),
                CDIALOG_BTNFLAG_OK
            );
          CDialogSetTransientFor(NULL);
        }

      return;
}

/*
 *      Asks user for input in response to a question, returns
 *      VPI_YES, VPI_NO, or VPI_UNAVAILABLE.
 *
 *    Similar blocking behavour as VPIMessage().
 *
 *      Given plug-in id and editor id are optional.
 */
int VPIQuestion(
        vpi_id *id, int editor_id,  /* Can be NULL and -1. */
        const char *title,
        const char *message,
        const char *details,
        int type,             /* One of VPI_MESSAGE_*. */
        vpi_flag response_flags,    /* Any or'ed set of VPI_RESPONSE_FLAG_*. */
        vpi_flag default_response   /* One of VPI_RESPONSE_FLAG_*. */
)
{
      int status, icon_code;
        vma_plugin_struct *pi = VMA_PLUGIN(id);


      switch(type)
      {
          case VPI_MESSAGE_QUESTION:
            icon_code = CDIALOG_ICON_QUESTION;
            break;
        case VPI_MESSAGE_ERROR:
          icon_code = CDIALOG_ICON_ERROR;
          break;
          case VPI_MESSAGE_WARNING:
            icon_code = CDIALOG_ICON_WARNING;
            break;
          default:
            icon_code = CDIALOG_ICON_INFO;
            break;
      }

      /* Note, the flags in response_flags and default_response are
       * designed to match those defined for the confirmation dialog.
       * So we can pass those values directly.
       */

      /* Plug-in pointer not given? */
        if(pi == NULL)
      {
          CDialogSetTransientFor(NULL);
            status = CDialogGetResponse(
            title,
            message,
            details,
                icon_code,
            response_flags,
                default_response
            );
      }
      else
      {
          ma_editor_struct *editor = VPIGetEditorFromID(id, editor_id);
          if((editor != NULL) ?
            (editor->initialized && !editor->processing) : FALSE
          )
            CDialogSetTransientFor(editor->toplevel);
          else
            CDialogSetTransientFor(NULL);
            status = CDialogGetResponse(
                title,
                message,
                details,
                icon_code,
                response_flags,
                default_response
            );
          CDialogSetTransientFor(NULL);
      }

      /* Also the return in status is designed to match those defined
       * for the VPI_RESPONSE_* codes, so we can return the status
       * value directly.
       */
      return(status);
}

/*
 *    Simplified version of VPIQuestion(), this one just returns
 *      VPI_RESPONSE_YES, VPI_RESPONSE_NO, or VPI_RESPONSE_NOT_AVAILBLE.
 */
int VPIQuestionSimple(
        vpi_id *id, int editor_id,      /* Can be NULL and -1. */
        const char *message
)
{
      return(VPIQuestion(
          id, editor_id,
          "Question",
          message,
          NULL,
          VPI_MESSAGE_QUESTION,
          VPI_RESPONSE_FLAG_YES | VPI_RESPONSE_FLAG_NO,
          VPI_RESPONSE_FLAG_YES           /* Defaults to yes. */
      ));
}


/*
 *    Maps the progress dialog (as needed) and sets the given values.
 *    If the dialog is already mapped then this will only update
 *    its values.
 *
 *    A return of 0 means the progress can continue, a return value of 1
 *    or higher means the progress should stop (user clicked on stop).
 *    The higher the return value, the greater the priority to stop.
 *
 *    Given plug-in id and editor id are optional.
 *
 *      Note that gtk_main_iteration() may be called within this
 *      function.
 */
int VPIProgress(
        vpi_id *id, int editor_id,
        const char *title,      /* Title of progress. */
        const char *message,    /* Message. */
        const char *stop_label, /* Stop button label. */
      int type,         /* One of VPI_MESSAGE_*. */
        double progress,      /* 0.0 to 1.0 (or -1.0). */
      unsigned int nblocks    /* 0 for continuous. */
)
{
      const u_int8_t **icon_data;
        vma_plugin_struct *pi = VMA_PLUGIN(id);


      /* Check if progress dialog is not mapped. */
        if(!ProgressDialogIsQuery())
      {
          if(pi != NULL)
          {
            ma_editor_struct *editor = VPIGetEditorFromID(id, editor_id);
            if((editor != NULL) ?
                (editor->initialized && !editor->processing) : FALSE
            )
                ProgressDialogSetTransientFor(editor->toplevel);
            else
                ProgressDialogSetTransientFor(NULL);
          }

          /* Set up icon. */
          switch(type)
          {
            case VPI_MESSAGE_IMPORT:
            icon_data = (const u_int8_t **)icon_import_32x32_xpm;
            break;

            case VPI_MESSAGE_EXPORT:
                icon_data = (const u_int8_t **)icon_export_32x32_xpm;
            break;

            case VPI_MESSAGE_RENDER:
                icon_data = (const u_int8_t **)icon_render_32x32_xpm;
            break;

              case VPI_MESSAGE_OPTIONS:
                icon_data = (const u_int8_t **)icon_options_32x32_xpm;
                break;

            default:
            icon_data = NULL;
            break;
          }

          /* Specify parameters for progress dialog and map it. */
          ProgressDialogMap(title, message, icon_data, stop_label);
      }
      else
      {
          if(progress < 0.0)
          {
            ProgressDialogUpdateUnknown(
                NULL, message, NULL,
                NULL,
                TRUE
            );
          }
          else
          {
            ProgressDialogUpdate(
                NULL, message, NULL,
                NULL,
                progress, nblocks,
                TRUE
            );
          }
      }

      return(ProgressDialogStopCount());
}

/*
 *    Unmaps the progress dialog.
 *
 *    Given plug-in id and editor id are optional.
 *
 *    Note that gtk_main_iteration() may be called within this
 *    function.
 */
void VPIProgressDone(vpi_id *id, int editor_id)
{
      if(ProgressDialogIsQuery())
      {
          ProgressDialogBreakQuery(TRUE);
          ProgressDialogSetTransientFor(NULL);
      }
      return;
}


/*
 *    Maps file browser for user input. The path_rtn list should
 *    not be modified by the calling function. The given ftype_rtn
 *    may be a pointer in the given ftype list.
 *
 *    Returns VPI_TRUE if a file was selected, or VPI_FALSE if
 *    the user canceled or file selecting was not available.
 */
int VPIFileSelect(
        vpi_id *id, int editor_id,
        const char *title,
        const char *ok_label, const char *cancel_label,
        const char *path,           /* Initial path, can be NULL. */
        vpi_ftype_struct **ftype, int total_ftypes,
        char ***path_rtn, int *total_path_rtns,
        vpi_ftype_struct **ftype_rtn
)
{
      int i, status = VPI_FALSE;
      vpi_ftype_struct *ftype_ptr;
      fb_type_struct **fb_ftype = NULL, *fb_ftype_rtn = NULL;
      gint fb_total_ftypes = 0;
      ma_editor_struct *editor;
        vma_plugin_struct *pi = VMA_PLUGIN(id);


      /* Reset returns. */
      if(path_rtn != NULL)
          (*path_rtn) = NULL;
      if(total_path_rtns != NULL)
          (*total_path_rtns) = 0;
      if(ftype_rtn != NULL)
          (*ftype_rtn) = NULL;

      if(pi == NULL)
          return(status);

      /* Get editor. */
      editor = VPIGetEditorFromID(id, editor_id);

      /* Check if file browser is busy. */
      if(FileBrowserIsQuery())
          return(status);

      /* Set file browser to be a transient for the editor window if it
       * is valid.
       */
      if((editor != NULL) ?
          (editor->initialized && !editor->processing) : FALSE
      )
          FileBrowserSetTransientFor(editor->toplevel);
      else
          FileBrowserSetTransientFor(NULL);


      /* Create file browser file type list from given vpi
       * file type list.
       */
      for(i = 0; i < total_ftypes; i++)
      {
          ftype_ptr = ftype[i];
          if(ftype_ptr == NULL)
            continue;

          FileBrowserTypeListNew(
            &fb_ftype, &fb_total_ftypes,
            (ftype_ptr->flags & VPI_FTYPE_EXT) ?
                ftype_ptr->ext : NULL,
            (ftype_ptr->flags & VPI_FTYPE_NAME) ?
                ftype_ptr->name : NULL
          );
      }

      /* Map file browser and get user response. */
      if(FileBrowserGetResponse(
          title, ok_label, cancel_label, path,
          fb_ftype, fb_total_ftypes,
          path_rtn, total_path_rtns,
          &fb_ftype_rtn
      ))
          status = VPI_TRUE;
      else
          status = VPI_FALSE;

      /* Unset file browser transient for. */
      FileBrowserSetTransientFor(NULL);

      /* Got user response? */
      if(status)
      {
          /* Got response, so update returns. Note that path_rtn and
           * total_path_rtns were already passed and set, so we can
           * skip those.
           */

          /* Update VPI file type return. */
          if((fb_ftype_rtn != NULL) ? (fb_ftype_rtn->ext != NULL) : 0)
          {
            const char *ext = (const char *)fb_ftype_rtn->ext;

            /* Itterate through VPI file types list and check ext
             * for match with the file browser's file type return
             * ext.
             */
            for(i = 0; i < total_ftypes; i++)
            {
                ftype_ptr = ftype[i];
                if(ftype_ptr == NULL)
                  continue;

                /* VPI file type structure has no extension? */
                if(!(ftype_ptr->flags & VPI_FTYPE_EXT))
                  continue;
                if(ftype_ptr->ext == NULL)
                  continue;

                /* Exceeded file browser file types? */
                if(i >= fb_total_ftypes)
                  break;

                /* Check if extensions are different. */
                if(strcmp(ftype_ptr->ext, ext))
                  continue;

                /* Got matching file type, update VPI file type
                 * return point to point to the currect VPI file type
                 * structure in the VPI file types list.
                 */
                if(ftype_rtn != NULL)
                  (*ftype_rtn) = ftype_ptr;
            }
          }
          else
          {
            /* No file type return available from file browser. */
          }
      }

      /* Deallocate file browser file type list. */
      FileBrowserDeleteTypeList(fb_ftype, fb_total_ftypes);
      fb_ftype = NULL;
      fb_total_ftypes = 0;

      return(status);
}

/*
 *    Simplified version of VPIFileSelect().
 *
 *    Returns a pointer to the selected path or NULL if cancel
 *    was selected. Return path is only valid on the same control level
 *    as the calling function.
 */
char *VPIFileSelectSimple(
        vpi_id *id, int editor_id,
        const char *path            /* Initial path, can be NULL. */
)
{
      int i, status;
      char **path_rtn;
      int total_path_rtns;
#define total_ftypes    1
      vpi_ftype_struct *ftype[total_ftypes], *ftype_ptr;


      /* Allocate file types list. */
      ftype[0] = ftype_ptr = VPIFTypeNew();
      if(ftype_ptr == NULL)
          return(NULL);

      ftype_ptr->flags = (VPI_FTYPE_EXT | VPI_FTYPE_NAME);
      ftype_ptr->ext = strdup("*.*");
      ftype_ptr->name = strdup("All Files");

      /* Call the complicated file select routine. */
      status = VPIFileSelect(
          id, editor_id,
          "Select File",
          "OK", "Cancel",
          path,
          ftype, total_ftypes,
          &path_rtn, &total_path_rtns,
          &ftype_ptr
      );

      /* Deallocate file types list. */
      for(i = 0; i < total_ftypes; i++)
          VPIFTypeDelete(ftype[i]);

#undef total_ftypes

      /* If we got response, then return the first path. */
      if((status) && (total_path_rtns > 0))
          return(path_rtn[0]);
      else
          return(NULL);
}


/*
 *      Returns the pointer to the editor's toplevel GtkWidget, the
 *      returned pointed will be a GtkWindow *.
 */
void *VPIGetEditorToplevel(vpi_id *id, int editor_id)
{
        ma_editor_struct *editor = VPIGetEditorFromID(id, editor_id);
      return((editor != NULL) ? editor->toplevel : NULL);
}


/*
 *    Value fetching abstraction layer.
 *
 *    Returns VPI_SUCCESS on success or VPI_ERROR_* on failure.
 */
int VPIGetP(vpi_id *id, int code, void **p)
{
      int status;
      char *s;
        vma_core_struct *core_ptr;
        vma_plugin_struct *pi = VMA_PLUGIN(id);


        if(pi == NULL)
            return(VPI_ERROR);
        if(p == NULL)
            return(VPI_ERROR_BAD_VALUE);

        core_ptr = VPIGetCoreFromID(id);

      switch(code)
      {
        /* These should be strings, call VPIGetS(). */
        case VPI_CODE_LANGUAGE:
        case VPI_CODE_COMPILE_LOCATION:
        case VPI_CODE_COMPILE_USER:
        case VPI_CODE_COMPILE_COMPILER:
        case VPI_CODE_VENDOR_NAME:

        case VPI_CODE_GLOBAL_DIR:
        case VPI_CODE_LOCAL_DIR:
        case VPI_CODE_TMP_DIR:

        case VPI_CODE_FONT_NAME_TEXT_EDITABLE:
          case VPI_CODE_FONT_NAME_TEXT_TERMINAL:

          status = VPIGetS(id, code, &s);
          (*p) = (void *)s;
          return(status);
          break;


        case VPI_CODE_X_DISPLAY:
          (*p) = GDK_DISPLAY();
          break;

        case VPI_CODE_IMLIB_HANDLE:
#ifdef HAVE_IMLIB
          (*p) = imlib_handle;
#else
          (*p) = NULL;
#endif
          break;

          case VPI_CODE_IMLIB2_HANDLE:
/* This isn't supported just yet. */
          (*p) = NULL;
          break;

          default:
            return(VPI_ERROR_NOT_FOUND);
            break;
      }

        return(VPI_SUCCESS);
}

int VPIGetS(vpi_id *id, int code, char **s)
{
        vma_core_struct *core_ptr;
        vma_plugin_struct *pi = VMA_PLUGIN(id);


        if(pi == NULL)
            return(VPI_ERROR);
        if(s == NULL)
            return(VPI_ERROR_BAD_VALUE);

        core_ptr = VPIGetCoreFromID(id);

      switch(code)
      {
        case VPI_CODE_LANGUAGE:
          (*s) = (char *)"en";
          break;
          case VPI_CODE_COMPILE_LOCATION:
          (*s) = (char *)COMPILE_LOCATION;
          break;
          case VPI_CODE_COMPILE_USER:
          (*s) = (char *)COMPILE_USER;
          break;
          case VPI_CODE_COMPILE_COMPILER:
            (*s) = (char *)COMPILE_COMPILER;
            break;
          case VPI_CODE_VENDOR_NAME:
          (*s) = (char *)"unset";
          break;

        case VPI_CODE_GLOBAL_DIR:
          (*s) = dname.data_global;
          break;
          case VPI_CODE_LOCAL_DIR:
            (*s) = dname.data_local;
            break;
          case VPI_CODE_TMP_DIR:
            (*s) = dname.tmp;
            break;

          case VPI_CODE_FONT_NAME_TEXT_EDITABLE:
          (*s) = VMACFGItemListGetValueS(
            option, VMA_CFG_PARM_FONT_NAME_EDITABLE
          );
          break;
        case VPI_CODE_FONT_NAME_TEXT_TERMINAL:
            (*s) = VMACFGItemListGetValueS(
                option, VMA_CFG_PARM_FONT_NAME_TERMINAL
            );
            break;


        default:
          (*s) = NULL;
          return(VPI_ERROR_NOT_FOUND);
          break;
      }

      return(VPI_SUCCESS);
}

int VPIGetI(vpi_id *id, int code, int *i)
{
      vma_core_struct *core_ptr;
      vma_plugin_struct *pi = VMA_PLUGIN(id);


        if(pi == NULL)
            return(VPI_ERROR);
        if(i == NULL)
            return(VPI_ERROR_BAD_VALUE);

      core_ptr = VPIGetCoreFromID(id);

        switch(code)
        {
        case VPI_CODE_VERSION_MAJOR:
          (*i) = PROG_VERSION_MAJOR;
          break;
          case VPI_CODE_VERSION_MINOR:
            (*i) = PROG_VERSION_MINOR;
            break;
          case VPI_CODE_VERSION_RELEASE:
            (*i) = PROG_VERSION_RELEASE;
            break;

        case VPI_CODE_MAX_LIGHTS:
            if(core_ptr != NULL)
                (*i) = VMA_LIGHTS_MAX;
            else
                (*i) = 0;
            break;
        case VPI_CODE_TOTAL_EDITORS:
          if(core_ptr != NULL)
            (*i) = core_ptr->total_editors;
          else
            (*i) = 0;
          break;
          case VPI_CODE_TOTAL_PLUGINS:
            if(core_ptr != NULL)
                (*i) = core_ptr->total_plugins;
            else
                (*i) = 0;
            break;

        case VPI_CODE_TOOLBAR_STYLE:
          (*i) = VMACFGItemListGetValueI(
                option, VMA_CFG_PARM_TOOLBAR_STYLE
            );
          break;
          case VPI_CODE_SHOW_TOOLTIPS:
            (*i) = VMACFGItemListGetValueI(
                option, VMA_CFG_PARM_SHOW_TOOLTIPS
            );
            break;
          case VPI_CODE_RECORD_LAST_POS_AND_SIZE:
            (*i) = VMACFGItemListGetValueI(
                option, VMA_CFG_PARM_RECORD_LAST_POS_AND_SIZE
            );
            break;
          case VPI_CODE_SHOW_TIPOFDAY:
            (*i) = VMACFGItemListGetValueI(
                option, VMA_CFG_PARM_SHOW_TIPOFDAY
            );
            break;


          default:
          (*i) = 0;
            return(VPI_ERROR_NOT_FOUND);
            break;
        }

        return(VPI_SUCCESS);
}

int VPIGetUI(vpi_id *id, int code, unsigned int *ui)
{
      int i;
      int status;
        vma_core_struct *core_ptr;
        vma_plugin_struct *pi = VMA_PLUGIN(id);


        if(pi == NULL)
            return(VPI_ERROR);
        if(ui == NULL)
            return(VPI_ERROR_BAD_VALUE);

        core_ptr = VPIGetCoreFromID(id);

        switch(code)
        {
          case VPI_CODE_VERSION_MAJOR:
          case VPI_CODE_VERSION_MINOR:
          case VPI_CODE_VERSION_RELEASE:

        case VPI_CODE_MAX_LIGHTS:
          case VPI_CODE_TOTAL_EDITORS:
          case VPI_CODE_TOTAL_PLUGINS:

        case VPI_CODE_TOOLBAR_STYLE:
        case VPI_CODE_SHOW_TOOLTIPS:
        case VPI_CODE_RECORD_LAST_POS_AND_SIZE:
        case VPI_CODE_SHOW_TIPOFDAY:

          status = VPIGetI(id, code, &i);
          (*ui) = (unsigned int)i;
          return(status);
          break;


          default:
            return(VPI_ERROR_NOT_FOUND);
            break;
        }

        return(VPI_SUCCESS); 
}

int VPIGetL(vpi_id *id, vpi_code_t code, long *l)
{
      int i;
        int status;
        vma_core_struct *core_ptr;
        vma_plugin_struct *pi = VMA_PLUGIN(id);


        if(pi == NULL)
            return(VPI_ERROR);
        if(l == NULL)
            return(VPI_ERROR_BAD_VALUE);

        core_ptr = VPIGetCoreFromID(id);

        switch(code)
        {
          case VPI_CODE_VERSION_MAJOR:
          case VPI_CODE_VERSION_MINOR:
          case VPI_CODE_VERSION_RELEASE:

          case VPI_CODE_MAX_LIGHTS:
          case VPI_CODE_TOTAL_EDITORS:
          case VPI_CODE_TOTAL_PLUGINS:

          case VPI_CODE_TOOLBAR_STYLE:
          case VPI_CODE_SHOW_TOOLTIPS:
          case VPI_CODE_RECORD_LAST_POS_AND_SIZE:
          case VPI_CODE_SHOW_TIPOFDAY:

            status = VPIGetI(id, code, &i);
            (*l) = (long)i;
            return(status);
            break;


          default:
            return(VPI_ERROR_NOT_FOUND);
            break;
        }

        return(VPI_SUCCESS);
}

int VPIGetUL(vpi_id *id, vpi_code_t code, unsigned long *ul)
{
        int i;
        int status;
        vma_core_struct *core_ptr;
        vma_plugin_struct *pi = VMA_PLUGIN(id);


        if(pi == NULL)
            return(VPI_ERROR);
        if(ul == NULL)
            return(VPI_ERROR_BAD_VALUE);

        core_ptr = VPIGetCoreFromID(id);

        switch(code)
        {
          case VPI_CODE_VERSION_MAJOR:
          case VPI_CODE_VERSION_MINOR:
          case VPI_CODE_VERSION_RELEASE:

          case VPI_CODE_MAX_LIGHTS:
          case VPI_CODE_TOTAL_EDITORS:
          case VPI_CODE_TOTAL_PLUGINS:

          case VPI_CODE_TOOLBAR_STYLE:
          case VPI_CODE_SHOW_TOOLTIPS:
          case VPI_CODE_RECORD_LAST_POS_AND_SIZE:
          case VPI_CODE_SHOW_TIPOFDAY:

            status = VPIGetI(id, code, &i);
            (*ul) = (unsigned long)i;
            return(status);
            break;

          case VPI_CODE_COMPILE_TIME:
          (*ul) = COMPILE_DATE;
            break;


          default:
            return(VPI_ERROR_NOT_FOUND);
            break;
        }

        return(VPI_SUCCESS);
}

int VPIGetF(vpi_id *id, int code, float *f)
{
        int i;
      unsigned long ul;
        int status;
        vma_core_struct *core_ptr;
        vma_plugin_struct *pi = VMA_PLUGIN(id);


        if(pi == NULL)
            return(VPI_ERROR);
        if(f == NULL)
            return(VPI_ERROR_BAD_VALUE);

        core_ptr = VPIGetCoreFromID(id);

        switch(code)
        {
          case VPI_CODE_VERSION_MAJOR:
          case VPI_CODE_VERSION_MINOR:
          case VPI_CODE_VERSION_RELEASE:

        case VPI_CODE_MAX_LIGHTS:
          case VPI_CODE_TOTAL_EDITORS:
          case VPI_CODE_TOTAL_PLUGINS:

        case VPI_CODE_TOOLBAR_STYLE:
          case VPI_CODE_SHOW_TOOLTIPS:
          case VPI_CODE_RECORD_LAST_POS_AND_SIZE:
          case VPI_CODE_SHOW_TIPOFDAY:

            status = VPIGetI(id, code, &i);
            (*f) = (float)i;
            return(status);
            break;


        case VPI_CODE_COMPILE_TIME:

            status = VPIGetUL(id, code, &ul);
            (*f) = (float)ul;
            return(status);
            break;





          default:
            return(VPI_ERROR_NOT_FOUND);
            break;
        }

        return(VPI_SUCCESS); 
}

int VPIGetD(vpi_id *id, int code, double *d)
{
        int i;
      unsigned long ul;
        int status;
        vma_core_struct *core_ptr;
        vma_plugin_struct *pi = VMA_PLUGIN(id);


        if(pi == NULL)
            return(VPI_ERROR);
        if(d == NULL)
            return(VPI_ERROR_BAD_VALUE);

        core_ptr = VPIGetCoreFromID(id);

        switch(code)
        {
          case VPI_CODE_VERSION_MAJOR:
          case VPI_CODE_VERSION_MINOR:
          case VPI_CODE_VERSION_RELEASE:

        case VPI_CODE_MAX_LIGHTS:
          case VPI_CODE_TOTAL_EDITORS:
          case VPI_CODE_TOTAL_PLUGINS:

        case VPI_CODE_TOOLBAR_STYLE:
          case VPI_CODE_SHOW_TOOLTIPS:
          case VPI_CODE_RECORD_LAST_POS_AND_SIZE:
          case VPI_CODE_SHOW_TIPOFDAY:

            status = VPIGetI(id, code, &i);
            (*d) = (double)i;
            return(status);
            break;


          case VPI_CODE_COMPILE_TIME:

            status = VPIGetUL(id, code, &ul);
            (*d) = (double)ul;
            return(status);
            break;




          default:
            return(VPI_ERROR_NOT_FOUND);
            break;
        }

        return(VPI_SUCCESS); 
}



/*
 *    Returns true if the given op_code is supported.
 */
int VPIQuery(vpi_id *id, int op_code)
{
      switch(op_code)
      {
        case VPI_OP_NULL:
        case VPI_OP_IMPORT:
        case VPI_OP_EXPORT:
        case VPI_OP_RENDER:
        case VPI_OP_CONFIGURE:
        case VPI_OP_CONFIGURATION_CHANGED:

        case VPI_SUPPORT_GTK:
        case VPI_SUPPORT_GTK_GLAREA:

          return(VPI_TRUE);
          break;

        default:
          return(VPI_FALSE);
          break;
      }
}

/*
 *      Sets the callback function func_ptr for the operation specified
 *    by op_code.
 *
 *    The func_ptr must point to a function defined on the plug-in
 *    and prototyped as follows:
 *
 *    int (*func_cb)(vpi_id *, vpi_op_*_struct *, void *)
 *
 *    The first input is the given id, the second is one of the
 *    vpi_op_*_struct structure pointers, and the third argument
 *    is the given client_data.
 *
 *      Returns VPI_SUCCESS on success or VPI_ERROR_* on failure.
 */
int VPISetOperationCB(
        vpi_id *id,
      int op_code,                    /* One of VPI_OP_*. */
        void *func_ptr,                 /* Can be NULL to disable. */
        void *client_data
)
{
      vma_plugin_struct *pi = VMA_PLUGIN(id);


      if(pi == NULL)
          return(VPI_ERROR);

      switch(op_code)
      {
        case VPI_OP_NULL:
          pi->null = func_ptr;
          pi->null_data = client_data;
          break;

          case VPI_OP_IMPORT:
            pi->import = func_ptr;
            pi->import_data = client_data;
            break;

          case VPI_OP_EXPORT:
            pi->export = func_ptr;
            pi->export_data = client_data;
            break;

        case VPI_OP_RENDER:
          pi->render = func_ptr;
          pi->render_data = client_data;
          break;

        case VPI_OP_CONFIGURE:
          pi->configure = func_ptr;
          pi->configure_data = client_data;
          break;

        case VPI_OP_CONFIGURATION_CHANGED:
          pi->configuration_changed = func_ptr;
            pi->configuration_changed_data = client_data;
            break;

/* Add support for additional operations here. */

        default:
          return(VPI_ERROR_NOT_SUPPORTED);
      }

      return(VPI_SUCCESS);
}

/*
 *    Unsets function callbacks to the operation specified by op_code.
 */
void VPIUnsetOperationCB(
        vpi_id *id,
      int op_code             /* One of VPI_OP_*. */
)
{
      VPISetOperationCB(id, op_code, NULL, NULL);
}


/*
 *    Extended Operation: Import
 *
 *    Adds a new file type extension for import support, returns non-zero
 *    on error.
 */
int VPIImportSetFileType(vpi_id *id, vpi_ftype_struct *ftype)
{
        int i;
        vma_plugin_struct *pi = VMA_PLUGIN(id);                  
      if((pi == NULL) || (ftype == NULL))
            return(VPI_ERROR);

      if(pi->total_import_ftypes < 0)
          pi->total_import_ftypes = 0;
      i = pi->total_import_ftypes;
      pi->total_import_ftypes = i + 1;

      pi->import_ftype_ext = (char **)realloc(
          pi->import_ftype_ext,
          pi->total_import_ftypes * sizeof(char *)
      );
      pi->import_ftype_name = (char **)realloc(
          pi->import_ftype_name,
          pi->total_import_ftypes * sizeof(char *)
      );
      if((pi->import_ftype_ext == NULL) ||
         (pi->import_ftype_name == NULL)
      )
      {
          pi->total_import_ftypes = 0;
          pi->import_ftype_ext = NULL;
          pi->import_ftype_name = NULL;
          return(VPI_ERROR_SYSTEM);
      }

      pi->import_ftype_ext[i] = strdup(
          (ftype->ext == NULL) ? "" : ftype->ext
      );
      pi->import_ftype_name[i] = strdup(
          (ftype->name == NULL) ? "" : ftype->name
      );

      return(VPI_SUCCESS);
}

/*
 *    Unsets all defined file types of this plug-in for import support.
 */
void VPIImportClearFileTypes(vpi_id *id)
{
      int i;
      vma_plugin_struct *pi = VMA_PLUGIN(id);
      if(pi == NULL)
          return;

      for(i = 0; i < pi->total_import_ftypes; i++)
      {
          free(pi->import_ftype_ext[i]);
          free(pi->import_ftype_name[i]);
      }
      free(pi->import_ftype_ext);
      pi->import_ftype_ext = NULL;
      free(pi->import_ftype_name);
      pi->import_ftype_name = NULL;
      pi->total_import_ftypes = 0;
}

/*
 *    Sets import file check function or unsets if import_fcheck is 
 *    NULL. Returns non-zero on error.
 */
int VPIImportSetFCheckFunc(
        vpi_id *id,
        int (*import_fcheck)(vpi_id *, const char *, const char *, void *),
        void *client_data
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        if(pi == NULL)
            return(VPI_ERROR);

      pi->import_fcheck = import_fcheck;
      pi->import_fcheck_data = client_data;

      return(VPI_SUCCESS);
}


/*
 *      Extended Operation: Export
 *
 *      Adds a new file type extension for export support, returns non-zero
 *      on error.
 */
int VPIExportSetFileType(vpi_id *id, vpi_ftype_struct *ftype)
{
        int i;
        vma_plugin_struct *pi = VMA_PLUGIN(id);
      if((pi == NULL) || (ftype == NULL))
          return(VPI_ERROR);

        if(pi->total_export_ftypes < 0) 
            pi->total_export_ftypes = 0; 
        i = pi->total_export_ftypes;
        pi->total_export_ftypes = i + 1;

        pi->export_ftype_ext = (char **)realloc(
            pi->export_ftype_ext,
            pi->total_export_ftypes * sizeof(char *)
        );
        pi->export_ftype_name = (char **)realloc(
            pi->export_ftype_name,
            pi->total_export_ftypes * sizeof(char *)
        );
        if((pi->export_ftype_ext == NULL) ||
           (pi->export_ftype_name == NULL)
        )
        {
            pi->total_export_ftypes = 0;
            pi->export_ftype_ext = NULL;
            pi->export_ftype_name = NULL;
            return(VPI_ERROR_SYSTEM);
        }

        pi->export_ftype_ext[i] = strdup(
          (ftype->ext == NULL) ? "" : ftype->ext
      );
        pi->export_ftype_name[i] = strdup(
          (ftype->name == NULL) ? "" : ftype->name
      );

        return(VPI_SUCCESS);
}

/*
 *      Unsets all defined file types of this plug-in for export support.
 */
void VPIExportClearFileTypes(vpi_id *id)
{
        int i;
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        if(pi == NULL)
            return;

        for(i = 0; i < pi->total_export_ftypes; i++)
        {
            free(pi->export_ftype_ext[i]);
            free(pi->export_ftype_name[i]);
        }
        free(pi->export_ftype_ext);
        pi->export_ftype_ext = NULL;
        free(pi->export_ftype_name);
        pi->export_ftype_name = NULL;
        pi->total_export_ftypes = 0;
}


/*
 *    Sets render menu item label or unsets if label is NULL.
 */
void VPIRenderSetLabel(vpi_id *id, const char *label)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        if(pi == NULL)
            return;

      free(pi->render_label);
      pi->render_label = ((label == NULL) ? NULL : strdup(label));
}


/*
 *    Deallocates the given list of XPM data lines in tar_buf
 *    and updates the return values.
 *
 *    If src_buf is not NULL then it will be parsed and its data
 *    copied to the given list of XPM data lines in tar_buf and
 *    updates the return values again. So calling this function
 *    with src_buf = NULL will basically just deallocate the entire
 *    tar_buf.
 */
static void VPIUpdateXPMData(
        u_int8_t ***tar_buf, int *tar_buf_lines,
        const u_int8_t **src_buf
)
{
#define vt  4
      int i, v[vt], lines, tbl;
      u_int8_t **tb;
      const char *cstrptr;


      if((tar_buf == NULL) || (tar_buf_lines == NULL))
          return;

      /* Deallocate existing data if any. */
      tb = *tar_buf;
      tbl = *tar_buf_lines;
      for(i = 0; i < tbl; i++)
          free(tb[i]);
      free(tb);
      (*tar_buf) = NULL;
      (*tar_buf_lines) = 0;


      /* No source buffer given? */
      if(src_buf == NULL)
          return;

      /* Get pointer to first line in src_buf and parse it. */
      cstrptr = (const char *)src_buf[0];
      if(cstrptr == NULL)
          return;

      /* Parse first line, format is:
       *
       *    <width> <height> <colors> <chars_per_color_value>
       */
      i = sscanf(
          cstrptr,
          "%i %i %i %i",
          &v[0], &v[1], &v[2], &v[3]
      );
      for(; i < vt; i++)
          v[i] = 0;

      /* Add up number of lines by adding: header line + height + number
       * of colors
       */
      lines = 1 + v[1] + v[2];

      /* Allocate target buffer. */
      if(lines > 0)
      {
          (*tar_buf) = tb = (u_int8_t **)calloc(lines, sizeof(u_int8_t *));
          if(tb != NULL)
          {
            for(i = 0; i < lines; i++)
                tb[i] = (u_int8_t *)strdup(
                  (const char *)src_buf[i]
                );
          }
          /* Update lines return. */
          (*tar_buf_lines) = lines;
      }

#undef vt
}


/*
 *    Allocate a new vpi_appearance_struct with reset values.
 */
vpi_appearance_struct *VPIAppearanceNew(void)
{
      vpi_appearance_struct *v = (vpi_appearance_struct *)calloc(
          1, sizeof(vpi_appearance_struct)
      );
      if(v != NULL)
      {

      }
      return(v);
}

/*
 *      Deallocates the given vpi_appearance_struct and any
 *      allocated resources.
 */
void VPIAppearanceDelete(vpi_appearance_struct *v)
{
        vpi_flag flags;

        if(v == NULL)
            return;

        flags = v->flags;

      if(flags & VPI_APPEARANCE_FLAG_TITLE)
          free(v->title);
      if(flags & VPI_APPEARANCE_FLAG_DESCRIPTION)
          free(v->description);

        /* Do not deallocate icons. */

      /* Deallocate structure itself. */
        free(v);

      return;
}

/*
 *    Sets apperance values to the plug-in.
 */
void VPIAppearanceSet(vpi_id *id, const vpi_appearance_struct *v)
{
      GdkWindow *window = (GdkWindow *)GDK_ROOT_PARENT();
        GtkStyle *style = gtk_widget_get_default_style();
      vma_plugin_struct *pi = VMA_PLUGIN(id);


      if((pi == NULL) || (v == NULL))
          return;

      if(v->flags & VPI_APPEARANCE_FLAG_TITLE)
      {
          free(pi->title);
          pi->title = ((v->title == NULL) ?
            NULL : strdup(v->title)
          );
      }
        if(v->flags & VPI_APPEARANCE_FLAG_DESCRIPTION)
        {
            free(pi->description);
            pi->description = ((v->description == NULL) ? 
                NULL : strdup(v->description)
            );
        }
        if(v->flags & VPI_APPEARANCE_FLAG_ICON_STD)
      {



      }
        if(v->flags & VPI_APPEARANCE_FLAG_ICON_LIST_STD)
      {
          /* Deallocate existing standard list icon data. */
          if(pi->icon_pixmap != NULL)
          {
            gdk_pixmap_unref(pi->icon_pixmap);
            pi->icon_pixmap = NULL;
          }
            if(pi->icon_mask != NULL)
            {
                gdk_bitmap_unref(pi->icon_mask);
                pi->icon_mask = NULL;
            }

          /* Create new standard list icon. */
          if((v->icon_list_std != NULL) && (window != NULL) && (style != NULL))
          {
            /* Copy icon data. */
            VPIUpdateXPMData(
                &pi->list_icon_data, &pi->list_icon_lines,
                (const u_int8_t **)v->icon_list_std
            );
            /* Create icon (use coppied data). */
            pi->icon_pixmap = gdk_pixmap_create_from_xpm_d(
                window, &pi->icon_mask,
                &style->bg[GTK_STATE_NORMAL],
                (gchar **)pi->list_icon_data
            );
          }
      }
        if(v->flags & VPI_APPEARANCE_FLAG_ICON_LIST_DISABLED)
      {



      }
}

/*
 *    Gets apperance values from the plug-in.
 *
 *    The return must be deallocated by VPIAppearanceDelete().
 */
vpi_appearance_struct *VPIAppearanceGet(vpi_id *id)
{
      vma_plugin_struct *pi = VMA_PLUGIN(id);
      vpi_appearance_struct *v;


        if(pi == NULL)
            return(NULL);

      v = VPIAppearanceNew();
      if(v == NULL)
          return(v);

      v->flags = (VPI_APPEARANCE_FLAG_TITLE |
            VPI_APPEARANCE_FLAG_DESCRIPTION
      );
      v->title = ((pi->title == NULL) ?
          NULL : strdup(pi->title)
      );
        v->description = ((pi->description == NULL) ?
            NULL : strdup(pi->description)
        );

/* No real way to return xpm icon data just now... */

        return(v);
}



/*
 *    Works just like POSIX stat().
 */
int VPIStat(vpi_id *id, const char *path, struct stat *stat_buf)
{
      if((id == NULL) || (path == NULL))
      {
          errno = EFAULT;
          return(-1);
      }

      if(stat_buf == NULL)
      {
          struct stat tmp_stat_buf;
          return(stat(path, &tmp_stat_buf));
      }
      else
      {
          return(stat(path, stat_buf));
      }
}

/*
 *    Works just like SVr4 lstat().
 */
int VPILStat(vpi_id *id, const char *path, struct stat *stat_buf)
{
        if((id == NULL) || (path == NULL))
        {
            errno = EFAULT;
            return(-1);
        }

        if(stat_buf == NULL)
        {
            struct stat tmp_stat_buf;
            return(lstat(path, &tmp_stat_buf));
        }
        else
        {   
            return(lstat(path, stat_buf));
        }
}


/*
 *    File IO functions, work just like the ANSI C stdio counterparts
 *    when identical.
 */
FILE *VPIFOpen(vpi_id *id, const char *path, const char *mode)
{
      if((id == NULL) || (path == NULL) || (mode == NULL))
        {
            errno = EFAULT;
            return(NULL);
      }

        return(FOpen(path, mode));
}

int VPIFGetC(vpi_id *id, FILE *fp)
{
        if((id == NULL) || (fp == NULL))
        {
            errno = EFAULT;
            return(EOF);
      }

      return(fgetc(fp));
}

char *VPIFGetS(vpi_id *id, char *s, int size, FILE *fp)
{
        if((id == NULL) || (fp == NULL) || (s == NULL))
        {
            errno = EFAULT;
            return(NULL);
      }

      return(fgets(s, size, fp));
}

long VPIFRead(vpi_id *id, void *ptr, long size, long nmemb, FILE *fp)
{
        if((id == NULL) || (fp == NULL) || (ptr == NULL))
        {
            errno = EFAULT;
            return(0);
      }

      return((long)fread(ptr, (size_t)size, (size_t)nmemb, fp));
}

int VPIFPutC(vpi_id *id, int c, FILE *fp)
{
        if((id == NULL) || (fp == NULL))
        {
            errno = EFAULT;
            return(EOF);
      }

      return(fputc(c, fp));
}

int VPIFPutS(vpi_id *id, const char *s, FILE *fp)
{
        if((id == NULL) || (fp == NULL) || (s == NULL))
        {
            errno = EFAULT;
            return(EOF);
      }

        return(fputs(s, fp));
}

long VPIFWrite(vpi_id *id, const void *ptr, long size, long nmemb, FILE *fp)
{
        if((id == NULL) || (fp == NULL) || (ptr == NULL))
        {
            errno = EFAULT;
            return(0);
      }

        return((long)fwrite(ptr, (size_t)size, (size_t)nmemb, fp));
}

int VPIFSeek(vpi_id *id, FILE *fp, long offset, int whence)
{
      if((id == NULL) || (fp == NULL))
        {
            errno = EFAULT;
          return(-1);
      }

      return(fseek(fp, offset, whence));
}

long VPIFTell(vpi_id *id, FILE *fp)
{
        if((id == NULL) || (fp == NULL))
        {
            errno = EFAULT;
            return(-1);
      }

      return(ftell(fp));
}

void VPIRewind(vpi_id *id, FILE *fp)
{
        if((id == NULL) || (fp == NULL))
        {
            errno = EFAULT;
            return;
      }

      rewind(fp);
}

void VPIFClose(vpi_id *id, FILE *fp)
{
        if((id == NULL) || (fp == NULL))
        {
            errno = EFAULT;
            return;
      }

      FClose(fp);
}

/*
 *    Seeks to next line, escape sequences will be parsed.
 */
void VPIFSeekNextLine(vpi_id *id, FILE *fp)
{
      if(id != NULL)
          FSeekNextLine(fp);
      return;
}

/*
 *    Seeks fp past any blank characters (spaces and tabs).
 */
void VPIFSeekPastSpaces(vpi_id *id, FILE *fp)
{
      if(id != NULL)
          FSeekPastSpaces(fp);
      return;
}

/*
 *    Seeks fp past the first occurance of c or EOF.
 */
void VPIFSeekPastChar(vpi_id *id, FILE *fp, char c)
{
      if(id != NULL)
            FSeekPastChar(fp, c);
        return;

}

/*
 *      Returns a dynamically allocated string containing
 *      the value as a string obtained from the file specified
 *      by fp. Reads from the current position to the next new
 *      line character or EOF.
 *
 *      Escape sequences will be parsed and spaces will be
 *      stripped.
 *
 *      The fp is positioned after the new line or at the EOF.
 */
char *VPIFGetString(vpi_id *id, FILE *fp)
{
      if(id != NULL)
          return(FGetString(fp));
      else
          return(NULL);
}

/*
 *      Works just like VPIFGetString() except the string is loaded
 *      literally and the only escape sequence to be handled will
 *      be the two characters '\\' '\n', if/when those two characters
 *      are encountered the character '\n' will be saved into the return
 *      string.
 *
 *      Spaces will not be striped, the fp will be positioned after the
 *      newline or EOF (whichever is encountered first).
 */
char *VPIFGetStringLined(vpi_id *id, FILE *fp)
{
      if(id != NULL)
          return(FGetStringLined(fp));
      else
          return(NULL);
}

/*
 *      Works just like VPIFGetString() except the string is loaded
 *      literally and no escape sequences parsed, that would be all
 *      characters from the current given fp position to the first
 *      encountered newline ('\n') character (escaped or not).
 *
 *      Spaces will not be striped, the fp will be positioned after the
 *      newline or EOF (whichever is encountered first).
 */
char *VPIFGetStringLiteral(vpi_id *id, FILE *fp)
{
        if(id != NULL)
          return(FGetStringLiteral(fp));
      else
          return(NULL);
}



/*
 *    Get pointers to model header data on specified editor.
 *
 *      Returns VPI_SUCCESS on success or VPI_ERROR_* on failure.
 */
int VPIEditorGetHeader(
        vpi_id *id, int editor_id,
        const char **filename,          /* Loaded file name, can return NULL. */
        void ***mh_item, int *total_mh_items
)
{
      vma_plugin_struct *pi = VMA_PLUGIN(id);
      ma_editor_struct *editor;


        if(mh_item != NULL)
            *mh_item = NULL;
        if(total_mh_items != NULL)
            *total_mh_items = 0;

      if(pi == NULL)
          return(VPI_ERROR);

      editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return(VPI_ERROR_NOT_FOUND);

        if(mh_item != NULL)
            *mh_item = editor->mh_item;
        if(total_mh_items != NULL)
            *total_mh_items = editor->total_mh_items;

      return(VPI_SUCCESS);
}

/*
 *    Get pointers to models on specified editor.
 *
 *      Returns VPI_SUCCESS on success or VPI_ERROR_* on failure.
 */
int VPIEditorGetModels(
        vpi_id *id, int editor_id,
        v3d_model_struct ***model, int *total_models
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
      ma_editor_struct *editor;


        if(model != NULL)
            *model = NULL;
        if(total_models != NULL)
            *total_models = 0;

        if(pi == NULL)
            return(VPI_ERROR);

        editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return(VPI_ERROR_NOT_FOUND);

      if(model != NULL)
          *model = editor->model;
      if(total_models != NULL)
          *total_models = editor->total_models;

      return(VPI_SUCCESS);
}

/*
 *    Get camera values.
 *
 *      Returns VPI_SUCCESS on success or VPI_ERROR_* on failure.
 */
int VPIEditorGetCamera(
        vpi_id *id, int editor_id, vpi_camera_struct **cam
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        ma_editor_struct *editor;
      vma_view3d_struct *view3d;
      static vpi_camera_struct s_cam;


        if((pi == NULL) || (cam == NULL))
            return(VPI_ERROR);

      /* Set return pointer. */
      *cam = &s_cam;

      /* Reset return buffer by just resetting the flags. */
      s_cam.flags = 0;

        editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return(VPI_ERROR_NOT_FOUND);

      /* Get pointer to first 3d view. */
      view3d = ((VMA_MAX_3D_VIEWS_PER_EDITOR > 0) ?
          editor->view3d[0] : NULL
      );
      if(view3d == NULL)
          return(VPI_ERROR);

      if(TRUE)
      {
          double mag;

            s_cam.flags = (VPI_CAMERA_POS | VPI_CAMERA_DIR |
                VPI_CAMERA_UP | VPI_CAMERA_FOV | VPI_CAMERA_ASPECT |
                VPI_CAMERA_CLIP_NEAR | VPI_CAMERA_CLIP_FAR
            );
            s_cam.pos_x = view3d->cam_x;
            s_cam.pos_y = view3d->cam_y;
            s_cam.pos_z = view3d->cam_z;
            s_cam.dir_x = sin(view3d->cam_h);
            s_cam.dir_y = cos(view3d->cam_h);
            s_cam.dir_z = -sin(view3d->cam_p);
            mag = sqrt(
                (s_cam.dir_x * s_cam.dir_x) +
                (s_cam.dir_y * s_cam.dir_y) +
                (s_cam.dir_z * s_cam.dir_z)
            );
            if(mag > 0.0)
            {
                s_cam.dir_x = s_cam.dir_x / mag;
                s_cam.dir_y = s_cam.dir_y / mag;
                s_cam.dir_z = s_cam.dir_z / mag;
            }
            s_cam.up_x = 0.0;
            s_cam.up_y = 0.0;
            s_cam.up_z = (((view3d->cam_p > (0.5 * PI)) &&
                (view3d->cam_p < (1.5 * PI))) ? -1.0 : 1.0
            );
            s_cam.fov = view3d->cam_fov; /* In radians. */
            s_cam.aspect = 1.33333;
            s_cam.clip_near = view3d->cam_clip_near;
            s_cam.clip_far = view3d->cam_clip_far;
      }

      return(VPI_SUCCESS);
}

/*
 *    Gets light values for a specific light specified by light_num.
 *    The given light_num corresponds to a light on the editor's light
 *    list (not the light lists passed to the plug-ins).
 *
 *      Returns VPI_SUCCESS on success or VPI_ERROR_* on failure. Can also
 *    return VPI_ERROR_NOT_FOUND even if the light number is valid but
 *    that light is not enabled.
 */
int VPIEditorGetLight(
        vpi_id *id, int editor_id,
        vpi_light_struct **light,
        int light_num                   /* Get values from this light. */
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
      int i;
        ma_editor_struct *editor;
      vma_light_struct *vlight_ptr;
      static vpi_light_struct s_light;


        if((pi == NULL) || (light == NULL))
            return(VPI_ERROR);

        /* Set return pointer. */
        *light = &s_light;

        /* Reset return buffer by resetting the flags. */
      s_light.flags = 0;

        editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return(VPI_ERROR_NOT_FOUND);

      i = light_num;
      if((i < 0) || (i >= VMA_LIGHTS_MAX))
          return(VPI_ERROR_NOT_FOUND);
      vlight_ptr = &(editor->light[i]);

      /* Check if light is not enabled, if not enabled then return
       * VPI_ERROR_NOT_FOUND.
       */
      if(!(vlight_ptr->flags & VMA_LIGHT_FLAG_ENABLED))
          return(VPI_ERROR_NOT_FOUND);

      /* Begin setting up return buffer. */
      s_light.flags = (VPI_LIGHT_POS |
          VPI_LIGHT_AMBIENT | VPI_LIGHT_DIFFUSE | VPI_LIGHT_SPECULAR
      );
      s_light.pos_x = vlight_ptr->x;
      s_light.pos_y = vlight_ptr->y;
      s_light.pos_z = vlight_ptr->z;

      /* Check if light is directional. */
      if(vlight_ptr->spot_cutoff < (0.5 * PI))
      {
          s_light.flags |= (VPI_LIGHT_DIR | VPI_LIGHT_SPOT_CUTOFF);
          s_light.dir_x = sin(vlight_ptr->heading);
            s_light.dir_y = cos(vlight_ptr->heading);
            s_light.dir_z = -sin(vlight_ptr->pitch);
          s_light.spot_cutoff = vlight_ptr->spot_cutoff;
      }
      else
      {
          s_light.dir_x = 0.0;
          s_light.dir_y = 0.0;
          s_light.dir_z = 0.0;
          s_light.spot_cutoff = (1.0 * PI);
      }

      s_light.ambient.a = vlight_ptr->ambient.a;
        s_light.ambient.r = vlight_ptr->ambient.r;
        s_light.ambient.g = vlight_ptr->ambient.g;
        s_light.ambient.b = vlight_ptr->ambient.b;

      s_light.diffuse.a = vlight_ptr->diffuse.a;
        s_light.diffuse.r = vlight_ptr->diffuse.r;
        s_light.diffuse.g = vlight_ptr->diffuse.g;
        s_light.diffuse.b = vlight_ptr->diffuse.b;

      s_light.specular.a = vlight_ptr->specular.a;
        s_light.specular.r = vlight_ptr->specular.r;
        s_light.specular.g = vlight_ptr->specular.g;
        s_light.specular.b = vlight_ptr->specular.b;

      return(VPI_SUCCESS);
}

/*
 *    Get list of all enabled lights on the editor. The total_lights
 *    return will be set to the number of enabled lights.
 *
 *    Returns VPI_SUCCESS on success or VPI_ERROR_* on failure.
 */
int VPIEditorGetLights(
        vpi_id *id, int editor_id, vpi_light_struct **light, int *total_lights
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        int i, nlights;
      vpi_light_struct *light_rtn;
      static vpi_light_struct slight[VMA_LIGHTS_MAX];


        if((pi == NULL) || (light == NULL) || (total_lights == NULL))
            return(VPI_ERROR);

      nlights = 0;      /* Reset number of enabled lights. */
      /* Itterate through our static VPI lights buffer. */
      for(i = 0; i < VMA_LIGHTS_MAX; i++)
      {
          /* Get each light to check if its enabled and fetch its
           * values to our VPI lights buffer segment.
           */
          if(VPIEditorGetLight(
            id, editor_id,
            &light_rtn,
            i                 /* Light number. */
          ) == VPI_SUCCESS)
          {
            if(light_rtn != NULL)
            {
                vpi_flag flags = light_rtn->flags;
                vpi_light_struct *s_light_ptr = &(slight[nlights]);


                s_light_ptr->flags = flags;
                if(flags & VPI_LIGHT_POS)
                {
                  s_light_ptr->pos_x = light_rtn->pos_x;
                        s_light_ptr->pos_y = light_rtn->pos_y;
                        s_light_ptr->pos_z = light_rtn->pos_z;
                }
                if(flags & VPI_LIGHT_DIR)
                    {
                        s_light_ptr->dir_x = light_rtn->dir_x;
                        s_light_ptr->dir_y = light_rtn->dir_y;
                        s_light_ptr->dir_z = light_rtn->dir_z;
                    }
                    if(flags & VPI_LIGHT_AMBIENT)
                  memcpy(
                      &s_light_ptr->ambient,
                      &light_rtn->ambient,
                      sizeof(vpi_color_struct)
                  );
                    if(flags & VPI_LIGHT_DIFFUSE)
                        memcpy(
                            &s_light_ptr->diffuse,
                            &light_rtn->diffuse,
                            sizeof(vpi_color_struct)
                        );
                    if(flags & VPI_LIGHT_SPECULAR)
                        memcpy(
                            &s_light_ptr->specular,
                            &light_rtn->specular,
                            sizeof(vpi_color_struct)
                        );
                if(flags & VPI_LIGHT_SPOT_CUTOFF)
                  s_light_ptr->spot_cutoff = light_rtn->spot_cutoff;
            }

            /* This light is enabled, so increment enabled lights 
             * count.
             */
            nlights++;
          }
      }

      /* Update returns. */
      *light = slight;
      *total_lights = nlights;

      return(VPI_SUCCESS);
}

/*
 *    Returns the model pointer of the model specified by model_num
 *    on the editor or NULL on error.
 */
v3d_model_struct *VPIEditorGetModelByNumber(
        vpi_id *id, int editor_id, int model_num
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        ma_editor_struct *editor;

        if(pi == NULL)
            return(NULL);

        editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return(NULL);

      if((model_num < 0) || (model_num >= editor->total_models))
          return(NULL);

      return(editor->model[model_num]);
}


/*
 *    Creates a new model on the specified editor and returns
 *    the model pointer and index.
 */
v3d_model_struct *VPIEditorModelNew(
        vpi_id *id, int editor_id,
      int create_position,    /* VPI_POSITION_*. */
      int *model_num,
      int type, const char *name
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        int i, n;
      GtkCList *models_clist;
      ma_editor_struct *editor;
      v3d_model_struct *model_ptr = NULL;
      gchar *val[1];


      if(model_num != NULL)
          *model_num = -1;

        if(pi == NULL)
            return(NULL);

        editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return(NULL);

      if(!editor->initialized || editor->processing)
          return(NULL);

        /* Sync data on editor before any operations. */
        EditorSyncData(editor);

      /* Get models clist. */
      models_clist = (GtkCList *)editor->models_list;
      if(models_clist == NULL)
          return(NULL);

/* Check write protect? */

      if(editor->total_models < 0)
          editor->total_models = 0;

      /* Create a new model structure first. */
      model_ptr = V3DModelCreate(type, name);
      if(model_ptr == NULL)
          return(NULL);

      /* Handle by create position, i is reset to -1 as it will be
       * updated to a valid insert position or left as -1 on failure.
       */
      i = -1;
      switch(create_position)
      {
        case VPI_POSITION_FIRST:
          i = 0;
          /* Allocate more pointers. */
          editor->total_models++;
          editor->model = (v3d_model_struct **)realloc(
            editor->model,
            editor->total_models * sizeof(v3d_model_struct *)
          );
          if(editor->model == NULL)
          {
            editor->total_models = 0;
            V3DModelDestroy(model_ptr);
            return(NULL);
          }
          /* Shift pointers. */
          for(n = editor->total_models - 1; n > i; n--)
            editor->model[n] = editor->model[n - 1];
          break;

          case VPI_POSITION_LAST:
            /* Allocate more pointers. */
          i = editor->total_models;
            editor->total_models = i + 1;
            editor->model = (v3d_model_struct **)realloc(
                editor->model,
                editor->total_models * sizeof(v3d_model_struct *)
            );
            if(editor->model == NULL)
            {
                editor->total_models = 0;
                V3DModelDestroy(model_ptr);
                return(NULL);
            }
          /* No need to shift pointers when appending. */
            break;

        case VPI_POSITION_SELECTED:
          i = EditorSelectedModelIndex(editor);
          if((i < 0) || (i > editor->total_models))
            i = editor->total_models;
          /* Allocate more pointers. */
            editor->total_models++;
            editor->model = (v3d_model_struct **)realloc(
                editor->model,
                editor->total_models * sizeof(v3d_model_struct *)
            );
            if(editor->model == NULL)
            {
                editor->total_models = 0;
                V3DModelDestroy(model_ptr);
                return(NULL);
            }
            /* Shift pointers. */
            for(n = editor->total_models - 1; n > i; n--)
                editor->model[n] = editor->model[n - 1];
            break;
      }
      /* Unable to allocate more pointers? */
      if(i < 0)
      {
            V3DModelDestroy(model_ptr);
          return(NULL);
      }

      /* Index i now specifies the valid new index for the new
       * model to be created on the editor.
       */
      editor->model[i] = model_ptr;

      /* Insert new item into models clist. */
      val[0] = g_strdup((name == NULL) ? "(null)" : name);
      gtk_clist_insert(models_clist, i, val);
      g_free(val[0]);

      /* Update new item on models list. */
      EditorListModelsSet(
          GTK_WIDGET(models_clist), i,
          model_ptr, FALSE
      );

      /* Update has changes on editor. */
      if(!editor->has_changes)
          editor->has_changes = TRUE;

        /* Update menus and redraw views. */
        EditorUpdateMenus(editor);
        EditorUpdateAllViewMenus(editor);
        EditorRedrawAllViews(editor);

      /* Update new model index return. */
        if(model_num != NULL)
            (*model_num) = i;

      return(model_ptr);
}

/*      
 *      Deletes the specified model from the specified editor.
 */
void VPIEditorModelDelete(
        vpi_id *id, int editor_id, int model_num
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        int i, n;
        GtkCList *models_clist;
        ma_editor_struct *editor;


        if(pi == NULL)   
            return;

        editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return;

        if(!editor->initialized || editor->processing)
            return;

      /* Sync data on editor before any operations. */
      EditorSyncData(editor);

      /* Get models clist. */
        models_clist = (GtkCList *)editor->models_list;
        if(models_clist == NULL)
            return;

      /* Get model number and see if it exists. */
      i = model_num;
      if((i < 0) || (i >= editor->total_models))
          return;

      /* Delete actual model. */
      V3DModelDestroy(editor->model[i]);

      /* Reduce and shift pointers. */
      editor->total_models--;
      if(editor->total_models < 0)
          editor->total_models = 0;
      for(n = i; n < editor->total_models; n++)
          editor->model[n] = editor->model[n + 1];

      /* Remove pointer array to models if all models got deleted. */
      if(editor->total_models == 0)
      {
          free(editor->model);
          editor->model = NULL;
      }

      /* Unselect model item if we are deleting the selected one. */
      if(EditorSelectedModelIndex(editor) == i)
          editor->selected_model_item = -1;
 
        /* Remove row on models clist. */
        gtk_clist_remove(models_clist, i);

        /* Update has changes on editor. */
        if(!editor->has_changes)
            editor->has_changes = TRUE;

        /* Update menus and redraw views. */
        EditorUpdateMenus(editor);
        EditorUpdateAllViewMenus(editor);
        EditorRedrawAllViews(editor);
}


/*      
 *      Selects the specified model on the specified editor, if
 *    model_num is -1 then all models will be unselected.
 */
void VPIEditorModelSelect(
        vpi_id *id, int editor_id, int model_num
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        GtkCList *clist;
        ma_editor_struct *editor;


        if(pi == NULL)
            return;

        editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return;

        if(!editor->initialized || editor->processing)
            return;

      clist = (GtkCList *)editor->models_list;
      if(clist == NULL)
          return;

      /* Unselect all? */
      if(model_num < 0)
      {
          gtk_clist_unselect_all(clist);
      }
      /* Reselect? */
      else if(model_num == EditorSelectedModelIndex(editor))
      {
          gtk_clist_unselect_all(clist);
          gtk_clist_select_row(clist, model_num, 0);
      }
        else
        {
            gtk_clist_select_row(clist, model_num, 0);
        }
}

/*
 *    Returns the selected model number on the editor or -1 on error/none
 *    selected.
 */
v3d_model_struct *VPIEditorModelGetSelected(
        vpi_id *id, int editor_id, int *model_num
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
      gint i;
        ma_editor_struct *editor;
      v3d_model_struct *model_ptr;


      if(model_num != NULL)
          *model_num = -1;

        if(pi == NULL)
            return(NULL);

        editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return(NULL);

      i = EditorSelectedModelIndex(editor);
      if((i < 0) || (i >= editor->total_models))
          return(NULL);

      model_ptr = editor->model[i];
      if(model_ptr == NULL)
          return(NULL);

      if(model_num != NULL)
          *model_num = i;

      return(model_ptr);
}

/*
 *      Instructs the editor to (re)select the specified primitive if it
 *      is valid.  If pn is -1 then all primitives will be unselected.
 */
void VPIEditorPrimitiveSelect(
        vpi_id *id, int editor_id, int pn
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        GtkCList *clist;
        ma_editor_struct *editor;


        if(pi == NULL)
            return;

        editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return;

        if(!editor->initialized || editor->processing)
            return;

        clist = (GtkCList *)editor->primitives_list;
        if(clist == NULL)
            return;

        /* Unselect all? */
        if(pn < 0)
        {
            gtk_clist_unselect_all(clist);
        }
      else
      {
          gint i;

          /* Check if primitive is already selected. */
          for(i = 0; i < editor->total_selected_primitives; i++)
          {
            if(editor->selected_primitive[i] == pn)
                break;
          }
          /* Already selected? */
          if(i < editor->total_selected_primitives)
            gtk_clist_unselect_row(clist, pn, 0);

          /* Select new row. */
          gtk_clist_select_row(clist, pn, 0);
        }
}

/*
 *      Returns the curret selected primitives on the editor or NULL.
 *      The returned pointer must be free'ed by the calling function.
 */
int *VPIEditorPrimitiveGetSelected(
        vpi_id *id, int editor_id, int *total
)
{
        vma_plugin_struct *pi = VMA_PLUGIN(id);
        gint t, *s;
        ma_editor_struct *editor;


        if(total != NULL)
            *total = 0;

        if(pi == NULL)
            return(NULL);

        editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return(NULL);

      /* No primitives selected? */
      if(editor->selected_primitive == NULL)
          return(NULL);

      /* Get total number of primitives selected. */
      t = editor->total_selected_primitives;
      if(total != NULL)
          *total = t;

      /* Allocate list of selected primitives if there are any selected. */
      if(t > 0)
      {
          s = (gint *)g_malloc(t * sizeof(gint));
          if(s != NULL)
            memcpy(s, editor->selected_primitive, t * sizeof(gint));
      }
      else
      {
          s = NULL;
      }

      return(s);
}

/*
 *    Redraw editor.
 *
 *    If refresh_lists is VPI_TRUE then the lists will be refreshed.
 */
void VPIEditorRedraw(vpi_id *id, int editor_id, int refresh_lists)
{
      gint model_num;
      v3d_model_struct *m;
      ma_editor_struct *editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
          return;

        /* Get pointer to selected model if any. */
        model_num = EditorSelectedModelIndex(editor);
        m = V3DModelListGetPtr(
            editor->model, editor->total_models, model_num
        );

      /* One primitive selected? */
        if((m != NULL) && (editor->total_selected_primitives == 1))
        {
            gint pn = editor->selected_primitive[0];
            gpointer p;

          if((pn >= 0) && (pn < m->total_primitives))
            p = m->primitive[pn];
          else
            p = NULL;

          if((p != NULL) && refresh_lists)
          {
            EditorListDeleteValuesG(editor);
            EditorListAddValuesRG(editor, p);
            }
      }

      /* Update menus. */
        EditorUpdateMenus(editor);
      EditorUpdateAllViewMenus(editor);

      /* Redraw views if mapped. */
      if(editor->map_state)
      {
          EditorRedrawAllViews(editor);
      }
}

/*
 *    Returns VPI_TRUE if the editor's has_changes flag is set,
 *    otherwise returns VPI_FALSE.
 */
gint VPIEditorGetHasChanges(vpi_id *id, int editor_id)
{
        ma_editor_struct *editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return(VPI_FALSE);

      return((editor->has_changes) ? VPI_TRUE : VPI_FALSE);
}

/*
 *    Sets the has_changes flag on the editor.
 */
void VPIEditorSetHasChanges(vpi_id *id, int editor_id, int has_changes)
{
      gboolean b = (has_changes) ? TRUE : FALSE;
        ma_editor_struct *editor = VPIGetEditorFromID(id, editor_id);
        if(editor == NULL)
            return;

      if(editor->has_changes != b)
      {
          editor->has_changes = b;

          /* Update menus. */
          EditorUpdateMenus(editor);
          EditorUpdateAllViewMenus(editor);
      }
}


/*
 *    Returns a statically allocated string describing the given
 *    error (or success) code.
 */
const char *VPIErrorString(vpi_id *id, int error_code)
{
      switch(error_code)
      {
        case VPI_SUCCESS:
          return("success");
          break;

        case VPI_ERROR_GENERAL:
          return("general error");
          break;

        case VPI_ERROR_NOT_FOUND:
          return("not found");
          break;

        case VPI_ERROR_SYSTEM:
          return("system error");
          break;

        case VPI_ERROR_USER_ABORT:
          return("user abort");
          break;

        case VPI_ERROR_BAD_VALUE:
          return("bad value");
          break;

        case VPI_ERROR_NOT_SUPPORTED:
          return("not supported");
          break;

        default:
          return("unknown error");
          break;
      }
}

/*
 *    Creates a new tempory file and returns the FILE pointer opened
 *    for writing with the stream positioned at the beginning.
 *
 *    The name_prefix specifies the prefix for the name of the new
 *    tempory file, the limits on the prefix are defined by the
 *    platform's tempnam() function. But does not mean that VPI uses
 *    the tempnam() function (which VPI does not).
 *
 *    The new file will be placed in Vertex's tempory files directory.
 *
 *    If (and only if) the return path new_name is not NULL then the
 *    path to the new file name will be returned. The returned value is
 *    dynamically allocated so the calling function must deallocate it.
 */
FILE *VPICreateTemporyFile(
        vpi_id *id,
        const char *name_prefix,
        char **new_path_rtn
)
{
      vma_core_struct *core_ptr;
      vma_plugin_struct *pi = VMA_PLUGIN(id);


      if(new_path_rtn != NULL)
          *new_path_rtn = NULL;

      if((pi == NULL) || (name_prefix == NULL))
          return(NULL);

      core_ptr = VPIGetCoreFromID(id);

      return(VMAMakeOpenTmpFile(
          core_ptr,
          dname.tmp,
          name_prefix,
          new_path_rtn
      ));
}

/*
 *      Moves the object specified by old_path to the location specified
 *      by new_path. This works the same as the ANSI C rename(), so it
 *      can be used to rename objects as well.
 */
int VPIMove(vpi_id *id, const char *old_path, const char *new_path)
{
        if((id == NULL) || (old_path == NULL) || (new_path == NULL))
      {
          errno = EFAULT;
            return(-1);
      }

      return(rename(old_path, new_path));
}

/*
 *      Coppies the object specified by src_path to the location
 *      specified by tar_path.
 *
 *      The src_path and/or tar_path cannot reffer to a directory or a
 *    link that points to a directory.
 *
 *      If the target object exists then it will be atomitically
 *    overwritten.
 *
 *    Returns 0 on success or -1 on error, errno will be set.
 */
int VPICopy(vpi_id *id, const char *src_path, const char *tar_path)
{
      int c;
      FILE *src_fp, *tar_fp;
      struct stat stat_buf;


      if((id == NULL) || (src_path == NULL) || (tar_path == NULL))
        {
            errno = EFAULT;
            return(-1);
        }

      /* Check if the source file exists. */
      if(VPIStat(id, src_path, &stat_buf))
          return(-1);

      /* Is source file a directory? */
      if(S_ISDIR(stat_buf.st_mode))
      {
          errno = EINVAL;
          return(-1);
      }

      /* Check if target exists. */
      if(!VPIStat(id, tar_path, &stat_buf))
      {
          /* Is target a directory? */
          if(S_ISDIR(stat_buf.st_mode))
          {
                errno = EINVAL;
                return(-1);
          }
      }


      /* Open source and target files. */
      src_fp = VPIFOpen(id, src_path, "rb");
      if(src_fp == NULL)
          return(-1);

      tar_fp = VPIFOpen(id, tar_path, "wb");
        if(tar_fp == NULL)
      {
          VPIFClose(id, src_fp);
            return(-1);
      }

      /* Begin copying. */
      c = VPIFGetC(id, src_fp);
      while(c != EOF)
      {
          VPIFPutC(id, c, tar_fp);
          c = VPIFGetC(id, src_fp);
      }

      /* Close files. */
      VPIFClose(id, src_fp);
      VPIFClose(id, tar_fp);

      return(0);
}

/*
 *    Creates a new directory specified by the given path.
 *
 *      Returns VPI_SUCCESS on success or VPI_ERROR_* on failure (can
 *    return VPI_ERROR if directory already exists).
 */
int VPIMkDir(
        vpi_id *id, const char *path, mode_t m, int make_parents_as_needed
)
{
      if((id == NULL) || (path == NULL))
        {
            errno = EFAULT;
          return(VPI_ERROR);
      }

      if(make_parents_as_needed)
      {
          int status = rmkdir(path, m);
          if(status)
                return(VPI_ERROR);
            else
                return(VPI_SUCCESS);
      }
      else
      {
          int status = mkdir(path, m);
          if(status)
            return(VPI_ERROR);
          else
            return(VPI_SUCCESS);
      }
}

/*
 *    Same as POSIX rmdir().
 */
int VPIRmDir(vpi_id *id, const char *path)
{
      if((id == NULL) || (path == NULL))
        {
            errno = EFAULT;
          return(-1);
      }

      return(rmdir(path));
}

/*
 *      Returns a dynamically allocated array with pointers each
 *      pointing to dynamically allocated strings listing the directory
 *      contents of the given path. The returned array and strings must
 *      be deallocated by the calling function.
 *      
 *      If nentries is not NULL then the number of entries in the
 *      returned array of strings will be set.   
 * 
 *      Can return NULL on error.
 */
char **VPIDirEnts(
        vpi_id *id, const char *path, int *nentries_rtn
)
{
      int strc;
      char **strv;

      if(nentries_rtn != NULL)
          (*nentries_rtn) = 0;

      if((id == NULL) || (path == NULL))
          return(NULL);


      strv = GetDirEntNames(path);
      if(strv == NULL)
          return(NULL);

      for(strc = 0; strv[strc] != NULL; strc++);

      if(nentries_rtn != NULL)
            (*nentries_rtn) = strc;

      return(strv);
}

/*
 *      Same as POSIX.1 unlink().
 */
int VPIUnlink(vpi_id *id, const char *path)
{
      if((id == NULL) || (path == NULL))
        {
            errno = EFAULT;
          return(-1);
      }

      return(unlink(path));
} 


/*
 *    Creates a symbolic link of the given path that contains the
 *    given value. Works just like POSIX symlink().
 *
 *    If symlinks are not available on this system, then -1 wlll
 *    be returned.
 */
int VPISymLink(vpi_id *id, const char *value, const char *path)
{
      if((id == NULL) || (value == NULL) || (path == NULL))
      {
          errno = EFAULT;
          return(-1);
      }

      return(symlink(value, path));
}

/*
 *      Creates a hard link of the given path that contains the
 *      given value. Works just like POSIX link().
 *
 *      If hard links are not available on this system, then -1 wlll
 *      be returned.
 */
int VPILink(vpi_id *id, const char *value, const char *path)
{
        if((id == NULL) || (value == NULL) || (path == NULL))
        {
            errno = EFAULT;
            return(-1);
        }

        return(link(value, path));
}


/*
 *      Returns a pointer to the value of the given link specified
 *      by path. The returned pointer may not be deallocated or
 *      modified.
 *
 *    Can return NULL on error.
 */
char *VPIGetLink(vpi_id *id, const char *path)
{
      int bytes_read;
      static char value[PATH_MAX + NAME_MAX];


      if((id == NULL) || (path == NULL))
      {
          errno = EFAULT;
            return(NULL);
      }

      bytes_read = readlink(path, value, PATH_MAX + NAME_MAX - 1);
      if(bytes_read < 0)
          return(NULL);

      /* Sanitize number of bytes read. */
      if(bytes_read >= (PATH_MAX + NAME_MAX))
          bytes_read = PATH_MAX + NAME_MAX - 1;

      /* Need to null terminate the value. */
      value[bytes_read] = '\0';

      return(value);
}

/*
 *      Executes the given command.
 *
 *      It does not use system(), it uses exec() for security reasons.
 *      If block is VPI_TRUE then the execution will block untill the
 *      process has exited, otherwise it returns immediatly.
 *
 *      For VPIExecO() and VPIExecOA(), the optional stdout_file and
 *      stderr_file paths can be given. The VPIExecO() will overwrite
 *      any existing output file while VPIExecOA() will appened to any
 *      existing file. Output files are immediatly available for opening
 *    on return.
 *
 *      Returns a pid on success or 0 on failure.
 */
int VPIExec(
      vpi_id *id, const char *command, int block
)
{
      pid_t pid = 0;

      if((id == NULL) || (command == NULL))
          return((int)pid);

      if(block)
          pid = ExecB(command);
      else
          pid = Exec(command);

      return((int)pid);
}

int VPIExecO(
        vpi_id *id, const char *command, int block,
        const char *stdout_file, const char *stderr_file
)
{
        pid_t pid = 0;

        if((id == NULL) || (command == NULL))
            return((int)pid);

        if(block)
            pid = ExecBOE(command, stdout_file, stderr_file);
        else
            pid = ExecOE(command, stdout_file, stderr_file);

        return((int)pid);
}

int VPIExecAO(
        vpi_id *id, const char *command, int block,
        const char *stdout_file, const char *stderr_file
)
{
        pid_t pid = 0;

        if((id == NULL) || (command == NULL))
            return((int)pid);

        if(block)
            pid = ExecBAOE(command, stdout_file, stderr_file);
        else
            pid = ExecAOE(command, stdout_file, stderr_file);

        return((int)pid);
}


/*
 *    Returns VPI_TRUE if the given pid is running or VPI_FALSE if it
 *    is not running.
 */
int VPIIsRunning(vpi_id *id, int pid)
{
        struct sched_param sp;


        if((id == NULL) || (pid <= 0))
            return(VPI_FALSE);

        if(sched_getparam((pid_t)pid, &sp) == 0)
            return(VPI_TRUE);
        else
            return(VPI_FALSE);
}

/* 
 *      Same as POSIX.1 kill().
 */
int VPIKill(vpi_id *id, int pid, int s)
{
        if((id == NULL) || (pid <= 0))
      {
          errno = ESRCH;
            return(-1);
      }

      return(kill((pid_t)pid, s));
}

Generated by  Doxygen 1.6.0   Back to index