Logo Search packages:      
Sourcecode: vertex version File versions

vmacb.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>

#include <gtk/gtk.h>

#include "guiutils.h"
#include "cdialog.h"
#include "csd.h"
#include "fsd.h"
#include "fb.h"
#include "progressdialog.h"
#include "pdialog.h"
#include "fprompt.h"

#include "msglist.h"

#include "editor.h"
#include "editorviewcb.h"
#include "prefwin.h"
#include "scratchpad.h"
#include "backup.h"
#include "print.h"
#include "printwin.h"
#include "aboutdialog.h"
#include "tipofday.h"
#include "splash.h"

#include "vmacfg.h"
#include "vmacfglist.h"
#include "vma.h"
#include "vmahelp.h"
#include "config.h"
#include "messages.h"

#ifdef MEMWATCH
# include "memwatch.h"
#endif


void VMASignalCB(int s);
void VMAShutdownCB(vma_core_struct *core_ptr);
gint VMATimeoutCB(gpointer data);
gint VMABackupTimeoutCB(gpointer data);
gint VMAPluginManageTimeoutCB(gpointer data);

void VMAShowTipOfDayNextTimeToggleCB(GtkWidget *widget, gpointer data);

void VMANewEditor(vma_core_struct *core_ptr);
void VMANewEditorCB(GtkWidget *widget, gpointer data);
void VMAScratchPadMapCB(GtkWidget *widget, gpointer data);

void VMAAboutDialogMapCB(GtkWidget *widget, gpointer data);

void VMAHelpContentsCB(GtkWidget *widget, gpointer data);
void VMAHelpTutorialCB(GtkWidget *widget, gpointer data);
void VMAHelpViewingCB(GtkWidget *widget, gpointer data);
void VMAHelpKeyboardCB(GtkWidget *widget, gpointer data);
void VMAHelpV3DFormatCB(GtkWidget *widget, gpointer data);
void VMAHelpPluginsCB(GtkWidget *widget, gpointer data);
void VMATipOfDayCB(GtkWidget *widget, gpointer data);

void VMARecordFBPath(
      const char *new_path,
      char *rec_path,
      int must_be_dir
);


/*
 *    Signal callback.
 */
void VMASignalCB(int s)
{
      static int segfault_count = 0;

      switch(s)
      {
        case SIGINT:
        case SIGTERM:
        case SIGKILL:
          need_close_all_windows = TRUE;
          break;

        case SIGSEGV:
          segfault_count++;
          fprintf(stderr,
 "%s triggered a segmentation fault (%i times)\n",
            PROG_NAME,
            segfault_count
          );
          if(segfault_count >= 3)
          {
            fprintf(stderr,
 "%s attempting immediate process exit().\n",
                PROG_NAME
            );
            gtk_exit(1);
          }
          else
          {
            need_close_all_windows = TRUE;
          }
          break;
      }
}

/*
 *    Deallocates all resources on the core structure but not the
 *    core structure itself.
 */
