/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdlib.h>
#include <stdio.h>
#include "appenv.h"
#include "about_dialog.h"
#include "actionarea.h"
#include "app_procs.h"
#include "brightness_contrast.h"
#include "brushes.h"
#include "by_color_select.h"
#include "channels_dialog.h"
#include "colormaps.h"
#include "color_balance.h"
#include "commands.h"
#include "convert.h"
#include "curves.h"
#include "desaturate.h"
#include "channel_ops.h"
#include "drawable.h"
#include "equalize.h"
#include "fileops.h"
#include "floating_sel.h"
#include "gdisplay_ops.h"
#include "general.h"
#include "gimage_cmds.h"
#include "gimage_mask.h"
#include "gimprc.h"
#include "global_edit.h"
#include "gradient.h"
#include "histogram_tool.h"
#include "hue_saturation.h"
#include "image_render.h"
#include "indexed_palette.h"
#include "info_window.h"
#include "interface.h"
#include "invert.h"
#include "layers_dialog.h"
#include "layer_select.h"
#include "levels.h"
#include "palette.h"
#include "patterns.h"
#include "plug_in.h"
#include "posterize.h"
#include "resize.h"
#include "scale.h"
#include "threshold.h"
#include "tips_dialog.h"
#include "tools.h"
#include "undo.h"

/*  external functions  */
extern void layers_dialog_layer_merge_query (GImage *, int);

typedef struct {
  GtkWidget *dlg;
  GtkWidget *height_entry;
  GtkWidget *width_entry;
  int width;
  int height;
  int type;
  int fill_type;
} NewImageValues;

typedef struct
{
  GtkWidget * shell;
  Resize *    resize;
  int         gimage_id;
} ImageResize;

/*  new image local functions  */
static void file_new_ok_callback (GtkWidget *, gpointer);
static void file_new_cancel_callback (GtkWidget *, gpointer);
static gint file_new_delete_callback (GtkWidget *, GdkEvent *, gpointer);
static void file_new_toggle_callback (GtkWidget *, gpointer);

/*  static variables  */
static   int          last_width = 256;
static   int          last_height = 256;
static   int          last_type = RGB;
static   int          last_fill_type = BACKGROUND_FILL;

/*  preferences local functions  */
static void file_prefs_ok_callback (GtkWidget *, GtkWidget *);
static void file_prefs_save_callback (GtkWidget *, GtkWidget *);
static void file_prefs_cancel_callback (GtkWidget *, GtkWidget *);
static gint file_prefs_delete_callback (GtkWidget *, GdkEvent *, GtkWidget *);
static void file_prefs_toggle_callback (GtkWidget *, gpointer);
static void file_prefs_text_callback (GtkWidget *, gpointer);
static void file_prefs_preview_size_callback (GtkWidget *, gpointer);

/*  static variables  */
static   GtkWidget   *prefs_dlg = NULL;
static   int          old_transparency_type;
static   int          old_transparency_size;
static   int          old_levels_of_undo;
static   int          old_marching_speed;
static   int          old_allow_resize_windows;
static   int          old_auto_save;
static   int          old_preview_size;
static   int          old_no_cursor_updating;
static   int          old_show_tool_tips;
static   int          old_cubic_interpolation;
static   int          old_confirm_on_close;
static   int          old_default_width;
static   int          old_default_height;
static   int          old_default_type;
static   int          new_dialog_run;
static   int          old_stingy_memory_use;
static   int          old_tile_cache_size;
static   int          old_install_cmap;
static   int          old_cycled_marching_ants;
static   char *       old_temp_path;
static   char *       old_swap_path;
static   char *       old_brush_path;
static   char *       old_pattern_path;
static   char *       old_palette_path;
static   char *       old_plug_in_path;
static   char *       old_gradient_path;

static   char *       edit_temp_path = NULL;
static   char *       edit_swap_path = NULL;
static   char *       edit_brush_path = NULL;
static   char *       edit_pattern_path = NULL;
static   char *       edit_palette_path = NULL;
static   char *       edit_plug_in_path = NULL;
static   char *       edit_gradient_path = NULL;
static   int          edit_stingy_memory_use;
static   int          edit_tile_cache_size;
static   int          edit_install_cmap;
static   int          edit_cycled_marching_ants;


/*  local functions  */
static void   image_resize_callback (GtkWidget *, gpointer);
static void   image_scale_callback (GtkWidget *, gpointer);
static void   image_cancel_callback (GtkWidget *, gpointer);
static gint   image_delete_callback (GtkWidget *, GdkEvent *, gpointer);
static void   gimage_mask_feather_callback (GtkWidget *, gpointer, gpointer);
static void   gimage_mask_border_callback (GtkWidget *, gpointer, gpointer);
static void   gimage_mask_grow_callback (GtkWidget *, gpointer, gpointer);
static void   gimage_mask_shrink_callback (GtkWidget *, gpointer, gpointer);

/*  variables declared in gimage_mask.c--we need them to set up
 *  initial values for the various dialog boxes which query for values
 */
extern double gimage_mask_feather_radius;
extern int    gimage_mask_border_radius;
extern int    gimage_mask_grow_pixels;
extern int    gimage_mask_shrink_pixels;


static void
file_new_ok_callback (GtkWidget *widget,
		      gpointer   data)
{
  NewImageValues *vals;
  GImage *gimage;
  GDisplay *gdisplay;
  Layer *layer;
  int type;

  vals = data;

  vals->width = atoi (gtk_entry_get_text (GTK_ENTRY (vals->width_entry)));
  vals->height = atoi (gtk_entry_get_text (GTK_ENTRY (vals->height_entry)));

  gtk_widget_destroy (vals->dlg);

  last_width = vals->width;
  last_height = vals->height;
  last_type = vals->type;
  last_fill_type = vals->fill_type;

  switch (vals->fill_type)
    {
    case BACKGROUND_FILL:
    case WHITE_FILL:
      type = (vals->type == RGB) ? RGB_GIMAGE : GRAY_GIMAGE;
      break;
    case TRANSPARENT_FILL:
      type = (vals->type == RGB) ? RGBA_GIMAGE : GRAYA_GIMAGE;
      break;
    default:
      type = RGB_IMAGE;
      break;
    }

  gimage = gimage_new (vals->width, vals->height, vals->type);

  /*  Make the background (or first) layer  */
  layer = layer_new (gimage->ID, gimage->width, gimage->height,
		     type, "Background", OPAQUE_OPACITY, NORMAL);

  if (layer) {
    /*  add the new layer to the gimage  */
    gimage_disable_undo (gimage);
    gimage_add_layer (gimage, layer, 0);
    gimage_enable_undo (gimage);
    
    drawable_fill (GIMP_DRAWABLE(layer), vals->fill_type);

    gimage_clean_all (gimage);
    
    gdisplay = gdisplay_new (gimage, 0x0101);
  }

  g_free (vals);
}

static gint
file_new_delete_callback (GtkWidget *widget,
			  GdkEvent *event,
			  gpointer data)
{
  file_new_cancel_callback (widget, data);

  return TRUE;
}
  

static void
file_new_cancel_callback (GtkWidget *widget,
			  gpointer   data)
{
  NewImageValues *vals;

  vals = data;

  gtk_widget_destroy (vals->dlg);
  g_free (vals);
}

static void
file_new_toggle_callback (GtkWidget *widget,
			  gpointer   data)
{
  int *val;

  if (GTK_TOGGLE_BUTTON (widget)->active)
    {
      val = data;
      *val = (long) gtk_object_get_user_data (GTK_OBJECT (widget));
    }
}

