fileops.c 60.1 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 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
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18
 */
19

20
21
#include "config.h"

22
23
24
25
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif

Sven Neumann's avatar
Sven Neumann committed
26
#include <gtk/gtk.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
27

Elliot Lee's avatar
Elliot Lee committed
28
29
#include <ctype.h>
#include <errno.h>
30
#include <stdio.h>
31
#include <stdlib.h>
Elliot Lee's avatar
Elliot Lee committed
32
33
34
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
35
#ifdef HAVE_UNISTD_H
Elliot Lee's avatar
Elliot Lee committed
36
#include <unistd.h>
37
#endif
Elliot Lee's avatar
Elliot Lee committed
38
39
#include <errno.h>

40
#ifdef G_OS_WIN32
41
42
#include <direct.h>		/* For _mkdir() */
#define mkdir(path,mode) _mkdir(path)
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <io.h>
#ifndef S_IWUSR
#define S_IWUSR _S_IWRITE
#endif
#ifndef S_IRUSR
#define S_IRUSR _S_IREAD
#endif
#ifndef S_IWGRP
#define S_IWGRP (_S_IWRITE>>3)
#define S_IWOTH (_S_IWRITE>>6)
#endif
#ifndef S_IRGRP
#define S_IRGRP (_S_IREAD>>3)
#define S_IROTH (_S_IREAD>>6)
#endif
#define uid_t gint
#define gid_t gint
#define geteuid() 0
#define getegid() 0
62
63
#endif

Sven Neumann's avatar
Sven Neumann committed
64
65
#include "apptypes.h"

Elliot Lee's avatar
Elliot Lee committed
66
#include "appenv.h"
67
#include "channel.h"
68
#include "cursorutil.h"
69
#include "dialog_handler.h"
70
71
#include "docindex.h"
#include "drawable.h"
Elliot Lee's avatar
Elliot Lee committed
72
73
#include "gdisplay.h"
#include "gimage.h"
74
#include "gimpcontext.h"
75
#include "gimpdrawable.h"
76
#include "gimpui.h"
77
#include "gimprc.h"
Elliot Lee's avatar
Elliot Lee committed
78
#include "fileops.h"
79
#include "fileopsP.h"
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
80
#include "layer.h"
81
#include "menus.h"
Elliot Lee's avatar
Elliot Lee committed
82
83
#include "plug_in.h"
#include "procedural_db.h"
84
#include "temp_buf.h"
85
#include "undo.h"
Elliot Lee's avatar
Elliot Lee committed
86

87
#include "libgimp/gimphelpui.h"
88
#include "libgimp/gimpmath.h"
89

90
91
92
#include "libgimp/gimpintl.h"


93
94
95
#define REVERT_DATA_KEY "revert_confirm_dialog"


96
typedef struct _OverwriteData OverwriteData;
Elliot Lee's avatar
Elliot Lee committed
97

98
struct _OverwriteData
Elliot Lee's avatar
Elliot Lee committed
99
{
100
101
  gchar *full_filename;
  gchar *raw_filename;
Elliot Lee's avatar
Elliot Lee committed
102
103
};

104

105
106
107
static void    file_open_dialog_create      (void);
static void    file_save_dialog_create      (void);

108
109
110
111
112
static void    file_overwrite               (gchar         *filename,
					     gchar         *raw_filename);
static void    file_overwrite_callback      (GtkWidget     *widget,
					     gboolean       overwrite,
					     gpointer       data);
113
114
115
static void    file_revert_confirm_callback (GtkWidget     *widget,
					     gboolean       revert,
					     gpointer       data);
116

117
118
119
static GimpImage * file_open_image          (const gchar   *filename,
					     const gchar   *raw_filename,
					     const gchar   *open_mode,
120
121
					     RunModeType    run_mode,
					     gint          *status);
122

123
static gint    file_save                    (GimpImage     *gimage,
124
125
					     gchar         *filename,
					     gchar         *raw_filename,
126
127
					     RunModeType    run_mode,
					     gboolean       set_filename);
128

129
130
static void    file_open_genbutton_callback (GtkWidget     *widget,
					     gpointer       data);
131

132
133
static void    file_open_clistrow_callback  (GtkWidget     *widget,
					     gint           row);
134

135
136
static void    file_open_ok_callback        (GtkWidget     *widget,
					     gpointer       data);
137

138
139
static void    file_save_ok_callback        (GtkWidget     *widget,
					     gpointer       data);
140