void VMAShutdownCB(vma_core_struct *core_ptr)
{
      gint i;
      guint *toid;
/*    guint *idleid; */
      ma_editor_struct *editor;


      if(core_ptr == NULL)
          return;


      /* Stop all print jobs. */
      for(i = 0; i < core_ptr->total_print_jobs; i++)
          PrintJobDelete(core_ptr->print_job[i]);
      g_free(core_ptr->print_job);
      core_ptr->print_job = NULL;
      core_ptr->total_print_jobs = 0;


      /* Remove GTK+ idle and timeout callbacks. */
#define DO_REMOVE_TOID        \
{ \
 if((*toid) != (guint)(-1)) \
 { \
  gtk_timeout_remove(*toid); \
  (*toid) = (guint)(-1); \
 } \
}
#define DO_REMOVE_IDLEID      \
{ \
 if((*idleid) != (guint)(-1)) \
 { \
  gtk_idle_remove(*idleid); \
  (*idleid) = (guint)(-1); \
 } \
}

      toid = &core_ptr->backup_toid;
      DO_REMOVE_TOID

      toid = &core_ptr->plugin_manage_toid;
      DO_REMOVE_TOID
/*
        idleid = &core_ptr->plugin_manage_idleid;
        DO_REMOVE_IDLEID
 */
#undef DO_REMOVE_TOID
#undef DO_REMOVE_IDLEID

      /* Unload all plug-ins, calling their shutdown functions as
       * needed.
       */
      for(i = 0; i < core_ptr->total_plugins; i++)
      {
          VPIUnload(core_ptr->plugin[i]);
          core_ptr->plugin[i] = NULL;
      }
      g_free(core_ptr->plugin);
      core_ptr->plugin = NULL;
      core_ptr->total_plugins = 0;


      /* No more reenterant resources exist from this point on. */

      /* Delete scratch pad. */
      if(core_ptr->scratch_pad != NULL)
      {
          ScratchPadDelete(core_ptr->scratch_pad);
          core_ptr->scratch_pad = NULL;
      }

      /* Delete all editor structures. */
      for(i = 0; i < core_ptr->total_editors; i++)
      {
          editor = core_ptr->editor[i];
          if(editor == NULL)
            continue;

          EditorDelete(editor);
      }
      g_free(core_ptr->editor);
      core_ptr->editor = NULL;
      core_ptr->total_editors = 0;

      /* Delete preferences window. */
      if(core_ptr->pref_win != NULL)
      {
          PrefDelete(core_ptr->pref_win);
          core_ptr->pref_win = NULL;
      }

      /* Delete print window. */
      if(core_ptr->print_win != NULL)
      {
          PrintWinDelete(core_ptr->print_win);
          core_ptr->print_win = NULL;
      }

      /* Delete about dialog. */
      if(core_ptr->about_dialog != NULL)
      {
          AboutDialogDelete(core_ptr->about_dialog);
          core_ptr->about_dialog = NULL;
      }

      /* Delete tip of day window. */
      if(core_ptr->todwin != NULL)
      {
          TODWinDelete(core_ptr->todwin);
          core_ptr->todwin = NULL;
      }

      /* Delete splash window (this should already be deleted at
       * startup, but we delete again just in case).
       */
      if(core_ptr->splash_win != NULL)
      {
          SplashDelete(core_ptr->splash_win);
          core_ptr->splash_win = NULL;
      }
}


/*
 *    Standard timeout callback.
 *
 *    Checks if need_close_all_windows is set to TRUE and if so, begins
 *    checking of all supported GUI queries are inactive and if no
 *    editors or releated windows are processing. If all checks pass 
 *    then gtk_main_quit() will be called to begin the shut down 
 *    process.
 *
 *    If need_close_all_windows is FALSE then the following will be
 *    checked.
 *
 *    If all windows are unmapped (closed) then the shutdown process
 *    will be performed.
 *
 *    All print jobs will be managed.
 */