void
file_new_cmd_callback (GtkWidget *widget,
		       gpointer   client_data)
{
  GDisplay *gdisp;
  NewImageValues *vals;
  GtkWidget *button;
  GtkWidget *label;
  GtkWidget *vbox;
  GtkWidget *table;
  GtkWidget *frame;
  GtkWidget *radio_box;
  GSList *group;
  char buffer[32];

  if(!new_dialog_run)
    {
      last_width = default_width;
      last_height = default_height;
      last_type = default_type;
      new_dialog_run = 1;  
    }

  /*  Before we try to determine the responsible gdisplay,
   *  make sure this wasn't called from the toolbox
   */
  if ((long) client_data)
    gdisp = gdisplay_active ();
  else
    gdisp = NULL;

  vals = g_malloc (sizeof (NewImageValues));
  vals->fill_type = last_fill_type;

  if (gdisp)
    {
      vals->width = gdisp->gimage->width;
      vals->height = gdisp->gimage->height;
      vals->type = gimage_base_type (gdisp->gimage);
    }
  else
    {
      vals->width = last_width;
      vals->height = last_height;
      vals->type = last_type;
    }

  if (vals->type == INDEXED)
    vals->type = RGB;    /* no indexed images */

  vals->dlg = gtk_dialog_new ();
  gtk_window_set_wmclass (GTK_WINDOW (vals->dlg), "new_image", "Gimp");
  gtk_window_set_title (GTK_WINDOW (vals->dlg), "New Image");
  gtk_window_position (GTK_WINDOW (vals->dlg), GTK_WIN_POS_MOUSE);

  /* handle the wm close signal */
  gtk_signal_connect (GTK_OBJECT (vals->dlg), "delete_event",
		      GTK_SIGNAL_FUNC (file_new_delete_callback),
		      vals);

  gtk_container_border_width (GTK_CONTAINER (GTK_DIALOG (vals->dlg)->action_area), 2);

  button = gtk_button_new_with_label ("OK");
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
                      (GtkSignalFunc) file_new_ok_callback,
                      vals);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dlg)->action_area),
		      button, TRUE, TRUE, 0);
  gtk_widget_grab_default (button);
  gtk_widget_show (button);

  button = gtk_button_new_with_label ("Cancel");
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
                      (GtkSignalFunc) file_new_cancel_callback,
                      vals);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dlg)->action_area),
		      button, TRUE, TRUE, 0);
  gtk_widget_show (button);


  vbox = gtk_vbox_new (FALSE, 1);
  gtk_container_border_width (GTK_CONTAINER (vbox), 2);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dlg)->vbox),
		      vbox, TRUE, TRUE, 0);
  gtk_widget_show (vbox);

  table = gtk_table_new (2, 2, FALSE);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
  gtk_widget_show (table);

  label = gtk_label_new ("Width:");
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
		    GTK_FILL, GTK_FILL, 0, 0);
  gtk_widget_show (label);

  label = gtk_label_new ("Height:");
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
		    GTK_FILL, GTK_FILL, 0, 0);
  gtk_widget_show (label);

  vals->width_entry = gtk_entry_new ();
  gtk_widget_set_usize (vals->width_entry, 75, 0);
  sprintf (buffer, "%d", vals->width);
  gtk_entry_set_text (GTK_ENTRY (vals->width_entry), buffer);
  gtk_table_attach (GTK_TABLE (table), vals->width_entry, 1, 2, 0, 1,
		    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  gtk_widget_show (vals->width_entry);

  vals->height_entry = gtk_entry_new ();
  gtk_widget_set_usize (vals->height_entry, 75, 0);
  sprintf (buffer, "%d", vals->height);
  gtk_entry_set_text (GTK_ENTRY (vals->height_entry), buffer);
  gtk_table_attach (GTK_TABLE (table), vals->height_entry, 1, 2, 1, 2,
		    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  gtk_widget_show (vals->height_entry);


  frame = gtk_frame_new ("Image Type");
  gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  gtk_widget_show (frame);

  radio_box = gtk_vbox_new (FALSE, 1);
  gtk_container_border_width (GTK_CONTAINER (radio_box), 2);
  gtk_container_add (GTK_CONTAINER (frame), radio_box);
  gtk_widget_show (radio_box);

  button = gtk_radio_button_new_with_label (NULL, "RGB");
  group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  gtk_box_pack_start (GTK_BOX (radio_box), button, TRUE, TRUE, 0);
  gtk_object_set_user_data (GTK_OBJECT (button), (gpointer) RGB);
  gtk_signal_connect (GTK_OBJECT (button), "toggled",
		      (GtkSignalFunc) file_new_toggle_callback,
		      &vals->type);
  if (vals->type == RGB)
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_widget_show (button);

  button = gtk_radio_button_new_with_label (group, "Grayscale");
  group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  gtk_box_pack_start (GTK_BOX (radio_box), button, TRUE, TRUE, 0);
  gtk_object_set_user_data (GTK_OBJECT (button), (gpointer) GRAY);
  gtk_signal_connect (GTK_OBJECT (button), "toggled",
		      (GtkSignalFunc) file_new_toggle_callback,
		      &vals->type);
  if (vals->type == GRAY)
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_widget_show (button);


  frame = gtk_frame_new ("Fill Type");
  gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  gtk_widget_show (frame);

  radio_box = gtk_vbox_new (FALSE, 1);
  gtk_container_border_width (GTK_CONTAINER (radio_box), 2);
  gtk_container_add (GTK_CONTAINER (frame), radio_box);
  gtk_widget_show (radio_box);

  button = gtk_radio_button_new_with_label (NULL, "Background");
  group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  gtk_box_pack_start (GTK_BOX (radio_box), button, TRUE, TRUE, 0);
  gtk_object_set_user_data (GTK_OBJECT (button), (gpointer) BACKGROUND_FILL);
  gtk_signal_connect (GTK_OBJECT (button), "toggled",
		      (GtkSignalFunc) file_new_toggle_callback,
		      &vals->fill_type);
  if (vals->fill_type == BACKGROUND_FILL)
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_widget_show (button);

  button = gtk_radio_button_new_with_label (group, "White");
  group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  gtk_box_pack_start (GTK_BOX (radio_box), button, TRUE, TRUE, 0);
  gtk_object_set_user_data (GTK_OBJECT (button), (gpointer) WHITE_FILL);
  gtk_signal_connect (GTK_OBJECT (button), "toggled",
		      (GtkSignalFunc) file_new_toggle_callback,
		      &vals->fill_type);
  if (vals->fill_type == WHITE_FILL)
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_widget_show (button);

  button = gtk_radio_button_new_with_label (group, "Transparent");
  group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  gtk_box_pack_start (GTK_BOX (radio_box), button, TRUE, TRUE, 0);
  gtk_object_set_user_data (GTK_OBJECT (button), (gpointer) TRANSPARENT_FILL);
  gtk_signal_connect (GTK_OBJECT (button), "toggled",
		      (GtkSignalFunc) file_new_toggle_callback,
		      &vals->fill_type);
  if (vals->fill_type == TRANSPARENT_FILL)
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_widget_show (button);

  gtk_widget_show (vals->dlg);
}

void
file_open_cmd_callback (GtkWidget *widget,
			gpointer   client_data)
{
  file_open_callback (widget, client_data);
}

void
file_save_cmd_callback (GtkWidget *widget,
			gpointer   client_data)
{
  file_save_callback (widget, client_data);
}

void
file_save_as_cmd_callback (GtkWidget *widget,
			   gpointer   client_data)
{
  file_save_as_callback (widget, client_data);
}


/* Some information regarding preferences, compiled by Raph Levien 11/3/97.

   The following preference items cannot be set on the fly (at least
   according to the existing pref code - it may be that changing them
   so they're set on the fly is not hard).

   temp-path
   swap-path
   brush-path
   pattern-path
   plug-in-path
   palette-path
   gradient-path
   stingy-memory-use
   tile-cache-size
   install-cmap
   cycled-marching-ants

   All of these now have variables of the form edit_temp_path, which
   are copied from the actual variables (e.g. temp_path) the first time
   the dialog box is started.

   Variables of the form old_temp_path represent the values at the
   time the dialog is opened - a cancel copies them back from old to
   the real variables or the edit variables, depending on whether they
   can be set on the fly.

   Here are the remaining issues as I see them:

   Still no settings for default-brush, default-gradient,
   default-palette, default-pattern, gamma-correction, color-cube,
   show-rulers, ruler-units. No widget for confirm-on-close although
   a lot of stuff is there.

   No UI feedback for the fact that some settings won't take effect
   until the next Gimp restart.

   The semantics of "save" are a little funny - it only saves the
   settings that are different from the way they were when the dialog
   was opened. So you can set something, close the window, open it
   up again, click "save" and have nothing happen. To change this
   to more intuitive semantics, we should have a whole set of init_
   variables that are set the first time the dialog is opened (along
   with the edit_ variables that are currently set). Then, the save
   callback checks against the init_ variable rather than the old_.

   */

/* Copy the string from source to destination, freeing the string stored
   in the destination if there is one there already. */
static void
file_prefs_strset (char **dst, char *src)
{
  if (*dst != NULL)
    g_free (*dst);
  *dst = g_strdup (src);
}


/* Duplicate the string, but treat NULL as the empty string. */
static char *
file_prefs_strdup (char *src)
{
  return g_strdup (src == NULL ? "" : src);
}

/* Compare two strings, but treat NULL as the empty string. */
static int
file_prefs_strcmp (char *src1, char *src2)
{
  return strcmp (src1 == NULL ? "" : src1,
		   src2 == NULL ? "" : src2);
}

static void
file_prefs_ok_callback (GtkWidget *widget,
			GtkWidget *dlg)
{

  if (levels_of_undo < 0) 
    {
      message_box("Error: Levels of undo must be zero or greater.", 
		  NULL, NULL);
      levels_of_undo = old_levels_of_undo;
      return;
    }
  if (marching_speed < 50)
    {
      message_box("Error: Marching speed must be 50 or greater.",
		  NULL, NULL);
      marching_speed = old_marching_speed;
      return;
    }
  if (default_width < 1)
    {
      message_box("Error: Default width must be one or greater.",
		  NULL, NULL);
      default_width = old_default_width;
      return;
    }
  if (default_height < 1)
    {
      message_box("Error: Default height must be one or greater.",
		  NULL, NULL);
      default_height = old_default_height;
      return;
    }  
      
  gtk_widget_destroy (dlg);
  prefs_dlg = NULL;

  if (show_tool_tips)
    gtk_tooltips_enable (tool_tips);
  else
    gtk_tooltips_disable (tool_tips);
}

static void
file_prefs_save_callback (GtkWidget *widget,
			  GtkWidget *dlg)
{
  GList *update = NULL; /* options that should be updated in .gimprc */
  GList *remove = NULL; /* options that should be commented out */
  int save_stingy_memory_use;
  int save_tile_cache_size;
  int save_install_cmap;
  int save_cycled_marching_ants;
  gchar *save_temp_path;
  gchar *save_swap_path;
  gchar *save_brush_path;
  gchar *save_pattern_path;
  gchar *save_palette_path;
  gchar *save_plug_in_path;
  gchar *save_gradient_path;

  file_prefs_ok_callback (widget, dlg);

  /* Save variables so that we can restore them later */
  save_stingy_memory_use = stingy_memory_use;
  save_tile_cache_size = tile_cache_size;
  save_install_cmap = install_cmap;
  save_cycled_marching_ants = cycled_marching_ants;
  save_temp_path = temp_path;
  save_swap_path = swap_path;
  save_brush_path = brush_path;
  save_pattern_path = pattern_path;
  save_palette_path = palette_path;
  save_plug_in_path = plug_in_path;
  save_gradient_path = gradient_path;

  if (levels_of_undo != old_levels_of_undo)
    update = g_list_append (update, "undo-levels");
  if (marching_speed != old_marching_speed)
    update = g_list_append (update, "marching-ants-speed");
  if (allow_resize_windows != old_allow_resize_windows)
    update = g_list_append (update, "allow-resize-windows");
  if (auto_save != old_auto_save)
    {
      update = g_list_append (update, "auto-save");
      remove = g_list_append (remove, "dont-auto-save");
    }
  if (no_cursor_updating != old_no_cursor_updating)
    {
      update = g_list_append (update, "cursor-updating");
      remove = g_list_append (remove, "no-cursor-updating");
    }
  if (show_tool_tips != old_show_tool_tips)
    {
      update = g_list_append (update, "show-tool-tips");
      remove = g_list_append (remove, "dont-show-tool-tips");
    }
  if (cubic_interpolation != old_cubic_interpolation)
    update = g_list_append (update, "cubic-interpolation");
  if (confirm_on_close != old_confirm_on_close)
    update = g_list_append (update, "confirm-on-close");
  if (default_width != old_default_width ||
      default_height != old_default_height)
    update = g_list_append (update, "default-image-size");
  if (default_type != old_default_type)
    update = g_list_append (update, "default-image-type");
  if (preview_size != old_preview_size)
    update = g_list_append (update, "preview-size");
  if (transparency_type != old_transparency_type)
    update = g_list_append (update, "transparency-type");
  if (transparency_size != old_transparency_size)
    update = g_list_append (update, "transparency-size");
  if (edit_stingy_memory_use != stingy_memory_use)
    {
      update = g_list_append (update, "stingy-memory-use");
      stingy_memory_use = edit_stingy_memory_use;
    }
  if (edit_tile_cache_size != tile_cache_size)
    {
      update = g_list_append (update, "tile-cache-size");
      tile_cache_size = edit_tile_cache_size;
    }
  if (edit_install_cmap != install_cmap)
    {
      update = g_list_append (update, "install-colormap");
      install_cmap = edit_install_cmap;
    }
  if (edit_cycled_marching_ants != cycled_marching_ants)
    {
      update = g_list_append (update, "colormap-cycling");
      cycled_marching_ants = edit_cycled_marching_ants;
    }
  if (file_prefs_strcmp (temp_path, edit_temp_path))
    {
      update = g_list_append (update, "temp-path");
      temp_path = edit_temp_path;
    }
  if (file_prefs_strcmp (swap_path, edit_swap_path))
    {
      update = g_list_append (update, "swap-path");
      swap_path = edit_swap_path;
    }
  if (file_prefs_strcmp (brush_path, edit_brush_path))
    {
      update = g_list_append (update, "brush-path");
      brush_path = edit_brush_path;
    }
  if (file_prefs_strcmp (pattern_path, edit_pattern_path))
    {
      update = g_list_append (update, "pattern-path");
      pattern_path = edit_pattern_path;
    }
  if (file_prefs_strcmp (palette_path, edit_palette_path))
    {
      update = g_list_append (update, "palette-path");
      palette_path = edit_palette_path;
    }
  if (file_prefs_strcmp (plug_in_path, edit_plug_in_path))
    {
      update = g_list_append (update, "plug-in-path");
      plug_in_path = edit_plug_in_path;
    }
  if (file_prefs_strcmp (gradient_path, edit_gradient_path))
    {
      update = g_list_append (update, "gradient-path");
      gradient_path = edit_gradient_path;
    }
  save_gimprc (&update, &remove);

  /* Restore variables which must not change */
  stingy_memory_use = save_stingy_memory_use;
  tile_cache_size = save_tile_cache_size;
  install_cmap = save_install_cmap;
  cycled_marching_ants = save_cycled_marching_ants;
  temp_path = save_temp_path;
  swap_path = save_swap_path;
  brush_path = save_brush_path;
  pattern_path = save_pattern_path;
  palette_path = save_palette_path;
  plug_in_path = save_plug_in_path;
  gradient_path = save_gradient_path;
  
  g_list_free (update);
  g_list_free (remove);
}

static int
file_prefs_delete_callback (GtkWidget *widget,
			    GdkEvent *event,
			    GtkWidget *dlg) 
{
  file_prefs_cancel_callback (widget, dlg);

  /* the widget is already destroyed here no need to try again */
  return TRUE;
}

static void
file_prefs_cancel_callback (GtkWidget *widget,
			    GtkWidget *dlg)
{
  gtk_widget_destroy (dlg);
  prefs_dlg = NULL;

  levels_of_undo = old_levels_of_undo;
  marching_speed = old_marching_speed;
  allow_resize_windows = old_allow_resize_windows;
  auto_save = old_auto_save;
  no_cursor_updating = old_no_cursor_updating;
  show_tool_tips = old_show_tool_tips;
  cubic_interpolation = old_cubic_interpolation;
  confirm_on_close = old_confirm_on_close;
  default_width = old_default_width;
  default_height = old_default_height;
  default_type = old_default_type;
  if (preview_size != old_preview_size)
    {
      lc_dialog_rebuild (old_preview_size);
      layer_select_update_preview_size ();
    }

  if ((transparency_type != old_transparency_type) ||
      (transparency_size != old_transparency_size))
    {
      transparency_type = old_transparency_type;
      transparency_size = old_transparency_size;

      render_setup (transparency_type, transparency_size);
      layer_invalidate_previews (-1);
      gimage_invalidate_previews ();
      gdisplays_expose_full ();
      gdisplays_flush ();
    }

  edit_stingy_memory_use = old_stingy_memory_use;
  edit_tile_cache_size = old_tile_cache_size;
  edit_install_cmap = old_install_cmap;
  edit_cycled_marching_ants = old_cycled_marching_ants;
  file_prefs_strset (&edit_temp_path, old_temp_path);
  file_prefs_strset (&edit_swap_path, old_swap_path);
  file_prefs_strset (&edit_brush_path, old_brush_path);
  file_prefs_strset (&edit_pattern_path, old_pattern_path);
  file_prefs_strset (&edit_palette_path, old_palette_path);
  file_prefs_strset (&edit_plug_in_path, old_plug_in_path);
  file_prefs_strset (&edit_gradient_path, old_gradient_path);
}

static void
file_prefs_toggle_callback (GtkWidget *widget,
			    gpointer   data)
{
  int *val;

  if (data==&allow_resize_windows)
    allow_resize_windows = GTK_TOGGLE_BUTTON (widget)->active;
  else if (data==&auto_save)
    auto_save = GTK_TOGGLE_BUTTON (widget)->active;
  else if (data==&no_cursor_updating)
    no_cursor_updating = GTK_TOGGLE_BUTTON (widget)->active;
  else if (data==&show_tool_tips)
    show_tool_tips = GTK_TOGGLE_BUTTON (widget)->active;
  else if (data==&cubic_interpolation)
    cubic_interpolation = GTK_TOGGLE_BUTTON (widget)->active;
  else if (data==&confirm_on_close)
    confirm_on_close = GTK_TOGGLE_BUTTON (widget)->active;
  else if (data==&old_stingy_memory_use)
    old_stingy_memory_use = GTK_TOGGLE_BUTTON (widget)->active;
  else if (data==&old_install_cmap)
    old_install_cmap = GTK_TOGGLE_BUTTON (widget)->active;
  else if (data==&old_cycled_marching_ants)
    old_cycled_marching_ants = GTK_TOGGLE_BUTTON (widget)->active;
  else if (data==&default_type)
    {
      default_type = (long) gtk_object_get_user_data (GTK_OBJECT (widget));
    } 
  else if (GTK_TOGGLE_BUTTON (widget)->active)
    {
      val = data;
      *val = (long) gtk_object_get_user_data (GTK_OBJECT (widget));
      render_setup (transparency_type, transparency_size);
      layer_invalidate_previews (-1);
      gimage_invalidate_previews ();
      gdisplays_expose_full ();
      gdisplays_flush ();
    }
}

static void
file_prefs_preview_size_callback (GtkWidget *widget,
                                  gpointer   data)
{
  lc_dialog_rebuild ((long)data);
  layer_select_update_preview_size ();
}

static void
file_prefs_text_callback (GtkWidget *widget,
			  gpointer   data)
{
  int *val;

  val = data;
  *val = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
}

static void
file_prefs_string_callback (GtkWidget *widget,
			    gpointer   data)
{
  gchar **val;

  val = data;
  file_prefs_strset (val, gtk_entry_get_text (GTK_ENTRY (widget)));
}

void
file_pref_cmd_callback (GtkWidget *widget,
			gpointer   client_data)
{
  GtkWidget *button;
  GtkWidget *frame;
  GtkWidget *out_frame;
  GtkWidget *vbox;
  GtkWidget *hbox;
  GtkWidget *abox;
  GtkWidget *label;
  GtkWidget *radio_box;
  GtkWidget *entry;
  GtkWidget *menu;
  GtkWidget *menuitem;
  GtkWidget *optionmenu;
  GtkWidget *notebook;
  GtkWidget *table;
  GSList *group;
  char buffer[32];
  char *transparencies[] =
  {
    "Light Checks",
    "Mid-Tone Checks",
    "Dark Checks",
    "White Only",
    "Gray Only",
    "Black Only",
  };
  char *checks[] =
  {
    "Small Checks",
    "Medium Checks",
    "Large Checks",
  };
  int transparency_vals[] =
  {
    LIGHT_CHECKS,
    GRAY_CHECKS,
    DARK_CHECKS,
    WHITE_ONLY,
    GRAY_ONLY,
    BLACK_ONLY,
  };
  int check_vals[] =
  {
    SMALL_CHECKS,
    MEDIUM_CHECKS,
    LARGE_CHECKS,
  };
  struct {
    char *label;
    char **mpath;
  } dirs[] =
    {
      {"Temp dir:", &edit_temp_path},
      {"Swap dir:", &edit_swap_path},
      {"Brushes dir:", &edit_brush_path},
      {"Gradients dir:", &edit_gradient_path},
      {"Patterns dir:", &edit_pattern_path},
      {"Palette dir:", &edit_palette_path},
      {"Plug-in dir:", &edit_plug_in_path}
    };
    struct {
      char *label;
      int size;
    } preview_sizes[] =
    {
      {"None",0},
      {"Small",32},
      {"Medium",64},
      {"Large",128}
    }; 
  int ntransparencies = sizeof (transparencies) / sizeof (transparencies[0]);
  int nchecks = sizeof (checks) / sizeof (checks[0]);
  int ndirs = sizeof(dirs) / sizeof (dirs[0]);
  int npreview_sizes = sizeof(preview_sizes) / sizeof (preview_sizes[0]); 
  int i;

  if (!prefs_dlg)
    {
      if (edit_temp_path == NULL)
	{
	  /* first time dialog is opened - copy config vals to edit
             variables. */
	  edit_temp_path = file_prefs_strdup (temp_path);	
	  edit_swap_path = file_prefs_strdup (swap_path);
	  edit_brush_path = file_prefs_strdup (brush_path);
	  edit_pattern_path = file_prefs_strdup (pattern_path);
	  edit_palette_path = file_prefs_strdup (palette_path);
	  edit_plug_in_path = file_prefs_strdup (plug_in_path);
	  edit_gradient_path = file_prefs_strdup (gradient_path);
	  edit_stingy_memory_use = stingy_memory_use;
	  edit_tile_cache_size = tile_cache_size;
	  edit_install_cmap = install_cmap;
	  edit_cycled_marching_ants = cycled_marching_ants;
	}
      old_transparency_type = transparency_type;
      old_transparency_size = transparency_size;
      old_levels_of_undo = levels_of_undo;
      old_marching_speed = marching_speed;
      old_allow_resize_windows = allow_resize_windows;
      old_auto_save = auto_save;
      old_preview_size = preview_size;
      old_no_cursor_updating = no_cursor_updating;
      old_show_tool_tips = show_tool_tips;
      old_cubic_interpolation = cubic_interpolation;
      old_confirm_on_close = confirm_on_close;
      old_default_width = default_width;
      old_default_height = default_height;
      old_default_type = default_type;
      old_stingy_memory_use = edit_stingy_memory_use;
      old_tile_cache_size = edit_tile_cache_size;
      old_install_cmap = edit_install_cmap;
      old_cycled_marching_ants = edit_cycled_marching_ants;
      file_prefs_strset (&old_temp_path, edit_temp_path);
      file_prefs_strset (&old_swap_path, edit_swap_path);
      file_prefs_strset (&old_brush_path, edit_brush_path);
      file_prefs_strset (&old_pattern_path, edit_pattern_path);
      file_prefs_strset (&old_palette_path, edit_palette_path);
      file_prefs_strset (&old_plug_in_path, edit_plug_in_path);
      file_prefs_strset (&old_gradient_path, edit_gradient_path);

      prefs_dlg = gtk_dialog_new ();
      gtk_window_set_wmclass (GTK_WINDOW (prefs_dlg), "preferences", "Gimp");
      gtk_window_set_title (GTK_WINDOW (prefs_dlg), "Preferences");

      /* handle the wm close signal */
      gtk_signal_connect (GTK_OBJECT (prefs_dlg), "delete_event",
			  GTK_SIGNAL_FUNC (file_prefs_delete_callback),
			  prefs_dlg);

      gtk_container_border_width (GTK_CONTAINER (GTK_DIALOG (prefs_dlg)->action_area), 2);
      
      /* Action area */
      button = gtk_button_new_with_label ("OK");
      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
      gtk_signal_connect (GTK_OBJECT (button), "clicked",
			  (GtkSignalFunc) file_prefs_ok_callback,
			  prefs_dlg);
      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (prefs_dlg)->action_area),
			  button, TRUE, TRUE, 0);
      gtk_widget_grab_default (button);
      gtk_widget_show (button);

      button = gtk_button_new_with_label ("Save");
      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
      gtk_signal_connect (GTK_OBJECT (button), "clicked",
			  (GtkSignalFunc) file_prefs_save_callback,
			  prefs_dlg);
      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (prefs_dlg)->action_area),
			  button, TRUE, TRUE, 0);
      gtk_widget_grab_default (button);
      gtk_widget_show (button);

      button = gtk_button_new_with_label ("Cancel");
      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
      gtk_signal_connect (GTK_OBJECT (button), "clicked",
			  (GtkSignalFunc) file_prefs_cancel_callback,
			  prefs_dlg);
      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (prefs_dlg)->action_area),
			  button, TRUE, TRUE, 0);
      gtk_widget_show (button);

      notebook = gtk_notebook_new ();
      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (prefs_dlg)->vbox),
			  notebook, TRUE, TRUE, 0);

      /* Display page */
      out_frame = gtk_frame_new ("Display settings");
      gtk_container_border_width (GTK_CONTAINER (out_frame), 10);
      gtk_widget_show (out_frame);

      vbox = gtk_vbox_new (FALSE, 2);
      gtk_container_border_width (GTK_CONTAINER (vbox), 1);
      gtk_container_add (GTK_CONTAINER (out_frame), vbox);
      gtk_widget_show (vbox);

      hbox = gtk_hbox_new (FALSE, 2);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
      gtk_widget_show (hbox);

      frame = gtk_frame_new ("Image size"); 
      gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
      gtk_widget_show (frame);

      abox = gtk_vbox_new (FALSE, 2);
      gtk_container_border_width (GTK_CONTAINER (abox), 1);
      gtk_container_add (GTK_CONTAINER (frame), abox);
      gtk_widget_show (abox);

      table = gtk_table_new (2, 2, FALSE);
      gtk_table_set_row_spacings (GTK_TABLE (table), 2);
      gtk_table_set_col_spacings (GTK_TABLE (table), 2);
      gtk_box_pack_start (GTK_BOX (abox), table, TRUE, TRUE, 0);
      gtk_widget_show (table);
      
      label = gtk_label_new ("Width:");
      gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
      gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
			GTK_FILL, GTK_FILL, 0, 0);
      gtk_widget_show (label);

      label = gtk_label_new ("Height:");
      gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
      gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
			GTK_FILL, GTK_FILL, 0, 0);
      gtk_widget_show (label);
      
      entry = gtk_entry_new ();
      gtk_widget_set_usize (entry, 25, 0);
      sprintf (buffer, "%d", default_width);
      gtk_entry_set_text (GTK_ENTRY (entry), buffer);
      gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1,
                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
      gtk_signal_connect (GTK_OBJECT (entry), "changed",
                          (GtkSignalFunc) file_prefs_text_callback,
                          &default_width);
      gtk_widget_show (entry);

      entry = gtk_entry_new ();
      gtk_widget_set_usize (entry, 25, 0);
      sprintf (buffer, "%d", default_height);
      gtk_entry_set_text (GTK_ENTRY (entry), buffer); 
      gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2,
			GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
      gtk_signal_connect (GTK_OBJECT (entry), "changed",
			  (GtkSignalFunc) file_prefs_text_callback,
                          &default_height);
      gtk_widget_show (entry);

      frame = gtk_frame_new ("Image type");
      gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
      gtk_widget_show (frame);

      radio_box = gtk_vbox_new (FALSE, 1);
      gtk_container_border_width (GTK_CONTAINER (radio_box), 2);
      gtk_container_add (GTK_CONTAINER (frame), radio_box);
      gtk_widget_show (radio_box);

      button = gtk_radio_button_new_with_label (NULL, "RGB");
      group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
      gtk_box_pack_start (GTK_BOX (radio_box), button, TRUE, TRUE, 0);
      gtk_object_set_user_data (GTK_OBJECT (button), (gpointer) RGB);
      if (default_type == RGB)
	gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
      gtk_signal_connect (GTK_OBJECT (button), "toggled",
			  (GtkSignalFunc) file_prefs_toggle_callback,
			  &default_type);
      gtk_widget_show (button);
      button = gtk_radio_button_new_with_label (group, "Grayscale");
      group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
      gtk_box_pack_start (GTK_BOX (radio_box), button, TRUE, TRUE, 0);
      gtk_object_set_user_data (GTK_OBJECT (button), (gpointer) GRAY);
      if (last_type == GRAY) 
	  gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
      gtk_signal_connect (GTK_OBJECT (button), "toggled",
                         (GtkSignalFunc) file_prefs_toggle_callback,
			  &default_type);
      gtk_widget_show (button);
      hbox = gtk_hbox_new (FALSE, 2);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
      gtk_widget_show (hbox);
      
      label = gtk_label_new ("Preview size:");
      gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
      gtk_widget_show (label);
      
      menu = gtk_menu_new ();
      for (i = 0; i < npreview_sizes; i++)
        {
          menuitem = gtk_menu_item_new_with_label (preview_sizes[i].label);
	  gtk_menu_append (GTK_MENU (menu), menuitem);
	  gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
			      (GtkSignalFunc) file_prefs_preview_size_callback,
			      (gpointer)((long)preview_sizes[i].size));
	  gtk_widget_show (menuitem);
	}
      optionmenu = gtk_option_menu_new ();
      gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), menu);
      gtk_box_pack_start (GTK_BOX (hbox), optionmenu, TRUE, TRUE, 0);
      gtk_widget_show (optionmenu);
      for (i = 0; i < npreview_sizes; i++)
	if (preview_size==preview_sizes[i].size)
	  gtk_option_menu_set_history(GTK_OPTION_MENU (optionmenu),i);
	  
      button = gtk_check_button_new_with_label("Cubic interpolation");
      gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button),
                                   cubic_interpolation);
      gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
      gtk_signal_connect (GTK_OBJECT (button), "toggled",
                          (GtkSignalFunc) file_prefs_toggle_callback,
                          &cubic_interpolation);
      gtk_widget_show (button);

      hbox = gtk_hbox_new (FALSE, 2);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
      gtk_widget_show (hbox);

      frame = gtk_frame_new ("Transparency Type");
      gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
      gtk_widget_show (frame);

      radio_box = gtk_vbox_new (FALSE, 2);
      gtk_container_border_width (GTK_CONTAINER (radio_box), 2);
      gtk_container_add (GTK_CONTAINER (frame), radio_box);
      gtk_widget_show (radio_box);

      group = NULL;
      for (i = 0; i < ntransparencies; i++)
        {
	  button = gtk_radio_button_new_with_label (group, transparencies[i]);
          group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
          gtk_box_pack_start (GTK_BOX (radio_box), button, TRUE, TRUE, 0);
          gtk_object_set_user_data (GTK_OBJECT (button),
				    (gpointer) ((long) transparency_vals[i]));
          if (transparency_vals[i] == transparency_type)
            gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
          gtk_signal_connect (GTK_OBJECT (button), "toggled",
                              (GtkSignalFunc) file_prefs_toggle_callback,
                              &transparency_type);
          gtk_widget_show (button);
        }
      frame = gtk_frame_new ("Check Size");
      gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
      gtk_widget_show (frame);

      radio_box = gtk_vbox_new (FALSE, 2);
      gtk_container_border_width (GTK_CONTAINER (radio_box), 2);
      gtk_container_add (GTK_CONTAINER (frame), radio_box);
      gtk_widget_show (radio_box);

      group = NULL;
      for (i = 0; i < nchecks; i++)
        {
          button = gtk_radio_button_new_with_label (group, checks[i]);
          group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
          gtk_box_pack_start (GTK_BOX (radio_box), button, TRUE, TRUE, 0);
          gtk_object_set_user_data (GTK_OBJECT (button),
				    (gpointer) ((long) check_vals[i]));
          if (check_vals[i] == transparency_size)
            gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
          gtk_signal_connect (GTK_OBJECT (button), "toggled",
                              (GtkSignalFunc) file_prefs_toggle_callback,
                              &transparency_size);
          gtk_widget_show (button);
        }
      

      label = gtk_label_new ("Display");
      gtk_notebook_append_page (GTK_NOTEBOOK(notebook), out_frame, label);

      /* Interface */
      out_frame = gtk_frame_new ("Interface settings");
      gtk_container_border_width (GTK_CONTAINER (out_frame), 10);
      gtk_widget_show (out_frame);

      vbox = gtk_vbox_new (FALSE, 2);
      gtk_container_border_width (GTK_CONTAINER (vbox), 1);
      gtk_container_add (GTK_CONTAINER (out_frame), vbox);
      gtk_widget_show (vbox);
      
      hbox = gtk_hbox_new (FALSE, 2);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
      gtk_widget_show (hbox);

      label = gtk_label_new ("Levels of undo:");
      gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
      gtk_widget_show (label);

      entry = gtk_entry_new ();
      gtk_widget_set_usize (entry, 75, 0);
      sprintf (buffer, "%d", levels_of_undo);
      gtk_entry_set_text (GTK_ENTRY (entry), buffer);
      gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
      gtk_signal_connect (GTK_OBJECT (entry), "changed",
                          (GtkSignalFunc) file_prefs_text_callback,
                          &levels_of_undo);
      gtk_widget_show (entry);
      
      button = gtk_check_button_new_with_label("Resize window on zoom");
      gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button),
                                   allow_resize_windows);
      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
      gtk_signal_connect (GTK_OBJECT (button), "toggled",
                          (GtkSignalFunc) file_prefs_toggle_callback,
                          &allow_resize_windows);
      gtk_widget_show (button);
      
      button = gtk_check_button_new_with_label("Auto save");
      gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button),
                                   auto_save);
      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
      gtk_signal_connect (GTK_OBJECT (button), "toggled",
                          (GtkSignalFunc) file_prefs_toggle_callback,
                          &auto_save);
      gtk_widget_show (button);

      button = gtk_check_button_new_with_label("Disable cursor updating");
      gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button),
                                   no_cursor_updating);
      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
      gtk_signal_connect (GTK_OBJECT (button), "toggled",
                          (GtkSignalFunc) file_prefs_toggle_callback,
                          &no_cursor_updating);
      gtk_widget_show (button);

      button = gtk_check_button_new_with_label("Show tool tips");
      gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button),
                                   show_tool_tips);
      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
      gtk_signal_connect (GTK_OBJECT (button), "toggled",
                          (GtkSignalFunc) file_prefs_toggle_callback,
                          &show_tool_tips);
      gtk_widget_show (button);

      hbox = gtk_hbox_new (FALSE, 2);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
      gtk_widget_show (hbox);

      label = gtk_label_new ("Marching ants speed:");
      gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
      gtk_widget_show (label);

      entry = gtk_entry_new ();
      gtk_widget_set_usize (entry, 75, 0);
      sprintf (buffer, "%d", marching_speed);
      gtk_entry_set_text (GTK_ENTRY (entry), buffer);
      gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
      gtk_signal_connect (GTK_OBJECT (entry), "changed",
                          (GtkSignalFunc) file_prefs_text_callback,
                          &marching_speed);
      gtk_widget_show (entry);      

      label = gtk_label_new ("Interface");
      gtk_notebook_append_page (GTK_NOTEBOOK(notebook), out_frame, label);

      /* Environment */
      out_frame = gtk_frame_new ("Environment settings");
      gtk_container_border_width (GTK_CONTAINER (out_frame), 10);
      gtk_widget_set_usize (out_frame, 320, 200);
      gtk_widget_show (out_frame);

      vbox = gtk_vbox_new (FALSE, 2);
      gtk_container_border_width (GTK_CONTAINER (vbox), 1);
      gtk_container_add (GTK_CONTAINER (out_frame), vbox);
      gtk_widget_show (vbox);
      
      button = gtk_check_button_new_with_label("Conservative memory usage");
      gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button),
                                   stingy_memory_use);
      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
      gtk_signal_connect (GTK_OBJECT (button), "toggled",
			  (GtkSignalFunc) file_prefs_toggle_callback,
			  &old_stingy_memory_use);
      gtk_widget_show (button);
      
      hbox = gtk_hbox_new (FALSE, 2);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
      gtk_widget_show (hbox);

      label = gtk_label_new ("Tile cache size (bytes):");
      gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
      gtk_widget_show (label);

      entry = gtk_entry_new ();
      gtk_widget_set_usize (entry, 75, 0);
      sprintf (buffer, "%d", old_tile_cache_size);
      gtk_entry_set_text (GTK_ENTRY (entry), buffer);
      gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
      gtk_signal_connect (GTK_OBJECT (entry), "changed",
                          (GtkSignalFunc) file_prefs_text_callback,
                          &old_tile_cache_size);
      gtk_widget_show (entry);
      
      button = gtk_check_button_new_with_label("Install colormap (8-bit only)");
      gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button),
				   install_cmap);
      gtk_signal_connect (GTK_OBJECT (button), "toggled",
                          (GtkSignalFunc) file_prefs_toggle_callback,
                          &old_install_cmap);
      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
      gtk_widget_show (button);

      button = gtk_check_button_new_with_label("Colormap cycling (8-bit only)");
      gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button),
                                   cycled_marching_ants);
      gtk_signal_connect (GTK_OBJECT (button), "toggled",
                          (GtkSignalFunc) file_prefs_toggle_callback,
                          &old_cycled_marching_ants);
      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
      gtk_widget_show (button);
      
      label = gtk_label_new ("Environment");
      gtk_notebook_append_page (GTK_NOTEBOOK(notebook), out_frame, label);

      /* Directories */
      out_frame = gtk_frame_new ("Directories settings");
      gtk_container_border_width (GTK_CONTAINER (out_frame), 10);
      gtk_widget_set_usize (out_frame, 320, 200);
      gtk_widget_show (out_frame);

      vbox = gtk_vbox_new (FALSE, 2);
      gtk_container_border_width (GTK_CONTAINER (vbox), 1);
      gtk_container_add (GTK_CONTAINER (out_frame), vbox);
      gtk_widget_show (vbox);

      table = gtk_table_new (ndirs+1, 2, FALSE);
      gtk_table_set_row_spacings (GTK_TABLE (table), 2);
      gtk_table_set_col_spacings (GTK_TABLE (table), 2);
      gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
      gtk_widget_show (table);

      for (i = 0; i < ndirs; i++)
	{
	  label = gtk_label_new (dirs[i].label);
	  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
	  gtk_table_attach (GTK_TABLE (table), label, 0, 1, i, i+1,
                            GTK_FILL, GTK_FILL, 0, 0);
	  gtk_widget_show (label);
 
          entry = gtk_entry_new ();
          gtk_widget_set_usize (entry, 25, 0);
          gtk_entry_set_text (GTK_ENTRY (entry), *(dirs[i].mpath));
	  gtk_signal_connect (GTK_OBJECT (entry), "changed",
			      (GtkSignalFunc) file_prefs_string_callback,
			      dirs[i].mpath);
          gtk_table_attach (GTK_TABLE (table), entry, 1, 2, i, i+1,
                            GTK_EXPAND | GTK_FILL, 0, 0, 0);
          gtk_widget_show (entry); 
	}

      label = gtk_label_new ("Directories");
      gtk_notebook_append_page (GTK_NOTEBOOK(notebook), out_frame, label);

      gtk_widget_show (notebook);

      gtk_widget_show (prefs_dlg);
    }
}