141
142
143
144
static void    file_dialog_show             (GtkWidget     *filesel);
static gint    file_dialog_hide             (GtkWidget     *filesel);
static void    file_update_name             (PlugInProcDef *proc,
					     GtkWidget     *filesel);
145

146
147
148
149
static void    file_open_type_callback      (GtkWidget     *widget,
					     gpointer       data);
static void    file_save_type_callback      (GtkWidget     *widget,
					     gpointer       data);
150

151
152
153
154
static void    file_convert_string          (gchar         *instr,
					     gchar         *outmem,
					     gint           maxmem,
					     gint          *nmem);
155

156
static gchar * file_absolute_filename       (gchar         *name);
157

158
159
160
161
162
163
static gint    file_check_single_magic      (gchar         *offset,
					     gchar         *type,
					     gchar         *value,
					     gint           headsize,
					     guchar        *file_head,
					     FILE          *ifp);
Elliot Lee's avatar
Elliot Lee committed
164

165
166
167
168
static gint    file_check_magic_list        (GSList        *magics_list,
					     gint           headsize,
					     guchar        *head,
					     FILE          *ifp);
Elliot Lee's avatar
Elliot Lee committed
169

170
171
static void    file_update_menus            (GSList        *procs,
					     gint           image_type);
Elliot Lee's avatar
Elliot Lee committed
172

173
174
static GSList* clist_to_slist               (GtkCList      *file_list);

175
176


177
178
static GtkWidget  *fileload     = NULL;
static GtkWidget  *filesave     = NULL;
179
180
static GtkWidget  *open_options = NULL;
static GtkWidget  *save_options = NULL;
181

182
/* widgets for the open_options menu */
183
184
185
186
static GtkPreview *open_options_preview        = NULL;
static GtkWidget  *open_options_fixed          = NULL;
static GtkWidget  *open_options_label          = NULL;
static GtkWidget  *open_options_frame          = NULL;
187
static GtkWidget  *open_options_genbuttonlabel = NULL;
188

189
/* Some state for the thumbnailer */
190
static gchar *preview_fullname = NULL;
191

192
193
GSList *load_procs = NULL;
GSList *save_procs = NULL;
Elliot Lee's avatar
Elliot Lee committed
194
195
196
197

static PlugInProcDef *load_file_proc = NULL;
static PlugInProcDef *save_file_proc = NULL;

198
199
static GimpImage *the_gimage   = NULL;
static gboolean   set_filename = TRUE;
200
201

extern GSList *display_list; /* from gdisplay.c */
Elliot Lee's avatar
Elliot Lee committed
202
203
204


void
205
file_ops_pre_init (void)
Elliot Lee's avatar
Elliot Lee committed
206
207
208
209
{
}