gint VMATimeoutCB(gpointer data)
{
      static gbool reenterant = FALSE;
      gbool still_processing, has_changes, all_unmapped;
      gint i;
      guint *toid;
/*    guint *idleid; */
      GtkWidget *transient_for_w = NULL;
      ma_editor_struct *editor;
      vma_pref_struct *pref_win;
      print_win_struct *print_win;
        print_job_struct *pj;
      vma_core_struct *core_ptr = (vma_core_struct *)data;
      if(core_ptr == NULL)
          return(FALSE);

      if(reenterant)
          return(TRUE);
      else
          reenterant = TRUE;


/* Macro to remove the timeout id pointed to by toid. */
#define DO_REMOVE_TOID        \
{ \
 if((*toid) != (guint)(-1)) \
 { \
  gtk_timeout_remove(*toid); \
  (*toid) = (guint)(-1); \
 } \
}
#define DO_REMOVE_IDLEID      \
{ \
 if((*idleid) != (guint)(-1)) \
 { \
  gtk_idle_remove(*idleid); \
  (*idleid) = (guint)(-1); \
 } \
}

/* Macro to remove all timeout callbacks and call gtk_main_quit(). */
#define DO_GTK_MAIN_QUIT      \
{ \
 /* Remove GTK+ timeout callbacks. */ \
 toid = &vma_manage_toid; \
 DO_REMOVE_TOID \
 \
 toid = &core_ptr->backup_toid; \
 DO_REMOVE_TOID \
 \
 toid = &core_ptr->plugin_manage_toid; \
 DO_REMOVE_TOID \
/* \
 idleid = &core_ptr->plugin_manage_idleid; \
 DO_REMOVE_IDLEID \
 */ \
 \
 /* Flush GTK+ events. */ \
 while(gtk_events_pending() > 0) \
  gtk_main_iteration(); \
 \
 /* Break out of main GTK+ loop. */ \
 gtk_main_quit(); \
}

/* Macro to reschedual timeout callback to this function and return FALSE. */
#define DO_RETURN_RESCHEDUAL  \
{ \
 /* Reschedual call to this function. */ \
 vma_manage_toid = gtk_timeout_add( \
  1000,     /* 1 second interval. */ \
  (GtkFunction)VMATimeoutCB, \
  core_ptr \
 ); \
\
 reenterant = FALSE; \
 /* Its okay to return FALSE because we just reschedualed another call to \
  * this function above. \
  */ \
 return(FALSE); \
}

/* Macro to return FALSE, thus removing the timeout callback to this
 * function.
 */
#define DO_RETURN_NO_RESCHEDUAL     \
{ \
 vma_manage_toid = (guint)-1; \
 reenterant = FALSE; \
 return(FALSE); \
}

/* Macro to return TRUE, keeping the current timeout callback to this
 * function.
 */
#define DO_RETURN_CURRENT_SCHEDUAL  \
{ \
 reenterant = FALSE; \
 return(TRUE); \
}


        /* Need to close all windows? */
      if(need_close_all_windows)
      {
            /* Check if any dialogs are in query, break query as needed
             * and return. Let next call to this function handle rest of
             * closing all windows.
             */   
            if(CDialogIsQuery())
            {
                CDialogBreakQuery();
            DO_RETURN_CURRENT_SCHEDUAL
            }
            if(FileBrowserIsQuery())
            {
                FileBrowserBreakQuery();
            DO_RETURN_CURRENT_SCHEDUAL
            }
            if(ProgressDialogIsQuery())
            {
                ProgressDialogBreakQuery(FALSE);
            DO_RETURN_CURRENT_SCHEDUAL
            }
            if(FSDIsQuery())
            {
                FSDBreakQuery();
            DO_RETURN_CURRENT_SCHEDUAL
            }
            if(CSDIsQuery())
            {
                CSDBreakQuery();
            DO_RETURN_CURRENT_SCHEDUAL
            }
            if(PDialogIsQuery())
            {
                PDialogBreakQuery();
            DO_RETURN_CURRENT_SCHEDUAL
            }
            if(FPromptIsQuery())
            {
                FPromptBreakQuery();
            DO_RETURN_CURRENT_SCHEDUAL
            }
            /* All dialogs not in query. */


            /* Reset close all windows marker, which initially
           * triggered this case.
           */
            need_close_all_windows = FALSE;

          /* Reset still processing marker, which indicates that there
           * are still windows that are processing and cannot be closed.
           */
            still_processing = FALSE;

          /* Reset has changes marker, which indicates there is atleast
           * one window with unsaved modified data.
           */
          has_changes = FALSE;

          /* Begin checking through all windows to see if any are
           * still processing or have changes.
           */

          /* Editor windows. */
            for(i = 0; i < core_ptr->total_editors; i++)
            {
                editor = core_ptr->editor[i];
                if(editor == NULL)
                    continue;

                if(editor->initialized)
            {
                if(editor->processing)
                  still_processing = TRUE;

                if(editor->has_changes)
                {
                  /* Use this editor's toplevel window as the
                   * transient_for_w for the cdialog used in
                   * confirmation later.
                   */
                  transient_for_w = editor->toplevel;
                  has_changes = TRUE;
                }

                }
            }

          /* Preferences window. */
          pref_win = core_ptr->pref_win;
          if((pref_win != NULL) ? pref_win->initialized : 0)
          {
            if(pref_win->processing)
                still_processing = TRUE;
          }

          /* Print window. */
            print_win = core_ptr->print_win;
            if((print_win != NULL) ? print_win->initialized : 0)
            {   
/*
                if(print_win->processing)
                    still_processing = TRUE;
 */
            }  


          /* Begin checking results, to see if any windows are still
           * processing or have unsaved changed data.
           */

            /* Any still processing? */
            if(still_processing)
            {
                /* One or more window is still processing, cannot close
             * now so we need to return. The next call to this
             * function won't close all windows since we set the
             * global marker for that to FALSE.
             */
            DO_RETURN_CURRENT_SCHEDUAL
            }

          /* Any have changed data? */
          if(has_changes)
          {
            /* Found some changed data that was not saved. */
            int status;

            CDialogSetTransientFor(transient_for_w);
            status = CDialogGetResponse(
"Changes detected!",
"There are changes to one or more of the editors\n\
that have not been saved. Are you sure you want to\n\
exit and discard those changes?",
"The program is about to exit and some changed data have\n\
not been saved. If you say no then the program will not\n\
exit and you will have a chance to save those changes, or\n\
you can say yes to exit and discard those changes.",
                CDIALOG_ICON_WARNING,
                CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO |
                CDIALOG_BTNFLAG_HELP,
                CDIALOG_BTNFLAG_NO
                );
            CDialogSetTransientFor(NULL);
            switch(status)
            {
              case CDIALOG_RESPONSE_YES:
                  case CDIALOG_RESPONSE_YES_TO_ALL:
                  case CDIALOG_RESPONSE_OK:
                /* Break out of GTK main loop and remove timeout
                 * callback to this function.
                 */
                DO_GTK_MAIN_QUIT

                /* Return and do not keep schedual callback to this
                 * function.
                 */
                DO_RETURN_NO_RESCHEDUAL
                break;
            }
          }
          else
          {
            /* No changed data found. */

            /* Break out of GTK main loop and remove timeout callback
             * to this function.
             */
            DO_GTK_MAIN_QUIT

                /* Return and do not keep schedual callback to this function. */
            DO_RETURN_NO_RESCHEDUAL
          }
      }

      /* Begin checking if any window is still mapped, if they are
       * then all_unmapped will be set to FALSE.
       */
      all_unmapped = TRUE;

      /* Editor windows. */
      for(i = 0; i < core_ptr->total_editors; i++)
        {
            editor = core_ptr->editor[i];
            if(editor == NULL)
                continue;

            if(editor->initialized && editor->map_state)
          {
            all_unmapped = FALSE;
            break;
          }
        }

      /* Preferanecs window. */
      pref_win = core_ptr->pref_win;
      if((pref_win != NULL) ? pref_win->initialized : 0)
      {
          if(pref_win->map_state)
            all_unmapped = FALSE;  
      }

      /* Were all windows unmapped? */
      if(all_unmapped)
      {
          /* All windows are unmapped, this implies program needs to
           * exit.
           */

          /* Break out of GTK main loop and remove timeout callback
           * to this function.
           */
          DO_GTK_MAIN_QUIT

          /* Return and do not keep schedual callback to this function. */
          DO_RETURN_NO_RESCHEDUAL
      }

      /* Manage print jobs. */
      for(i = 0; i < core_ptr->total_print_jobs; i++)
      {
          pj = core_ptr->print_job[i];
          if(pj == NULL)
            continue;

          /* Manage this print job. */
          if(!PrintJobManage(pj))
          {
            /* Print job manage returned false, implying it's done
             * and we need to delete it.
             */
            PrintJobDelete(pj);
            core_ptr->print_job[i] = pj = NULL;
            continue;
          }
      }


      DO_RETURN_RESCHEDUAL

#undef DO_RETURN_RESCHEDUAL
#undef DO_RETURN_NO_RESCHEDUAL
#undef DO_RETURN_CURRENT_SCHEDUAL

#undef DO_GTK_MAIN_QUIT
#undef DO_REMOVE_TOID
#undef DO_REMOVE_IDLEID
}