void
file_close_cmd_callback (GtkWidget *widget,
			 gpointer   client_data)
{
  GDisplay *gdisp;

  gdisp = gdisplay_active ();

  gdisplay_close_window (gdisp, FALSE);
}

void
file_quit_cmd_callback (GtkWidget *widget,
			gpointer   client_data)
{
  app_exit (0);
}

void
edit_cut_cmd_callback (GtkWidget *widget,
		       gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  global_edit_cut (gdisp);
}

void
edit_copy_cmd_callback (GtkWidget *widget,
			gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  global_edit_copy (gdisp);
}

void
edit_paste_cmd_callback (GtkWidget *widget,
			 gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  global_edit_paste (gdisp, 0);
}

void
edit_paste_into_cmd_callback (GtkWidget *widget,
			      gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  global_edit_paste (gdisp, 1);
}

void
edit_clear_cmd_callback (GtkWidget *widget,
			 gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  edit_clear (gdisp->gimage, gimage_active_drawable (gdisp->gimage));

  gdisplays_flush ();
}

void
edit_fill_cmd_callback (GtkWidget *widget,
			gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  edit_fill (gdisp->gimage, gimage_active_drawable (gdisp->gimage));

  gdisplays_flush ();
}

void
edit_stroke_cmd_callback (GtkWidget *widget,
			  gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_mask_stroke (gdisp->gimage, gimage_active_drawable (gdisp->gimage));

  gdisplays_flush ();
}

