gimp/app/base/tile-swap.c

637 lines
15 KiB
C
Raw Normal View History

/* GIMP - The GNU Image Manipulation Program
app/Makefile.am app/channel_pvt.h app/drawable_pvt.h app/gdisplayF.h 2000-12-29 Michael Natterer <mitch@gimp.org> * app/Makefile.am * app/channel_pvt.h * app/drawable_pvt.h * app/gdisplayF.h * app/gimpdrawableP.h * app/gimpimageP.h * app/layer_pvt.h * app/toolsF.h: removed these files. * app/apptypes.h * tools/pdbgen/enums.pl: added tons of opaque typedefs and enums. * tools/pdbgen/pdb/brush_select.pdb * tools/pdbgen/pdb/brushes.pdb * tools/pdbgen/pdb/channel.pdb * tools/pdbgen/pdb/color.pdb * tools/pdbgen/pdb/convert.pdb * tools/pdbgen/pdb/display.pdb * tools/pdbgen/pdb/drawable.pdb * tools/pdbgen/pdb/fileops.pdb * tools/pdbgen/pdb/gradient_select.pdb * tools/pdbgen/pdb/gradients.pdb * tools/pdbgen/pdb/help.pdb * tools/pdbgen/pdb/image.pdb * tools/pdbgen/pdb/layer.pdb * tools/pdbgen/pdb/pattern_select.pdb * tools/pdbgen/pdb/patterns.pdb * tools/pdbgen/pdb/selection.pdb * tools/pdbgen/pdb/tools.pdb * app/*: chainsaw #include cleanup: - Never (never!!) include stuff in header files except where we need access to structures' contents (like derived objects). - Added prototypes and proper formating in many files. - The #include order in *all* *.c files is as follows: #include "config.h" #include <system stuff> #include <gtk/gtk.h> #include "apptypes.h" #include "gimp stuff" #include "libgimp stuff" #include "libgimp/gimpintl.h" By following this scheme we can easily see a file's dependencies from it's #include's and can grep for the inclusion to find out where a file is used. * tools/pdbgen/app.pl: changed to follow the include scheme above. * libgimp/Makefile.am * libgimp/gimpuitypes.h: new file, included from libgimp/gimpui.h and from app/apptypes.h. * libgimp/gimpcolorbutton.[ch] * libgimp/gimpdialog.[ch] * libgimp/gimphelpui.[ch] * libgimp/gimpparasite.[ch] * libgimp/gimppatheditor.[ch] * libgimp/gimpprotocol.c * libgimp/gimpquerybox.[ch] * libgimp/gimpsizeentry.[ch] * libgimp/gimptypes.h * libgimp/gimpui.h * libgimp/gimpunit.h * libgimp/gimpunitmenu.[ch] * libgimp/gimpwidgets.[ch]: changed accordingly. * plug-ins/FractalExplorer/Dialogs.c * plug-ins/gdyntext/message_window.c * plug-ins/imagemap/imap_default_dialog.c * plug-ins/imagemap/imap_file.c: these files used to include "libgimp/gimpui.h" without including "libgimp/gimp.h". This is no longer possible because the libgimpui headers don't inlcude "libgimp/gimpunit.h" any more.
2000-12-29 15:22:01 +00:00
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
1997-11-24 22:05:25 +00:00
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
1997-11-24 22:05:25 +00:00
#include <unistd.h>
#endif
removed from CVS, they are generated. 2001-12-07 Sven Neumann <sven@gimp.org> * app/core/gimpmarshal.[ch]: removed from CVS, they are generated. * app/base/Makefile.am * app/base/base-enums.h: new file defining enums that are to be registered. Used to build app/base/base-enums.c. * app/base/base-types.h: include base-enums.h. * tools/pdbgen/Makefile.am * tools/pdbgen/enumcode.pl * tools/pdbgen/enums.pl: parse the new base-enums.h file and modified the perl voodoo so it doesn't prefix enums with GIMP_ that are already properly namespaced. * app/core/core-types.h: don't need to chop GIMP from enum. * app/pdb/color_cmds.c * app/pdb/tools_cmds.c * libgimp/gimpenums.h * plug-ins/script-fu/script-fu-constants.c: regenerated. * app/config/gimpconfig-deserialize.[ch] * app/config/gimpconfig-serialize.[ch] * app/config/gimpconfig.[ch]: made GimpConfig an interface including a reasonable default implementation that works on object properties. * app/config/Makefile.am * app/config/gimpbaseconfig.[ch]: new GimpBaseConfig using the GimpConfig interface. Yet only used for testing from app/main.c. * app/main.c: test the new GimpBaseConfig object. * app/gimprc.c * app/base/base-config.h * app/base/*.c * app/core/gimpdatafiles.c * app/core/gimpdrawable-transform.c * app/core/gimppreviewcache.c * app/gui/preferences-dialog.c * app/paint-funcs/paint-funcs.c * app/xcf/xcf-seek.c: need to include glib-object.h since base-config contains registered enums now. Follow name change of InterpolationType to GimpInterpolationType.
2001-12-07 16:10:53 +00:00
#include <glib-object.h>
#include <glib/gstdio.h>
removed from CVS, they are generated. 2001-12-07 Sven Neumann <sven@gimp.org> * app/core/gimpmarshal.[ch]: removed from CVS, they are generated. * app/base/Makefile.am * app/base/base-enums.h: new file defining enums that are to be registered. Used to build app/base/base-enums.c. * app/base/base-types.h: include base-enums.h. * tools/pdbgen/Makefile.am * tools/pdbgen/enumcode.pl * tools/pdbgen/enums.pl: parse the new base-enums.h file and modified the perl voodoo so it doesn't prefix enums with GIMP_ that are already properly namespaced. * app/core/core-types.h: don't need to chop GIMP from enum. * app/pdb/color_cmds.c * app/pdb/tools_cmds.c * libgimp/gimpenums.h * plug-ins/script-fu/script-fu-constants.c: regenerated. * app/config/gimpconfig-deserialize.[ch] * app/config/gimpconfig-serialize.[ch] * app/config/gimpconfig.[ch]: made GimpConfig an interface including a reasonable default implementation that works on object properties. * app/config/Makefile.am * app/config/gimpbaseconfig.[ch]: new GimpBaseConfig using the GimpConfig interface. Yet only used for testing from app/main.c. * app/main.c: test the new GimpBaseConfig object. * app/gimprc.c * app/base/base-config.h * app/base/*.c * app/core/gimpdatafiles.c * app/core/gimpdrawable-transform.c * app/core/gimppreviewcache.c * app/gui/preferences-dialog.c * app/paint-funcs/paint-funcs.c * app/xcf/xcf-seek.c: need to include glib-object.h since base-config contains registered enums now. Follow name change of InterpolationType to GimpInterpolationType.
2001-12-07 16:10:53 +00:00
#include "libgimpbase/gimpbase.h"
#include "libgimpconfig/gimpconfig.h"
#ifdef G_OS_WIN32
#include <windows.h>
#include "libgimpbase/gimpwin32-io.h"
#endif
new directory app/base/ 2001-05-15 Michael Natterer <mitch@gimp.org> * configure.in: new directory app/base/ * app/Makefile.am * app/boundary.[ch] * app/brush_scale.[ch] * app/gimpchecks.h * app/gimplut.[ch] * app/pixel_processor.[ch] * app/pixel_region.[ch] * app/pixel_surround.[ch] * app/temp_buf.[ch] * app/tile.[ch] * app/tile_cache.[ch] * app/tile_manager.[ch] * app/tile_manager_pvt.h * app/tile_pvt.h * app/tile_swap.[ch]: moved to base/ * app/base/Makefile.am * app/base/base-types.h * app/base/*: new directory for the sub-object pixel maniplation and storage stuff. Does not include Gtk+ or anything outside base/. Did some cleanup in all files. * app/appenums.h * app/apptypes.h * app/core/gimpimage.h: removed types which are now in base/base-types.h. * app/base/base-config.[ch] * app/gimprc.[ch]: put the config variables for base/ to their own file so base/ doesn not have to include gimprc.h (does not yet work, i.e. the variables are un-configurable right now) * app/main.c: set a log handler for "Gimp-Base". * app/paint-funcs/Makefile.am * app/paint-funcs/paint-funcs.[ch]: removed the color hash which maps RGB to color indices because it's a totally standalone system which has nothing to do with the paint-funcs and introduced a GimpImage dependency. paint-funcs/ should be considered on the same sub-object (glib-only) level as base/, only in a different directory. * app/core/Makefile.am * app/core/gimpimage-colorhash.[ch]: put the color hash here. * app/gimage.c: don't invalidate the color hash here... * app/core/gimpimage.c: ... but in the colormap_changed() default inplementation. Initialize the hash in class_init(). * tools/pdbgen/Makefile.am: scan app/base/base-types.h for enums. * tools/pdbgen/enums.pl: regenerated. * app/[lots] * app/core/[of] * app/gui/[files] * app/pdb/[all] * app/tools/[over] * app/widgets/[the] * tools/pdbgen/pdb/[place]: changed #includes accordingly. And use base_config->value instead of the stuff from gimprc.h.
2001-05-15 11:25:25 +00:00
#include "base-types.h"
1997-11-24 22:05:25 +00:00
#ifndef _O_BINARY
#define _O_BINARY 0
#endif
#ifndef _O_TEMPORARY
#define _O_TEMPORARY 0
#endif
#include "base-utils.h"
#include "tile.h"
#include "tile-rowhints.h"
new directory app/base/ 2001-05-15 Michael Natterer <mitch@gimp.org> * configure.in: new directory app/base/ * app/Makefile.am * app/boundary.[ch] * app/brush_scale.[ch] * app/gimpchecks.h * app/gimplut.[ch] * app/pixel_processor.[ch] * app/pixel_region.[ch] * app/pixel_surround.[ch] * app/temp_buf.[ch] * app/tile.[ch] * app/tile_cache.[ch] * app/tile_manager.[ch] * app/tile_manager_pvt.h * app/tile_pvt.h * app/tile_swap.[ch]: moved to base/ * app/base/Makefile.am * app/base/base-types.h * app/base/*: new directory for the sub-object pixel maniplation and storage stuff. Does not include Gtk+ or anything outside base/. Did some cleanup in all files. * app/appenums.h * app/apptypes.h * app/core/gimpimage.h: removed types which are now in base/base-types.h. * app/base/base-config.[ch] * app/gimprc.[ch]: put the config variables for base/ to their own file so base/ doesn not have to include gimprc.h (does not yet work, i.e. the variables are un-configurable right now) * app/main.c: set a log handler for "Gimp-Base". * app/paint-funcs/Makefile.am * app/paint-funcs/paint-funcs.[ch]: removed the color hash which maps RGB to color indices because it's a totally standalone system which has nothing to do with the paint-funcs and introduced a GimpImage dependency. paint-funcs/ should be considered on the same sub-object (glib-only) level as base/, only in a different directory. * app/core/Makefile.am * app/core/gimpimage-colorhash.[ch]: put the color hash here. * app/gimage.c: don't invalidate the color hash here... * app/core/gimpimage.c: ... but in the colormap_changed() default inplementation. Initialize the hash in class_init(). * tools/pdbgen/Makefile.am: scan app/base/base-types.h for enums. * tools/pdbgen/enums.pl: regenerated. * app/[lots] * app/core/[of] * app/gui/[files] * app/pdb/[all] * app/tools/[over] * app/widgets/[the] * tools/pdbgen/pdb/[place]: changed #includes accordingly. And use base_config->value instead of the stuff from gimprc.h.
2001-05-15 11:25:25 +00:00
#include "tile-swap.h"
#include "tile-private.h"
#include "gimp-intl.h"
1997-11-24 22:05:25 +00:00
typedef enum
{
SWAP_IN = 1,
SWAP_OUT,
SWAP_DELETE
} SwapCommand;
typedef gint (* SwapFunc) (gint fd,
Tile *tile,
SwapCommand cmd);
app/Makefile.am app/channel_pvt.h app/drawable_pvt.h app/gdisplayF.h 2000-12-29 Michael Natterer <mitch@gimp.org> * app/Makefile.am * app/channel_pvt.h * app/drawable_pvt.h * app/gdisplayF.h * app/gimpdrawableP.h * app/gimpimageP.h * app/layer_pvt.h * app/toolsF.h: removed these files. * app/apptypes.h * tools/pdbgen/enums.pl: added tons of opaque typedefs and enums. * tools/pdbgen/pdb/brush_select.pdb * tools/pdbgen/pdb/brushes.pdb * tools/pdbgen/pdb/channel.pdb * tools/pdbgen/pdb/color.pdb * tools/pdbgen/pdb/convert.pdb * tools/pdbgen/pdb/display.pdb * tools/pdbgen/pdb/drawable.pdb * tools/pdbgen/pdb/fileops.pdb * tools/pdbgen/pdb/gradient_select.pdb * tools/pdbgen/pdb/gradients.pdb * tools/pdbgen/pdb/help.pdb * tools/pdbgen/pdb/image.pdb * tools/pdbgen/pdb/layer.pdb * tools/pdbgen/pdb/pattern_select.pdb * tools/pdbgen/pdb/patterns.pdb * tools/pdbgen/pdb/selection.pdb * tools/pdbgen/pdb/tools.pdb * app/*: chainsaw #include cleanup: - Never (never!!) include stuff in header files except where we need access to structures' contents (like derived objects). - Added prototypes and proper formating in many files. - The #include order in *all* *.c files is as follows: #include "config.h" #include <system stuff> #include <gtk/gtk.h> #include "apptypes.h" #include "gimp stuff" #include "libgimp stuff" #include "libgimp/gimpintl.h" By following this scheme we can easily see a file's dependencies from it's #include's and can grep for the inclusion to find out where a file is used. * tools/pdbgen/app.pl: changed to follow the include scheme above. * libgimp/Makefile.am * libgimp/gimpuitypes.h: new file, included from libgimp/gimpui.h and from app/apptypes.h. * libgimp/gimpcolorbutton.[ch] * libgimp/gimpdialog.[ch] * libgimp/gimphelpui.[ch] * libgimp/gimpparasite.[ch] * libgimp/gimppatheditor.[ch] * libgimp/gimpprotocol.c * libgimp/gimpquerybox.[ch] * libgimp/gimpsizeentry.[ch] * libgimp/gimptypes.h * libgimp/gimpui.h * libgimp/gimpunit.h * libgimp/gimpunitmenu.[ch] * libgimp/gimpwidgets.[ch]: changed accordingly. * plug-ins/FractalExplorer/Dialogs.c * plug-ins/gdyntext/message_window.c * plug-ins/imagemap/imap_default_dialog.c * plug-ins/imagemap/imap_file.c: these files used to include "libgimp/gimpui.h" without including "libgimp/gimp.h". This is no longer possible because the libgimpui headers don't inlcude "libgimp/gimpunit.h" any more.
2000-12-29 15:22:01 +00:00
#define MAX_OPEN_SWAP_FILES 16
1997-11-24 22:05:25 +00:00
typedef struct _SwapFile SwapFile;
typedef struct _SwapFileGap SwapFileGap;
1997-11-24 22:05:25 +00:00
struct _SwapFile
1997-11-24 22:05:25 +00:00
{
gchar *filename;
gint fd;
GList *gaps;
gint64 swap_file_end;
gint64 cur_position;
1997-11-24 22:05:25 +00:00
};
struct _SwapFileGap
1997-11-24 22:05:25 +00:00
{
gint64 start;
gint64 end;
1997-11-24 22:05:25 +00:00
};
static void tile_swap_command (Tile *tile,
gint command);
static void tile_swap_default_in (SwapFile *swap_file,
Tile *tile);
static void tile_swap_default_out (SwapFile *swap_file,
Tile *tile);
static void tile_swap_default_delete (SwapFile *swap_file,
Tile *tile);
1997-11-24 22:05:25 +00:00
static gint64 tile_swap_find_offset (SwapFile *swap_file,
gint64 bytes);
static void tile_swap_open (SwapFile *swap_file);
static void tile_swap_resize (SwapFile *swap_file,
gint64 new_size);
static SwapFileGap * tile_swap_gap_new (gint64 start,
gint64 end);
static void tile_swap_gap_destroy (SwapFileGap *gap);
1997-11-24 22:05:25 +00:00
static SwapFile * gimp_swap_file = NULL;
static const gint64 swap_file_grow = 1024 * TILE_WIDTH * TILE_HEIGHT * 4;
static gboolean seek_err_msg = TRUE;
static gboolean read_err_msg = TRUE;
static gboolean write_err_msg = TRUE;
#ifdef G_OS_WIN32
#define LARGE_SEEK(f, o, w) _lseeki64 (f, o, w)
#define LARGE_TRUNCATE(f, s) win32_large_truncate (f, s)
static gint
win32_large_truncate (gint fd,
gint64 size)
{
if (LARGE_SEEK (fd, size, SEEK_SET) == size &&
SetEndOfFile ((HANDLE) _get_osfhandle (fd)))
return 0;
else
return -1;
}
#else
#define LARGE_SEEK(f, o, t) lseek (f, o, t)
#define LARGE_TRUNCATE(f, s) ftruncate (f, s)
#endif
#ifdef GIMP_UNSTABLE
1997-11-24 22:05:25 +00:00
static void
tile_swap_print_gaps (SwapFile *swap_file)
1997-11-24 22:05:25 +00:00
{
GList *list;
1997-11-24 22:05:25 +00:00
for (list = swap_file->gaps; list; list = list->next)
1997-11-24 22:05:25 +00:00
{
SwapFileGap *gap = list->data;
1997-11-24 22:05:25 +00:00
g_print (" %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT"\n",
gap->start, gap->end);
1997-11-24 22:05:25 +00:00
}
}
#endif
1997-11-24 22:05:25 +00:00
void
tile_swap_init (const gchar *path)
{
gchar *basename;
gchar *dirname;
g_return_if_fail (gimp_swap_file == NULL);
g_return_if_fail (path != NULL);
dirname = gimp_config_path_expand (path, TRUE, NULL);
basename = g_strdup_printf ("gimpswap.%lu", (unsigned long) get_pid ());
/* create the swap directory if it doesn't exist */
if (! g_file_test (dirname, G_FILE_TEST_EXISTS))
g_mkdir_with_parents (dirname,
S_IRUSR | S_IXUSR | S_IWUSR |
S_IRGRP | S_IXGRP |
S_IROTH | S_IXOTH);
gimp_swap_file = g_slice_new (SwapFile);
gimp_swap_file->filename = g_build_filename (dirname, basename, NULL);
gimp_swap_file->gaps = NULL;
gimp_swap_file->swap_file_end = 0;
gimp_swap_file->cur_position = 0;
gimp_swap_file->fd = -1;
g_free (basename);
g_free (dirname);
}
1997-11-24 22:05:25 +00:00
void
tile_swap_exit (void)
1997-11-24 22:05:25 +00:00
{
#ifdef HINTS_SANITY
extern int tile_exist_peak;
g_printerr ("Tile exist peak was %d Tile structs (%d bytes)",
tile_exist_peak, tile_exist_peak * sizeof(Tile));
#endif
if (tile_global_refcount () != 0)
g_warning ("tile ref count balance: %d\n", tile_global_refcount ());
1997-11-24 22:05:25 +00:00
g_return_if_fail (gimp_swap_file != NULL);
1997-11-24 22:05:25 +00:00
#ifdef GIMP_UNSTABLE
if (gimp_swap_file->swap_file_end != 0)
1997-11-24 22:05:25 +00:00
{
g_warning ("swap file not empty: \"%s\"\n",
gimp_filename_to_utf8 (gimp_swap_file->filename));
tile_swap_print_gaps (gimp_swap_file);
1997-11-24 22:05:25 +00:00
}
#endif
1997-11-24 22:05:25 +00:00
#ifdef G_OS_WIN32
/* should close before unlink */
if (gimp_swap_file->fd > 0)
{
close (gimp_swap_file->fd);
gimp_swap_file->fd = -1;
}
#endif
g_unlink (gimp_swap_file->filename);
1997-11-24 22:05:25 +00:00
g_free (gimp_swap_file->filename);
g_slice_free (SwapFile, gimp_swap_file);
1997-11-24 22:05:25 +00:00
gimp_swap_file = NULL;
1997-11-24 22:05:25 +00:00
}
/* check if we can open a swap file */
gboolean
tile_swap_test (void)
1997-11-24 22:05:25 +00:00
{
g_return_val_if_fail (gimp_swap_file != NULL, FALSE);
1997-11-24 22:05:25 +00:00
/* make sure this duplicates the open() call from tile_swap_open() */
gimp_swap_file->fd = g_open (gimp_swap_file->filename,
O_CREAT | O_RDWR | _O_BINARY | _O_TEMPORARY,
S_IRUSR | S_IWUSR);
1997-11-24 22:05:25 +00:00
if (gimp_swap_file->fd != -1)
{
close (gimp_swap_file->fd);
gimp_swap_file->fd = -1;
g_unlink (gimp_swap_file->filename);
1997-11-24 22:05:25 +00:00
return TRUE;
}
1997-11-24 22:05:25 +00:00
return FALSE;
1997-11-24 22:05:25 +00:00
}
void
tile_swap_in (Tile *tile)
{
if (tile->swap_offset == -1)
{
tile_alloc (tile);
return;
}
tile_swap_command (tile, SWAP_IN);
}
void
tile_swap_out (Tile *tile)
{
tile_swap_command (tile, SWAP_OUT);
}
void
tile_swap_delete (Tile *tile)
{
tile_swap_command (tile, SWAP_DELETE);
}
static void
tile_swap_command (Tile *tile,
gint command)
1997-11-24 22:05:25 +00:00
{
if (gimp_swap_file->fd == -1)
1997-11-24 22:05:25 +00:00
{
tile_swap_open (gimp_swap_file);
1997-11-24 22:05:25 +00:00
if (G_UNLIKELY (gimp_swap_file->fd == -1))
return;
1997-11-24 22:05:25 +00:00
}
switch (command)
1997-11-24 22:05:25 +00:00
{
case SWAP_IN:
tile_swap_default_in (gimp_swap_file, tile);
break;
case SWAP_OUT:
tile_swap_default_out (gimp_swap_file, tile);
break;
case SWAP_DELETE:
tile_swap_default_delete (gimp_swap_file, tile);
break;
1997-11-24 22:05:25 +00:00
}
}
/* The actual swap file code. The swap file consists of tiles
* which have been moved out to disk in order to conserve memory.
* The swap file format is free form. Any tile in memory may
* end up anywhere on disk.
* An actual tile in the swap file consists only of the tile data.
* The offset of the tile on disk is stored in the tile data structure
* in memory.
*/
static void
tile_swap_default_in (SwapFile *swap_file,
Tile *tile)
1997-11-24 22:05:25 +00:00
{
gint nleft;
gint64 offset;
1997-11-24 22:05:25 +00:00
if (tile->data)
return;
if (swap_file->cur_position != tile->swap_offset)
1997-11-24 22:05:25 +00:00
{
swap_file->cur_position = tile->swap_offset;
1997-11-24 22:05:25 +00:00
offset = LARGE_SEEK (swap_file->fd, tile->swap_offset, SEEK_SET);
1997-11-24 22:05:25 +00:00
if (offset == -1)
{
if (seek_err_msg)
g_message ("unable to seek to tile location on disk: %s",
g_strerror (errno));
seek_err_msg = FALSE;
return;
}
1997-11-24 22:05:25 +00:00
}
tile_alloc (tile);
nleft = tile->size;
1997-11-24 22:05:25 +00:00
while (nleft > 0)
{
gint err;
do
{
err = read (swap_file->fd, tile->data + tile->size - nleft, nleft);
}
while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
1997-11-24 22:05:25 +00:00
if (err <= 0)
{
if (read_err_msg)
g_message ("unable to read tile data from disk: "
"%s (%d/%d bytes read)",
g_strerror (errno), err, nleft);
read_err_msg = FALSE;
return;
}
1997-11-24 22:05:25 +00:00
nleft -= err;
}
swap_file->cur_position += tile->size;
1997-11-24 22:05:25 +00:00
/* Do not delete the swap from the file */
/* tile_swap_default_delete (swap_file, fd, tile); */
read_err_msg = seek_err_msg = TRUE;
1997-11-24 22:05:25 +00:00
}
static void
tile_swap_default_out (SwapFile *swap_file,
Tile *tile)
1997-11-24 22:05:25 +00:00
{
gint bytes;
gint nleft;
gint64 offset;
gint64 newpos;
1997-11-24 22:05:25 +00:00
bytes = TILE_WIDTH * TILE_HEIGHT * tile->bpp;
/* If there is already a valid swap_offset, use it */
if (tile->swap_offset == -1)
newpos = tile_swap_find_offset (swap_file, bytes);
else
newpos = tile->swap_offset;
1997-11-24 22:05:25 +00:00
if (swap_file->cur_position != newpos)
1997-11-24 22:05:25 +00:00
{
offset = LARGE_SEEK (swap_file->fd, newpos, SEEK_SET);
1997-11-24 22:05:25 +00:00
if (offset == -1)
{
if (seek_err_msg)
g_message ("unable to seek to tile location on disk: %s",
g_strerror (errno));
seek_err_msg = FALSE;
return;
}
swap_file->cur_position = newpos;
1997-11-24 22:05:25 +00:00
}
nleft = tile->size;
1997-11-24 22:05:25 +00:00
while (nleft > 0)
{
gint err = write (swap_file->fd, tile->data + tile->size - nleft, nleft);
1997-11-24 22:05:25 +00:00
if (err <= 0)
{
if (write_err_msg)
g_message ("unable to write tile data to disk: "
"%s (%d/%d bytes written)",
g_strerror (errno), err, nleft);
write_err_msg = FALSE;
return;
}
1997-11-24 22:05:25 +00:00
nleft -= err;
}
swap_file->cur_position += tile->size;
1997-11-24 22:05:25 +00:00
/* Do NOT free tile->data because we may be pre-swapping.
* tile->data is freed in tile_cache_zorch_next
*/
tile->dirty = FALSE;
tile->swap_offset = newpos;
write_err_msg = seek_err_msg = TRUE;
1997-11-24 22:05:25 +00:00
}
static void
tile_swap_default_delete (SwapFile *swap_file,
Tile *tile)
1997-11-24 22:05:25 +00:00
{
SwapFileGap *gap;
SwapFileGap *gap2;
GList *tmp;
GList *tmp2;
gint64 start;
gint64 end;
1997-11-24 22:05:25 +00:00
if (tile->swap_offset == -1)
return;
start = tile->swap_offset;
end = start + TILE_WIDTH * TILE_HEIGHT * tile->bpp;
tile->swap_offset = -1;
tmp = swap_file->gaps;
1997-11-24 22:05:25 +00:00
while (tmp)
{
gap = tmp->data;
if (end == gap->start)
{
gap->start = start;
if (tmp->prev)
{
gap2 = tmp->prev->data;
if (gap->start == gap2->end)
{
gap2->end = gap->end;
tile_swap_gap_destroy (gap);
swap_file->gaps =
g_list_remove_link (swap_file->gaps, tmp);
g_list_free (tmp);
}
}
break;
}
1997-11-24 22:05:25 +00:00
else if (start == gap->end)
{
gap->end = end;
if (tmp->next)
{
gap2 = tmp->next->data;
if (gap->end == gap2->start)
{
gap2->start = gap->start;
tile_swap_gap_destroy (gap);
swap_file->gaps =
g_list_remove_link (swap_file->gaps, tmp);
g_list_free (tmp);
}
}
break;
}
1997-11-24 22:05:25 +00:00
else if (end < gap->start)
{
gap = tile_swap_gap_new (start, end);
tmp2 = g_list_alloc ();
tmp2->data = gap;
tmp2->next = tmp;
tmp2->prev = tmp->prev;
if (tmp->prev)
tmp->prev->next = tmp2;
tmp->prev = tmp2;
if (tmp == swap_file->gaps)
swap_file->gaps = tmp2;
break;
}
1997-11-24 22:05:25 +00:00
else if (!tmp->next)
{
gap = tile_swap_gap_new (start, end);
tmp->next = g_list_alloc ();
tmp->next->data = gap;
tmp->next->prev = tmp;
break;
}
1997-11-24 22:05:25 +00:00
tmp = tmp->next;
}
if (!swap_file->gaps)
1997-11-24 22:05:25 +00:00
{
gap = tile_swap_gap_new (start, end);
swap_file->gaps = g_list_append (swap_file->gaps, gap);
1997-11-24 22:05:25 +00:00
}
tmp = g_list_last (swap_file->gaps);
1997-11-24 22:05:25 +00:00
gap = tmp->data;
if (gap->end == swap_file->swap_file_end)
1997-11-24 22:05:25 +00:00
{
tile_swap_resize (swap_file, gap->start);
1997-11-24 22:05:25 +00:00
tile_swap_gap_destroy (gap);
swap_file->gaps = g_list_remove_link (swap_file->gaps, tmp);
1997-11-24 22:05:25 +00:00
g_list_free (tmp);
}
}
static void
tile_swap_open (SwapFile *swap_file)
{
g_return_if_fail (swap_file->fd == -1);
/* duplicate this open() call in tile_swap_test() */
swap_file->fd = g_open (swap_file->filename,
O_CREAT | O_RDWR | _O_BINARY | _O_TEMPORARY,
S_IRUSR | S_IWUSR);
if (swap_file->fd == -1)
g_message (_("Unable to open swap file. GIMP has run out of memory "
"and cannot use the swap file. Some parts of your images "
"may be corrupted. Try to save your work using different "
"filenames, restart GIMP and check the location of the "
"swap directory in your Preferences."));
}
static void
tile_swap_resize (SwapFile *swap_file,
gint64 new_size)
1997-11-24 22:05:25 +00:00
{
if (swap_file->swap_file_end > new_size)
{
if (LARGE_TRUNCATE (swap_file->fd, new_size) != 0)
{
g_message (_("Failed to resize swap file: %s"), g_strerror (errno));
return;
}
}
swap_file->swap_file_end = new_size;
1997-11-24 22:05:25 +00:00
}
static gint64
tile_swap_find_offset (SwapFile *swap_file,
gint64 bytes)
1997-11-24 22:05:25 +00:00
{
SwapFileGap *gap;
GList *tmp;
gint64 offset;
1997-11-24 22:05:25 +00:00
tmp = swap_file->gaps;
1997-11-24 22:05:25 +00:00
while (tmp)
{
gap = tmp->data;
if ((gap->end - gap->start) >= bytes)
{
offset = gap->start;
gap->start += bytes;
if (gap->start == gap->end)
{
tile_swap_gap_destroy (gap);
swap_file->gaps = g_list_remove_link (swap_file->gaps, tmp);
g_list_free (tmp);
}
return offset;
}
1997-11-24 22:05:25 +00:00
tmp = tmp->next;
}
offset = swap_file->swap_file_end;
1997-11-24 22:05:25 +00:00
tile_swap_resize (swap_file, swap_file->swap_file_end + swap_file_grow);
1997-11-24 22:05:25 +00:00
if ((offset + bytes) < (swap_file->swap_file_end))
1997-11-24 22:05:25 +00:00
{
gap = tile_swap_gap_new (offset + bytes, swap_file->swap_file_end);
swap_file->gaps = g_list_append (swap_file->gaps, gap);
1997-11-24 22:05:25 +00:00
}
return offset;
}
static SwapFileGap *
tile_swap_gap_new (gint64 start,
gint64 end)
1997-11-24 22:05:25 +00:00
{
SwapFileGap *gap = g_slice_new (SwapFileGap);
1997-11-24 22:05:25 +00:00
gap->start = start;
gap->end = end;
1997-11-24 22:05:25 +00:00
return gap;
}
static void
tile_swap_gap_destroy (SwapFileGap *gap)
1997-11-24 22:05:25 +00:00
{
g_slice_free (SwapFileGap, gap);
1997-11-24 22:05:25 +00:00
}