/*
 *    Backup timeout callback.
 *
 *    Any editors that happen to be processing will be skipped.
 */
gint VMABackupTimeoutCB(gpointer data)
{
        static gbool reenterant = FALSE;
      gint i;
      int min, max, new_index_highest;
      ma_editor_struct *editor;
        vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
            return(FALSE);

        if(reenterant)
            return(TRUE);
        else
            reenterant = TRUE;

      /* Itterate through each editor. */
        for(i = 0; i < core_ptr->total_editors; i++)
        {
            editor = core_ptr->editor[i];
            if(editor == NULL)
                continue;

          /* Skip this editor if it is not initialized, is currently
           * processing, or does not have data with an assoicated 
           * filename.
           */
          if(!editor->initialized || editor->processing ||
               (editor->loaded_filename == NULL)
          )
            continue;

          /* Mark as processing. */
          EditorSetBusy(editor);
          editor->processing = TRUE;

          VMAStatusBarMessage(editor->sb, "Automatic backup in progress...");
          VMAStatusBarProgress(editor->sb, 0.0);

          /* Make backup. */
          min = 1;
          max = VMACFGItemListGetValueI(
            option, VMA_CFG_PARM_BACKUP_MAX
          );
          new_index_highest = VMACFGItemListGetValueI(
            option, VMA_CFG_PARM_BACKUP_NEW_INDEX_HIGHEST
          );
          if(VMABackupFile(
            editor->loaded_filename,
            min, max,
            (new_index_highest) ?
                VMA_BACKUP_ORDER_HL : VMA_BACKUP_ORDER_LH,
            1           /* Can remove overflow. */
          ) == VMA_BACKUP_SUCCESS)
          {
            VMAStatusBarMessage(editor->sb, "Automatic backup done");
          }
          else
          {
                VMAStatusBarMessage(editor->sb, "Automatic backup failed!");
          }

          VMAStatusBarProgress(editor->sb, 0.0);

            /* Mark as done processing. */
            EditorSetReady(editor);
            editor->processing = FALSE;
 
          /* Need to update menus on editor. */
          EditorUpdateMenus(editor);
          EditorUpdateAllViewMenus(editor);
        }


        /* Schedual next backup timeout callback for this function, since
         * this function always returns FALSE past this point.
         */
        i = VMACFGItemListGetValueI(option, VMA_CFG_PARM_BACKUP_PERIODIC_INT);
        if(i > 0)
        {
            core_ptr->backup_toid = gtk_timeout_add(
                i * 60 * 1000,  /* Convert to milliseconds. */
                (GtkFunction)VMABackupTimeoutCB,
                (gpointer)core_ptr
            );
        }
        else
        {
            core_ptr->backup_toid = (guint)-1;
        }

      reenterant = FALSE;
        /* Return FALSE, since a NEW timeout callback has just been
         * schedualed for this function by this function so we can return
         * FALSE indicating not to call this function again for the
         * previous (old) timeout.
         */
      return(FALSE);
}