void
edit_undo_cmd_callback (GtkWidget *widget,
			gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  undo_pop (gdisp->gimage);
}

void
edit_redo_cmd_callback (GtkWidget *widget,
			gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  undo_redo (gdisp->gimage);
}

void
edit_named_cut_cmd_callback (GtkWidget *widget,
			     gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  named_edit_cut (gdisp);
}

void
edit_named_copy_cmd_callback (GtkWidget *widget,
			      gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  named_edit_copy (gdisp);
}

void
edit_named_paste_cmd_callback (GtkWidget *widget,
			       gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  named_edit_paste (gdisp);
}

void
select_toggle_cmd_callback (GtkWidget *widget,
			    gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  selection_hide (gdisp->select, (void *) gdisp);
  gdisplays_flush ();
}

void
select_invert_cmd_callback (GtkWidget *widget,
			    gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_mask_invert (gdisp->gimage);
  gdisplays_flush ();
}

void
select_all_cmd_callback (GtkWidget *widget,
			 gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_mask_all (gdisp->gimage);
  gdisplays_flush ();
}

void
select_none_cmd_callback (GtkWidget *widget,
			  gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_mask_none (gdisp->gimage);
  gdisplays_flush ();
}

void
select_float_cmd_callback (GtkWidget *widget,
			   gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_mask_float (gdisp->gimage, gimage_active_drawable (gdisp->gimage), 0, 0);
  gdisplays_flush ();
}