void
210
file_ops_post_init (void)
Elliot Lee's avatar
Elliot Lee committed
211
{
212
  GimpItemFactoryEntry entry;
Elliot Lee's avatar
Elliot Lee committed
213
214
215
216
217
218
  PlugInProcDef *file_proc;
  GSList *tmp;

  load_procs = g_slist_reverse (load_procs);
  save_procs = g_slist_reverse (save_procs);

219
  for (tmp = load_procs; tmp;  tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
220
    {
221
222
      gchar *help_page;

Elliot Lee's avatar
Elliot Lee committed
223
224
      file_proc = tmp->data;

Michael Natterer's avatar
Michael Natterer committed
225
226
      help_page = g_strconcat ("filters/",
			       g_basename (file_proc->prog),
227
228
229
230
			       ".html",
			       NULL);
      g_strdown (help_page);

231
232
233
      entry.entry.path            = file_proc->menu_path;
      entry.entry.accelerator     = NULL;
      entry.entry.callback        = file_open_type_callback;
234
      entry.entry.callback_action = 0;
235
236
237
      entry.entry.item_type       = NULL;
      entry.help_page             = help_page;
      entry.description           = NULL;
Elliot Lee's avatar
Elliot Lee committed
238

239
      menus_create_item_from_full_path (&entry, NULL, file_proc);
Elliot Lee's avatar
Elliot Lee committed
240
241
    }

242
  for (tmp = save_procs; tmp; tmp = g_slist_next (tmp))
Elliot Lee's avatar
Elliot Lee committed
243
    {
244
245
      gchar *help_page;

Elliot Lee's avatar
Elliot Lee committed
246
247
      file_proc = tmp->data;

Michael Natterer's avatar
Michael Natterer committed
248
249
      help_page = g_strconcat ("filters/",
			       g_basename (file_proc->prog),
250
251
252
253
			       ".html",
			       NULL);
      g_strdown (help_page);

254
255
256
      entry.entry.path            = file_proc->menu_path;
      entry.entry.accelerator     = NULL;
      entry.entry.callback        = file_save_type_callback;
257
      entry.entry.callback_action = 0;
258
259
260
      entry.entry.item_type       = NULL;
      entry.help_page             = help_page;
      entry.description           = NULL;
Elliot Lee's avatar
Elliot Lee committed
261

262
      menus_create_item_from_full_path (&entry, NULL, file_proc);
Elliot Lee's avatar
Elliot Lee committed
263
264
265
    }
}

266
267
static void
file_open_dialog_create (void)
Elliot Lee's avatar
Elliot Lee committed
268
{
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  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");

  gtk_container_set_border_width (GTK_CONTAINER (fileload), 2);
  gtk_container_set_border_width 
    (GTK_CONTAINER (GTK_FILE_SELECTION (fileload)->button_area), 2);

  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",
     GTK_SIGNAL_FUNC (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",
     GTK_SIGNAL_FUNC (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");
Elliot Lee's avatar
Elliot Lee committed
306

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  {
    GtkWidget *frame;
    GtkWidget *vbox;
    GtkWidget *hbox;
    GtkWidget *option_menu;
    GtkWidget *load_menu;
    GtkWidget *open_options_genbutton;

    open_options = gtk_hbox_new (TRUE, 1);

    /* format-chooser frame */
    frame = gtk_frame_new (_("Determine File Type"));
    gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
    gtk_box_pack_start (GTK_BOX (open_options), frame, TRUE, TRUE, 4);

    vbox = gtk_vbox_new (FALSE, 2);
    gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
    gtk_container_add (GTK_CONTAINER (frame), vbox);

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

    option_menu = gtk_option_menu_new ();
    gtk_box_pack_start (GTK_BOX (hbox), option_menu, FALSE, FALSE, 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_widget_show (vbox);
    gtk_widget_show (frame);

    /* Preview frame */
    open_options_frame = frame = gtk_frame_new ("");
    gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
    gtk_box_pack_end (GTK_BOX (open_options), frame, FALSE, TRUE, 4);

    vbox = gtk_vbox_new (FALSE, 2);
    gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
    gtk_container_add (GTK_CONTAINER (frame), vbox);

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

    open_options_genbutton = gtk_button_new ();
    gtk_signal_connect (GTK_OBJECT (open_options_genbutton), "clicked",
			GTK_SIGNAL_FUNC (file_open_genbutton_callback),
			fileload);
    gtk_box_pack_start (GTK_BOX (hbox), open_options_genbutton,
			TRUE, FALSE, 0);
    gtk_widget_show (open_options_genbutton);	

    open_options_fixed = gtk_fixed_new ();
    gtk_widget_set_usize (open_options_fixed, 80, 60);
    gtk_container_add (GTK_CONTAINER (GTK_BIN (open_options_genbutton)),
		       open_options_fixed);
    gtk_widget_show (open_options_fixed);
Elliot Lee's avatar
Elliot Lee committed
366
367

    {
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
      GtkWidget* abox;
      GtkWidget* sbox;
      GtkWidget* align;

      sbox = gtk_vbox_new (TRUE, 0);
      gtk_container_add (GTK_CONTAINER (open_options_fixed), sbox);
      gtk_widget_show (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), align, FALSE, TRUE, 0);
      gtk_widget_show (align);

      abox = gtk_hbox_new (FALSE, 0);
      gtk_container_add (GTK_CONTAINER (align), abox);
      gtk_widget_show (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));
390

391
392
393
394
395
      open_options_genbuttonlabel = gtk_label_new (_("Generate\nPreview"));
      gtk_box_pack_start (GTK_BOX (abox), open_options_genbuttonlabel,
			  FALSE, TRUE, 0);
      gtk_widget_show (open_options_genbuttonlabel);
    }
396

397
398
399
    open_options_label = gtk_label_new ("");
    gtk_box_pack_start (GTK_BOX (vbox), open_options_label, FALSE, FALSE, 0);
    gtk_widget_show (open_options_label); 
400

401
402
    gtk_widget_show (vbox);
    gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
403

404
405
406
407
    /* pack the containing open_options hbox into the open-dialog */
    gtk_box_pack_end (GTK_BOX (GTK_FILE_SELECTION (fileload)->main_vbox),
		      open_options, FALSE, FALSE, 0);
  }
Elliot Lee's avatar
Elliot Lee committed
408

409
410
  gtk_frame_set_label (GTK_FRAME (open_options_frame), _("Preview"));
  gtk_label_set_text (GTK_LABEL (open_options_label), _("No Selection."));
411

412
413
414
  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);
Michael Natterer's avatar
Michael Natterer committed
415
416

  gtk_widget_show (open_options);
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
}

static void
file_save_dialog_create (void)
{
  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_container_set_border_width (GTK_CONTAINER (filesave), 2);
  gtk_container_set_border_width 
    (GTK_CONTAINER (GTK_FILE_SELECTION (filesave)->button_area), 2);

  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",
     GTK_SIGNAL_FUNC (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");

  {
    GtkWidget *frame;
    GtkWidget *hbox;
    GtkWidget *label;
    GtkWidget *option_menu;
    GtkWidget *save_menu;

    save_options = gtk_hbox_new (TRUE, 1);
456

457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
    frame = gtk_frame_new (_("Save Options"));
    gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
    gtk_box_pack_start (GTK_BOX (save_options), frame, TRUE, TRUE, 4);

    hbox = gtk_hbox_new (FALSE, 4);
    gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
    gtk_container_add (GTK_CONTAINER (frame), hbox);
    gtk_widget_show (hbox);

    label = gtk_label_new (_("Determine File Type:"));
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 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_widget_show (frame);

    /* pack the containing save_options hbox into the save-dialog */
    gtk_box_pack_end (GTK_BOX (GTK_FILE_SELECTION (filesave)->main_vbox),
		      save_options, FALSE, FALSE, 0);
  }

  gtk_widget_show (save_options);
}

void
file_open_callback (GtkWidget *widget,
		    gpointer   data)
{
  if (!fileload)
    file_open_dialog_create ();

  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"));
Elliot Lee's avatar
Elliot Lee committed
501
502
503
504
505

  file_dialog_show (fileload);
}

void
506
507
file_save_callback (GtkWidget *widget,
		    gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
508
509
510
511
{
  GDisplay *gdisplay;

  gdisplay = gdisplay_active ();
512
513
514
  if (! gdisplay)
    return;

515
  if (! gimp_image_active_drawable (gdisplay->gimage))
516
    return;
Elliot Lee's avatar
Elliot Lee committed
517
518

  /*  Only save if the gimage has been modified  */
519
  if (!trust_dirty_flag || gdisplay->gimage->dirty != 0)
Elliot Lee's avatar
Elliot Lee committed
520
521
522
    {
      if (gdisplay->gimage->has_filename == FALSE)
	{
523
	  file_save_as_callback (widget, data);
Elliot Lee's avatar
Elliot Lee committed
524
525
	}
      else
526
	{
527
	  gchar *filename;
528
529
530
	  gchar *raw_filename;
	  gint   status;

531
	  filename     = g_strdup (gimp_image_filename (gdisplay->gimage));
532
	  raw_filename = g_basename (filename);
Sven Neumann's avatar
Sven Neumann committed
533
	  
534
	  status = file_save (gdisplay->gimage,
535
			      filename,
536
			      raw_filename,
537
538
			      RUN_WITH_LAST_VALS,
			      TRUE);
539
540
541
542

	  if (status != PDB_SUCCESS &&
	      status != PDB_CANCEL)
	    {
543
	      g_message (_("Save failed.\n%s"), filename);
544
	    }
545
546

	  g_free (filename);
547
	}
Elliot Lee's avatar
Elliot Lee committed
548
549
550
551
    }
}

void
552
553
file_save_as_callback (GtkWidget *widget,
		       gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
554
555
556
{
  GDisplay *gdisplay;

Marc Lehmann's avatar
Marc Lehmann committed
557
  gdisplay = gdisplay_active ();
558
559
560
  if (! gdisplay)
    return;

561
  if (! gimp_image_active_drawable (gdisplay->gimage))
562
563
    return;

Marc Lehmann's avatar
Marc Lehmann committed
564
565
  the_gimage = gdisplay->gimage;

566
567
  set_filename = TRUE;

Elliot Lee's avatar
Elliot Lee committed
568
  if (!filesave)
569
570
571
572
573
574
575
576
577
578
579
580
581
582
    file_save_dialog_create ();

  gtk_widget_set_sensitive (GTK_WIDGET (filesave), TRUE);
  if (GTK_WIDGET_VISIBLE (filesave))
    return;

  gtk_window_set_title (GTK_WINDOW (filesave), _("Save Image"));

  gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesave),
                                   gdisplay->gimage->has_filename ?
                                   gimp_image_filename (gdisplay->gimage) :
                                   "." G_DIR_SEPARATOR_S);

  switch (gimp_drawable_type (gimp_image_active_drawable (gdisplay->gimage)))
Elliot Lee's avatar
Elliot Lee committed
583
    {
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
    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;
Elliot Lee's avatar
Elliot Lee committed
602
603
    }

604
605
  file_dialog_show (filesave);
}
Elliot Lee's avatar
Elliot Lee committed
606

607
608
609
610
611
void
file_save_a_copy_as_callback (GtkWidget *widget,
			      gpointer   data)
{
  GDisplay *gdisplay;
612

613
614
615
  gdisplay = gdisplay_active ();
  if (! gdisplay)
    return;
616

617
618
619
620
  if (! gimp_image_active_drawable (gdisplay->gimage))
    return;

  the_gimage = gdisplay->gimage;
Elliot Lee's avatar
Elliot Lee committed
621

622
  set_filename = FALSE;
Elliot Lee's avatar
Elliot Lee committed
623

624
625
  if (!filesave)
    file_save_dialog_create ();
Elliot Lee's avatar
Elliot Lee committed
626

627
628
629
  gtk_widget_set_sensitive (GTK_WIDGET (filesave), TRUE);
  if (GTK_WIDGET_VISIBLE (filesave))
    return;
630

631
  gtk_window_set_title (GTK_WINDOW (filesave), _("Save a Copy of the Image"));
632

633
634
635
636
  gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesave),
                                   gdisplay->gimage->has_filename ?
                                   gimp_image_filename (gdisplay->gimage) :
                                   "." G_DIR_SEPARATOR_S);
Elliot Lee's avatar
Elliot Lee committed
637

638
  switch (gimp_drawable_type (gimp_image_active_drawable (gdisplay->gimage)))
Elliot Lee's avatar
Elliot Lee committed
639
    {
640
    case RGB_GIMAGE:
641
      file_update_menus (save_procs, PLUG_IN_RGB_IMAGE);
Elliot Lee's avatar
Elliot Lee committed
642
      break;
643
    case RGBA_GIMAGE:
644
      file_update_menus (save_procs, PLUG_IN_RGBA_IMAGE);
Elliot Lee's avatar
Elliot Lee committed
645
      break;
646
    case GRAY_GIMAGE:
647
      file_update_menus (save_procs, PLUG_IN_GRAY_IMAGE);
648
649
      break;
    case GRAYA_GIMAGE:
650
      file_update_menus (save_procs, PLUG_IN_GRAYA_IMAGE);
651
652
      break;
    case INDEXED_GIMAGE:
653
      file_update_menus (save_procs, PLUG_IN_INDEXED_IMAGE);
654
655
      break;
    case INDEXEDA_GIMAGE:
656
      file_update_menus (save_procs, PLUG_IN_INDEXEDA_IMAGE);
Elliot Lee's avatar
Elliot Lee committed
657
658
659
660
661
662
      break;
    }

  file_dialog_show (filesave);
}