/*
 *    Plug-ins manage timeout callback.
 */
gint VMAPluginManageTimeoutCB(gpointer data)
{
        static gbool reenterant = FALSE;
      gbool init_called = FALSE;
      gint i;
      ma_editor_struct *editor;
      vma_plugin_struct *plugin_ptr;
      VPI_PROTO_RETURN_MANAGE (*manage_func)(VPI_PROTO_INPUT_MANAGE);
        vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
            return(FALSE);

        if(reenterant)
            return(TRUE);
        else
            reenterant = TRUE;

      /* Itterate through each plug-in. */
      for(i = 0; i < core_ptr->total_plugins; i++)
      {
          plugin_ptr = core_ptr->plugin[i];
          if((plugin_ptr == NULL) ? 1 : (plugin_ptr->handle == NULL))
            continue;

          /* Skip plug-in if it is busy processing. */
          if(plugin_ptr->processing)
            continue;

          /* Need to call initialization routine for plugin? */
          if(plugin_ptr->need_call_init)
          {
            VPI_PROTO_RETURN_INIT (*init_func)(VPI_PROTO_INPUT_INIT) =
                VPIGetFunction(plugin_ptr, VPI_PROTO_NAME_INIT);


            /* Mark that we no longer need to call plug-in's
             * initialize function.
             */
            plugin_ptr->need_call_init = 0;

            /* Since we're calling the initialize function, we need
             * to mark that we need to call the shutdown function.
             */
            plugin_ptr->need_call_shutdown = 1;

            /* Got pointer to plug-in's initialize function? */
            if(init_func != NULL)
            {
                gint n, status;
                vpi_init_struct v;


                /* Set up initialize value structure. */
                v.flags = (VPI_FLAG_INIT_START_TYPE |
                  VPI_FLAG_INIT_FILENAME |
                  VPI_FLAG_INIT_ARGC | VPI_FLAG_INIT_ARGV
                );
                v.start_type = VPI_INIT_START_TYPE_STANDARD;
                v.filename = ((plugin_ptr->filename == NULL) ?
                  NULL : g_strdup(plugin_ptr->filename)
                );
                v.argc = 0;
                v.argv = NULL;

                /* Call plug-in's initialize function. */
                plugin_ptr->processing = 1;
                status = init_func((vpi_id *)plugin_ptr, &v);
                init_called = TRUE;
                    plugin_ptr->processing = 0;


                /* Deallocate initialize value structure members. */
                g_free(v.filename);
                for(n = 0; n < v.argc; n++)
                  g_free(v.argv[n]);
                g_free(v.argv);

                /* Plug-in's initialization function return false? */
                    if(!status)
                    {
                        /* Initialization failed. */
                        VPIDisable(plugin_ptr);
                        continue;
                    }
            }
          } /* Need to call initialization routine for plugin? */

          /* Call management function. */
          manage_func = plugin_ptr->manage;
          if(manage_func != NULL)
          {
            gint status;
            vpi_manage_struct v;


                /* Set up manage value structure. */
            v.flags = VPI_FLAG_MANAGE_CLIENT_DATA;
            v.client_data = plugin_ptr->client_data;

            /* Call plug-in's manage function. */
                plugin_ptr->processing = 1;
                status = manage_func((vpi_id *)plugin_ptr, &v);
                plugin_ptr->processing = 0;

            /* Deallocate manage value structure members. */
/* None. */

            /* Plug-in's manage function returned false? */
                if(!status)
                {
                    /* Manage failed. */
                    VPIDisable(plugin_ptr);
                    continue;
                }
          }

      }


      /* If atleast one plug-in initialize function was called, then
       * we need to update some resources.
       */
      if(init_called)
      {
          /* Editor render menu items. */
          for(i = 0; i < core_ptr->total_editors; i++)
          {
            editor = core_ptr->editor[i];
            if(editor == NULL)
                continue;

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

            EditorRenderMenuRegenerate(editor);
          }
/* Put other resources that depend on when a plug-in's 
 * initialize function was called.
 */

      }


        /* Schedual next plugin timeout callback for this function, since
         * this function always returns FALSE past this point.
         */
        core_ptr->plugin_manage_toid = gtk_timeout_add(
            50,
            (GtkFunction)VMAPluginManageTimeoutCB,
            (gpointer)core_ptr
        );

        reenterant = FALSE;
        /* Return FALSE, since a NEW timeout callback has just been
         * schedualed for this function by this function so we can return
         * FALSE indicating not to call this function again for the
         * previous (old) timeout.
         */
        return(FALSE);
}