void
select_sharpen_cmd_callback (GtkWidget *widget,
			     gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_mask_sharpen (gdisp->gimage);
  gdisplays_flush ();
}

void
select_border_cmd_callback (GtkWidget *widget,
			    gpointer   client_data)
{
  GDisplay * gdisp;
  char initial[16];

  gdisp = gdisplay_active ();

  sprintf (initial, "%d", gimage_mask_border_radius);
  query_string_box ("Border Selection", "Border selection by:", initial,
		    gimage_mask_border_callback, (gpointer) gdisp->gimage->ID);
}

void
select_feather_cmd_callback (GtkWidget *widget,
			     gpointer   client_data)
{
  GDisplay * gdisp;
  char initial[16];

  gdisp = gdisplay_active ();

  sprintf (initial, "%f", gimage_mask_feather_radius);
  query_string_box ("Feather Selection", "Feather selection by:", initial,
		    gimage_mask_feather_callback, (gpointer) gdisp->gimage->ID);
}

void
select_grow_cmd_callback (GtkWidget *widget,
			  gpointer   client_data)
{
  GDisplay * gdisp;
  char initial[16];

  gdisp = gdisplay_active ();

  sprintf (initial, "%d", gimage_mask_grow_pixels);
  query_string_box ("Grow Selection", "Grow selection by:", initial,
		    gimage_mask_grow_callback, (gpointer) gdisp->gimage->ID);
}