Manish Singh's avatar
Manish Singh committed
663
void
664
665
file_revert_callback (GtkWidget *widget,
		      gpointer   data)
Manish Singh's avatar
Manish Singh committed
666
{
667
  GDisplay  *gdisplay;
Manish Singh's avatar
Manish Singh committed
668
  GimpImage *gimage;
669
  GtkWidget *query_box;
Manish Singh's avatar
Manish Singh committed
670
671

  gdisplay = gdisplay_active ();
672
  if (!gdisplay || !gdisplay->gimage)
673
    return;
Manish Singh's avatar
Manish Singh committed
674

675
676
677
678
679
  gimage = gdisplay->gimage;

  query_box = gtk_object_get_data (GTK_OBJECT (gimage), REVERT_DATA_KEY);

  if (gimage->has_filename == FALSE)
680
    {
681
682
      g_message (_("Revert failed.\n"
		   "No filename associated with this image."));
683
    }
684
685
686
687
  else if (query_box)
    {
      gdk_window_raise (query_box->window);
    }
Manish Singh's avatar
Manish Singh committed
688
689
  else
    {
690
      gchar *text;
Manish Singh's avatar
Manish Singh committed
691

692
693
694
695
      text = g_strdup_printf (_("Reverting %s to\n"
				"%s\n\n"
				"(You will loose all your changes\n"
				"including all undo information)"),
696
697
			      g_basename (gimp_image_filename (gimage)),
			      gimp_image_filename (gimage));
698

699
700
701
702
703
704
      query_box = gimp_query_boolean_box (_("Revert Image?"),
					  gimp_standard_help_func,
					  "file/revert.html",
					  FALSE,
					  text,
					  _("Yes"), _("No"),
705
					  GTK_OBJECT (gimage), "destroy",
706
707
708
709
710
					  file_revert_confirm_callback,
					  gimage);

      g_free (text);

711
712
      gtk_object_set_data (GTK_OBJECT (gimage), REVERT_DATA_KEY, query_box);

713
      gtk_widget_show (query_box);
Manish Singh's avatar
Manish Singh committed
714
715
716
    }
}