/*
 *    Show tip of day next time toggle callback.
 */
void VMAShowTipOfDayNextTimeToggleCB(GtkWidget *widget, gpointer data)
{
      u_int8_t ui8;
      GtkToggleButton *tb = (GtkToggleButton *)widget;
      vma_core_struct *core_ptr = (vma_core_struct *)data;
      if((tb == NULL) || (core_ptr == NULL))
          return;

      /* Check if toggle button is active. */
      ui8 = ((tb->active) ? 1 : 0);

      /* Record value in configuration. */
      VMACFGItemListMatchSetValue(
          option, VMA_CFG_PARM_SHOW_TIPOFDAY,
          &ui8, TRUE
      );
}


/*
 *    Creates a new editor on the core structure.
 *    If one is already initailized but unmapped, then
 *    that one will be mapped and no new editor will be created.
 */
void VMANewEditor(vma_core_struct *core_ptr)
{
      gint i;
      ma_editor_struct *editor, *new_editor = NULL;


      if(core_ptr == NULL)
          return;

        /* Check if one is already initailized and unmapped. */
      for(i = 0; i < core_ptr->total_editors; i++)
      {
          editor = core_ptr->editor[i];
          if(editor == NULL)
            continue;

          if(editor->initialized && !editor->map_state)
            break;
      }
      if(i < core_ptr->total_editors)
      {
          /* Found one initialized but not mapped. */
          new_editor = core_ptr->editor[i];
      }
      else
      {
          /* Need to create a new one. */

          /* Check if a pointer in the array is NULL. */
          for(i = 0; i < core_ptr->total_editors; i++)
            {
            if(core_ptr->editor[i] == NULL)
                break;
          }
          if(i < core_ptr->total_editors)
          {
            /* Found a NULL pointer i, use it. */
                core_ptr->editor[i] = new_editor = EditorCreate(core_ptr);
          }
          else
          {
            /* Need to allocate more pointers. */
            i = core_ptr->total_editors;
            core_ptr->total_editors++;
                core_ptr->editor = (ma_editor_struct **)realloc(
                    core_ptr->editor,  
                    core_ptr->total_editors * sizeof(ma_editor_struct *)
                );
                if(core_ptr->editor == NULL)
                {
                    core_ptr->total_editors = 0;
                }
                else
                {
                    core_ptr->editor[i] = new_editor = EditorCreate(core_ptr);
            }
            }
        }
 
      /* Got new editor? */
      if(new_editor != NULL)
      {
          EditorReset(new_editor, FALSE);
          EditorUpdateMenus(new_editor);
          EditorMap(new_editor);
      }

      return;
}