void
select_shrink_cmd_callback (GtkWidget *widget,
			    gpointer   client_data)
{
  GDisplay * gdisp;
  char initial[16];

  gdisp = gdisplay_active ();

  sprintf (initial, "%d", gimage_mask_shrink_pixels);
  query_string_box ("Shrink Selection", "Shrink selection by:", initial,
		    gimage_mask_shrink_callback, (gpointer) gdisp->gimage->ID);
}

void
select_by_color_cmd_callback (GtkWidget *widget,
			      gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  gtk_widget_activate (tool_widgets[tool_info[(int) BY_COLOR_SELECT].toolbar_position]);
  by_color_select_initialize ((void *) gdisp->gimage);
}

void
select_save_cmd_callback (GtkWidget *widget,
			  gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  gimage_mask_save (gdisp->gimage);
  gdisplays_flush ();
}

void
view_zoomin_cmd_callback (GtkWidget *widget,
			  gpointer   client_data)
{
  GDisplay *gdisp;

  gdisp = gdisplay_active ();

  change_scale (gdisp, ZOOMIN);
}

void
view_zoomout_cmd_callback (GtkWidget *widget,
			   gpointer   client_data)
{
  GDisplay *gdisp;

  gdisp = gdisplay_active ();

  change_scale (gdisp, ZOOMOUT);
}

static void
view_zoom_val (GtkWidget *widget,
	       gpointer   client_data,
	       int        val)
{
  GDisplay *gdisp;

  gdisp = gdisplay_active ();

  change_scale (gdisp, val);
}

void
view_zoom_16_1_callback (GtkWidget *widget,
			 gpointer   client_data)
{
  view_zoom_val (widget, client_data, 1601);
}

void
view_zoom_8_1_callback (GtkWidget *widget,
			gpointer   client_data)
{
  view_zoom_val (widget, client_data, 801);
}

void
view_zoom_4_1_callback (GtkWidget *widget,
			gpointer   client_data)
{
  view_zoom_val (widget, client_data, 401);
}

void
view_zoom_2_1_callback (GtkWidget *widget,
			gpointer   client_data)
{
  view_zoom_val (widget, client_data, 201);
}

void
view_zoom_1_1_callback (GtkWidget *widget,
			gpointer   client_data)
{
  view_zoom_val (widget, client_data, 101);
}