Elliot Lee's avatar
Elliot Lee committed
717
void
718
file_open_by_extension_callback (GtkWidget *widget,
719
				 gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
720
721
722
723
724
{
  load_file_proc = NULL;
}

void
725
726
file_save_by_extension_callback (GtkWidget *widget,
				 gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
727
728
729
730
731
{
  save_file_proc = NULL;
}

static void
732
733
file_update_name (PlugInProcDef *proc,
		  GtkWidget     *filesel)
Elliot Lee's avatar
Elliot Lee committed
734
735
736
{
  if (proc->extensions_list)
    {
737
738
      gchar *text;
      gchar *last_dot;
Elliot Lee's avatar
Elliot Lee committed
739
740
      GString *s;

741
742
743
      text = gtk_entry_get_text (GTK_ENTRY (GTK_FILE_SELECTION (filesel)->selection_entry));
      last_dot = strrchr (text, '.');

Elliot Lee's avatar
Elliot Lee committed
744
745
746
747
748
749
750
751
752
      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, ".");
753
      g_string_append (s, (gchar *) proc->extensions_list->data);
Elliot Lee's avatar
Elliot Lee committed
754

755
      gtk_entry_set_text (GTK_ENTRY (GTK_FILE_SELECTION (filesel)->selection_entry), s->str);
Elliot Lee's avatar
Elliot Lee committed
756
757
758
759
760
761

      g_string_free (s, TRUE);
    }
}

static void
762
file_open_type_callback (GtkWidget *widget,
763
			 gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
764
{
765
  PlugInProcDef *proc = (PlugInProcDef *) data;
Elliot Lee's avatar
Elliot Lee committed
766
767
768
769
770
771
772

  file_update_name (proc, fileload);

  load_file_proc = proc;
}

static void
773
774
file_save_type_callback (GtkWidget *widget,
			 gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
775
{
776
  PlugInProcDef *proc = (PlugInProcDef *) data;
Elliot Lee's avatar
Elliot Lee committed
777
778
779
780
781
782

  file_update_name (proc, filesave);

  save_file_proc = proc;
}

783
static GimpImage *
784
785
786
file_open_image (const gchar *filename,
		 const gchar *raw_filename,
		 const gchar *open_mode,
787
		 RunModeType  run_mode,
788
		 gint        *status)
Elliot Lee's avatar
Elliot Lee committed
789
790
{
  PlugInProcDef *file_proc;
791
792
793
794
795
796
  ProcRecord    *proc;
  Argument      *args;
  Argument      *return_vals;
  gint           gimage_id;
  gint           i;
  struct stat    statbuf;
797
798

  *status = PDB_CANCEL;  /* inhibits error messages by caller */
Elliot Lee's avatar
Elliot Lee committed
799
800

  file_proc = load_file_proc;
801

Elliot Lee's avatar
Elliot Lee committed
802
803
804
805
806
  if (!file_proc)
    file_proc = file_proc_find (load_procs, filename);

  if (!file_proc)
    {
807
808
809
810
811
812
      /*  no errors when making thumbnails  */
      if (run_mode == RUN_INTERACTIVE)
	g_message (_("%s failed.\n"
		     "%s: Unknown file type."),
		   open_mode, filename);

Manish Singh's avatar
Manish Singh committed
813
      return NULL;
Elliot Lee's avatar
Elliot Lee committed
814
815
    }

816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
  /* check if we are opening a file */
  if (stat (filename, &statbuf) == 0)
    {
      uid_t euid;
      gid_t egid;

      if (! (statbuf.st_mode & S_IFREG))
	{
	  /*  no errors when making thumbnails  */
	  if (run_mode == RUN_INTERACTIVE)
	    g_message (_("%s failed.\n"
			 "%s is not a regular file."),
		       open_mode, filename);

	  return NULL;
	}

      euid = geteuid ();
      egid = getegid ();

      if (! ((statbuf.st_mode & S_IRUSR) ||

	     ((statbuf.st_mode & S_IRGRP) &&
	      (statbuf.st_uid != euid)) ||

	     ((statbuf.st_mode & S_IROTH) &&
	      (statbuf.st_uid != euid) &&
	      (statbuf.st_gid != egid))))
	{
	  /*  no errors when making thumbnails  */
	  if (run_mode == RUN_INTERACTIVE)
	    g_message (_("%s failed.\n"
			 "%s: Permission denied."),
		       open_mode, filename);

	  return NULL;
	}
    }

Elliot Lee's avatar
Elliot Lee committed
855
856
  proc = &file_proc->db_info;

857
  args = g_new0 (Argument, proc->num_args);
Elliot Lee's avatar
Elliot Lee committed
858
859
860
861

  for (i = 0; i < proc->num_args; i++)
    args[i].arg_type = proc->args[i].arg_type;

862
  args[0].value.pdb_int     = run_mode;
863
864
  args[1].value.pdb_pointer = (gchar *) filename;
  args[2].value.pdb_pointer = (gchar *) raw_filename;
Elliot Lee's avatar
Elliot Lee committed
865
866

  return_vals = procedural_db_execute (proc->name, args);
867
868

  *status   = return_vals[0].value.pdb_int;
869
  gimage_id = return_vals[1].value.pdb_int;
Elliot Lee's avatar
Elliot Lee committed
870
871
872
873

  procedural_db_destroy_args (return_vals, proc->num_values);
  g_free (args);

874
  if (*status == PDB_SUCCESS && gimage_id != -1)
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
875
    {
876
      GimpImage *gimage = pdb_id_to_image (gimage_id);
Sven Neumann's avatar
Sven Neumann committed
877

878
      if (gimage)
Sven Neumann's avatar
Sven Neumann committed
879
	{
880
881
	  layer_invalidate_previews (gimage);
	  channel_invalidate_previews (gimage);
Sven Neumann's avatar
Sven Neumann committed
882
	}
883

BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
884
885
      return pdb_id_to_image (gimage_id);
    }
886
887

  return NULL;
Manish Singh's avatar
Manish Singh committed
888
889
}

890
891
892
gint
file_open (gchar *filename,
	   gchar *raw_filename)
Manish Singh's avatar
Manish Singh committed
893
894
{
  GimpImage *gimage;
895
  GDisplay  *gdisplay;
896
  gchar     *absolute;
897
  gint       status;
Manish Singh's avatar
Manish Singh committed
898

899
900
  if ((gimage = file_open_image (filename,
				 raw_filename,
901
				 _("Open"),
902
903
				 RUN_INTERACTIVE,
				 &status)) != NULL)
Elliot Lee's avatar
Elliot Lee committed
904
    {
Manish Singh's avatar
Manish Singh committed
905
      /* enable & clear all undo steps */
906
      gimp_image_undo_enable (gimage);
Elliot Lee's avatar
Elliot Lee committed
907

Manish Singh's avatar
Manish Singh committed
908
      /* set the image to clean  */
909
      gimp_image_clean_all (gimage);
Elliot Lee's avatar
Elliot Lee committed
910

Manish Singh's avatar
Manish Singh committed
911
      /* display the image */
912
913
914
915
916
      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);
Elliot Lee's avatar
Elliot Lee committed
917

918
      absolute = file_absolute_filename (filename);
919
      document_index_add (absolute);
920
921
      menus_last_opened_add (absolute);
      g_free (absolute);
922
    }
Chris Lahey's avatar
Chris Lahey committed
923

924
  return status;
Elliot Lee's avatar
Elliot Lee committed
925
926
}

927
TempBuf *
928
make_thumb_tempbuf (GimpImage *gimage)
929
930
{
  gint w, h;
931
932
933
934
935
936
937
938
939

  if (gimage->width<=80 && gimage->height<=60)
    {
      w = gimage->width;
      h = gimage->height;
    }
  else
    {
      /* Ratio molesting to fit within .xvpic thumbnail size limits */
940
      if (60 * gimage->width < 80 * gimage->height)
941
942
	{
	  h = 60;
943
944
	  w = (60 * gimage->width) / gimage->height;
	  if (w == 0)
945
946
947
948
949
	    w = 1;
	}
      else
	{
	  w = 80;
950
951
	  h = (80 * gimage->height) / gimage->width;
	  if (h == 0)
952
953
954
955
956
957
958
959
960
	    h = 1;
	}
    }

  /*printf("tn: %d x %d -> ", w, h);fflush(stdout);*/

  return (gimp_image_composite_preview (gimage, GRAY_CHANNEL, w, h));
}

961
962
963
964
static guchar *
make_RGBbuf_from_tempbuf (TempBuf *tempbuf,
			  gint    *width_rtn,
			  gint    *height_rtn)
965
{
966
967
968
969
970
  gint    i, j, w, h;
  guchar *tbd;
  guchar *ptr;
  guchar *rtn = NULL;
  guchar  alpha, r, g, b;
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028

  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()");
    }

1029
  return (rtn);
1030
1031
}

1032
1033
gboolean
file_save_thumbnail (GimpImage  *gimage,
1034
		     const char *full_source_filename,
1035
		     TempBuf    *tempbuf)
1036
1037
{
  gint i,j;
1038
  gint w,h;
1039
  guchar *tbd;
1040
1041
1042
1043
  gchar* pathname;
  gchar* filename;
  gchar* xvpathname;
  gchar* thumbnailname;
1044
  GimpImageBaseType basetype;
1045
  FILE *fp;
1046
1047
  struct stat statbuf;

1048
  if (stat (full_source_filename, &statbuf) != 0)
1049
1050
1051
    {
      return FALSE;
    }
1052

1053
1054
1055
1056
1057
1058
1059
1060
  /* just for debugging 
   *  if (gimp_image_preview_valid (gimage, GRAY_CHANNEL))
   *   {
   *     g_print ("(incidentally, gimage already has a valid preview - %dx%d)\n",
   *	         gimage->comp_preview->width,
   *	         gimage->comp_preview->height);
   *   }
   */
1061

1062
1063
  pathname = g_dirname (full_source_filename);
  filename = g_basename (full_source_filename); /* Don't free! */
1064

1065
1066
  xvpathname = g_strconcat (pathname, G_DIR_SEPARATOR_S, ".xvpics",
			    NULL);
1067
1068
1069
1070

  thumbnailname = g_strconcat (xvpathname, G_DIR_SEPARATOR_S,
			       filename,
			       NULL);
1071

1072
  tbd = temp_buf_data (tempbuf);
1073
1074
1075

  w = tempbuf->width;
  h = tempbuf->height;
1076
  /*printf("tn: %d x %d\n", w, h);fflush(stdout);*/
1077

1078
  mkdir (xvpathname, 0755);
1079

1080
1081
1082
1083
  fp = fopen (thumbnailname, "wb");
  g_free (pathname);
  g_free (xvpathname);
  g_free (thumbnailname);
1084
1085
1086
1087
1088

  if (fp)
    {
      basetype = gimp_image_base_type(gimage);

1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
      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);
1100
1101
1102
1103
1104

      switch (basetype)
	{
	case INDEXED:
	case RGB:
1105
	  for (i=0; i<h; i++)
1106
	    {
1107
	      /* Do a cheap unidirectional error-spread to look better */
1108
	      gint rerr=0, gerr=0, berr=0, a;
1109
1110

	      for (j=0; j<w; j++)
1111
		{
1112
1113
		  gint32 r,g,b;

1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
		  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;
		    }
1129
1130
1131
1132
1133

		  r = CLAMP0255 (r);
		  g = CLAMP0255 (g);
		  b = CLAMP0255 (b);

1134
		  fputc(((r>>5)<<5) | ((g>>5)<<2) | (b>>6), fp);
1135
1136
1137
1138

		  rerr = r - ( (r>>5) * 255 ) / 7;
		  gerr = g - ( (g>>5) * 255 ) / 7;
		  berr = b - ( (b>>6) * 255 ) / 3;
1139
1140
1141
		}
	    }
	  break;
1142

1143
	case GRAY:
1144
	  for (i=0; i<h; i++)
1145
	    {
1146
	      /* Do a cheap unidirectional error-spread to look better */
1147
	      gint b3err=0, b2err=0, v, a;
1148
1149

	      for (j=0; j<w; j++)
1150
		{
1151
		  gint32 b3, b2;
1152

1153
		  v = *(tbd++);
1154
1155
1156
1157
1158
		  a = *(tbd++);

		  if (!(128 & a))
		    v = (( (i^j) & 4 ) << 5) | 64;

1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
		  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;
1169
1170
1171
		}
	    }
	  break;
1172

1173
1174
	default:
	  g_warning("UNKNOWN GIMAGE TYPE IN THUMBNAIL SAVE");
1175
	  break;
1176
	}
1177
1178

      fclose (fp);
1179
1180
1181
    }
  else /* Error writing thumbnail */
    {
1182
      return FALSE;
1183
1184
    }

1185