home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / script-fu / script-fu-scripts.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-08  |  64.8 KB  |  2,259 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <glib.h>        /* Include early for obscure Win32
  22.                    build reasons */
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <sys/types.h>
  27. #if HAVE_DIRENT_H
  28. #include <dirent.h>
  29. #endif
  30. #include <sys/stat.h>
  31. #include <ctype.h>        /* For toupper() */
  32.  
  33. #include <gtk/gtk.h>
  34.  
  35. #include <libgimp/gimp.h>
  36. #include <libgimp/gimpui.h>
  37.  
  38. #include "siod.h"
  39. #include "script-fu-scripts.h"
  40.  
  41. #include "script-fu-intl.h"
  42.  
  43. #ifdef G_OS_WIN32
  44. #define STRICT
  45. #include <windows.h>
  46.  
  47. #include <io.h>
  48.  
  49. #ifndef W_OK
  50. #define W_OK 2
  51. #endif
  52. #ifndef S_ISDIR
  53. #define S_ISDIR(m) ((m) & _S_IFDIR)
  54. #endif
  55. #ifndef S_ISREG
  56. #define S_ISREG(m) ((m) & _S_IFREG)
  57. #endif
  58.  
  59. #endif /* G_OS_WIN32 */
  60.  
  61. #define ESCAPE(string) gimp_strescape (string, NULL)
  62.  
  63. #define TEXT_WIDTH           100
  64. #define TEXT_HEIGHT           25
  65. #define COLOR_SAMPLE_WIDTH   100
  66. #define COLOR_SAMPLE_HEIGHT   15
  67. #define SLIDER_WIDTH         100
  68. #define SPINNER_WIDTH         75
  69. #define FONT_PREVIEW_WIDTH   100
  70.  
  71. #define DEFAULT_FONT_SIZE    240
  72.  
  73. #define MAX_STRING_LENGTH   4096
  74.  
  75.  
  76. typedef struct
  77. {
  78.   GtkAdjustment    *adj;
  79.   gfloat            value;
  80.   gfloat            lower;
  81.   gfloat            upper;
  82.   gfloat            step;
  83.   gfloat            page;
  84.   gint              digits;
  85.   SFAdjustmentType  type;
  86. } SFAdjustment;
  87.  
  88. typedef struct
  89. {
  90.   GtkWidget *preview;
  91.   GtkWidget *dialog;
  92.   gchar     *fontname;
  93. } SFFont;
  94.  
  95. typedef struct
  96. {
  97.   GtkWidget *fileselection;
  98.   gchar     *filename;
  99. } SFFilename;
  100.  
  101. typedef struct 
  102. {
  103.   gchar   *name;
  104.   gdouble  opacity;
  105.   gint     spacing;
  106.   gint     paint_mode;
  107. } SFBrush;
  108.  
  109. typedef struct 
  110. {
  111.   GSList  *list;
  112.   guint    history;
  113. } SFOption;
  114.  
  115. typedef union
  116. {
  117.   gint32         sfa_image;
  118.   gint32         sfa_drawable;
  119.   gint32         sfa_layer;
  120.   gint32         sfa_channel;
  121.   guchar         sfa_color[3];
  122.   gint32         sfa_toggle;
  123.   gchar         *sfa_value;
  124.   SFAdjustment   sfa_adjustment;
  125.   SFFont         sfa_font;
  126.   SFFilename     sfa_file;
  127.   gchar         *sfa_pattern;
  128.   gchar         *sfa_gradient;
  129.   SFBrush        sfa_brush;
  130.   SFOption       sfa_option;
  131. } SFArgValue;
  132.  
  133. typedef struct
  134. {
  135.   gchar         *script_name;
  136.   gchar         *pdb_name;
  137.   gchar         *description;
  138.   gchar         *help;
  139.   gchar         *author;
  140.   gchar         *copyright;
  141.   gchar         *date;
  142.   gchar         *img_types;
  143.   gint           num_args;
  144.   SFArgType     *arg_types;
  145.   gchar        **arg_labels;
  146.   SFArgValue    *arg_defaults;
  147.   SFArgValue    *arg_values;
  148.   gint32         image_based;
  149.   GimpParamDef  *args;     /*  used only temporary until installed  */
  150. } SFScript;
  151.  
  152. typedef struct
  153. {
  154.   GtkWidget    **args_widgets;
  155.   GtkWidget     *status;
  156.   GtkWidget     *about_dialog;
  157.   gchar         *window_title;
  158.   gchar         *last_command;
  159.   gint           command_count;
  160.   gint           consec_command_count;
  161. } SFInterface;
  162.  
  163.  
  164. /* External functions
  165.  */
  166. extern long  nlength (LISP obj);
  167.  
  168. /*
  169.  *  Local Functions
  170.  */
  171.  
  172. static gint       script_fu_install_script   (gpointer    foo,
  173.                           SFScript   *script,
  174.                           gpointer    bar);
  175. static gint       script_fu_remove_script    (gpointer    foo,
  176.                           SFScript   *script,
  177.                           gpointer    bar);
  178. static void       script_fu_script_proc      (gchar      *name,
  179.                           gint        nparams,
  180.                           GimpParam  *params,
  181.                           gint       *nreturn_vals,
  182.                           GimpParam **return_vals);
  183.  
  184. static SFScript * script_fu_find_script      (gchar      *script_name);
  185. static void       script_fu_free_script      (SFScript   *script);
  186. static void       script_fu_interface        (SFScript   *script);
  187. static void       script_fu_interface_quit   (SFScript   *script);
  188. static void       script_fu_error_msg        (gchar      *command);
  189.  
  190. static void       script_fu_ok_callback             (GtkWidget *widget,
  191.                              gpointer   data);
  192. static void       script_fu_about_callback          (GtkWidget *widget,
  193.                              gpointer   data);
  194. static void       script_fu_reset_callback          (GtkWidget *widget,
  195.                              gpointer   data);
  196. static void       script_fu_menu_callback           (gint32     id,
  197.                              gpointer   data);
  198.  
  199. static void       script_fu_file_selection_callback (GtkWidget *widget,
  200.                              gpointer   data);
  201.  
  202. static void       script_fu_font_preview_callback   (GtkWidget *widget,
  203.                              gpointer   data);
  204.  
  205. static void       script_fu_font_dialog_ok          (GtkWidget *widget,
  206.                              gpointer   data);
  207. static void       script_fu_font_dialog_cancel      (GtkWidget *widget,
  208.                              gpointer   data);
  209. static gint       script_fu_font_dialog_delete      (GtkWidget *widget,
  210.                              GdkEvent  *event,
  211.                              gpointer   data);
  212.  
  213. static void       script_fu_font_preview            (GtkWidget *preview,
  214.                              gchar     *fontname);
  215. static void       script_fu_pattern_preview         (gchar     *name,
  216.                              gint       width,
  217.                              gint       height,
  218.                              gint       bytes,
  219.                              gchar     *mask_data,
  220.                              gint       closing,
  221.                              gpointer   data);
  222. static void       script_fu_gradient_preview        (gchar     *name,
  223.                              gint       width,
  224.                              gdouble   *mask_data,
  225.                              gint       closing,
  226.                              gpointer   data);
  227. static void       script_fu_brush_preview           (gchar     *name,
  228.                              gdouble    opacity,
  229.                              gint       spacing,
  230.                              gint       paint_mode,
  231.                              gint       width,
  232.                              gint       height,
  233.                              gchar     *mask_data,
  234.                              gint       closing,
  235.                              gpointer   data);
  236.  
  237.  
  238. /*
  239.  *  Local variables
  240.  */
  241.  
  242. static struct stat  filestat;
  243. static GTree       *script_list = NULL;
  244. static SFInterface *sf_interface = NULL;  /*  there can only be at most one
  245.                           interactive interface  */
  246.                           
  247. extern gchar        siod_err_msg[];
  248.  
  249. /*
  250.  *  Function definitions
  251.  */
  252.  
  253. void
  254. script_fu_find_scripts (void)
  255. {
  256.   gchar *path_str;
  257.   gchar *home;
  258.   gchar *local_path;
  259.   gchar *path;
  260.   gchar *filename;
  261.   gchar *token;
  262.   gchar *next_token;
  263.   gchar *command;
  264.   gint   my_err;
  265.   DIR   *dir;
  266.   struct dirent *dir_ent;
  267.  
  268.   /*  Make sure to clear any existing scripts  */
  269.   if (script_list != NULL)
  270.     {
  271.       g_tree_traverse (script_list, 
  272.                (GTraverseFunc)script_fu_remove_script, 
  273.                G_IN_ORDER, 
  274.                NULL);
  275.       g_tree_destroy (script_list);
  276.     }
  277.  
  278. #ifdef ENABLE_NLS
  279.   script_list = g_tree_new ((GCompareFunc)strcoll);
  280. #else
  281.   script_list = g_tree_new ((GCompareFunc)strcmp);
  282. #endif
  283.  
  284.   path_str = gimp_gimprc_query ("script-fu-path");
  285.  
  286.   if (path_str == NULL)
  287.     return;
  288.  
  289.   /* Set local path to contain temp_path, where (supposedly)
  290.    * there may be working files.
  291.    */
  292.   home = g_get_home_dir ();
  293.   local_path = g_strdup (path_str);
  294.   
  295.   /* Search through all directories in the local path */
  296.   
  297.   next_token = local_path;
  298.   
  299.   token = strtok (next_token, G_SEARCHPATH_SEPARATOR_S);
  300.  
  301.   while (token)
  302.     {
  303.       if (*token == '~')
  304.     {
  305.       path = g_malloc (strlen (home) + strlen (token) + 2);
  306.       sprintf (path, "%s%s", home, token + 1);
  307.     }
  308.       else 
  309.     {
  310.       path = g_malloc (strlen (token) + 2);
  311.       strcpy (path, token);
  312.     }
  313.           
  314.       /* Check if directory exists and if it has any items in it */
  315.       my_err = stat (path, &filestat);
  316.       
  317.       if (!my_err && S_ISDIR (filestat.st_mode))
  318.     {
  319.       if (path[strlen (path) - 1] != G_DIR_SEPARATOR)
  320.         strcat (path, G_DIR_SEPARATOR_S);
  321.  
  322.       /* Open directory */
  323.       dir = opendir (path);
  324.       
  325.       if (!dir)
  326.         g_message ("error reading script directory \"%s\"", path);
  327.       else
  328.         {
  329.           while ((dir_ent = readdir (dir)))
  330.         {
  331.           filename = g_strdup_printf ("%s%s", path, dir_ent->d_name);
  332.           
  333.           if (g_strcasecmp (filename + strlen (filename) - 4, ".scm") == 0)
  334.             {
  335.               /* Check the file and see that it is not a sub-directory */
  336.               my_err = stat (filename, &filestat);
  337.               
  338.               if (!my_err && S_ISREG (filestat.st_mode))
  339.             {
  340.               gchar *qf = ESCAPE (filename);
  341. #ifdef __EMX__
  342.               _fnslashify(qf);
  343. #endif
  344.               command = g_strdup_printf ("(load \"%s\")", qf);
  345.               g_free (qf);
  346.  
  347.               if (repl_c_string (command, 0, 0, 1) != 0)
  348.                 script_fu_error_msg (command);
  349. #ifdef G_OS_WIN32
  350.               /* No, I don't know why, but this is 
  351.                * necessary on NT 4.0.
  352.                */
  353.               Sleep(0);
  354. #endif
  355.               g_free (command);
  356.             }
  357.             }
  358.           
  359.           g_free (filename);
  360.         } /* while */
  361.           
  362.           closedir (dir);
  363.         } /* else */
  364.     } /* if */
  365.  
  366.       g_free (path);
  367.       
  368.       token = strtok (NULL, G_SEARCHPATH_SEPARATOR_S);
  369.     } /* while */
  370.   
  371.   g_free (local_path);
  372.   g_free (path_str);
  373.  
  374.   /*  now that all scripts are read in and sorted, tell gimp about them  */
  375.   g_tree_traverse (script_list, 
  376.            (GTraverseFunc)script_fu_install_script, G_IN_ORDER, NULL);
  377. }
  378.  
  379. LISP
  380. script_fu_add_script (LISP a)
  381. {
  382.   GimpParamDef *args;
  383.   SFScript     *script;
  384.   gchar        *val;
  385.   gint          i;
  386.   guchar        color[3];
  387.   LISP          color_list;
  388.   LISP          adj_list;
  389.   LISP          brush_list;
  390.   LISP          option_list;
  391.   gchar        *s;
  392.  
  393.   /*  Check the length of a  */
  394.   if (nlength (a) < 7)
  395.     return my_err ("Too few arguments to script-fu-register", NIL);
  396.  
  397.   /*  Create a new script  */
  398.   script = g_new0 (SFScript, 1);
  399.  
  400.   /*  Find the script name  */
  401.   val = get_c_string (car (a));
  402.   script->script_name = g_strdup (val);
  403.   a = cdr (a);
  404.  
  405.   /* transform the function name into a name containing "_" for each "-".
  406.    * this does not hurt anybody, yet improves the life of many... ;)
  407.    */
  408.   script->pdb_name = g_strdup (val);
  409.  
  410.   for (s = script->pdb_name; *s; s++)
  411.     if (*s == '-')
  412.       *s = '_';
  413.  
  414.   /*  Find the script description  */
  415.   val = get_c_string (car (a));
  416.   script->description = g_strdup (val);
  417.   a = cdr (a);
  418.  
  419.   /*  Find the script help  */
  420.   val = get_c_string (car (a));
  421.   script->help = g_strdup (val);
  422.   a = cdr (a);
  423.  
  424.   /*  Find the script author  */
  425.   val = get_c_string (car (a));
  426.   script->author = g_strdup (val);
  427.   a = cdr (a);
  428.  
  429.   /*  Find the script copyright  */
  430.   val = get_c_string (car (a));
  431.   script->copyright = g_strdup (val);
  432.   a = cdr (a);
  433.  
  434.   /*  Find the script date  */
  435.   val = get_c_string (car (a));
  436.   script->date = g_strdup (val);
  437.   a = cdr (a);
  438.  
  439.   /*  Find the script image types  */
  440.   if (TYPEP (a, tc_cons))
  441.     {
  442.       val = get_c_string (car (a));
  443.       a = cdr (a);
  444.     }
  445.   else
  446.     {
  447.       val = get_c_string (a);
  448.       a = NIL;
  449.     }
  450.   script->img_types = g_strdup (val);
  451.  
  452.   /*  Check the supplied number of arguments  */
  453.   script->num_args = nlength (a) / 3;
  454.  
  455.   args = g_new (GimpParamDef, script->num_args + 1);
  456.   args[0].type = GIMP_PDB_INT32;
  457.   args[0].name = "run_mode";
  458.   args[0].description = "Interactive, non-interactive";
  459.  
  460.   script->arg_types    = g_new (SFArgType, script->num_args);
  461.   script->arg_labels   = g_new (gchar *, script->num_args);
  462.   script->arg_defaults = g_new0 (SFArgValue, script->num_args);
  463.   script->arg_values   = g_new0 (SFArgValue, script->num_args);
  464.  
  465.   if (script->num_args > 0)
  466.     {
  467.       for (i = 0; i < script->num_args; i++)
  468.     {
  469.       if (a != NIL)
  470.         {
  471.           if (!TYPEP (car (a), tc_flonum))
  472.         return my_err ("script-fu-register: argument types must be integer values", NIL);
  473.           script->arg_types[i] = get_c_long (car (a));
  474.           a = cdr (a);
  475.         }
  476.       else
  477.         return my_err ("script-fu-register: missing type specifier", NIL);
  478.  
  479.       if (a != NIL)
  480.         {
  481.           if (!TYPEP (car (a), tc_string))
  482.         return my_err ("script-fu-register: argument labels must be strings", NIL);
  483.           script->arg_labels[i] = g_strdup (get_c_string (car (a)));
  484.           a = cdr (a);
  485.         }
  486.       else
  487.         return my_err ("script-fu-register: missing arguments label", NIL);
  488.  
  489.       if (a != NIL)
  490.         {
  491.           switch (script->arg_types[i])
  492.         {
  493.         case SF_IMAGE:
  494.         case SF_DRAWABLE:
  495.         case SF_LAYER:
  496.         case SF_CHANNEL:
  497.           if (!TYPEP (car (a), tc_flonum))
  498.             return my_err ("script-fu-register: drawable defaults must be integer values", NIL);
  499.           script->arg_defaults[i].sfa_image = get_c_long (car (a));
  500.           script->arg_values[i].sfa_image = script->arg_defaults[i].sfa_image;
  501.  
  502.           switch (script->arg_types[i])
  503.             {
  504.             case SF_IMAGE:
  505.               args[i + 1].type = GIMP_PDB_IMAGE;
  506.               args[i + 1].name = "image";
  507.               break;
  508.  
  509.             case SF_DRAWABLE:
  510.               args[i + 1].type = GIMP_PDB_DRAWABLE;
  511.               args[i + 1].name = "drawable";
  512.               break;
  513.  
  514.             case SF_LAYER:
  515.               args[i + 1].type = GIMP_PDB_LAYER;
  516.               args[i + 1].name = "layer";
  517.               break;
  518.  
  519.             case SF_CHANNEL:
  520.               args[i + 1].type = GIMP_PDB_CHANNEL;
  521.               args[i + 1].name = "channel";
  522.               break;
  523.  
  524.             default:
  525.               break;
  526.             }
  527.  
  528.           args[i + 1].description = script->arg_labels[i];
  529.           break;
  530.  
  531.         case SF_COLOR:
  532.           if (!TYPEP (car (a), tc_cons))
  533.             return my_err ("script-fu-register: color defaults must be a list of 3 integers", NIL);
  534.           color_list = car (a);
  535.           color[0] = 
  536.             (guchar)(CLAMP (get_c_long (car (color_list)), 0, 255));
  537.           color_list = cdr (color_list);
  538.           color[1] = 
  539.             (guchar)(CLAMP (get_c_long (car (color_list)), 0, 255));
  540.           color_list = cdr (color_list);
  541.           color[2] = 
  542.             (guchar)(CLAMP (get_c_long (car (color_list)), 0, 255));
  543.           memcpy (script->arg_defaults[i].sfa_color, 
  544.               color, sizeof (guchar) * 3);
  545.           memcpy (script->arg_values[i].sfa_color, 
  546.               color, sizeof (guchar) * 3);
  547.  
  548.           args[i + 1].type = GIMP_PDB_COLOR;
  549.           args[i + 1].name = "color";
  550.           args[i + 1].description = script->arg_labels[i];
  551.           break;
  552.  
  553.         case SF_TOGGLE:
  554.           if (!TYPEP (car (a), tc_flonum))
  555.             return my_err ("script-fu-register: toggle default must be an integer value", NIL);
  556.           script->arg_defaults[i].sfa_toggle = 
  557.             (get_c_long (car (a))) ? TRUE : FALSE;
  558.           script->arg_values[i].sfa_toggle = 
  559.             script->arg_defaults[i].sfa_toggle;
  560.  
  561.           args[i + 1].type = GIMP_PDB_INT32;
  562.           args[i + 1].name = "toggle";
  563.           args[i + 1].description = script->arg_labels[i];
  564.           break;
  565.  
  566.         case SF_VALUE:  
  567.           if (!TYPEP (car (a), tc_string))
  568.             return my_err ("script-fu-register: value defaults must be string values", NIL);
  569.           script->arg_defaults[i].sfa_value = 
  570.             g_strdup (get_c_string (car (a)));
  571.           script->arg_values[i].sfa_value =  
  572.             g_strdup (script->arg_defaults[i].sfa_value);
  573.  
  574.           args[i + 1].type = GIMP_PDB_STRING;
  575.           args[i + 1].name = "value";
  576.           args[i + 1].description = script->arg_labels[i];
  577.           break;
  578.  
  579.         case SF_STRING:
  580.           if (!TYPEP (car (a), tc_string))
  581.             return my_err ("script-fu-register: string defaults must be string values", NIL);
  582.           script->arg_defaults[i].sfa_value = 
  583.             g_strdup (get_c_string (car (a)));
  584.           script->arg_values[i].sfa_value =  
  585.             g_strdup (script->arg_defaults[i].sfa_value);
  586.  
  587.           args[i + 1].type = GIMP_PDB_STRING;
  588.           args[i + 1].name = "string";
  589.           args[i + 1].description = script->arg_labels[i];
  590.           break;
  591.  
  592.         case SF_ADJUSTMENT:
  593.           if (!TYPEP (car (a), tc_cons))
  594.             return my_err ("script-fu-register: adjustment defaults must be a list", NIL);
  595.           adj_list = car (a);
  596.           script->arg_defaults[i].sfa_adjustment.value = 
  597.             get_c_double (car (adj_list));
  598.           adj_list = cdr (adj_list);
  599.           script->arg_defaults[i].sfa_adjustment.lower = 
  600.             get_c_double (car (adj_list));
  601.           adj_list = cdr (adj_list);
  602.           script->arg_defaults[i].sfa_adjustment.upper = 
  603.             get_c_double (car (adj_list));
  604.           adj_list = cdr (adj_list);
  605.           script->arg_defaults[i].sfa_adjustment.step = 
  606.             get_c_double (car (adj_list));
  607.           adj_list = cdr (adj_list);
  608.           script->arg_defaults[i].sfa_adjustment.page = 
  609.             get_c_double (car (adj_list));
  610.           adj_list = cdr (adj_list);
  611.           script->arg_defaults[i].sfa_adjustment.digits = 
  612.             get_c_long (car (adj_list));
  613.           adj_list = cdr (adj_list);
  614.           script->arg_defaults[i].sfa_adjustment.type = 
  615.             get_c_long (car (adj_list));
  616.           script->arg_values[i].sfa_adjustment.adj = NULL;
  617.           script->arg_values[i].sfa_adjustment.value = 
  618.             script->arg_defaults[i].sfa_adjustment.value;
  619.  
  620.           args[i + 1].type = GIMP_PDB_STRING;
  621.           args[i + 1].name = "value";
  622.           args[i + 1].description = script->arg_labels[i];
  623.           break;
  624.  
  625.         case SF_FILENAME:
  626.           if (!TYPEP (car (a), tc_string))
  627.             return my_err ("script-fu-register: filename defaults must be string values", NIL);
  628.           script->arg_defaults[i].sfa_file.filename = 
  629.             g_strdup (get_c_string (car (a)));
  630.  
  631. #ifdef G_OS_WIN32
  632.           /* Replace POSIX slashes with Win32 backslashes. This
  633.            * is just so script-fus can be written with only
  634.            * POSIX directory separators.
  635.            */
  636.           val = script->arg_defaults[i].sfa_file.filename;
  637.           while (*val)
  638.             {
  639.               if (*val == '/')
  640.             *val = '\\';
  641.               val++;
  642.             }
  643. #endif
  644.           script->arg_values[i].sfa_file.filename =  
  645.             g_strdup (script->arg_defaults[i].sfa_file.filename);
  646.           script->arg_values[i].sfa_file.fileselection = NULL;
  647.  
  648.           args[i + 1].type = GIMP_PDB_STRING;
  649.           args[i + 1].name = "filename";
  650.           args[i + 1].description = script->arg_labels[i];
  651.          break;
  652.  
  653.         case SF_FONT:
  654.           if (!TYPEP (car (a), tc_string))
  655.             return my_err ("script-fu-register: font defaults must be string values", NIL);
  656.           script->arg_defaults[i].sfa_font.fontname = 
  657.             g_strdup (get_c_string (car (a)));
  658.           script->arg_values[i].sfa_font.fontname =  
  659.             g_strdup (script->arg_defaults[i].sfa_font.fontname);
  660.           script->arg_values[i].sfa_font.preview = NULL;
  661.           script->arg_values[i].sfa_font.dialog = NULL;
  662.           
  663.           args[i + 1].type = GIMP_PDB_STRING;
  664.           args[i + 1].name = "font";
  665.           args[i + 1].description = script->arg_labels[i];
  666.           break;
  667.  
  668.         case SF_PATTERN:
  669.           if (!TYPEP (car (a), tc_string))
  670.             return my_err ("script-fu-register: pattern defaults must be string values", NIL);
  671.           script->arg_defaults[i].sfa_pattern = 
  672.             g_strdup (get_c_string (car (a)));
  673.           script->arg_values[i].sfa_pattern =  
  674.             g_strdup (script->arg_defaults[i].sfa_pattern);
  675.  
  676.           args[i + 1].type = GIMP_PDB_STRING;
  677.           args[i + 1].name = "pattern";
  678.           args[i + 1].description = script->arg_labels[i];
  679.           break;
  680.  
  681.         case SF_BRUSH:
  682.           if (!TYPEP (car (a), tc_cons))
  683.             return my_err ("script-fu-register: brush defaults must be a list", NIL);
  684.           brush_list = car (a);
  685.           script->arg_defaults[i].sfa_brush.name = 
  686.             g_strdup (get_c_string (car (brush_list)));
  687.           brush_list = cdr (brush_list);
  688.           script->arg_defaults[i].sfa_brush.opacity = 
  689.             get_c_double (car (brush_list));
  690.           brush_list = cdr (brush_list);
  691.           script->arg_defaults[i].sfa_brush.spacing = 
  692.             get_c_long (car (brush_list));
  693.           brush_list = cdr (brush_list);
  694.           script->arg_defaults[i].sfa_brush.paint_mode = 
  695.             get_c_long (car (brush_list));
  696.           script->arg_values[i].sfa_brush = 
  697.             script->arg_defaults[i].sfa_brush;
  698.           /* Need this since we need a copy of the string
  699.            * in the values area. We could free it later but the
  700.            * default one must hang around.
  701.            */
  702.           script->arg_values[i].sfa_brush.name = 
  703.             g_strdup(script->arg_defaults[i].sfa_brush.name);
  704.  
  705.           args[i + 1].type = GIMP_PDB_STRING;
  706.           args[i + 1].name = "brush";
  707.           args[i + 1].description = script->arg_labels[i];
  708.           break;
  709.  
  710.         case SF_GRADIENT:
  711.           if (!TYPEP (car (a), tc_string))
  712.             return my_err ("script-fu-register: gradient defaults must be string values", NIL);
  713.           script->arg_defaults[i].sfa_gradient = 
  714.             g_strdup (get_c_string (car (a)));
  715.           script->arg_values[i].sfa_gradient =  
  716.             g_strdup (script->arg_defaults[i].sfa_pattern);
  717.           
  718.           args[i + 1].type = GIMP_PDB_STRING;
  719.           args[i + 1].name = "gradient";
  720.           args[i + 1].description = script->arg_labels[i];
  721.           break;
  722.  
  723.         case SF_OPTION:
  724.           if (!TYPEP (car (a), tc_cons))
  725.             return my_err ("script-fu-register: option defaults must be a list", NIL);
  726.           for (option_list = car (a); 
  727.                option_list; 
  728.                option_list = cdr (option_list))
  729.             {
  730.               script->arg_defaults[i].sfa_option.list = 
  731.             g_slist_append (script->arg_defaults[i].sfa_option.list, 
  732.                     g_strdup (get_c_string (car (option_list))));
  733.             }
  734.           script->arg_defaults[i].sfa_option.history = 0;
  735.           script->arg_values[i].sfa_option.history = 0;
  736.  
  737.           args[i + 1].type = GIMP_PDB_INT32;
  738.           args[i + 1].name = "option";
  739.           args[i + 1].description = script->arg_labels[i];
  740.           break;
  741.  
  742.         default:
  743.           break;
  744.         }
  745.  
  746.           a = cdr (a);
  747.         }
  748.       else
  749.         return my_err ("script-fu-register: missing default argument", NIL);
  750.     }
  751.     }
  752.  
  753.   script->args = args;
  754.   g_tree_insert (script_list, gettext (script->description), script);
  755.  
  756.   return NIL;
  757. }
  758.  
  759. void
  760. script_fu_report_cc (gchar *command)
  761. {
  762.   if (sf_interface == NULL)
  763.     return;
  764.  
  765.   if (sf_interface->last_command && 
  766.       strcmp (sf_interface->last_command, command) == 0)
  767.     {
  768.       gchar *new_command;
  769.  
  770.       sf_interface->command_count++;
  771.  
  772.       new_command = g_strdup_printf ("%s <%d>", 
  773.                      command, sf_interface->command_count);
  774.       gtk_entry_set_text (GTK_ENTRY (sf_interface->status), new_command);
  775.       g_free (new_command);
  776.     }
  777.   else
  778.     {
  779.       sf_interface->command_count = 1;
  780.       gtk_entry_set_text (GTK_ENTRY (sf_interface->status), command);
  781.       g_free (sf_interface->last_command);
  782.       sf_interface->last_command = g_strdup (command);
  783.     }
  784.   
  785.   gdk_flush ();
  786. }
  787.  
  788.  
  789. /* 
  790.  *  The following function is a GTraverseFunction, Please 
  791.  *  note that it frees the script->args structure.  --Sven 
  792.  */
  793. static gint
  794. script_fu_install_script (gpointer  foo,
  795.               SFScript *script,
  796.               gpointer  bar)
  797. {
  798.   gchar *menu_path = NULL;
  799.  
  800.   /* Allow scripts with no menus */
  801.   if (strncmp (script->description, "<None>", 6) != 0)
  802.     menu_path = script->description;
  803.  
  804.   gimp_install_temp_proc (script->pdb_name,
  805.                           script->description,
  806.                           script->help,
  807.                           script->author,
  808.                           script->copyright,
  809.                           script->date,
  810.                           menu_path,
  811.                           script->img_types,
  812.                           GIMP_TEMPORARY,
  813.                           script->num_args + 1, 0,
  814.                           script->args, NULL,
  815.                           script_fu_script_proc);
  816.  
  817.   g_free (script->args);
  818.   script->args = NULL;
  819.  
  820.   return FALSE;
  821. }
  822.  
  823. /* 
  824.  *  The following function is a GTraverseFunction.
  825.  */
  826. static gint
  827. script_fu_remove_script (gpointer  foo,
  828.              SFScript *script,
  829.              gpointer  bar)
  830. {
  831.   script_fu_free_script (script);
  832.  
  833.   return FALSE;
  834. }
  835.  
  836.  
  837.  
  838. static void
  839. script_fu_script_proc (gchar       *name,
  840.                gint         nparams,
  841.                GimpParam   *params,
  842.                gint        *nreturn_vals,
  843.                GimpParam  **return_vals)
  844. {
  845.   static GimpParam  values[1];
  846.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  847.   GimpRunModeType   run_mode;
  848.   SFScript         *script;
  849.   gint              min_args;
  850.   gchar            *escaped;
  851.  
  852.   run_mode = params[0].data.d_int32;
  853.  
  854.   if (! (script = script_fu_find_script (name)))
  855.     status = GIMP_PDB_CALLING_ERROR;
  856.   else
  857.     {
  858.       if (script->num_args == 0)
  859.     run_mode = GIMP_RUN_NONINTERACTIVE;
  860.  
  861.       switch (run_mode)
  862.     {
  863.     case GIMP_RUN_INTERACTIVE:
  864.     case GIMP_RUN_WITH_LAST_VALS:
  865.       /*  Determine whether the script is image based (runs on an image) */
  866.       if (strncmp (script->description, "<Image>", 7) == 0)
  867.         {
  868.           script->arg_values[0].sfa_image    = params[1].data.d_image;
  869.           script->arg_values[1].sfa_drawable = params[2].data.d_drawable;
  870.           script->image_based = TRUE;
  871.         }
  872.       else
  873.         script->image_based = FALSE;
  874.  
  875.       /*  First acquire information with a dialog  */
  876.       /*  Skip this part if the script takes no parameters */ 
  877.       min_args = (script->image_based) ? 2 : 0;
  878.       if (script->num_args > min_args) 
  879.         {
  880.           script_fu_interface (script); 
  881.           break;
  882.         }  
  883.       /*  else fallthrough  */
  884.  
  885.     case GIMP_RUN_NONINTERACTIVE:
  886.       /*  Make sure all the arguments are there!  */
  887.       if (nparams != (script->num_args + 1))
  888.         status = GIMP_PDB_CALLING_ERROR;
  889.       if (status == GIMP_PDB_SUCCESS)
  890.         {
  891.           gchar *text = NULL;
  892.           gchar *command;
  893.           gchar *c;
  894.           gchar  buffer[MAX_STRING_LENGTH];
  895.           gint   length;
  896.           gint   i;
  897.  
  898.           length = strlen (script->script_name) + 3;
  899.  
  900.           for (i = 0; i < script->num_args; i++)
  901.         switch (script->arg_types[i])
  902.           {
  903.           case SF_IMAGE:
  904.           case SF_DRAWABLE:
  905.           case SF_LAYER:
  906.           case SF_CHANNEL:
  907.             length += 12;  /*  Maximum size of integer value will not exceed this many characters  */
  908.             break;
  909.  
  910.           case SF_COLOR:
  911.             length += 16;  /*  Maximum size of color string: '(XXX XXX XXX)  */
  912.             break;
  913.  
  914.           case SF_TOGGLE:
  915.             length += 6;   /*  Maximum size of (TRUE, FALSE)  */
  916.             break;
  917.  
  918.           case SF_VALUE:
  919.             length += strlen (params[i + 1].data.d_string) + 1;
  920.             break;
  921.  
  922.           case SF_STRING:
  923.           case SF_FILENAME:
  924.             escaped = ESCAPE (params[i + 1].data.d_string);
  925.             length += strlen (escaped) + 3;
  926.             g_free (escaped);
  927.             break;
  928.  
  929.           case SF_ADJUSTMENT:
  930.             length += strlen (params[i + 1].data.d_string) + 1;
  931.             break;
  932.  
  933.           case SF_FONT:
  934.           case SF_PATTERN:
  935.           case SF_GRADIENT:
  936.           case SF_BRUSH:
  937.             length += strlen (params[i + 1].data.d_string) + 3;
  938.             break;            
  939.  
  940.           case SF_OPTION:
  941.             length += strlen (params[i + 1].data.d_string) + 1;
  942.             break;
  943.  
  944.           default:
  945.             break;
  946.           }
  947.  
  948.           c = command = g_new (gchar, length);
  949.  
  950.           if (script->num_args)
  951.                 {
  952.                   sprintf (command, "(%s ", script->script_name);
  953.                   c += strlen (script->script_name) + 2;
  954.  
  955.                   for (i = 0; i < script->num_args; i++)
  956.                     {
  957.                       switch (script->arg_types[i])
  958.                         {
  959.                         case SF_IMAGE:
  960.                         case SF_DRAWABLE:
  961.                         case SF_LAYER:
  962.                         case SF_CHANNEL:
  963.                           g_snprintf (buffer, sizeof (buffer), "%d",
  964.                       params[i + 1].data.d_image);
  965.                           text = buffer;
  966.                           break;
  967.  
  968.                         case SF_COLOR:
  969.                           g_snprintf (buffer, sizeof (buffer), "'(%d %d %d)",
  970.                       params[i + 1].data.d_color.red,
  971.                       params[i + 1].data.d_color.green,
  972.                       params[i + 1].data.d_color.blue);
  973.                           text = buffer;
  974.                           break;
  975.  
  976.                         case SF_TOGGLE:
  977.                           g_snprintf (buffer, sizeof (buffer), "%s",
  978.                       (params[i + 1].data.d_int32) ? "TRUE" 
  979.                                                    : "FALSE");
  980.                           text = buffer;
  981.                           break;
  982.  
  983.                         case SF_VALUE:
  984.                           text = params[i + 1].data.d_string;
  985.                           break;
  986.  
  987.                         case SF_STRING:
  988.                         case SF_FILENAME:
  989.                           escaped = ESCAPE (params[i + 1].data.d_string);
  990.                           g_snprintf (buffer, sizeof (buffer), "\"%s\"",
  991.                       escaped);
  992.                           g_free (escaped);
  993.                           text = buffer;
  994.                           break;
  995.  
  996.                         case SF_ADJUSTMENT:
  997.                           text = params[i + 1].data.d_string;
  998.                           break;
  999.  
  1000.                         case SF_FONT:
  1001.                         case SF_PATTERN:
  1002.                         case SF_GRADIENT:
  1003.                         case SF_BRUSH:
  1004.                           g_snprintf (buffer, sizeof (buffer), "\"%s\"",
  1005.                       params[i + 1].data.d_string);
  1006.                           text = buffer;
  1007.                           break;
  1008.  
  1009.                         case SF_OPTION:
  1010.                           text = params[i + 1].data.d_string;
  1011.                           break;
  1012.  
  1013.                         default:
  1014.                           break;
  1015.                         }
  1016.  
  1017.                       if (i == script->num_args - 1)
  1018.                         sprintf (c, "%s)", text);
  1019.                       else
  1020.                         sprintf (c, "%s ", text);
  1021.  
  1022.                       c += strlen (text) + 1;
  1023.                     }
  1024.                 }
  1025.           else
  1026.         sprintf (command, "(%s)", script->script_name);
  1027.  
  1028.           /*  run the command through the interpreter  */
  1029.           if (repl_c_string (command, 0, 0, 1) != 0)
  1030.         script_fu_error_msg (command);
  1031.      
  1032.           g_free (command);
  1033.         }
  1034.       break;
  1035.  
  1036.     default:
  1037.       break;
  1038.     }
  1039.     }
  1040.  
  1041.   *nreturn_vals = 1;
  1042.   *return_vals = values;
  1043.  
  1044.   values[0].type = GIMP_PDB_STATUS;
  1045.   values[0].data.d_status = status;
  1046. }
  1047.  
  1048. /* this is a GTraverseFunction */
  1049. static gint
  1050. script_fu_lookup_script (gpointer  *foo,
  1051.              SFScript  *script,
  1052.              gchar    **name)
  1053. {
  1054.   if (strcmp (script->pdb_name, *name) == 0)
  1055.     {  
  1056.       /* store the script in the name pointer and stop the traversal */
  1057.       *name = (gchar *)script;
  1058.       return TRUE;
  1059.     }
  1060.   else
  1061.     return FALSE;
  1062. }
  1063.  
  1064. static SFScript *
  1065. script_fu_find_script (gchar *pdb_name)
  1066. {
  1067.   gchar *script;
  1068.   
  1069.   script = pdb_name;
  1070.   g_tree_traverse (script_list, 
  1071.            (GTraverseFunc)script_fu_lookup_script, G_IN_ORDER, &script);
  1072.   if (script == pdb_name)
  1073.     return NULL;
  1074.   else
  1075.     return (SFScript *)script;
  1076. }
  1077.  
  1078. static void
  1079. script_fu_free_script (SFScript *script)
  1080. {
  1081.   gint i;
  1082.  
  1083.   /*  Uninstall the temporary procedure for this script  */
  1084.   gimp_uninstall_temp_proc (script->script_name);
  1085.  
  1086.   if (script)
  1087.     {
  1088.       g_free (script->script_name);
  1089.       g_free (script->description);
  1090.       g_free (script->help);
  1091.       g_free (script->author);
  1092.       g_free (script->copyright);
  1093.       g_free (script->date);
  1094.       g_free (script->img_types);
  1095.       g_free (script->arg_types);
  1096.  
  1097.       for (i = 0; i < script->num_args; i++)
  1098.     {
  1099.       g_free (script->arg_labels[i]);
  1100.       switch (script->arg_types[i])
  1101.         {
  1102.         case SF_IMAGE:
  1103.         case SF_DRAWABLE:
  1104.         case SF_LAYER:
  1105.         case SF_CHANNEL:
  1106.         case SF_COLOR:
  1107.           break;
  1108.  
  1109.         case SF_VALUE:
  1110.         case SF_STRING:
  1111.           g_free (script->arg_defaults[i].sfa_value);
  1112.           g_free (script->arg_values[i].sfa_value);
  1113.           break;
  1114.  
  1115.         case SF_ADJUSTMENT:
  1116.           break;
  1117.  
  1118.         case SF_FILENAME:
  1119.           g_free (script->arg_defaults[i].sfa_file.filename);
  1120.           g_free (script->arg_values[i].sfa_file.filename);
  1121.           break;
  1122.  
  1123.         case SF_FONT:
  1124.           g_free (script->arg_defaults[i].sfa_font.fontname);
  1125.           g_free (script->arg_values[i].sfa_font.fontname);
  1126.           break;
  1127.  
  1128.         case SF_PATTERN:
  1129.           g_free (script->arg_defaults[i].sfa_pattern);
  1130.           g_free (script->arg_values[i].sfa_pattern);
  1131.           break;
  1132.  
  1133.         case SF_GRADIENT:
  1134.           g_free (script->arg_defaults[i].sfa_gradient);
  1135.           g_free (script->arg_values[i].sfa_gradient);
  1136.           break;
  1137.  
  1138.         case SF_BRUSH:
  1139.           g_free (script->arg_defaults[i].sfa_brush.name);
  1140.           g_free (script->arg_values[i].sfa_brush.name);
  1141.           break;
  1142.  
  1143.         case SF_OPTION:
  1144.           g_slist_foreach (script->arg_defaults[i].sfa_option.list, 
  1145.                    (GFunc)g_free, NULL);
  1146.           if (script->arg_defaults[i].sfa_option.list)
  1147.         g_slist_free (script->arg_defaults[i].sfa_option.list);
  1148.           break;
  1149.  
  1150.         default:
  1151.           break;
  1152.         }
  1153.     }
  1154.  
  1155.       g_free (script->arg_labels);
  1156.       g_free (script->arg_defaults);
  1157.       g_free (script->arg_values);
  1158.  
  1159.       g_free (script);
  1160.     }
  1161. }
  1162.  
  1163. static void
  1164. script_fu_interface (SFScript *script)
  1165. {
  1166.   GtkWidget *dlg;
  1167.   GtkWidget *main_box;
  1168.   GtkWidget *frame;
  1169.   GtkWidget *sep;
  1170.   GtkWidget *button;
  1171.   GtkWidget *menu;
  1172.   GtkWidget *table;
  1173.   GtkWidget *vbox;
  1174.   GtkWidget *hbox;
  1175.   GtkWidget *bbox;
  1176.   GtkWidget *menu_item;
  1177.   GSList    *list;
  1178.   gchar     *buf;
  1179.   gint       start_args;
  1180.   gint       i;
  1181.   guint      j;
  1182.  
  1183.   static gboolean gtk_initted = FALSE;
  1184.  
  1185.   /*  Simply return if there is already an interface. This is an
  1186.       ugly workaround for the fact that we can not process two
  1187.       scripts at a time.  */
  1188.   if (sf_interface != NULL)
  1189.     return;
  1190.  
  1191.   g_return_if_fail (script != NULL);
  1192.  
  1193.   if (!gtk_initted)
  1194.     {
  1195.       INIT_I18N_UI();
  1196.  
  1197.       gimp_ui_init ("script-fu", TRUE);
  1198.  
  1199.       gtk_initted = TRUE;
  1200.     }
  1201.  
  1202.   sf_interface = g_new0 (SFInterface, 1);
  1203.   sf_interface->args_widgets = g_new0 (GtkWidget *, script->num_args);
  1204.   
  1205.   /* strip the first part of the menupath if it contains _("/Script-Fu/") */
  1206.   buf = strstr (gettext (script->description), _("/Script-Fu/"));
  1207.   if (buf)
  1208.     sf_interface->window_title = g_strdup_printf (_("Script-Fu: %s"), 
  1209.                           (buf + strlen (_("/Script-Fu/"))));
  1210.   else 
  1211.     sf_interface->window_title = g_strdup_printf (_("Script-Fu: %s"), 
  1212.                         gettext (script->description));
  1213.  
  1214.   buf = strstr (sf_interface->window_title, "...");
  1215.   if (buf)
  1216.     *buf = '\0';
  1217.  
  1218.   dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  1219.   gtk_quit_add_destroy (1, GTK_OBJECT (dlg));
  1220.   gtk_window_set_title (GTK_WINDOW (dlg), sf_interface->window_title);
  1221.   gtk_window_set_wmclass (GTK_WINDOW (dlg), "script_fu", "Gimp");
  1222.   gtk_signal_connect_object (GTK_OBJECT (dlg), "delete_event",
  1223.                  GTK_SIGNAL_FUNC (script_fu_interface_quit),
  1224.                  (GtkObject *) script);
  1225.                  
  1226.   gimp_help_connect_help_accel (dlg, gimp_standard_help_func,
  1227.                 "filters/script-fu.html");
  1228.   
  1229.   /* the vbox holding all widgets */
  1230.   main_box = gtk_vbox_new (FALSE, 0);
  1231.   gtk_container_add (GTK_CONTAINER (dlg), main_box);
  1232.  
  1233.   /* the script arguments frame */
  1234.   frame = gtk_frame_new (_("Script Arguments"));
  1235.   gtk_container_set_border_width (GTK_CONTAINER (frame), 4);
  1236.   gtk_box_pack_start (GTK_BOX (main_box), frame, TRUE, TRUE, 0);
  1237.  
  1238.   /* the vbox holding all widgets */
  1239.   vbox = gtk_vbox_new (FALSE, 2);
  1240.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  1241.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  1242.  
  1243.   /*  The argument table  */
  1244.   table = gtk_table_new (script->num_args + 1, 2, FALSE);
  1245.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1246.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  1247.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  1248.   gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
  1249.  
  1250.   start_args = (script->image_based) ? 2 : 0;
  1251.  
  1252.   for (i = start_args; i < script->num_args; i++)
  1253.     {
  1254.       /*  we add a colon after the label; 
  1255.       some languages want an extra space here */
  1256.       gchar     *label_text = 
  1257.     g_strdup_printf (_("%s:"), gettext (script->arg_labels[i]));
  1258.       gfloat     label_yalign = 0.5;
  1259.       gboolean   widget_leftalign = TRUE;
  1260.  
  1261.       switch (script->arg_types[i])
  1262.     {
  1263.     case SF_IMAGE:
  1264.     case SF_DRAWABLE:
  1265.     case SF_LAYER:
  1266.     case SF_CHANNEL:
  1267.       sf_interface->args_widgets[i] = gtk_option_menu_new ();
  1268.       switch (script->arg_types[i])
  1269.         {
  1270.         case SF_IMAGE:
  1271.           menu = gimp_image_menu_new (NULL, script_fu_menu_callback,
  1272.                       &script->arg_values[i].sfa_image,
  1273.                       script->arg_values[i].sfa_image);
  1274.           break;
  1275.  
  1276.         case SF_DRAWABLE:
  1277.           menu = gimp_drawable_menu_new (NULL, script_fu_menu_callback,
  1278.                          &script->arg_values[i].sfa_drawable,
  1279.                          script->arg_values[i].sfa_drawable);
  1280.           break;
  1281.  
  1282.         case SF_LAYER:
  1283.           menu = gimp_layer_menu_new (NULL, script_fu_menu_callback,
  1284.                       &script->arg_values[i].sfa_layer,
  1285.                       script->arg_values[i].sfa_layer);
  1286.           break;
  1287.  
  1288.         case SF_CHANNEL:
  1289.           menu = gimp_channel_menu_new (NULL, script_fu_menu_callback,
  1290.                         &script->arg_values[i].sfa_channel,
  1291.                         script->arg_values[i].sfa_channel);
  1292.           break;
  1293.  
  1294.         default:
  1295.           menu = NULL;
  1296.           break;
  1297.         }
  1298.       gtk_option_menu_set_menu (GTK_OPTION_MENU (sf_interface->args_widgets[i]),
  1299.                     menu);
  1300.       break;
  1301.  
  1302.     case SF_COLOR:
  1303.       sf_interface->args_widgets[i] =
  1304.         gimp_color_button_new (_("Script-Fu Color Selection"),
  1305.                    COLOR_SAMPLE_WIDTH, COLOR_SAMPLE_HEIGHT,
  1306.                    script->arg_values[i].sfa_color, 3);
  1307.       break;
  1308.  
  1309.     case SF_TOGGLE:
  1310.       g_free (label_text);
  1311.       label_text = NULL;
  1312.       sf_interface->args_widgets[i] =
  1313.         gtk_check_button_new_with_label (gettext (script->arg_labels[i]));
  1314.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sf_interface->args_widgets[i]),
  1315.                        script->arg_values[i].sfa_toggle);
  1316.       gtk_signal_connect (GTK_OBJECT (sf_interface->args_widgets[i]), "toggled",
  1317.                   GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1318.                   &script->arg_values[i].sfa_toggle);
  1319.       break;
  1320.  
  1321.     case SF_VALUE:
  1322.     case SF_STRING:
  1323.       widget_leftalign = FALSE;
  1324.  
  1325.       sf_interface->args_widgets[i] = gtk_entry_new ();
  1326.       gtk_widget_set_usize (sf_interface->args_widgets[i], TEXT_WIDTH, 0);
  1327.       gtk_entry_set_text (GTK_ENTRY (sf_interface->args_widgets[i]),
  1328.                   script->arg_values[i].sfa_value);
  1329.       break;
  1330.  
  1331.     case SF_ADJUSTMENT:
  1332.       script->arg_values[i].sfa_adjustment.adj = (GtkAdjustment *)
  1333.         gtk_adjustment_new (script->arg_values[i].sfa_adjustment.value, 
  1334.                 script->arg_defaults[i].sfa_adjustment.lower, 
  1335.                 script->arg_defaults[i].sfa_adjustment.upper, 
  1336.                 script->arg_defaults[i].sfa_adjustment.step, 
  1337.                 script->arg_defaults[i].sfa_adjustment.page, 0);
  1338.       switch (script->arg_defaults[i].sfa_adjustment.type)
  1339.         {
  1340.         case SF_SLIDER:
  1341.           label_yalign = 1.0;
  1342.           widget_leftalign = FALSE;
  1343.  
  1344.           sf_interface->args_widgets[i] =
  1345.         gtk_hscale_new (script->arg_values[i].sfa_adjustment.adj);
  1346.           gtk_widget_set_usize (GTK_WIDGET (sf_interface->args_widgets[i]), 
  1347.                     SLIDER_WIDTH, -1);
  1348.           gtk_scale_set_digits (GTK_SCALE (sf_interface->args_widgets[i]), 
  1349.                     script->arg_defaults[i].sfa_adjustment.digits);
  1350.           gtk_scale_set_draw_value (GTK_SCALE (sf_interface->args_widgets[i]), TRUE);
  1351.           gtk_range_set_update_policy (GTK_RANGE (sf_interface->args_widgets[i]), 
  1352.                        GTK_UPDATE_DELAYED);
  1353.           break;
  1354.  
  1355.         case SF_SPINNER:
  1356.           sf_interface->args_widgets[i] =
  1357.         gtk_spin_button_new (script->arg_values[i].sfa_adjustment.adj, 0, 0);
  1358.           gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (sf_interface->args_widgets[i]), TRUE);
  1359.           gtk_widget_set_usize (sf_interface->args_widgets[i], SPINNER_WIDTH, 0);
  1360.           gtk_spin_button_set_digits (GTK_SPIN_BUTTON (sf_interface->args_widgets[i]),
  1361.                       script->arg_defaults[i].sfa_adjustment.digits);
  1362.           gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (sf_interface->args_widgets[i]), TRUE);
  1363.           break;
  1364.         default: /* this shouldn't happen */
  1365.           sf_interface->args_widgets[i] = NULL;
  1366.           break;
  1367.         }
  1368.       break;
  1369.  
  1370.     case SF_FILENAME:
  1371.       widget_leftalign = FALSE
  1372. ;
  1373.       sf_interface->args_widgets[i] =
  1374.         gimp_file_selection_new (_("Script-Fu File Selection"),
  1375.                      script->arg_values[i].sfa_file.filename,
  1376.                      FALSE, TRUE);
  1377.       script->arg_values[i].sfa_file.fileselection = sf_interface->args_widgets[i];
  1378.  
  1379.       gtk_signal_connect (GTK_OBJECT (sf_interface->args_widgets[i]),
  1380.                   "filename_changed",
  1381.                   (GtkSignalFunc) script_fu_file_selection_callback,
  1382.                   &script->arg_values[i].sfa_file);
  1383.       break;
  1384.  
  1385.     case SF_FONT:
  1386.       widget_leftalign = FALSE;
  1387.  
  1388.       sf_interface->args_widgets[i] = gtk_button_new ();
  1389.       script->arg_values[i].sfa_font.preview = gtk_label_new ("");
  1390.       script->arg_values[i].sfa_font.dialog = NULL;
  1391.       gtk_widget_set_usize (sf_interface->args_widgets[i], FONT_PREVIEW_WIDTH, 0);
  1392.       gtk_container_add (GTK_CONTAINER (sf_interface->args_widgets[i]),
  1393.                  script->arg_values[i].sfa_font.preview);
  1394.       gtk_widget_show (script->arg_values[i].sfa_font.preview);
  1395.  
  1396.       script_fu_font_preview (script->arg_values[i].sfa_font.preview,
  1397.                   script->arg_values[i].sfa_font.fontname);
  1398.  
  1399.       gtk_signal_connect (GTK_OBJECT (sf_interface->args_widgets[i]), "clicked",
  1400.                   (GtkSignalFunc) script_fu_font_preview_callback,
  1401.                   &script->arg_values[i].sfa_font);      
  1402.       break;
  1403.  
  1404.     case SF_PATTERN:
  1405.       sf_interface->args_widgets[i] =
  1406.         gimp_pattern_select_widget(_("Script-fu Pattern Selection"),
  1407.                        script->arg_values[i].sfa_pattern, 
  1408.                        script_fu_pattern_preview,
  1409.                        &script->arg_values[i].sfa_pattern);
  1410.       break;
  1411.     case SF_GRADIENT:
  1412.       sf_interface->args_widgets[i] =
  1413.         gimp_gradient_select_widget(_("Script-Fu Gradient Selection"),
  1414.                     script->arg_values[i].sfa_gradient, 
  1415.                     script_fu_gradient_preview,
  1416.                     &script->arg_values[i].sfa_gradient);
  1417.       break;
  1418.  
  1419.     case SF_BRUSH:
  1420.       sf_interface->args_widgets[i] = 
  1421.         gimp_brush_select_widget(_("Script-Fu Brush Selection"),
  1422.                      script->arg_values[i].sfa_brush.name, 
  1423.                      script->arg_values[i].sfa_brush.opacity, 
  1424.                      script->arg_values[i].sfa_brush.spacing, 
  1425.                      script->arg_values[i].sfa_brush.paint_mode, 
  1426.                      script_fu_brush_preview,
  1427.                      &script->arg_values[i].sfa_brush);
  1428.       break;
  1429.  
  1430.     case SF_OPTION:
  1431.       sf_interface->args_widgets[i] = gtk_option_menu_new ();
  1432.       menu = gtk_menu_new ();
  1433.       for (list = script->arg_defaults[i].sfa_option.list, j = 0; 
  1434.            list; 
  1435.            list = g_slist_next (list), j++)
  1436.         {
  1437.           menu_item = gtk_menu_item_new_with_label (gettext ((gchar *)list->data));
  1438.           gtk_object_set_user_data (GTK_OBJECT (menu_item), 
  1439.                     GUINT_TO_POINTER (j));
  1440.           gtk_menu_append (GTK_MENU (menu), menu_item);
  1441.           gtk_widget_show (menu_item);
  1442.         }
  1443.       gtk_option_menu_set_menu (GTK_OPTION_MENU (sf_interface->args_widgets[i]),
  1444.                     menu);
  1445.       gtk_option_menu_set_history (GTK_OPTION_MENU (sf_interface->args_widgets[i]), 
  1446.                             script->arg_values[i].sfa_option.history);
  1447.       break;
  1448.       
  1449.     default:
  1450.       break;
  1451.     }
  1452.  
  1453.       gimp_table_attach_aligned (GTK_TABLE (table), 0, i,
  1454.                  label_text, 1.0, label_yalign,
  1455.                  sf_interface->args_widgets[i], 1, 
  1456.                  widget_leftalign);
  1457.       g_free (label_text);
  1458.     }
  1459.  
  1460.   gtk_widget_show (table);
  1461.  
  1462.   /*  Reset to defaults */
  1463.   hbox = gtk_hbox_new (FALSE, 0);
  1464.   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
  1465.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
  1466.  
  1467.   button = gtk_button_new_with_label (_("Reset to Defaults"));
  1468.   gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 2, 0);
  1469.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1470.                       (GtkSignalFunc) script_fu_reset_callback,
  1471.               script);
  1472.   gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1473.   gtk_widget_show (button);
  1474.   gtk_widget_show (hbox);
  1475.  
  1476.   gtk_widget_show (vbox);
  1477.   gtk_widget_show (frame);
  1478.  
  1479.   /*  Separator  */
  1480.   sep = gtk_hseparator_new ();
  1481.   gtk_box_pack_start (GTK_BOX (main_box), sep, FALSE, FALSE, 0);
  1482.   gtk_widget_show (sep);
  1483.  
  1484.   /*  Action area  */
  1485.   hbox = gtk_hbox_new (FALSE, 0);
  1486.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
  1487.   gtk_box_pack_start (GTK_BOX (main_box), hbox, FALSE, TRUE, 0);
  1488.  
  1489.   bbox = gtk_hbutton_box_new ();
  1490.   gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 4);
  1491.   gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);
  1492.  
  1493.   button = gtk_button_new_with_label (_("About"));
  1494.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  1495.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1496.                       GTK_SIGNAL_FUNC (script_fu_about_callback),
  1497.                       script);
  1498.   gtk_container_add (GTK_CONTAINER (bbox), button);  
  1499.   gtk_widget_show (button);
  1500.  
  1501.   gtk_widget_show (bbox);
  1502.  
  1503.   bbox = gtk_hbutton_box_new ();
  1504.   gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 4);
  1505.   gtk_box_pack_end (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);
  1506.  
  1507.   button = gtk_button_new_with_label (_("OK"));
  1508.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  1509.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1510.               GTK_SIGNAL_FUNC (script_fu_ok_callback),
  1511.               script);
  1512.   gtk_container_add (GTK_CONTAINER (bbox), button);  
  1513.   gtk_widget_grab_default (button);
  1514.   gtk_widget_show (button);
  1515.  
  1516.   button = gtk_button_new_with_label (_("Cancel"));
  1517.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  1518.   gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
  1519.                  GTK_SIGNAL_FUNC (script_fu_interface_quit),
  1520.                  (GtkObject *) script);
  1521.   gtk_container_add (GTK_CONTAINER (bbox), button);  
  1522.   gtk_widget_show (button);
  1523.  
  1524.   gtk_widget_show (bbox);
  1525.   gtk_widget_show (hbox);
  1526.  
  1527.   /* The statusbar (well it's a faked statusbar...) */
  1528.   hbox = gtk_hbox_new (FALSE, 0);
  1529.   gtk_box_pack_start (GTK_BOX (main_box), hbox, FALSE, FALSE, 2);
  1530.   gtk_widget_show (hbox);
  1531.  
  1532.   sf_interface->status = gtk_entry_new ();
  1533.   gtk_entry_set_editable (GTK_ENTRY (sf_interface->status), FALSE);
  1534.   gtk_box_pack_start (GTK_BOX (hbox), sf_interface->status, TRUE, TRUE, 2);
  1535.   gtk_entry_set_text (GTK_ENTRY (sf_interface->status), 
  1536.               sf_interface->window_title);
  1537.   gtk_widget_show (sf_interface->status);
  1538.  
  1539.   gtk_widget_show (main_box);
  1540.   gtk_widget_show (dlg);
  1541.  
  1542.   gtk_main ();
  1543. }
  1544.  
  1545. static void
  1546. script_fu_interface_quit (SFScript *script)
  1547. {
  1548.   gint i;
  1549.  
  1550.   g_return_if_fail (script != NULL);
  1551.   g_return_if_fail (sf_interface != NULL);  
  1552.  
  1553.   g_free (sf_interface->window_title);
  1554.  
  1555.   if (sf_interface->about_dialog)
  1556.     gtk_widget_destroy (sf_interface->about_dialog);
  1557.  
  1558.   for (i = 0; i < script->num_args; i++)
  1559.     switch (script->arg_types[i])
  1560.       {
  1561.       case SF_FONT:
  1562.     if (script->arg_values[i].sfa_font.dialog != NULL)
  1563.       {
  1564.         gtk_widget_destroy (script->arg_values[i].sfa_font.dialog);
  1565.         script->arg_values[i].sfa_font.dialog = NULL;
  1566.       }
  1567.     break;
  1568.  
  1569.       case SF_PATTERN:
  1570.       gimp_pattern_select_widget_close_popup (sf_interface->args_widgets[i]); 
  1571.     break;
  1572.  
  1573.       case SF_GRADIENT:
  1574.       gimp_gradient_select_widget_close_popup (sf_interface->args_widgets[i]); 
  1575.     break;
  1576.  
  1577.       case SF_BRUSH:
  1578.       gimp_brush_select_widget_close_popup (sf_interface->args_widgets[i]); 
  1579.     break;
  1580.  
  1581.       default:
  1582.     break;
  1583.       }
  1584.  
  1585.   g_free (sf_interface->args_widgets);
  1586.   g_free (sf_interface->last_command);
  1587.  
  1588.   g_free (sf_interface);
  1589.   sf_interface = NULL;
  1590.  
  1591.   /*  
  1592.    *  We do not call gtk_main_quit() earlier to reduce the possibility
  1593.    *  that script_fu_script_proc() is called from gimp_extension_process()
  1594.    *  while we are not finished with the current script. This sucks!
  1595.    */
  1596.  
  1597.   gtk_main_quit ();
  1598. }
  1599.  
  1600. static void
  1601. script_fu_pattern_preview (gchar    *name,
  1602.                gint      width,
  1603.                gint      height,
  1604.                gint      bytes,
  1605.                gchar    *mask_data,
  1606.                gint      closing,
  1607.                gpointer  data)
  1608. {
  1609.   gchar **pname;
  1610.  
  1611.   pname = (gchar **) data;
  1612.  
  1613.   g_free (*pname);
  1614.   *pname = g_strdup (name);
  1615. }
  1616.  
  1617. static void
  1618. script_fu_gradient_preview (gchar    *name,
  1619.                 gint      width,
  1620.                 gdouble  *mask_data,
  1621.                 gint      closing,
  1622.                 gpointer  data)
  1623. {
  1624.   gchar **gname;
  1625.  
  1626.   gname = (gchar **) data;
  1627.  
  1628.   g_free (*gname);
  1629.   *gname = g_strdup (name);
  1630. }
  1631.  
  1632. static void      
  1633. script_fu_brush_preview (gchar    *name,
  1634.              gdouble   opacity,
  1635.              gint      spacing,
  1636.              gint      paint_mode,
  1637.              gint      width,
  1638.              gint      height,
  1639.              gchar    *mask_data,
  1640.              gint      closing,
  1641.              gpointer  data)
  1642. {
  1643.   SFBrush *brush;
  1644.  
  1645.   brush = (SFBrush *) data;
  1646.  
  1647.   g_free (brush->name);
  1648.   brush->name       = g_strdup (name);
  1649.   brush->opacity    = opacity;
  1650.   brush->spacing    = spacing;
  1651.   brush->paint_mode = paint_mode;
  1652. }
  1653.  
  1654. static void
  1655. script_fu_font_preview (GtkWidget *preview,
  1656.             gchar     *data)
  1657. {
  1658.   GdkFont *font;
  1659.   gchar *fontname;
  1660.   gchar *family;
  1661.  
  1662.   if (data == NULL) 
  1663.     return;
  1664.  
  1665.   fontname = g_strdup (data);
  1666.  
  1667.   /* Check if the fontname is valid and the font is present */
  1668.   font = gdk_font_load (fontname);
  1669.  
  1670.   if (font != NULL)
  1671.     {
  1672.       gdk_font_unref (font);
  1673.  
  1674.       strtok (fontname, "-");
  1675.       family = strtok (NULL, "-");
  1676.       g_strup (family);
  1677.  
  1678.       gtk_label_set_text (GTK_LABEL (preview), family);
  1679.     }
  1680.   else
  1681.     {
  1682.       gtk_label_set_text (GTK_LABEL (preview), _("NOT SET"));
  1683.     }
  1684.   
  1685.   g_free (fontname);
  1686. }
  1687.  
  1688. static void
  1689. script_fu_ok_callback (GtkWidget *widget,
  1690.                gpointer   data)
  1691. {
  1692.   GdkFont   *font;
  1693.   GtkWidget *menu_item;
  1694.   gchar     *escaped;
  1695.   gchar     *text = NULL;
  1696.   gchar     *command;
  1697.   gchar     *c;
  1698.   gchar      buffer[MAX_STRING_LENGTH];
  1699.   gint       length;
  1700.   gint       i;
  1701.  
  1702.   SFScript  *script = (SFScript *) data;
  1703.   
  1704.   /* Check if choosen fonts are there */
  1705.   for (i = 0; i < script->num_args; i++)
  1706.     if (script->arg_types[i] == SF_FONT)
  1707.       {
  1708.     font = gdk_font_load (script->arg_values[i].sfa_font.fontname);
  1709.     if (font == NULL)
  1710.       {
  1711.         g_message (_("At least one font you've choosen is invalid.\n"
  1712.              "Please check your settings.\n"));
  1713.         return;
  1714.       }
  1715.     else
  1716.       gdk_font_unref (font);
  1717.       }
  1718.   
  1719.   length = strlen (script->script_name) + 3;
  1720.  
  1721.   for (i = 0; i < script->num_args; i++)
  1722.     switch (script->arg_types[i])
  1723.       {
  1724.       case SF_IMAGE:
  1725.       case SF_DRAWABLE:
  1726.       case SF_LAYER:
  1727.       case SF_CHANNEL:
  1728.     length += 12;  /*  Maximum size of integer value will not exceed this many characters  */
  1729.     break;
  1730.  
  1731.       case SF_COLOR:
  1732.     length += 16;  /*  Maximum size of color string: '(XXX XXX XXX)  */
  1733.     break;
  1734.  
  1735.       case SF_TOGGLE:
  1736.     length += 6;   /*  Maximum size of (TRUE, FALSE)  */
  1737.     break;
  1738.  
  1739.       case SF_VALUE:
  1740.     length += strlen (gtk_entry_get_text (GTK_ENTRY (sf_interface->args_widgets[i]))) + 1;
  1741.     break;
  1742.  
  1743.       case SF_STRING:
  1744.     escaped = ESCAPE (gtk_entry_get_text (GTK_ENTRY (sf_interface->args_widgets[i])));
  1745.     length += strlen (escaped) + 3;
  1746.     g_free (escaped);
  1747.     break;
  1748.  
  1749.       case SF_ADJUSTMENT:
  1750.     length += 24;  /*  Maximum size of float value should not exceed this many characters  */
  1751.     break;
  1752.  
  1753.       case SF_FILENAME:
  1754.     escaped = ESCAPE (script->arg_values[i].sfa_file.filename);
  1755.     length += strlen (escaped) + 3;
  1756.     g_free (escaped);
  1757.     break;
  1758.  
  1759.       case SF_FONT:
  1760.     length += strlen (script->arg_values[i].sfa_font.fontname) + 3;
  1761.     break;
  1762.  
  1763.       case SF_PATTERN:
  1764.     length += strlen (script->arg_values[i].sfa_pattern) + 3;
  1765.     break;
  1766.  
  1767.       case SF_GRADIENT:
  1768.     length += strlen (script->arg_values[i].sfa_gradient) + 3;
  1769.     break;
  1770.  
  1771.       case SF_BRUSH:
  1772.     length += strlen (script->arg_values[i].sfa_brush.name) + 3;
  1773.     length += 36; /* Maximum size of three ints for opacity, spacing,mode*/
  1774.     break;
  1775.  
  1776.       case SF_OPTION:
  1777.     length += 12;  /*  Maximum size of integer value will not exceed this many characters  */
  1778.     break;
  1779.  
  1780.       default:
  1781.     break;
  1782.       }
  1783.  
  1784.   c = command = g_new (gchar, length);
  1785.  
  1786.   sprintf (command, "(%s ", script->script_name);
  1787.   c += strlen (script->script_name) + 2;
  1788.   for (i = 0; i < script->num_args; i++)
  1789.     {
  1790.       switch (script->arg_types[i])
  1791.     {
  1792.     case SF_IMAGE:
  1793.     case SF_DRAWABLE:
  1794.     case SF_LAYER:
  1795.     case SF_CHANNEL:
  1796.       g_snprintf (buffer, sizeof (buffer), "%d",
  1797.               script->arg_values[i].sfa_image);
  1798.       text = buffer;
  1799.       break;
  1800.  
  1801.      case SF_COLOR:
  1802.       g_snprintf (buffer, sizeof (buffer), "'(%d %d %d)",
  1803.               script->arg_values[i].sfa_color[0],
  1804.               script->arg_values[i].sfa_color[1],
  1805.               script->arg_values[i].sfa_color[2]);
  1806.       text = buffer;
  1807.       break;
  1808.  
  1809.     case SF_TOGGLE:
  1810.       g_snprintf (buffer, sizeof (buffer), "%s",
  1811.               (script->arg_values[i].sfa_toggle) ? "TRUE" : "FALSE");
  1812.       text = buffer;
  1813.       break;
  1814.  
  1815.     case SF_VALUE:
  1816.       text = gtk_entry_get_text (GTK_ENTRY (sf_interface->args_widgets[i]));
  1817.       g_free (script->arg_values[i].sfa_value);
  1818.       script->arg_values[i].sfa_value = g_strdup (text); 
  1819.       break;
  1820.  
  1821.     case SF_STRING:
  1822.       text = gtk_entry_get_text (GTK_ENTRY (sf_interface->args_widgets[i]));
  1823.       g_free (script->arg_values[i].sfa_value);
  1824.       script->arg_values[i].sfa_value = g_strdup (text); 
  1825.       escaped = ESCAPE (text);
  1826.       g_snprintf (buffer, sizeof (buffer), "\"%s\"", escaped);
  1827.       g_free (escaped);
  1828.       text = buffer;
  1829.       break;
  1830.  
  1831.     case SF_ADJUSTMENT:
  1832.       switch (script->arg_defaults[i].sfa_adjustment.type)
  1833.         {
  1834.         case SF_SLIDER:
  1835.           script->arg_values[i].sfa_adjustment.value =
  1836.         script->arg_values[i].sfa_adjustment.adj->value;
  1837.           g_snprintf (buffer, sizeof (buffer), "%f",
  1838.               script->arg_values[i].sfa_adjustment.value);
  1839.           text = buffer;
  1840.           break;
  1841.  
  1842.         case SF_SPINNER:
  1843.           script->arg_values[i].sfa_adjustment.value = 
  1844.         gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (sf_interface->args_widgets[i]));
  1845.           g_snprintf (buffer, sizeof (buffer), "%f",
  1846.               script->arg_values[i].sfa_adjustment.value);
  1847.           text = buffer;
  1848.           break;
  1849.  
  1850.         default:
  1851.           break;
  1852.         }
  1853.       break;
  1854.  
  1855.     case SF_FILENAME:
  1856.       escaped = ESCAPE (script->arg_values[i].sfa_file.filename);
  1857.       g_snprintf (buffer, sizeof (buffer), "\"%s\"", escaped);
  1858.       g_free (escaped);
  1859.       text = buffer;
  1860.       break;
  1861.  
  1862.     case SF_FONT:
  1863.       g_snprintf (buffer, sizeof (buffer), "\"%s\"",
  1864.               script->arg_values[i].sfa_font.fontname);
  1865.       text = buffer;
  1866.       break;
  1867.  
  1868.     case SF_PATTERN:
  1869.       g_snprintf (buffer, sizeof (buffer), "\"%s\"",
  1870.               script->arg_values[i].sfa_pattern);
  1871.       text = buffer;
  1872.       break;
  1873.  
  1874.     case SF_GRADIENT:
  1875.       g_snprintf (buffer, sizeof (buffer), "\"%s\"",
  1876.               script->arg_values[i].sfa_gradient);
  1877.       text = buffer;
  1878.       break;
  1879.  
  1880.     case SF_BRUSH:
  1881.       g_snprintf (buffer, sizeof (buffer), "'(\"%s\" %f %d %d)",
  1882.               script->arg_values[i].sfa_brush.name,
  1883.               script->arg_values[i].sfa_brush.opacity,
  1884.               script->arg_values[i].sfa_brush.spacing,
  1885.               script->arg_values[i].sfa_brush.paint_mode);
  1886.       text = buffer;
  1887.       break;
  1888.  
  1889.     case SF_OPTION:
  1890.       menu_item = 
  1891.         gtk_menu_get_active (GTK_MENU (gtk_option_menu_get_menu (GTK_OPTION_MENU (sf_interface->args_widgets[i]))));
  1892.       script->arg_values[i].sfa_option.history = 
  1893.         GPOINTER_TO_UINT (gtk_object_get_user_data (GTK_OBJECT (menu_item))); 
  1894.       g_snprintf (buffer, sizeof (buffer), "%d",
  1895.               script->arg_values[i].sfa_option.history);
  1896.       text = buffer;
  1897.       break;
  1898.  
  1899.     default:
  1900.       break;
  1901.     }
  1902.  
  1903.       if (i == script->num_args - 1)
  1904.     sprintf (c, "%s)", text);
  1905.       else
  1906.     sprintf (c, "%s ", text);
  1907.       c += strlen (text) + 1;
  1908.     }
  1909.  
  1910.   /*  run the command through the interpreter  */
  1911.   if (repl_c_string (command, 0, 0, 1) != 0)
  1912.     script_fu_error_msg (command);
  1913.  
  1914.   g_free (command);
  1915.  
  1916.   script_fu_interface_quit (script);
  1917. }
  1918.  
  1919. static void
  1920. script_fu_about_callback (GtkWidget *widget,
  1921.               gpointer   data)
  1922. {
  1923.   GtkWidget *dialog;
  1924.   GtkWidget *frame;
  1925.   GtkWidget *vbox;
  1926.   GtkWidget *hbox;
  1927.   GtkWidget *button;
  1928.   GtkWidget *label;
  1929.   GtkWidget *table;
  1930.   GtkWidget *text;
  1931.   GtkWidget *vscrollbar;
  1932.  
  1933.   SFScript  *script = (SFScript *) data;
  1934.  
  1935.   if (sf_interface->about_dialog == NULL)
  1936.     {
  1937.       dialog = gtk_dialog_new ();
  1938.       gtk_window_set_title (GTK_WINDOW (dialog), sf_interface->window_title);
  1939.       gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
  1940.       gtk_signal_connect_object (GTK_OBJECT (dialog), "delete_event",
  1941.                  GTK_SIGNAL_FUNC (gtk_widget_destroy),
  1942.                  GTK_OBJECT (dialog));
  1943.  
  1944.       gimp_help_connect_help_accel (dialog, gimp_standard_help_func,
  1945.                     "filters/script-fu.html");
  1946.   
  1947.       frame = gtk_frame_new (NULL);
  1948.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  1949.       gtk_container_set_border_width (GTK_CONTAINER (frame), 2);
  1950.       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame,
  1951.               TRUE, TRUE, 0);
  1952.       gtk_widget_show (frame);
  1953.       
  1954.       vbox = gtk_vbox_new (FALSE, 2);
  1955.       gtk_container_add (GTK_CONTAINER (frame), vbox);
  1956.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  1957.       gtk_widget_show (vbox);
  1958.  
  1959.       /* the name */
  1960.       hbox = gtk_hbox_new (FALSE, 2);
  1961.       gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
  1962.       gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  1963.       gtk_widget_show (hbox);
  1964.       
  1965.       label = gtk_label_new (script->script_name);
  1966.       gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
  1967.       gtk_widget_show (label);
  1968.  
  1969.       /* the help display */
  1970.       table = gtk_table_new (2, 2, FALSE);
  1971.       gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
  1972.       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
  1973.       gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
  1974.       gtk_widget_show (table);
  1975.  
  1976.       text = gtk_text_new (NULL, NULL);
  1977.       gtk_text_set_editable (GTK_TEXT (text), FALSE);
  1978.       gtk_text_set_word_wrap (GTK_TEXT (text), TRUE);      
  1979.       gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
  1980.             GTK_EXPAND | GTK_SHRINK | GTK_FILL,
  1981.             GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  1982.       gtk_widget_set_usize (text, 200, 60);
  1983.       gtk_widget_show (text);
  1984.  
  1985.       vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
  1986.       gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
  1987.             GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  1988.       gtk_widget_show (vscrollbar);
  1989.  
  1990.       gtk_widget_realize (text);
  1991.       gtk_text_freeze (GTK_TEXT (text));
  1992.       gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
  1993.                script->help, -1);
  1994.    
  1995.       /* author, copyright, etc. */
  1996.       table = gtk_table_new (2, 4, FALSE);
  1997.       gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1998.       gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  1999.       gtk_widget_show (table);
  2000.  
  2001.       label = gtk_label_new (script->author);
  2002.       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  2003.       gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  2004.                  _("Author:"), 1.0, 0.5,
  2005.                  label, 1, FALSE);
  2006.  
  2007.       label = gtk_label_new (script->copyright);
  2008.       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); 
  2009.       gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
  2010.                  _("Copyright:"), 1.0, 0.5,
  2011.                  label, 1, FALSE);
  2012.  
  2013.       label = gtk_label_new (script->date);
  2014.       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); 
  2015.       gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
  2016.                  _("Date:"), 1.0, 0.5,
  2017.                  label, 1, FALSE);
  2018.  
  2019.       if (strlen (script->img_types) > 0)
  2020.     {
  2021.       label = gtk_label_new (script->img_types);
  2022.       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); 
  2023.       gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
  2024.                      _("Image Types:"), 1.0, 0.5,
  2025.                      label, 1, FALSE);
  2026.     }
  2027.  
  2028.       gtk_widget_show (frame);
  2029.       gtk_text_thaw (GTK_TEXT (text));
  2030.  
  2031.       /*  action area  */
  2032.       gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 2);
  2033.       button = gtk_button_new_with_label (_("Close"));
  2034.       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  2035.       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
  2036.                  GTK_SIGNAL_FUNC (gtk_widget_destroy),
  2037.                  GTK_OBJECT (dialog));
  2038.       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), 
  2039.               button, TRUE, TRUE, 0);
  2040.       gtk_widget_grab_default (button);
  2041.       gtk_widget_show (button);
  2042.  
  2043.       sf_interface->about_dialog = dialog;
  2044.  
  2045.       gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  2046.               GTK_SIGNAL_FUNC (gtk_widget_destroyed),
  2047.               &sf_interface->about_dialog);
  2048.     }
  2049.  
  2050.   gtk_window_set_position (GTK_WINDOW (sf_interface->about_dialog),
  2051.                GTK_WIN_POS_MOUSE);  
  2052.   gtk_widget_show (sf_interface->about_dialog);
  2053. }
  2054.  
  2055. static void
  2056. script_fu_reset_callback (GtkWidget *widget,
  2057.               gpointer   data)
  2058. {
  2059.   gint i, j;
  2060.  
  2061.   SFScript *script = (SFScript *) data;
  2062.  
  2063.   for (i = 0; i < script->num_args; i++)
  2064.     switch (script->arg_types[i])
  2065.       {
  2066.       case SF_IMAGE:
  2067.       case SF_DRAWABLE:
  2068.       case SF_LAYER:
  2069.       case SF_CHANNEL:
  2070.     break;
  2071.  
  2072.       case SF_COLOR:
  2073.     for (j = 0; j < 3; j++)
  2074.       {
  2075.         script->arg_values[i].sfa_color[j] = 
  2076.           script->arg_defaults[i].sfa_color[j];
  2077.       }
  2078.     gimp_color_button_update (GIMP_COLOR_BUTTON (sf_interface->args_widgets[i]));
  2079.     break;
  2080.  
  2081.       case SF_TOGGLE:
  2082.     script->arg_values[i].sfa_toggle = script->arg_defaults[i].sfa_toggle;
  2083.     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sf_interface->args_widgets[i]),
  2084.                       script->arg_values[i].sfa_toggle);
  2085.     break;
  2086.  
  2087.       case SF_VALUE:
  2088.       case SF_STRING:
  2089.     g_free (script->arg_values[i].sfa_value);
  2090.     script->arg_values[i].sfa_value =
  2091.       g_strdup (script->arg_defaults[i].sfa_value); 
  2092.     gtk_entry_set_text (GTK_ENTRY (sf_interface->args_widgets[i]), 
  2093.                 script->arg_values[i].sfa_value);
  2094.     break;
  2095.  
  2096.       case SF_ADJUSTMENT:
  2097.     script->arg_values[i].sfa_adjustment.value =
  2098.       script->arg_defaults[i].sfa_adjustment.value;
  2099.     gtk_adjustment_set_value (script->arg_values[i].sfa_adjustment.adj, 
  2100.                   script->arg_values[i].sfa_adjustment.value);
  2101.     break;
  2102.  
  2103.       case SF_FILENAME:
  2104.     g_free (script->arg_values[i].sfa_file.filename);
  2105.     script->arg_values[i].sfa_file.filename =
  2106.       g_strdup (script->arg_defaults[i].sfa_file.filename);
  2107.     gimp_file_selection_set_filename
  2108.       (GIMP_FILE_SELECTION (script->arg_values[i].sfa_file.fileselection),
  2109.        script->arg_values[i].sfa_file.filename);
  2110.     break;
  2111.  
  2112.       case SF_FONT:
  2113.     g_free (script->arg_values[i].sfa_font.fontname);
  2114.     script->arg_values[i].sfa_font.fontname =
  2115.       g_strdup (script->arg_defaults[i].sfa_font.fontname);
  2116.     if (script->arg_values[i].sfa_font.dialog)
  2117.       {
  2118.         gtk_font_selection_dialog_set_font_name
  2119.           (GTK_FONT_SELECTION_DIALOG (script->arg_values[i].sfa_font.dialog),
  2120.            script->arg_values[i].sfa_font.fontname);
  2121.       }    
  2122.     script_fu_font_preview (script->arg_values[i].sfa_font.preview,
  2123.                 script->arg_values[i].sfa_font.fontname);
  2124.     break;
  2125.  
  2126.       case SF_PATTERN:
  2127.       gimp_pattern_select_widget_set_popup
  2128.       (sf_interface->args_widgets[i], script->arg_defaults[i].sfa_pattern);  
  2129.     break;
  2130.  
  2131.       case SF_GRADIENT:
  2132.       gimp_gradient_select_widget_set_popup
  2133.       (sf_interface->args_widgets[i], script->arg_defaults[i].sfa_gradient);  
  2134.     break;
  2135.  
  2136.       case SF_BRUSH:
  2137.       gimp_brush_select_widget_set_popup
  2138.       (sf_interface->args_widgets[i],
  2139.        script->arg_defaults[i].sfa_brush.name,
  2140.        script->arg_defaults[i].sfa_brush.opacity, 
  2141.        script->arg_defaults[i].sfa_brush.spacing, 
  2142.        script->arg_defaults[i].sfa_brush.paint_mode);  
  2143.     break;
  2144.  
  2145.       case SF_OPTION:
  2146.     script->arg_values[i].sfa_option.history = 
  2147.       script->arg_defaults[i].sfa_option.history;
  2148.     gtk_option_menu_set_history (GTK_OPTION_MENU (sf_interface->args_widgets[i]), 
  2149.                      script->arg_values[i].sfa_option.history);
  2150.  
  2151.       default:
  2152.     break;
  2153.       }
  2154. }
  2155.  
  2156. static void
  2157. script_fu_menu_callback  (gint32   id,
  2158.               gpointer data)
  2159. {
  2160.   *((gint32 *) data) = id;
  2161. }
  2162.  
  2163. static void
  2164. script_fu_file_selection_callback (GtkWidget *widget,
  2165.                    gpointer   data)
  2166. {
  2167.   SFFilename *file;
  2168.  
  2169.   file = (SFFilename *) data;
  2170.  
  2171.   if (file->filename)
  2172.     g_free (file->filename);
  2173.  
  2174.   file->filename = 
  2175.     gimp_file_selection_get_filename (GIMP_FILE_SELECTION (file->fileselection));
  2176. }
  2177.  
  2178. static void
  2179. script_fu_font_preview_callback (GtkWidget *widget,
  2180.                  gpointer   data)
  2181. {
  2182.   GtkFontSelectionDialog *fsd;
  2183.   SFFont *font;
  2184.  
  2185.   font = (SFFont *) data;
  2186.  
  2187.   if (!font->dialog)
  2188.     {
  2189.       font->dialog = gtk_font_selection_dialog_new (_("Script-Fu Font Selection"));
  2190.       fsd = GTK_FONT_SELECTION_DIALOG (font->dialog);
  2191.  
  2192.       gtk_signal_connect (GTK_OBJECT (fsd->ok_button), "clicked",
  2193.               GTK_SIGNAL_FUNC (script_fu_font_dialog_ok),
  2194.               font);
  2195.       gtk_signal_connect (GTK_OBJECT (fsd), "delete_event",
  2196.               GTK_SIGNAL_FUNC (script_fu_font_dialog_delete),
  2197.               font);
  2198.       gtk_signal_connect (GTK_OBJECT (fsd), "destroy",
  2199.               GTK_SIGNAL_FUNC (gtk_widget_destroyed),
  2200.               &font->dialog);
  2201.       gtk_signal_connect (GTK_OBJECT (fsd->cancel_button), "clicked",
  2202.               GTK_SIGNAL_FUNC (script_fu_font_dialog_cancel),
  2203.               font);
  2204.     }
  2205.   else
  2206.     fsd = GTK_FONT_SELECTION_DIALOG (font->dialog);
  2207.  
  2208.   gtk_font_selection_dialog_set_font_name (fsd, font->fontname);
  2209.   gtk_window_set_position (GTK_WINDOW (font->dialog), GTK_WIN_POS_MOUSE);
  2210.   gtk_widget_show (font->dialog);
  2211. }
  2212.  
  2213. static void
  2214. script_fu_font_dialog_ok (GtkWidget *widget,
  2215.               gpointer   data)
  2216. {
  2217.   SFFont *font;
  2218.   gchar  *fontname;
  2219.  
  2220.   font = (SFFont *) data;
  2221.  
  2222.   fontname = gtk_font_selection_dialog_get_font_name (GTK_FONT_SELECTION_DIALOG (font->dialog));
  2223.   if (fontname != NULL)
  2224.     {
  2225.       g_free (font->fontname);
  2226.       font->fontname = fontname;
  2227.     }
  2228.   gtk_widget_hide (font->dialog);
  2229.  
  2230.   script_fu_font_preview (font->preview, font->fontname);
  2231. }
  2232.  
  2233. static void
  2234. script_fu_font_dialog_cancel (GtkWidget *widget,
  2235.                   gpointer   data)
  2236. {
  2237.   SFFont *font;
  2238.  
  2239.   font = (SFFont *) data;
  2240.  
  2241.   gtk_widget_hide (font->dialog);
  2242. }
  2243.  
  2244. static gint
  2245. script_fu_font_dialog_delete (GtkWidget *widget,
  2246.                   GdkEvent  *event,
  2247.                   gpointer   data)
  2248. {
  2249.   script_fu_font_dialog_cancel (widget, data);
  2250.   return TRUE;
  2251. }
  2252.  
  2253. static void
  2254. script_fu_error_msg (gchar *command)
  2255. {
  2256.   g_message (_("Script-Fu Error while executing\n %s\n%s"), 
  2257.          command, siod_err_msg);
  2258. }
  2259.