void
view_zoom_1_2_callback (GtkWidget *widget,
			gpointer   client_data)
{
  view_zoom_val (widget, client_data, 102);
}

void
view_zoom_1_4_callback (GtkWidget *widget,
			gpointer   client_data)
{
  view_zoom_val (widget, client_data, 104);
}

void
view_zoom_1_8_callback (GtkWidget *widget,
			gpointer   client_data)
{
  view_zoom_val (widget, client_data, 108);
}

void
view_zoom_1_16_callback (GtkWidget *widget,
			 gpointer   client_data)
{
  view_zoom_val (widget, client_data, 116);
}

void
view_window_info_cmd_callback (GtkWidget *widget,
			       gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  if (! gdisp->window_info_dialog)
    gdisp->window_info_dialog = info_window_create ((void *) gdisp);

  info_dialog_popup (gdisp->window_info_dialog);
}

void
view_toggle_rulers_cmd_callback (GtkWidget *widget,
				 gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  /* This routine use promiscuous knowledge of gtk internals
   *  in order to hide and show the rulers "smoothly". This
   *  is kludgy and a hack and may break if gtk is changed
   *  internally.
   */

  if (!GTK_CHECK_MENU_ITEM (widget)->active)
    {
      if (GTK_WIDGET_VISIBLE (gdisp->origin))
	{
	  gtk_widget_unmap (gdisp->origin);
	  gtk_widget_unmap (gdisp->hrule);
	  gtk_widget_unmap (gdisp->vrule);

	  GTK_WIDGET_UNSET_FLAGS (gdisp->origin, GTK_VISIBLE);
	  GTK_WIDGET_UNSET_FLAGS (gdisp->hrule, GTK_VISIBLE);
	  GTK_WIDGET_UNSET_FLAGS (gdisp->vrule, GTK_VISIBLE);

	  gtk_widget_queue_resize (GTK_WIDGET (gdisp->origin->parent));
	}
    }
  else
    {
      if (!GTK_WIDGET_VISIBLE (gdisp->origin))
	{
	  gtk_widget_map (gdisp->origin);
	  gtk_widget_map (gdisp->hrule);
	  gtk_widget_map (gdisp->vrule);

	  GTK_WIDGET_SET_FLAGS (gdisp->origin, GTK_VISIBLE);
	  GTK_WIDGET_SET_FLAGS (gdisp->hrule, GTK_VISIBLE);
	  GTK_WIDGET_SET_FLAGS (gdisp->vrule, GTK_VISIBLE);

	  gtk_widget_queue_resize (GTK_WIDGET (gdisp->origin->parent));
	}
    }
}

void
view_toggle_guides_cmd_callback (GtkWidget *widget,
				 gpointer   client_data)
{
  GDisplay * gdisp;
  int old_val;

  gdisp = gdisplay_active ();

  old_val = gdisp->draw_guides;
  gdisp->draw_guides = GTK_CHECK_MENU_ITEM (widget)->active;

  if ((old_val != gdisp->draw_guides) && gdisp->gimage->guides)
    {
      gdisplay_expose_full (gdisp);
      gdisplays_flush ();
    }
}

void
view_snap_to_guides_cmd_callback (GtkWidget *widget,
				  gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gdisp->snap_to_guides = GTK_CHECK_MENU_ITEM (widget)->active;
}

void
view_new_view_cmd_callback (GtkWidget *widget,
			    gpointer   client_data)
{
  GDisplay *gdisp;

  gdisp = gdisplay_active ();

  gdisplay_new_view (gdisp);
}

void
view_shrink_wrap_cmd_callback (GtkWidget *widget,
			       gpointer   client_data)
{
  GDisplay *gdisp;

  gdisp = gdisplay_active ();

  if (gdisp)
    shrink_wrap_display (gdisp);
}

void
image_equalize_cmd_callback (GtkWidget *widget,
			     gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  image_equalize ((void *) gdisp->gimage);
  gdisplays_flush ();
}

void
image_invert_cmd_callback (GtkWidget *widget,
			   gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  image_invert ((void *) gdisp->gimage);
  gdisplays_flush ();
}

void
image_posterize_cmd_callback (GtkWidget *widget,
			      gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  gtk_widget_activate (tool_widgets[tool_info[(int) POSTERIZE].toolbar_position]);
  posterize_initialize ((void *) gdisp);
}

void
image_threshold_cmd_callback (GtkWidget *widget,
			      gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  gtk_widget_activate (tool_widgets[tool_info[(int) THRESHOLD].toolbar_position]);
  threshold_initialize ((void *) gdisp);
}

void
image_color_balance_cmd_callback (GtkWidget *widget,
				  gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  gtk_widget_activate (tool_widgets[tool_info[(int) COLOR_BALANCE].toolbar_position]);
  color_balance_initialize ((void *) gdisp);
}

void
image_brightness_contrast_cmd_callback (GtkWidget *widget,
					gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  gtk_widget_activate (tool_widgets[tool_info[(int) BRIGHTNESS_CONTRAST].toolbar_position]);
  brightness_contrast_initialize ((void *) gdisp);
}

void
image_hue_saturation_cmd_callback (GtkWidget *widget,
				   gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  gtk_widget_activate (tool_widgets[tool_info[(int) HUE_SATURATION].toolbar_position]);
  hue_saturation_initialize ((void *) gdisp);
}

void
image_curves_cmd_callback (GtkWidget *widget,
			   gpointer client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  gtk_widget_activate (tool_widgets[tool_info[(int) CURVES].toolbar_position]);
  curves_initialize ((void *) gdisp);
}

void
image_levels_cmd_callback (GtkWidget *widget,
			   gpointer client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  gtk_widget_activate (tool_widgets[tool_info[(int) LEVELS].toolbar_position]);
  levels_initialize ((void *) gdisp);
}

void
image_desaturate_cmd_callback (GtkWidget *widget,
			       gpointer client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  image_desaturate ((void *) gdisp->gimage);
  gdisplays_flush ();
}

void
channel_ops_duplicate_cmd_callback (GtkWidget *widget,
				    gpointer client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  channel_ops_duplicate ((void *) gdisp->gimage);
}

void
channel_ops_offset_cmd_callback (GtkWidget *widget,
				 gpointer client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  channel_ops_offset ((void *) gdisp->gimage);
}

void
image_convert_rgb_cmd_callback (GtkWidget *widget,
				gpointer client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  convert_to_rgb ((void *) gdisp->gimage);
}

void
image_convert_grayscale_cmd_callback (GtkWidget *widget,
				      gpointer client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  convert_to_grayscale ((void *) gdisp->gimage);
}

void
image_convert_indexed_cmd_callback (GtkWidget *widget,
				    gpointer client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  convert_to_indexed ((void *) gdisp->gimage);
}

void
image_resize_cmd_callback (GtkWidget *widget,
			   gpointer client_data)
{
  static ActionAreaItem action_items[2] =
  {
    { "OK", image_resize_callback, NULL, NULL },
    { "Cancel", image_cancel_callback, NULL, NULL }
  };
  GDisplay * gdisp;
  GtkWidget *vbox;
  ImageResize *image_resize;

  gdisp = gdisplay_active ();

  /*  the ImageResize structure  */
  image_resize = (ImageResize *) g_malloc (sizeof (ImageResize));
  image_resize->gimage_id = gdisp->gimage->ID;
  image_resize->resize = resize_widget_new (ResizeWidget, gdisp->gimage->width, gdisp->gimage->height);

  /*  the dialog  */
  image_resize->shell = gtk_dialog_new ();
  gtk_window_set_wmclass (GTK_WINDOW (image_resize->shell), "image_resize", "Gimp");
  gtk_window_set_title (GTK_WINDOW (image_resize->shell), "Image Resize");
  gtk_window_set_policy (GTK_WINDOW (image_resize->shell), FALSE, FALSE, TRUE);
  gtk_window_position (GTK_WINDOW (image_resize->shell), GTK_WIN_POS_MOUSE);

  /* handle the wm close signal */
  gtk_signal_connect (GTK_OBJECT (image_resize->shell), "delete_event",
		      GTK_SIGNAL_FUNC (image_delete_callback),
		      image_resize);

  /*  the main vbox  */
  vbox = gtk_vbox_new (FALSE, 1);
  gtk_container_border_width (GTK_CONTAINER (vbox), 1);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (image_resize->shell)->vbox), vbox, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (vbox), image_resize->resize->resize_widget, FALSE, FALSE, 0);

  action_items[0].user_data = image_resize;
  action_items[1].user_data = image_resize;
  build_action_area (GTK_DIALOG (image_resize->shell), action_items, 2, 0);

  gtk_widget_show (image_resize->resize->resize_widget);
  gtk_widget_show (vbox);
  gtk_widget_show (image_resize->shell);
}

