Files
gimp/app/fileops.c
Michael Natterer e46eaf8687 Reorganized the core menu items (everything except <Image>/Filters).
1999-11-20  Michael Natterer  <mitch@gimp.org>

	Reorganized the core menu items (everything except
	<Image>/Filters). Everything is of course trivial to change again,
	so please comment on the new "menu feeling" ;-)

	* app/menus.[ch]:

	- Applied the suggestions collected by Olof.
	- Added "..." to all items which open a dialog.
	- Introduced some additional separators (e.g. in "Dialogs").
	- Reorder some plugins and the color correct tools after
	  initialisation.
	- A menu entry to invoke the tooltips inspector.
	- A debugging menu entry which dumps the menu paths and their help
	  pages (will of course go away when the help sys is consistent).

	There are currently two identical "Help" menus because
	<Toolbox>/Help trashes the menu bar if the toolbox is too narrow
	(gtk doesn't seem to support multi-line menubars, any idea?)

	* app/app_procs.c: call menus_reorder_plugins() after loading the
	plugins to beautify the "Xtns" menu.

	* app/commands.[ch]: reordered some functions to match the new
	menu structure (for easier source navigation) and renamed some to
	be consistent (e.g. all help functions are now called help_*).

	Show/Hide the rulers with ordinary gtk_widget_[show|hide]()
	commands. I've tested it several times and it looks exactly the
	same as the old code which used internal gtk knowledge.

	* app/gdisplay.c: applied the menu changes to
	gdisplay_set_menu_sensitivity().

	* app/gimphelp.[ch]: new public function gimp_context_help() which
	invokes the tooltips inspector. Code cleanup.

	* app/resize.c: changed the dialogs' titles to match the menu entries.

	* app/session.c: renamed the gradient selection cmd callback to be
	consistent with brushes/patterns.

	* app/tools.c: added "..." to the menu paths of the tools which
	have dialogs.

	* app/fileops.c
	* app/channels_dialog.c
	* app/layers_dialog.c
	* app/paths_dialog.c: added some "...".

	* plug-ins/common/align_layers.c
	* plug-ins/common/autostretch_hsv.c
	* plug-ins/common/c_astretch.c
	* plug-ins/common/color_enhance.c
	* plug-ins/common/compose.c
	* plug-ins/common/decompose.c
	* plug-ins/common/mail.c
	* plug-ins/common/normalize.c
	* plug-ins/common/threshold_alpha.c
	* plug-ins/dbbrowser/dbbrowser.c
	* plug-ins/fp/fp.c
	* plug-ins/print/print.c
	* plug-ins/rcm/rcm.c: changed the menu paths and added "...".
1999-11-20 12:12:41 +00:00

2107 lines
51 KiB
C

/* The GIMP -- an image manipulation program
* Copyright (C) 1995, 1996, 1997 Spencer Kimball and Peter Mattis
* Copyright (C) 1997 Josh MacDonald
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include <glib.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#ifdef G_OS_WIN32
#include <direct.h> /* For _mkdir() */
#define mkdir(path,mode) _mkdir(path)
#endif
#include "appenv.h"
#include "cursorutil.h"
#include "dialog_handler.h"
#include "gdisplay.h"
#include "general.h"
#include "gimage.h"
#include "gimpcontext.h"
#include "gimpui.h"
#include "fileops.h"
#include "menus.h"
#include "layer.h"
#include "channel.h"
#include "plug_in.h"
#include "procedural_db.h"
#include "gimprc.h"
#include "docindex.h"
#include "undo.h"
#include "libgimp/gimpintl.h"
#include "libgimp/gimpmath.h"
typedef struct _OverwriteBox OverwriteBox;
struct _OverwriteBox
{
GtkWidget *obox;
gchar *full_filename;
gchar *raw_filename;
};
static void file_overwrite (char *filename,
char *raw_filename);
static void file_overwrite_yes_callback (GtkWidget *, gpointer);
static void file_overwrite_no_callback (GtkWidget *, gpointer);
static GimpImage * file_open_image (char *filename,
char *raw_filename,
RunModeType runmode);
static void genbutton_callback (GtkWidget *, gpointer);
static void file_open_clistrow_callback (GtkWidget *, gint);
static void file_open_ok_callback (GtkWidget *, gpointer);
static void file_save_ok_callback (GtkWidget *, gpointer);
static void file_dialog_show (GtkWidget *filesel);
static int file_dialog_hide (GtkWidget *filesel);
static void file_update_name (PlugInProcDef *proc,
GtkWidget *filesel);
static void file_load_type_callback (GtkWidget *, gpointer);
static void file_save_type_callback (GtkWidget *, gpointer);
static void file_convert_string (char *instr,
char *outmem,
int maxmem,
int *nmem);
static int file_check_single_magic (char *offset,
char *type,
char *value,
int headsize,
guchar *file_head,
FILE *ifp);
static int file_check_magic_list (GSList *magics_list,
int headsize,
guchar *head,
FILE *ifp);
static void file_update_menus (GSList *procs,
int image_type);
static GtkWidget *fileload = NULL;
static GtkWidget *filesave = NULL;
static GtkWidget *open_options = NULL;
static GtkWidget *save_options = NULL;
/* widgets for the open_options menu */
static GtkPreview *open_options_preview = NULL;
static GtkWidget *open_options_fixed = NULL;
static GtkWidget *open_options_label = NULL;
static GtkWidget *open_options_frame = NULL;
static GtkWidget *open_options_genbuttonlabel = NULL;
/* Some state for the thumbnailer */
static gchar *preview_fullname = NULL;
GSList *load_procs = NULL;
GSList *save_procs = NULL;
static PlugInProcDef *load_file_proc = NULL;
static PlugInProcDef *save_file_proc = NULL;
static GimpImage *the_gimage = NULL;
extern GSList *display_list; /* from gdisplay.c */
#define FILE_ERR_MESSAGE(str) G_STMT_START{ \
if (message_handler == MESSAGE_BOX) \
gimp_message_box ((str), file_message_box_close_callback, (void *) fs); \
else \
g_message (str); \
gtk_widget_set_sensitive (GTK_WIDGET (fs), TRUE); }G_STMT_END
static void
file_message_box_close_callback (GtkWidget *widget,
gpointer data)
{
GtkFileSelection *fs;
fs = (GtkFileSelection *) data;
gtk_widget_set_sensitive (GTK_WIDGET (fs), TRUE);
}
void
file_ops_pre_init (void)
{
}
void
file_ops_post_init (void)
{
GimpItemFactoryEntry entry;
PlugInProcDef *file_proc;
GSList *tmp;
load_procs = g_slist_reverse (load_procs);
save_procs = g_slist_reverse (save_procs);
tmp = load_procs;
while (tmp)
{
gchar *help_page;
file_proc = tmp->data;
tmp = tmp->next;
help_page = g_strconcat ("filters/",
g_basename (file_proc->prog),
".html",
NULL);
g_strdown (help_page);
entry.entry.path = file_proc->menu_path;
entry.entry.accelerator = NULL;
entry.entry.callback = file_load_type_callback;
entry.entry.callback_action = 0;
entry.entry.item_type = NULL;
entry.help_page = help_page;
entry.description = NULL;
menus_create_item_from_full_path (&entry, file_proc);
}
tmp = save_procs;
while (tmp)
{
gchar *help_page;
file_proc = tmp->data;
tmp = tmp->next;
help_page = g_strconcat ("filters/",
g_basename (file_proc->prog),
".html",
NULL);
g_strdown (help_page);
entry.entry.path = file_proc->menu_path;
entry.entry.accelerator = NULL;
entry.entry.callback = file_save_type_callback;
entry.entry.callback_action = 0;
entry.entry.item_type = NULL;
entry.help_page = help_page;
entry.description = NULL;
menus_create_item_from_full_path (&entry, file_proc);
}
}
void
file_open_callback (GtkWidget *widget,
gpointer data)
{
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *label;
GtkWidget *option_menu;
GtkWidget *load_menu;
GtkWidget *open_options_genbutton;
if (!fileload)
{
fileload = gtk_file_selection_new (_("Load Image"));
gtk_window_set_position (GTK_WINDOW (fileload), GTK_WIN_POS_MOUSE);
gtk_window_set_wmclass (GTK_WINDOW (fileload), "load_image", "Gimp");
dialog_register_fileload (fileload);
gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (fileload)->cancel_button),
"clicked",
GTK_SIGNAL_FUNC (file_dialog_hide),
GTK_OBJECT (fileload));
gtk_signal_connect (GTK_OBJECT (fileload),
"delete_event",
GTK_SIGNAL_FUNC (file_dialog_hide),
NULL);
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileload)->ok_button), "clicked", (GtkSignalFunc) file_open_ok_callback, fileload);
gtk_quit_add_destroy (1, GTK_OBJECT (fileload));
gtk_clist_set_selection_mode (GTK_CLIST
(GTK_FILE_SELECTION (fileload)->file_list),
GTK_SELECTION_EXTENDED);
/* Catch file-clist clicks so we can update the preview thumbnail */
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileload)->file_list), "select_row", (GtkSignalFunc) file_open_clistrow_callback, fileload);
/* Connect the "F1" help key */
gimp_help_connect_help_accel (fileload,
gimp_standard_help_func,
"open/dialogs/file_open.html");
}
else
{
gtk_widget_set_sensitive (GTK_WIDGET (fileload), TRUE);
if (GTK_WIDGET_VISIBLE (fileload))
return;
gtk_file_selection_set_filename (GTK_FILE_SELECTION(fileload),
"." G_DIR_SEPARATOR_S);
gtk_window_set_title (GTK_WINDOW (fileload), _("Load Image"));
}
if (!open_options)
{
GtkWidget* frame;
open_options = gtk_hbox_new (TRUE, 1);
/* format-chooser frame */
frame = gtk_frame_new (_("Open Options"));
{
gtk_frame_set_shadow_type (GTK_FRAME (frame),
GTK_SHADOW_ETCHED_IN);
vbox = gtk_vbox_new (FALSE, 0);
{
gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
gtk_container_add (GTK_CONTAINER (frame), vbox);
hbox = gtk_hbox_new (FALSE, 1);
{
gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
label = gtk_label_new (_("Determine file type:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 5);
gtk_widget_show (label);
option_menu = gtk_option_menu_new ();
gtk_box_pack_start (GTK_BOX (hbox), option_menu, FALSE, TRUE, 0);
gtk_widget_show (option_menu);
menus_get_load_menu (&load_menu, NULL);
gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), load_menu);
gtk_box_pack_start (GTK_BOX (open_options), frame, TRUE, TRUE, 5);
}
gtk_widget_show (hbox);
}
gtk_widget_show (vbox);
}
gtk_widget_show (frame);
/* Preview frame */
frame = gtk_frame_new ("");
open_options_frame = frame;
{
gtk_frame_set_shadow_type (GTK_FRAME (frame),
GTK_SHADOW_ETCHED_IN);
gtk_box_pack_end (GTK_BOX (open_options), frame, FALSE, TRUE, 5);
vbox = gtk_vbox_new (FALSE, 1);
{
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
gtk_container_add (GTK_CONTAINER (frame), vbox);
hbox = gtk_hbox_new (TRUE, 1);
{
gtk_container_set_border_width (GTK_CONTAINER (hbox), 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
open_options_genbutton = gtk_button_new();
{
gtk_signal_connect (GTK_OBJECT (open_options_genbutton),
"clicked",
(GtkSignalFunc) genbutton_callback,
fileload);
gtk_box_pack_end (GTK_BOX (hbox), open_options_genbutton,
TRUE, FALSE, 0);
}
gtk_widget_show (open_options_genbutton);
open_options_fixed = gtk_fixed_new ();
{
GtkWidget* abox;
GtkWidget* sbox;
gtk_widget_set_usize (open_options_fixed, 80, 60);
gtk_container_add (GTK_CONTAINER (GTK_BIN (open_options_genbutton)), open_options_fixed);
sbox = gtk_vbox_new(TRUE, 0);
{
GtkWidget* align;
gtk_container_add (GTK_CONTAINER (open_options_fixed),
GTK_WIDGET (sbox));
align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
{
gtk_widget_set_usize (align, 80, 60);
gtk_box_pack_start (GTK_BOX (sbox),
GTK_WIDGET (align),
FALSE, TRUE, 0);
abox = gtk_hbox_new (FALSE, 0);
{
gtk_container_add (GTK_CONTAINER (align), abox);
open_options_preview = GTK_PREVIEW (gtk_preview_new
(GTK_PREVIEW_COLOR));
{
gtk_box_pack_start (GTK_BOX (abox),
GTK_WIDGET (open_options_preview),
FALSE, TRUE, 0);
}
gtk_widget_show(GTK_WIDGET (open_options_preview));
open_options_genbuttonlabel = gtk_label_new(_("generate\npreview"));
{
gtk_box_pack_start (GTK_BOX (abox),
GTK_WIDGET (open_options_genbuttonlabel),
FALSE, TRUE, 0);
}
gtk_widget_show(GTK_WIDGET (open_options_genbuttonlabel));
}
gtk_widget_show(abox);
}
gtk_widget_show(align);
}
gtk_widget_show(sbox);
}
gtk_widget_show (open_options_fixed);
}
gtk_widget_show (hbox);
open_options_label = gtk_label_new ("");
{
gtk_box_pack_end (GTK_BOX (vbox), open_options_label,
FALSE, TRUE, 0);
}
gtk_widget_show (open_options_label);
}
gtk_widget_show (vbox);
}
gtk_widget_show (frame);
/* pack the containing open_options hbox into the load-dialog */
gtk_box_pack_end (GTK_BOX (GTK_FILE_SELECTION (fileload)->main_vbox),
open_options, FALSE, FALSE, 1);
}
gtk_frame_set_label (GTK_FRAME(open_options_frame), _("Preview"));
gtk_label_set_text (GTK_LABEL(open_options_label), _("No selection."));
gtk_widget_show (GTK_WIDGET(open_options_genbuttonlabel));
gtk_widget_hide (GTK_WIDGET(open_options_preview));
gtk_widget_set_sensitive (GTK_WIDGET(open_options_frame), FALSE);
gtk_widget_show (open_options);
file_dialog_show (fileload);
}
void
file_save_callback (GtkWidget *widget,
gpointer data)
{
GDisplay *gdisplay;
gdisplay = gdisplay_active ();
if (!gdisplay) return;
/* Only save if the gimage has been modified */
if (!trust_dirty_flag || gdisplay->gimage->dirty != 0)
{
if (gdisplay->gimage->has_filename == FALSE)
{
file_save_as_callback (widget, data);
}
else
{
file_save (gdisplay->gimage, gimage_filename (gdisplay->gimage),
g_basename (gimage_filename(gdisplay->gimage)), 2);
}
}
}
void
file_save_as_callback (GtkWidget *widget,
gpointer data)
{
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *option_menu;
GtkWidget *save_menu;
GDisplay *gdisplay;
gdisplay = gdisplay_active ();
if (!gdisplay) return;
the_gimage = gdisplay->gimage;
if (!filesave)
{
filesave = gtk_file_selection_new (_("Save Image"));
gtk_window_set_wmclass (GTK_WINDOW (filesave), "save_image", "Gimp");
gtk_window_set_position (GTK_WINDOW (filesave), GTK_WIN_POS_MOUSE);
gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesave)->cancel_button),
"clicked",
GTK_SIGNAL_FUNC (file_dialog_hide),
GTK_OBJECT (filesave));
gtk_signal_connect (GTK_OBJECT (filesave),
"delete_event",
GTK_SIGNAL_FUNC (file_dialog_hide),
NULL);
gtk_signal_connect
(GTK_OBJECT (GTK_FILE_SELECTION (filesave)->ok_button), "clicked",
(GtkSignalFunc) file_save_ok_callback,
filesave);
gtk_quit_add_destroy (1, GTK_OBJECT (filesave));
/* Connect the "F1" help key */
gimp_help_connect_help_accel (filesave,
gimp_standard_help_func,
"save/dialogs/file_save.html");
}
else
{
gtk_widget_set_sensitive (GTK_WIDGET (filesave), TRUE);
if (GTK_WIDGET_VISIBLE (filesave))
return;
gtk_file_selection_set_filename (GTK_FILE_SELECTION(filesave),
gdisplay->gimage->has_filename
? gimage_filename(gdisplay->gimage)
: "." G_DIR_SEPARATOR_S);
gtk_window_set_title (GTK_WINDOW (filesave), _("Save Image"));
}
if (!save_options)
{
save_options = gtk_frame_new (_("Save Options"));
gtk_frame_set_shadow_type (GTK_FRAME (save_options),
GTK_SHADOW_ETCHED_IN);
hbox = gtk_hbox_new (FALSE, 1);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
gtk_container_add (GTK_CONTAINER (save_options), hbox);
gtk_widget_show (hbox);
label = gtk_label_new (_("Determine file type:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
gtk_widget_show (label);
option_menu = gtk_option_menu_new ();
gtk_box_pack_start (GTK_BOX (hbox), option_menu, TRUE, TRUE, 0);
gtk_widget_show (option_menu);
menus_get_save_menu (&save_menu, NULL);
gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), save_menu);
gtk_box_pack_end (GTK_BOX (GTK_FILE_SELECTION (filesave)->main_vbox),
save_options, FALSE, FALSE, 5);
}
switch (drawable_type(gimage_active_drawable(gdisplay->gimage)))
{
case RGB_GIMAGE:
file_update_menus (save_procs, PLUG_IN_RGB_IMAGE);
break;
case RGBA_GIMAGE:
file_update_menus (save_procs, PLUG_IN_RGBA_IMAGE);
break;
case GRAY_GIMAGE:
file_update_menus (save_procs, PLUG_IN_GRAY_IMAGE);
break;
case GRAYA_GIMAGE:
file_update_menus (save_procs, PLUG_IN_GRAYA_IMAGE);
break;
case INDEXED_GIMAGE:
file_update_menus (save_procs, PLUG_IN_INDEXED_IMAGE);
break;
case INDEXEDA_GIMAGE:
file_update_menus (save_procs, PLUG_IN_INDEXEDA_IMAGE);
break;
}
gtk_widget_show (save_options);
file_dialog_show (filesave);
}
void
file_revert_callback (GtkWidget *widget,
gpointer data)
{
GDisplay *gdisplay;
GimpImage *gimage;
gchar *filename = NULL;
gdisplay = gdisplay_active ();
if (!gdisplay) return;
if (gdisplay->gimage->has_filename == FALSE)
g_message (_("Can't revert. No filename associated with this image"));
else
{
filename = gimage_filename (gdisplay->gimage);
gimage = file_open_image (filename, filename, RUN_INTERACTIVE);
if (gimage != NULL)
{
undo_free (gimage);
gdisplay_reconnect (gdisplay, gimage);
gimp_image_clean_all (gimage);
}
else
g_message (_("Revert failed."));
}
}
void
file_load_by_extension_callback (GtkWidget *widget,
gpointer data)
{
load_file_proc = NULL;
}
void
file_save_by_extension_callback (GtkWidget *widget,
gpointer data)
{
save_file_proc = NULL;
}
static void
file_update_name (PlugInProcDef *proc,
GtkWidget *filesel)
{
if (proc->extensions_list)
{
char* text = gtk_entry_get_text (GTK_ENTRY(GTK_FILE_SELECTION(filesel)->selection_entry));
char* last_dot = strrchr (text, '.');
GString *s;
if (last_dot == text || !text[0])
return;
s = g_string_new (text);
if (last_dot)
g_string_truncate (s, last_dot-text);
g_string_append (s, ".");
g_string_append (s, (char*) proc->extensions_list->data);
gtk_entry_set_text (GTK_ENTRY(GTK_FILE_SELECTION(filesel)->selection_entry), s->str);
g_string_free (s, TRUE);
}
}
static void
file_load_type_callback (GtkWidget *widget,
gpointer data)
{
PlugInProcDef* proc = (PlugInProcDef *) data;
file_update_name (proc, fileload);
load_file_proc = proc;
}
static void
file_save_type_callback (GtkWidget *widget,
gpointer data)
{
PlugInProcDef* proc = (PlugInProcDef *) data;
file_update_name (proc, filesave);
save_file_proc = proc;
}
static GimpImage*
file_open_image (char *filename,
char *raw_filename,
RunModeType runmode)
{
PlugInProcDef *file_proc;
ProcRecord *proc;
Argument *args;
Argument *return_vals;
int gimage_id;
gboolean status;
int i;
file_proc = load_file_proc;
if (!file_proc)
file_proc = file_proc_find (load_procs, filename);
if (!file_proc)
{
/* WARNING */
return NULL;
}
proc = &file_proc->db_info;
args = g_new (Argument, proc->num_args);
memset (args, 0, (sizeof (Argument) * proc->num_args));
for (i = 0; i < proc->num_args; i++)
args[i].arg_type = proc->args[i].arg_type;
args[0].value.pdb_int = runmode;
args[1].value.pdb_pointer = filename;
args[2].value.pdb_pointer = raw_filename;
return_vals = procedural_db_execute (proc->name, args);
status = (return_vals[0].value.pdb_int == PDB_SUCCESS);
gimage_id = return_vals[1].value.pdb_int;
procedural_db_destroy_args (return_vals, proc->num_values);
g_free (args);
if (status)
{
layer_invalidate_previews(gimage_get_ID(gimage_id));
channel_invalidate_previews(gimage_get_ID(gimage_id));
return pdb_id_to_image (gimage_id);
}
else
return NULL;
}
int
file_open (char *filename,
char *raw_filename)
{
GimpImage *gimage;
GDisplay *gdisplay;
if ((gimage = file_open_image (filename, raw_filename, RUN_INTERACTIVE)) != NULL)
{
/* enable & clear all undo steps */
gimage_enable_undo (gimage);
/* set the image to clean */
gimage_clean_all (gimage);
/* display the image */
gdisplay = gdisplay_new (gimage, 0x0101);
/* always activate the first display */
if (g_slist_length (display_list) == 1)
gimp_context_set_display (gimp_context_get_user (), gdisplay);
idea_add (filename);
menus_last_opened_add (filename);
return TRUE;
}
return FALSE;
}
static TempBuf *
make_thumb_tempbuf (GimpImage* gimage)
{
gint w,h;
if (gimage->width<=80 && gimage->height<=60)
{
w = gimage->width;
h = gimage->height;
}
else
{
/* Ratio molesting to fit within .xvpic thumbnail size limits */
if (60*gimage->width < 80*gimage->height)
{
h = 60;
w = (60*gimage->width)/gimage->height;
if (w==0)
w = 1;
}
else
{
w = 80;
h = (80*gimage->height)/gimage->width;
if (h==0)
h = 1;
}
}
/*printf("tn: %d x %d -> ", w, h);fflush(stdout);*/
return (gimp_image_composite_preview (gimage, GRAY_CHANNEL, w, h));
}
static guchar *
make_RGBbuf_from_tempbuf (TempBuf *tempbuf,
gint *width_rtn,
gint *height_rtn)
{
int i,j,w,h;
guchar* tbd;
guchar* ptr;
guchar* rtn = NULL;
guchar alpha,r,g,b;
w = (*width_rtn) = tempbuf->width;
h = (*height_rtn) = tempbuf->height;
tbd = temp_buf_data (tempbuf);
switch (tempbuf->bytes)
{
case 4:
rtn = ptr = g_malloc (3 * w * h);
for (i=0; i<h; i++)
{
for (j=0; j<w; j++)
{
r = *(tbd++);
g = *(tbd++);
b = *(tbd++);
alpha = *(tbd++);
if (alpha & 128)
{
*(ptr++) = r;
*(ptr++) = g;
*(ptr++) = b;
}
else
{
r = (( (i^j) & 4 ) << 5) | 64;
*(ptr++) = r;
*(ptr++) = r;
*(ptr++) = r;
}
}
}
break;
case 2:
rtn = ptr = g_malloc (3 * w * h);
for (i=0; i<h; i++)
{
for (j=0; j<w; j++)
{
r = *(tbd++);
alpha = *(tbd++);
if (!(alpha & 128))
r = (( (i^j) & 4 ) << 5) | 64;
*(ptr++) = r;
*(ptr++) = r;
*(ptr++) = r;
}
}
break;
default:
g_warning("UNKNOWN TempBuf width in make_RGBbuf_from_tempbuf()");
}
return(rtn);
}
static gboolean
file_save_thumbnail (GimpImage * gimage,
const char *full_source_filename,
TempBuf *tempbuf)
{
gint i,j;
gint w,h;
unsigned char* tbd;
gchar* pathname;
gchar* filename;
gchar* xvpathname;
gchar* thumbnailname;
GimpImageBaseType basetype;
FILE* fp;
struct stat statbuf;
if (stat(full_source_filename, &statbuf) != 0)
{
return FALSE;
}
if (gimp_image_preview_valid (gimage, GRAY_CHANNEL))
{
/* just for debugging */
printf("(incidentally, gimage already has a valid preview - %dx%d)\n",
gimage->comp_preview->width,
gimage->comp_preview->height);
}
pathname = g_dirname(full_source_filename);
filename = g_basename(full_source_filename); /* Don't free! */
xvpathname = g_strconcat(pathname, G_DIR_SEPARATOR_S, ".xvpics",
NULL);
thumbnailname = g_strconcat (xvpathname, G_DIR_SEPARATOR_S,
filename,
NULL);
tbd = temp_buf_data(tempbuf);
w = tempbuf->width;
h = tempbuf->height;
/*printf("tn: %d x %d\n", w, h);fflush(stdout);*/
mkdir (xvpathname, 0755);
fp = fopen(thumbnailname,"wb");
g_free(pathname);
g_free(xvpathname);
g_free(thumbnailname);
if (fp)
{
basetype = gimp_image_base_type(gimage);
fprintf(fp,
"P7 332\n#IMGINFO:%dx%d %s (%d %s)\n"
"#END_OF_COMMENTS\n%d %d 255\n",
gimage->width, gimage->height,
(basetype == RGB) ? "RGB" :
(basetype == GRAY) ? "Greyscale" :
(basetype == INDEXED) ? "Indexed" :
"(UNKNOWN COLOUR TYPE)",
(int)statbuf.st_size,
(statbuf.st_size == 1) ? "byte" : "bytes",
w, h);
switch (basetype)
{
case INDEXED:
case RGB:
for (i=0; i<h; i++)
{
/* Do a cheap unidirectional error-spread to look better */
gint rerr=0, gerr=0, berr=0, a;
for (j=0; j<w; j++)
{
gint32 r,g,b;
if (128 & *(tbd + 3))
{
r = *(tbd++) + rerr;
g = *(tbd++) + gerr;
b = *(tbd++) + berr;
tbd++;
}
else
{
a = (( (i^j) & 4 ) << 5) | 64; /* cute. */
r = a + rerr;
g = a + gerr;
b = a + berr;
tbd += 4;
}
r = CLAMP0255 (r);
g = CLAMP0255 (g);
b = CLAMP0255 (b);
fputc(((r>>5)<<5) | ((g>>5)<<2) | (b>>6), fp);
rerr = r - ( (r>>5) * 255 ) / 7;
gerr = g - ( (g>>5) * 255 ) / 7;
berr = b - ( (b>>6) * 255 ) / 3;
}
}
break;
case GRAY:
for (i=0; i<h; i++)
{
/* Do a cheap unidirectional error-spread to look better */
gint b3err=0, b2err=0, v, a;
for (j=0; j<w; j++)
{
gint32 b3, b2;
v = *(tbd++);
a = *(tbd++);
if (!(128 & a))
v = (( (i^j) & 4 ) << 5) | 64;
b2 = v + b2err;
b3 = v + b3err;
b2 = CLAMP0255 (b2);
b3 = CLAMP0255 (b3);
fputc(((b3>>5)<<5) | ((b3>>5)<<2) | (b2>>6), fp);
b2err = b2 - ( (b2>>6) * 255 ) / 3;
b3err = b3 - ( (b3>>5) * 255 ) / 7;
}
}
break;
default:
g_warning("UNKNOWN GIMAGE TYPE IN THUMBNAIL SAVE");
}
fclose(fp);
}
else /* Error writing thumbnail */
{
return (FALSE);
}
return (TRUE);
}
int
file_save (GimpImage *gimage,
char *filename,
char *raw_filename,
gint mode)
{
PlugInProcDef *file_proc;
ProcRecord *proc;
Argument *args;
Argument *return_vals;
int return_val;
int i;
if (gimage_active_drawable (gimage) == NULL)
return FALSE;
file_proc = gimage_get_save_proc(gimage);
if (!file_proc)
file_proc = file_proc_find (save_procs, raw_filename);
if (!file_proc)
return FALSE;
proc = &file_proc->db_info;
args = g_new (Argument, proc->num_args);
memset (args, 0, (sizeof (Argument) * proc->num_args));
for (i = 0; i < proc->num_args; i++)
args[i].arg_type = proc->args[i].arg_type;
args[0].value.pdb_int = mode;
args[1].value.pdb_int = pdb_image_to_id(gimage);
args[2].value.pdb_int = drawable_ID (gimage_active_drawable (gimage));
args[3].value.pdb_pointer = filename;
args[4].value.pdb_pointer = raw_filename;
return_vals = procedural_db_execute (proc->name, args);
return_val = (return_vals[0].value.pdb_int == PDB_SUCCESS);
if (return_val)
{
/* set this image to clean */
gimage_clean_all (gimage);
/* these calls must come before the call to gimage_set_filename */
idea_add (filename);
menus_last_opened_add (filename);
/* use the same plug-in for this image next time */
/* DISABLED - gets stuck on first saved format... needs
attention --Adam */
/* gimage_set_save_proc(gimage, file_proc); */
/* Write a thumbnail for the saved image, where appropriate */
switch (thumbnail_mode)
{
case 0:
break;
default:
{
TempBuf* tempbuf;
tempbuf = make_thumb_tempbuf (gimage);
file_save_thumbnail (gimage, filename, tempbuf);
}
}
/* set the image title */
gimp_image_set_filename (gimage, filename);
/* note: 'filename' may have been free'd by above call! */
}
g_free (return_vals);
g_free (args);
return return_val;
}
/* The readXVThumb function source may be re-used under
the XFree86-style license. <adam@gimp.org> */
static guchar*
readXVThumb (const gchar *fnam,
gint *w,
gint *h,
gchar **imginfo /* caller frees if != NULL */)
{
FILE *fp;
const gchar *P7_332 = "P7 332";
gchar P7_buf[7];
gchar linebuf[200];
guchar *buf;
gint twofivefive;
void *ptr;
*w = *h = 0;
*imginfo = NULL;
fp = fopen (fnam, "rb");
if (!fp)
return (NULL);
fread (P7_buf, 6, 1, fp);
if (strncmp(P7_buf, P7_332, 6)!=0)
{
g_warning("Thumbnail doesn't have the 'P7 332' header.");
fclose(fp);
return(NULL);
}
/*newline*/
fread (P7_buf, 1, 1, fp);
do
{
ptr = fgets(linebuf, 199, fp);
if ((strncmp(linebuf, "#IMGINFO:", 9) == 0) &&
(linebuf[9] != '\0') &&
(linebuf[9] != '\n'))
{
if (linebuf[strlen(linebuf)-1] == '\n')
linebuf[strlen(linebuf)-1] = '\0';
if (linebuf[9] != '\0')
{
if (*imginfo)
g_free(*imginfo);
*imginfo = g_strdup (&linebuf[9]);
}
}
}
while (ptr && linebuf[0]=='#'); /* keep throwing away comment lines */
if (!ptr)
{
/* g_warning("Thumbnail ended - not an image?"); */
fclose(fp);
return(NULL);
}
sscanf(linebuf, "%d %d %d\n", w, h, &twofivefive);
if (twofivefive!=255)
{
g_warning("Thumbnail is of funky depth.");
fclose(fp);
return(NULL);
}
if ((*w)<1 || (*h)<1 || (*w)>80 || (*h)>60)
{
g_warning ("Thumbnail size bad. Corrupted?");
fclose(fp);
return (NULL);
}
buf = g_malloc((*w)*(*h));
fread(buf, (*w)*(*h), 1, fp);
fclose(fp);
return(buf);
}
/* don't call with preview_fullname as parameter! will be clobbered! */
static void
set_preview (const gchar *fullfname,
guchar *RGB_source,
gint RGB_w,
gint RGB_h)
{
guchar *thumb_rgb;
guchar *raw_thumb;
gint tnw,tnh, i;
gchar *pname;
gchar *fname;
gchar *tname;
gchar *imginfo = NULL;
struct stat file_stat;
struct stat thumb_stat;
gboolean thumb_may_be_outdated = FALSE;
gboolean show_generate_label = TRUE;
pname = g_dirname (fullfname);
fname = g_basename (fullfname); /* Don't free this! */
tname = g_strconcat (pname, G_DIR_SEPARATOR_S, ".xvpics", G_DIR_SEPARATOR_S,
fname,
NULL);
g_free (pname);
/* If the file is newer than its thumbnail, the thumbnail may
be out of date. */
if ((stat(tname, &thumb_stat)==0) &&
(stat(fullfname, &file_stat )==0))
{
if ((thumb_stat.st_mtime) < (file_stat.st_mtime))
{
thumb_may_be_outdated = TRUE;
}
}
raw_thumb = readXVThumb(tname, &tnw, &tnh, &imginfo);
g_free (tname);
gtk_frame_set_label (GTK_FRAME(open_options_frame),
fname);
if (preview_fullname)
{
g_free (preview_fullname);
}
preview_fullname = g_strdup (fullfname);
if (RGB_source)
{
gtk_preview_size (open_options_preview, RGB_w, RGB_h);
for (i=0; i<RGB_h; i++)
{
gtk_preview_draw_row(open_options_preview, &RGB_source[3*i*RGB_w],
0, i,
RGB_w);
}
}
else
{
if (raw_thumb)
{
thumb_rgb = g_malloc (3 * tnw * tnh);
for (i=0; i<tnw*tnh; i++)
{
thumb_rgb[i*3 ] = ((raw_thumb[i]>>5)*255)/7;
thumb_rgb[i*3+1] = (((raw_thumb[i]>>2)&7)*255)/7;
thumb_rgb[i*3+2] = (((raw_thumb[i])&3)*255)/3;
}
gtk_preview_size (open_options_preview, tnw, tnh);
for (i=0; i<tnh; i++)
{
gtk_preview_draw_row(open_options_preview, &thumb_rgb[3*i*tnw],
0, i,
tnw);
}
g_free (thumb_rgb);
}
}
if (raw_thumb || RGB_source) /* We can show *some* kind of preview. */
{
if (raw_thumb) /* Managed to commit thumbnail file to disk */
{
gtk_label_set_text (GTK_LABEL(open_options_label),
thumb_may_be_outdated ?
_("(this thumbnail may be out of date)") :
(imginfo ? imginfo : _("(no information)")));
if (imginfo)
g_free (imginfo);
}
else
{
switch (thumbnail_mode)
{
case 0:
gtk_label_set_text (GTK_LABEL(open_options_label),
_("(thumbnail saving is disabled)"));
break;
case 1:
gtk_label_set_text (GTK_LABEL(open_options_label),
_("(could not write thumbnail file)"));
break;
default:
gtk_label_set_text (GTK_LABEL(open_options_label),
_("(thumbnail file not written)"));
}
}
gtk_widget_show (GTK_WIDGET(open_options_preview));
gtk_widget_queue_draw (GTK_WIDGET(open_options_preview));
show_generate_label = FALSE;
g_free (raw_thumb);
}
else
{
if (imginfo)
g_free(imginfo);
gtk_widget_hide (GTK_WIDGET(open_options_preview));
gtk_label_set_text (GTK_LABEL(open_options_label),
_("no preview available"));
}
if (show_generate_label)
{
gtk_widget_hide (GTK_WIDGET(open_options_preview));
gtk_widget_show (GTK_WIDGET(open_options_genbuttonlabel));
}
else
{
gtk_widget_hide (GTK_WIDGET(open_options_genbuttonlabel));
gtk_widget_show (GTK_WIDGET(open_options_preview));
}
}
static void
file_open_clistrow_callback (GtkWidget *widget,
int data)
{
gchar *fullfname = NULL;
fullfname = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fileload));
gtk_widget_set_sensitive (GTK_WIDGET (open_options_frame), TRUE);
set_preview (fullfname, NULL, 0, 0);
}
static void
genbutton_callback (GtkWidget *widget,
gpointer data)
{
GimpImage* gimage_to_be_thumbed;
gchar* filename;
guchar* RGBbuf;
TempBuf* tempbuf;
gint RGBbuf_w;
gint RGBbuf_h;
/* added for multi-file preview generation... */
GtkFileSelection *fs;
gchar* mfilename = NULL;
gchar* filedirname;
struct stat buf;
int err;
fs = GTK_FILE_SELECTION (data);
if (!preview_fullname)
{
g_warning ("Tried to generate thumbnail for NULL filename.");
return;
}
filename = g_strdup (preview_fullname);
gimp_add_busy_cursors ();
gtk_widget_set_sensitive (GTK_WIDGET (fileload), FALSE);
/* new mult-file preview make: */
{
GList *row = GTK_CLIST(fs->file_list)->row_list;
gint rownum = 0;
gchar* temp;
filedirname = g_dirname (filename);
while (row)
{
if (GTK_CLIST_ROW(row)->state == GTK_STATE_SELECTED)
{
if (gtk_clist_get_cell_type(GTK_CLIST(fs->file_list),
rownum, 0) == GTK_CELL_TEXT)
{
gtk_clist_get_text (GTK_CLIST(fs->file_list),
rownum, 0, &temp);
mfilename = g_strdup (temp);
err = stat (mfilename, &buf);
if (! (err == 0 && (buf.st_mode & S_IFDIR)))
{ /* Is not directory. */
if (err)
{
g_free (mfilename);
mfilename = g_strconcat (filedirname,
G_DIR_SEPARATOR_S,
temp, NULL);
}
/* When doing multiple selections, the name
* of the first item touched with the cursor will
* become the text-field default - and we don't
* want to load that twice.
*/
if (strcmp (mfilename, filename) == 0)
{
goto next_iter;
}
if ((gimage_to_be_thumbed = file_open_image (mfilename,
temp,
RUN_NONINTERACTIVE)))
{
tempbuf = make_thumb_tempbuf (gimage_to_be_thumbed);
RGBbuf = make_RGBbuf_from_tempbuf (tempbuf, &RGBbuf_w, &RGBbuf_h);
switch (thumbnail_mode)
{
case 0:
break;
default:
file_save_thumbnail (gimage_to_be_thumbed, mfilename, tempbuf);
}
set_preview (mfilename, RGBbuf, RGBbuf_w, RGBbuf_h);
gimage_delete (gimage_to_be_thumbed);
if (RGBbuf)
g_free (RGBbuf);
}
else
{
gtk_label_set_text (GTK_LABEL(open_options_label),
_("(could not make preview)"));
}
}
}
}
next_iter:
if (mfilename)
{
g_free (mfilename);
mfilename = NULL;
}
rownum++;
row = g_list_next (row);
}
}
gtk_widget_set_sensitive (GTK_WIDGET (fileload), TRUE);
gimp_remove_busy_cursors (NULL);
if (filedirname)
g_free (filedirname);
g_free (filename);
}
static void
file_open_ok_callback (GtkWidget *widget,
gpointer data)
{
GtkFileSelection *fs;
gchar *filename;
gchar *raw_filename;
gchar *mfilename = NULL;
gchar *filedirname;
struct stat buf;
int err;
GString *s;
fs = GTK_FILE_SELECTION (data);
filename = gtk_file_selection_get_filename (fs);
raw_filename = gtk_entry_get_text (GTK_ENTRY(fs->selection_entry));
g_assert (filename && raw_filename);
if (strlen (raw_filename) == 0)
return;
err = stat (filename, &buf);
if (err == 0 && (buf.st_mode & S_IFDIR))
{
GString *s = g_string_new (filename);
if (s->str[s->len - 1] != G_DIR_SEPARATOR)
{
g_string_append_c (s, G_DIR_SEPARATOR);
}
gtk_file_selection_set_filename (fs, s->str);
g_string_free (s, TRUE);
return;
}
gtk_widget_set_sensitive (GTK_WIDGET (fs), FALSE);
if (err)
filename = raw_filename;
if (file_open (filename, raw_filename))
{
file_dialog_hide (data);
gtk_widget_set_sensitive (GTK_WIDGET (fs), TRUE);
}
else
{
s = g_string_new (_("Open failed: "));
g_string_append (s, raw_filename);
FILE_ERR_MESSAGE (s->str);
g_string_free (s, TRUE);
}
/*
* Now deal with multiple selections from the filesel clist
*/
/*
* FIXME: cope with cwd != fileselcwd != dirname(filename)
*/
/*
{
HistoryCallbackArg *callback_arg;
GList *row = fs->history_list;
while (row)
{
callback_arg = row->data;
printf ("(%s)\n", callback_arg->directory );
row = g_list_next (row);
}
}*/
/* filedirname = fs->history_list->data;*/
filedirname = g_dirname (filename);
{
GList *row = GTK_CLIST(fs->file_list)->row_list;
gint rownum = 0;
gchar* temp;
while (row)
{
if (GTK_CLIST_ROW(row)->state == GTK_STATE_SELECTED)
{
if (gtk_clist_get_cell_type(GTK_CLIST(fs->file_list),
rownum, 0) == GTK_CELL_TEXT)
{
gtk_clist_get_text (GTK_CLIST(fs->file_list),
rownum, 0, &temp);
/* When doing multiple selections, the name
* of the first item touched with the cursor will
* become the text-field default - and we don't
* want to load that twice.
*/
if (strcmp(temp, raw_filename)==0)
{
goto next_iter;
}
mfilename = g_strdup (temp);
err = stat (mfilename, &buf);
if (! (err == 0 && (buf.st_mode & S_IFDIR)))
{ /* Is not directory. */
if (err)
{
g_free (mfilename);
mfilename = g_strconcat (filedirname,
G_DIR_SEPARATOR_S,
temp, NULL);
}
if (file_open (mfilename, temp))
{
file_dialog_hide (data);
gtk_widget_set_sensitive (GTK_WIDGET (fs), TRUE);
}
else
{
s = g_string_new (_("Open failed: "));
g_string_append (s, temp);
FILE_ERR_MESSAGE (s->str);
g_string_free (s, TRUE);
}
}
}
}
next_iter:
if (mfilename)
{
g_free (mfilename);
mfilename = NULL;
}
rownum++;
row = g_list_next (row);
}
}
if (filedirname)
g_free (filedirname);
}
static void
file_save_ok_callback (GtkWidget *widget,
gpointer data)
{
GtkFileSelection *fs;
char* filename, *raw_filename;
GString* s;
struct stat buf;
int err;
fs = GTK_FILE_SELECTION (data);
filename = gtk_file_selection_get_filename (fs);
raw_filename = gtk_entry_get_text (GTK_ENTRY(fs->selection_entry));
err = stat (filename, &buf);
g_assert (filename && raw_filename);
if (err == 0)
{
if (buf.st_mode & S_IFDIR)
{
GString *s = g_string_new (filename);
g_string_append_c (s, G_DIR_SEPARATOR);
gtk_file_selection_set_filename (fs, s->str);
g_string_free (s, TRUE);
return;
}
else if (buf.st_mode & S_IFREG)
{
gtk_widget_set_sensitive (GTK_WIDGET (fs), FALSE);
file_overwrite (g_strdup (filename), g_strdup (raw_filename));
return;
}
else
{
s = g_string_new (NULL);
g_string_sprintf (s, _("%s is an irregular file (%s)"), raw_filename, g_strerror(errno));
}
} else {
gtk_widget_set_sensitive (GTK_WIDGET (fs), FALSE);
gimage_set_save_proc(the_gimage, save_file_proc);
if (file_save (the_gimage, filename, raw_filename, 0))
{
file_dialog_hide (data);
gtk_widget_set_sensitive (GTK_WIDGET (fs), TRUE);
return;
}
else
{
s = g_string_new (_("Save failed: "));
g_string_append (s, raw_filename);
}
}
FILE_ERR_MESSAGE (s->str);
g_string_free (s, TRUE);
}
static void
file_dialog_show (GtkWidget *filesel)
{
menus_set_sensitive_glue ("<Toolbox>", N_("/File/Open..."), FALSE);
menus_set_sensitive_glue ("<Image>", N_("/File/Open..."), FALSE);
menus_set_sensitive_glue ("<Image>", N_("/File/Save"), FALSE);
menus_set_sensitive_glue ("<Image>", N_("/File/Save as..."), FALSE);
gtk_widget_show (filesel);
}
static int
file_dialog_hide (GtkWidget *filesel)
{
gtk_widget_hide (filesel);
menus_set_sensitive_glue ("<Toolbox>", N_("/File/Open..."), TRUE);
menus_set_sensitive_glue ("<Image>", N_("/File/Open..."), TRUE);
if (gdisplay_active ())
{
menus_set_sensitive_glue ("<Image>", N_("/File/Save"), TRUE);
menus_set_sensitive_glue ("<Image>", N_("/File/Save as..."), TRUE);
}
return TRUE;
}
static void
file_overwrite (char *filename,
char *raw_filename)
{
OverwriteBox *overwrite_box;
GtkWidget *vbox;
GtkWidget *label;
char *overwrite_text;
overwrite_box = g_new (OverwriteBox, 1);
overwrite_text = g_strdup_printf (_("%s exists, overwrite?"), filename);
overwrite_box->full_filename = filename;
overwrite_box->raw_filename = raw_filename;
overwrite_box->obox = gimp_dialog_new (_("File Exists!"), "file_exists",
gimp_standard_help_func,
"save/file_exists.html",
GTK_WIN_POS_MOUSE,
FALSE, TRUE, FALSE,
_("Yes"), file_overwrite_yes_callback,
overwrite_box, NULL, TRUE, FALSE,
_("No"), file_overwrite_no_callback,
overwrite_box, NULL, FALSE, TRUE,
NULL);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (overwrite_box->obox)->vbox),
vbox);
label = gtk_label_new (overwrite_text);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, FALSE, 0);
gtk_widget_show (label);
gtk_widget_show (vbox);
gtk_widget_show (overwrite_box->obox);
g_free (overwrite_text);
}
static void
file_overwrite_yes_callback (GtkWidget *widget,
gpointer data)
{
OverwriteBox *overwrite_box;
GImage *gimage;
overwrite_box = (OverwriteBox *) data;
gtk_widget_destroy (overwrite_box->obox);
if ((gimage = the_gimage) != NULL &&
file_save (the_gimage, overwrite_box->full_filename, overwrite_box->raw_filename, 0))
{
the_gimage = NULL;
file_dialog_hide (filesave);
}
else
{
GString *s;
GtkWidget *fs;
fs = filesave;
s = g_string_new (_("Save failed: "));
g_string_append (s, overwrite_box->raw_filename);
FILE_ERR_MESSAGE (s->str);
g_string_free (s, TRUE);
}
g_free (overwrite_box->full_filename);
g_free (overwrite_box->raw_filename);
g_free (overwrite_box);
}
static void
file_overwrite_no_callback (GtkWidget *widget,
gpointer data)
{
OverwriteBox *overwrite_box;
overwrite_box = (OverwriteBox *) data;
gtk_widget_destroy (overwrite_box->obox);
g_free (overwrite_box->full_filename);
g_free (overwrite_box->raw_filename);
g_free (overwrite_box);
gtk_widget_set_sensitive (GTK_WIDGET(filesave), TRUE);
}
PlugInProcDef*
file_proc_find (GSList *procs,
char *filename)
{
PlugInProcDef *file_proc, *size_matched_proc;
GSList *all_procs = procs;
GSList *extensions;
GSList *prefixes;
char *extension;
char *p1, *p2;
FILE *ifp = NULL;
int head_size = -2, size_match_count = 0;
int match_val;
unsigned char head[256];
size_matched_proc = NULL;
extension = strrchr (filename, '.');
if (extension)
extension += 1;
/* At first look for magics */
while (procs)
{
file_proc = procs->data;
procs = procs->next;
if (file_proc->magics_list)
{
if (head_size == -2)
{
head_size = 0;
if ((ifp = fopen (filename, "rb")) != NULL)
head_size = fread ((char *)head, 1, sizeof (head), ifp);
}
if (head_size >= 4)
{
match_val = file_check_magic_list (file_proc->magics_list,
head_size, head, ifp);
if (match_val == 2) /* size match ? */
{ /* Use it only if no other magic matches */
size_match_count++;
size_matched_proc = file_proc;
}
else if (match_val)
{
fclose (ifp);
return (file_proc);
}
}
}
}
if (ifp) fclose (ifp);
if (size_match_count == 1) return (size_matched_proc);
procs = all_procs;
while (procs)
{
file_proc = procs->data;
procs = procs->next;
for (prefixes = file_proc->prefixes_list; prefixes; prefixes = prefixes->next)
{
p1 = filename;
p2 = (char*) prefixes->data;
if (strncmp (filename, prefixes->data, strlen (prefixes->data)) == 0)
return file_proc;
}
}
procs = all_procs;
while (procs)
{
file_proc = procs->data;
procs = procs->next;
for (extensions = file_proc->extensions_list; extension && extensions; extensions = extensions->next)
{
p1 = extension;
p2 = (char*) extensions->data;
while (*p1 && *p2)
{
if (tolower (*p1) != tolower (*p2))
break;
p1 += 1;
p2 += 1;
}
if (!(*p1) && !(*p2))
return file_proc;
}
}
return NULL;
}
static void
file_convert_string (char *instr,
char *outmem,
int maxmem,
int *nmem)
{
/* Convert a string in C-notation to array of char */
guchar *uin = (guchar *) instr;
guchar *uout = (guchar *) outmem;
guchar tmp[5], *tmpptr;
int k;
while ((*uin != '\0') && ((((char *)uout) - outmem) < maxmem))
{
if (*uin != '\\') /* Not an escaped character ? */
{
*(uout++) = *(uin++);
continue;
}
if (*(++uin) == '\0')
{
*(uout++) = '\\';
break;
}
switch (*uin)
{
case '0': case '1': case '2': case '3': /* octal */
for (tmpptr = tmp; (tmpptr-tmp) <= 3;)
{
*(tmpptr++) = *(uin++);
if ( (*uin == '\0') || (!isdigit (*uin))
|| (*uin == '8') || (*uin == '9'))
break;
}
*tmpptr = '\0';
sscanf ((char *)tmp, "%o", &k);
*(uout++) = k;
break;
case 'a': *(uout++) = '\a'; uin++; break;
case 'b': *(uout++) = '\b'; uin++; break;
case 't': *(uout++) = '\t'; uin++; break;
case 'n': *(uout++) = '\n'; uin++; break;
case 'v': *(uout++) = '\v'; uin++; break;
case 'f': *(uout++) = '\f'; uin++; break;
case 'r': *(uout++) = '\r'; uin++; break;
default : *(uout++) = *(uin++); break;
}
}
*nmem = ((char *)uout) - outmem;
}
static int
file_check_single_magic (char *offset,
char *type,
char *value,
int headsize,
guchar *file_head,
FILE *ifp)
{ /* Return values are 0: no match, 1: magic match, 2: size match */
long offs;
gulong num_testval, num_operatorval;
gulong fileval;
int numbytes, k, c = 0, found = 0;
char *num_operator_ptr, num_operator, num_test;
guchar mem_testval[256];
/* Check offset */
if (sscanf (offset, "%ld", &offs) != 1) return (0);
if (offs < 0) return (0);
/* Check type of test */
num_operator_ptr = NULL;
num_operator = '\0';
num_test = '=';
if (strncmp (type, "byte", 4) == 0)
{
numbytes = 1;
num_operator_ptr = type+4;
}
else if (strncmp (type, "short", 5) == 0)
{
numbytes = 2;
num_operator_ptr = type+5;
}
else if (strncmp (type, "long", 4) == 0)
{
numbytes = 4;
num_operator_ptr = type+4;
}
else if (strncmp (type, "size", 4) == 0)
{
numbytes = 5;
}
else if (strcmp (type, "string") == 0)
{
numbytes = 0;
}
else return (0);
/* Check numerical operator value if present */
if (num_operator_ptr && (*num_operator_ptr == '&'))
{
if (isdigit (num_operator_ptr[1]))
{
if (num_operator_ptr[1] != '0') /* decimal */
sscanf (num_operator_ptr+1, "%ld", &num_operatorval);
else if (num_operator_ptr[2] == 'x') /* hexadecimal */
sscanf (num_operator_ptr+3, "%lx", &num_operatorval);
else /* octal */
sscanf (num_operator_ptr+2, "%lo", &num_operatorval);
num_operator = *num_operator_ptr;
}
}
if (numbytes > 0) /* Numerical test ? */
{
/* Check test value */
if ((value[0] == '=') || (value[0] == '>') || (value[0] == '<'))
{
num_test = value[0];
value++;
}
if (!isdigit (value[0])) return (0);
if (value[0] != '0') /* decimal */
num_testval = strtol(value, NULL, 10);
else if (value[1] == 'x') /* hexadecimal */
num_testval = strtol(value+2, NULL, 16);
else /* octal */
num_testval = strtol(value+1, NULL, 8);
fileval = 0;
if (numbytes == 5) /* Check for file size ? */
{
struct stat buf;
if (fstat (fileno (ifp), &buf) < 0) return (0);
fileval = buf.st_size;
}
else if (offs + numbytes <= headsize) /* We have it in memory ? */
{
for (k = 0; k < numbytes; k++)
fileval = (fileval << 8) | (long)file_head[offs+k];
}
else /* Read it from file */
{
if (fseek (ifp, offs, SEEK_SET) < 0) return (0);
for (k = 0; k < numbytes; k++)
fileval = (fileval << 8) | (c = getc (ifp));
if (c == EOF) return (0);
}
if (num_operator == '&')
fileval &= num_operatorval;
if (num_test == '<')
found = (fileval < num_testval);
else if (num_test == '>')
found = (fileval > num_testval);
else
found = (fileval == num_testval);
if (found && (numbytes == 5)) found = 2;
}
else if (numbytes == 0) /* String test */
{
file_convert_string ((char *)value, (char *)mem_testval,
sizeof (mem_testval), &numbytes);
if (numbytes <= 0) return (0);
if (offs + numbytes <= headsize) /* We have it in memory ? */
{
found = (memcmp (mem_testval, file_head+offs, numbytes) == 0);
}
else /* Read it from file */
{
if (fseek (ifp, offs, SEEK_SET) < 0) return (0);
found = 1;
for (k = 0; found && (k < numbytes); k++)
{
c = getc (ifp);
found = (c != EOF) && (c == (int)mem_testval[k]);
}
}
}
return (found);
}
static int
file_check_magic_list (GSList *magics_list,
int headsize,
guchar *head,
FILE *ifp)
{
/* Return values are 0: no match, 1: magic match, 2: size match */
char *offset, *type, *value;
int and = 0;
int found = 0, match_val;
while (magics_list)
{
if ((offset = (char *)magics_list->data) == NULL) break;
if ((magics_list = magics_list->next) == NULL) break;
if ((type = (char *)magics_list->data) == NULL) break;
if ((magics_list = magics_list->next) == NULL) break;
if ((value = (char *)magics_list->data) == NULL) break;
magics_list = magics_list->next;
match_val = file_check_single_magic (offset, type, value,
headsize, head, ifp);
if (and)
found = found && match_val;
else
found = match_val;
and = (strchr (offset, '&') != NULL);
if ((!and) && found) return (match_val);
}
return (0);
}
static void
file_update_menus (GSList *procs,
int image_type)
{
PlugInProcDef *file_proc;
while (procs)
{
file_proc = procs->data;
procs = procs->next;
if (file_proc->db_info.proc_type != PDB_EXTENSION)
menus_set_sensitive (file_proc->menu_path,
(file_proc->image_types_val & image_type));
}
}