/*
 *    New editor callback.
 */
void VMANewEditorCB(GtkWidget *widget, gpointer data)
{
      vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
            return;

      VMANewEditor(core_ptr);

      return;
}

/*
 *      Map scratch pad.   
 */
void VMAScratchPadMapCB(GtkWidget *widget, gpointer data)
{
        vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
            return;

      if(core_ptr->scratch_pad != NULL)
      {
          /* Update scratch pad's target editors list. */
          ScratchPadUpdateTargetEditors(core_ptr->scratch_pad);

          /* Map scratch pad. */
          ScratchPadMap(core_ptr->scratch_pad);
      }

      return;
}


/*
 *    Maps the about dialog.
 */
void VMAAboutDialogMapCB(GtkWidget *widget, gpointer data)
{
      about_dialog_struct *ad;
      vma_core_struct *core_ptr = (vma_core_struct *)data;
      if(core_ptr == NULL)
          return;

      /* Get pointer to about dialot. */
      ad = core_ptr->about_dialog;

      /* About dialog not initialized yet? */
      if(ad == NULL)
      {
          /* Initialize about dialot now. */
          core_ptr->about_dialog = ad = AboutDialogNew(core_ptr);
      }

      /* About dialog not available and/or failed to initialize? */
      if(ad == NULL)
          return;

      /* Map the about dialog. */
      AboutDialogMap(ad);

      return;
}


/*
 *    Help contents callback.
 */
void VMAHelpContentsCB(GtkWidget *widget, gpointer data)
{
      vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
          return;

      VMAHelpFile(
          core_ptr,
          VMA_HELP_FILE_CONTENTS,
          TRUE
      );

      return;
}

/*
 *      Help tutorial callback.
 */
void VMAHelpTutorialCB(GtkWidget *widget, gpointer data)
{
        vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
            return;

        VMAHelpFile(
            core_ptr,
            VMA_HELP_FILE_TUTORIALS,
            TRUE
        );

      return;
}