void
image_scale_cmd_callback (GtkWidget *widget,
			  gpointer client_data)
{
  static ActionAreaItem action_items[2] =
  {
    { "OK", image_scale_callback, NULL, NULL },
    { "Cancel", image_cancel_callback, NULL, NULL }
  };
  GDisplay * gdisp;
  GtkWidget *vbox;
  ImageResize *image_scale;

  gdisp = gdisplay_active ();

  /*  the ImageResize structure  */
  image_scale = (ImageResize *) g_malloc (sizeof (ImageResize));
  image_scale->gimage_id = gdisp->gimage->ID;
  image_scale->resize = resize_widget_new (ScaleWidget, gdisp->gimage->width, gdisp->gimage->height);

  /*  the dialog  */
  image_scale->shell = gtk_dialog_new ();
  gtk_window_set_wmclass (GTK_WINDOW (image_scale->shell), "image_scale", "Gimp");
  gtk_window_set_title (GTK_WINDOW (image_scale->shell), "Image Scale");
  gtk_window_set_policy (GTK_WINDOW (image_scale->shell), FALSE, FALSE, TRUE);
  gtk_window_position (GTK_WINDOW (image_scale->shell), GTK_WIN_POS_MOUSE);

  /* handle the wm close signal */
  gtk_signal_connect (GTK_OBJECT (image_scale->shell), "delete_event",
		      GTK_SIGNAL_FUNC (image_delete_callback),
		      image_scale);

  /*  the main vbox  */
  vbox = gtk_vbox_new (FALSE, 1);
  gtk_container_border_width (GTK_CONTAINER (vbox), 1);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (image_scale->shell)->vbox), vbox, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (vbox), image_scale->resize->resize_widget, FALSE, FALSE, 0);

  action_items[0].user_data = image_scale;
  action_items[1].user_data = image_scale;
  build_action_area (GTK_DIALOG (image_scale->shell), action_items, 2, 0);

  gtk_widget_show (image_scale->resize->resize_widget);
  gtk_widget_show (vbox);
  gtk_widget_show (image_scale->shell);
}

void
image_histogram_cmd_callback (GtkWidget *widget,
			      gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();
  gtk_widget_activate (tool_widgets[tool_info[(int) HISTOGRAM].toolbar_position]);
  histogram_tool_initialize ((void *) gdisp);
}

void
layers_raise_cmd_callback (GtkWidget *widget,
			   gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_raise_layer (gdisp->gimage, gdisp->gimage->active_layer);
  gdisplays_flush ();
}

void
layers_lower_cmd_callback (GtkWidget *widget,
			   gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_lower_layer (gdisp->gimage, gdisp->gimage->active_layer);
  gdisplays_flush ();
}
  int value;

void
layers_anchor_cmd_callback (GtkWidget *widget,
			    gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  floating_sel_anchor (gimage_get_active_layer (gdisp->gimage));
  gdisplays_flush ();
}

void
layers_merge_cmd_callback (GtkWidget *widget,
			   gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  layers_dialog_layer_merge_query (gdisp->gimage, TRUE);
}

void
layers_flatten_cmd_callback (GtkWidget *widget,
			     gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_flatten (gdisp->gimage);
  gdisplays_flush ();
}

void
layers_alpha_select_cmd_callback (GtkWidget *widget,
				  gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_mask_layer_alpha (gdisp->gimage, gdisp->gimage->active_layer);
  gdisplays_flush ();
}

void
layers_mask_select_cmd_callback (GtkWidget *widget,
				 gpointer   client_data)
{
  GDisplay * gdisp;

  gdisp = gdisplay_active ();

  gimage_mask_layer_mask (gdisp->gimage, gdisp->gimage->active_layer);
  gdisplays_flush ();
}

void
tools_default_colors_cmd_callback (GtkWidget *widget,
				   gpointer   client_data)
{
  palette_set_default_colors ();
}

void
tools_swap_colors_cmd_callback (GtkWidget *widget,
				gpointer   client_data)
{
  palette_swap_colors ();
}

void
tools_select_cmd_callback (GtkWidget *widget,
			   gpointer   client_data)
{
  /*  Activate the approriate widget  */
  gtk_widget_activate (tool_widgets[tool_info[(long) client_data].toolbar_position]);
}

void
filters_repeat_cmd_callback (GtkWidget *widget,
			     gpointer   client_data)
{
  plug_in_repeat ((long) client_data);
}

void
dialogs_brushes_cmd_callback (GtkWidget *widget,
			      gpointer   client_data)
{
  create_brush_dialog ();
}

void
dialogs_patterns_cmd_callback (GtkWidget *widget,
			       gpointer   client_data)
{
  create_pattern_dialog ();
}

void
dialogs_palette_cmd_callback (GtkWidget *widget,
			      gpointer   client_data)
{
  palette_create ();
}

void
dialogs_gradient_editor_cmd_callback(GtkWidget *widget,
				     gpointer   client_data)
{
  grad_create_gradient_editor ();
} /* dialogs_gradient_editor_cmd_callback */

void
dialogs_lc_cmd_callback (GtkWidget *widget,
			 gpointer   client_data)
{
  GDisplay *gdisp;

  gdisp = gdisplay_active ();

  lc_dialog_create (gdisp->gimage->ID);
}

void
dialogs_indexed_palette_cmd_callback (GtkWidget *widget,
				      gpointer   client_data)
{
  GDisplay *gdisp;

  gdisp = gdisplay_active ();

  indexed_palette_create (gdisp->gimage->ID);
}

void
dialogs_tools_options_cmd_callback (GtkWidget *widget,
				    gpointer   client_data)
{
  tools_options_dialog_show ();
}

void
about_dialog_cmd_callback (GtkWidget *widget,
                           gpointer   client_data)
{
  about_dialog_create (FALSE);
}

void
tips_dialog_cmd_callback (GtkWidget *widget,
			  gpointer   client_data)
{
  tips_dialog_create ();
}


/****************************************************/
/**           LOCAL FUNCTIONS                      **/
/****************************************************/


/*********************/
/*  Local functions  */
/*********************/

static void
image_resize_callback (GtkWidget *w,
		       gpointer   client_data)
{
  ImageResize *image_resize;
  GImage *gimage;

  image_resize = (ImageResize *) client_data;
  if ((gimage = gimage_get_ID (image_resize->gimage_id)) != NULL)
    {
      if (image_resize->resize->width > 0 &&
	  image_resize->resize->height > 0) 
	{
	  gimage_resize (gimage,
			 image_resize->resize->width,
			 image_resize->resize->height,
			 image_resize->resize->off_x,
			 image_resize->resize->off_y);
	  gdisplays_flush ();
	}
      else 
	{
	  message_box("Resize Error: Both width and height must be greater than zero.", NULL, NULL);
	  return;
	}
    }

  gtk_widget_destroy (image_resize->shell);
  resize_widget_free (image_resize->resize);
  g_free (image_resize);
}

static void
image_scale_callback (GtkWidget *w,
		      gpointer   client_data)
{
  ImageResize *image_scale;
  GImage *gimage;

  image_scale = (ImageResize *) client_data;
  if ((gimage = gimage_get_ID (image_scale->gimage_id)) != NULL)
    {
      if (image_scale->resize->width > 0 &&
	  image_scale->resize->height > 0) 
	{
	  gimage_scale (gimage,
			image_scale->resize->width,
			image_scale->resize->height);
	  gdisplays_flush ();
	}
      else 
	{
	  message_box("Scale Error: Both width and height must be greater than zero.", NULL, NULL);
	  return;
	}
    }

  gtk_widget_destroy (image_scale->shell);
  resize_widget_free (image_scale->resize);
  g_free (image_scale);
}

static gint
image_delete_callback (GtkWidget *w,
		       GdkEvent *e,
		       gpointer client_data)
{
  image_cancel_callback (w, client_data);

  return TRUE;
}


static void
image_cancel_callback (GtkWidget *w,
		       gpointer   client_data)
{
  ImageResize *image_resize;

  image_resize = (ImageResize *) client_data;

  gtk_widget_destroy (image_resize->shell);
  resize_widget_free (image_resize->resize);
  g_free (image_resize);
}

static void
gimage_mask_feather_callback (GtkWidget *w,
			      gpointer   client_data,
			      gpointer   call_data)
{
  GImage *gimage;
  double feather_radius;

  if (!(gimage = gimage_get_ID ((int)client_data)))
    return;

  feather_radius = atof (call_data);

  gimage_mask_feather (gimage, feather_radius);
  gdisplays_flush ();
}


static void
gimage_mask_border_callback (GtkWidget *w,
			     gpointer   client_data,
			     gpointer   call_data)
{
  GImage *gimage;
  int border_radius;

  if (!(gimage = gimage_get_ID ((int)client_data)))
    return;

  border_radius = atoi (call_data);

  gimage_mask_border (gimage, border_radius);
  gdisplays_flush ();
}


static void
gimage_mask_grow_callback (GtkWidget *w,
			   gpointer   client_data,
			   gpointer   call_data)
{
  GImage *gimage;
  int grow_pixels;

  if (!(gimage = gimage_get_ID ((int)client_data)))
    return;

  grow_pixels = atoi (call_data);

  gimage_mask_grow (gimage, grow_pixels);
  gdisplays_flush ();
}


static void
gimage_mask_shrink_callback (GtkWidget *w,
			     gpointer   client_data,
			     gpointer   call_data)
{
  GImage *gimage;
  int shrink_pixels;

  if (!(gimage = gimage_get_ID ((int)client_data)))
    return;

  shrink_pixels = atoi (call_data);

  gimage_mask_shrink (gimage, shrink_pixels);
  gdisplays_flush ();
}