/*
 *    Help controlling the views callback.
 */
void VMAHelpViewingCB(GtkWidget *widget, gpointer data)
{
        vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
            return;

        VMAHelpFile(
            core_ptr,
            VMA_HELP_FILE_VIEWING,
            TRUE
        );

        return;
}

/*
 *    Help keyboard keys callback.
 */
void VMAHelpKeyboardCB(GtkWidget *widget, gpointer data)
{
        vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
            return;

        VMAHelpFile( 
            core_ptr,
            VMA_HELP_FILE_KEYBOARD,
            TRUE
        );

        return;
}

/*
 *    Help V3D format specification callback.
 */
void VMAHelpV3DFormatCB(GtkWidget *widget, gpointer data)
{
        vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
            return;

        VMAHelpFile(
            core_ptr,
            VMA_HELP_FILE_V3D_FORMAT,
            TRUE
        );

        return;
}

/*
 *      Help plugins callback.
 */
void VMAHelpPluginsCB(GtkWidget *widget, gpointer data)
{
        vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
            return;

        VMAHelpFile(
            core_ptr,
            VMA_HELP_FILE_PLUGINS,
            TRUE
        );

        return;
}


/*
 *    Show tip of day callback.
 */
void VMATipOfDayCB(GtkWidget *widget, gpointer data)
{
      static const char *tod_msglist[] = VMA_MSGLIST_TOD_MESSAGE_LIST;
      gbool show_tip_next_time;
      vma_core_struct *core_ptr = (vma_core_struct *)data;
        if(core_ptr == NULL)
            return;

      show_tip_next_time = (VMACFGItemListGetValueI(
          option, VMA_CFG_PARM_SHOW_TIPOFDAY
      ) ? TRUE : FALSE);

      if(core_ptr->todwin == NULL)
          core_ptr->todwin = TODWinNew(
            (gpointer)core_ptr,
            tod_msglist,
            show_tip_next_time,
            (gpointer)core_ptr,
            VMAShowTipOfDayNextTimeToggleCB
          );
      if(core_ptr->todwin != NULL)
          TODWinMapTip(
            core_ptr->todwin,
            time(NULL),
            -1
          );

      return;
}


/*
 *    File browser path record. This function should be called
 *    each time the file browser returns a path so that it is
 *    recorded for the next use on to rec_path.
 *
 *    rec_path should be one of the global fb record paths.
 *    new_path must be an absolute path.
 *
 *    If must_be_dir is true then the path will be shortened
 *    to just the parent dir if the path points something that is
 *    not a dir.
 *
 *    The rec_path buffer must be allocated to atleast the size
 *    of PATH_MAX bytes.
 */
void VMARecordFBPath(
      const char *new_path,
      char *rec_path,
      int must_be_dir
)
{
      struct stat stat_buf;
      char tmp_path[PATH_MAX + NAME_MAX];


      if((new_path == NULL) || (rec_path == NULL))
          return;

      /* New path must be absolute. */
      if((*new_path) != DIR_DELIMINATOR)
          return;

      /* Copy new path to tmp path. */
      strncpy(tmp_path, new_path, PATH_MAX + NAME_MAX);
      tmp_path[PATH_MAX + NAME_MAX - 1] = '\0';

      /* Check if new path is a dir? */
      if(must_be_dir)
      {
          if(!stat(tmp_path, &stat_buf))
          {
            if(!S_ISDIR(stat_buf.st_mode))
            {
                /* Not a dir and must be a dir, so get its parent. */
                int len = strlen(tmp_path);
                char *strptr;

                strptr = tmp_path + len - 1;
                while(strptr > tmp_path)
                {
                  if((*strptr) == DIR_DELIMINATOR)
                  {
                      (*strptr) = '\0';
                      break;
                  }

                  strptr--;
                }
            }
          }
      }

      /* Record path. */
      strncpy(
          rec_path,
          tmp_path,
          PATH_MAX      /* Just PATH_MAX bytes. */
      );
      rec_path[PATH_MAX  - 1] = '\0';

      return;
}

Generated by  Doxygen 1.6.0   Back to index