2004-02-15 Michael Natterer <mitch@gimp.org> * app/core/gimpdata.c (gimp_data_init): using FOO_GET_CLASS(instance) in a GInstanceInitFunc doesn't work because during instance init, the object's class is always set to be the class of the currently called init function. Use the second parameter of GInstanceInitFunc instead, which is the instance's real class. Fixes bug #134274.
396 lines
9.4 KiB
C
396 lines
9.4 KiB
C
/* The GIMP -- an image manipulation program
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* gimpdata.c
|
|
* Copyright (C) 2001 Michael Natterer <mitch@gimp.org>
|
|
*
|
|
* 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"
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include <glib-object.h>
|
|
|
|
#ifdef G_OS_WIN32
|
|
#include <io.h>
|
|
#define F_OK 0
|
|
#define W_OK 2
|
|
#define R_OK 4
|
|
#define X_OK 0 /* not really */
|
|
#define access(f,p) _access(f,p)
|
|
#endif
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
|
|
#include "core-types.h"
|
|
|
|
#include "gimpdata.h"
|
|
#include "gimpmarshal.h"
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
enum
|
|
{
|
|
DIRTY,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
|
|
static void gimp_data_class_init (GimpDataClass *klass);
|
|
static void gimp_data_init (GimpData *data,
|
|
GimpDataClass *data_class);
|
|
|
|
static void gimp_data_finalize (GObject *object);
|
|
|
|
static void gimp_data_name_changed (GimpObject *object);
|
|
static gint64 gimp_data_get_memsize (GimpObject *object,
|
|
gint64 *gui_size);
|
|
|
|
static void gimp_data_real_dirty (GimpData *data);
|
|
|
|
|
|
static guint data_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
static GimpViewableClass *parent_class = NULL;
|
|
|
|
|
|
GType
|
|
gimp_data_get_type (void)
|
|
{
|
|
static GType data_type = 0;
|
|
|
|
if (! data_type)
|
|
{
|
|
static const GTypeInfo data_info =
|
|
{
|
|
sizeof (GimpDataClass),
|
|
(GBaseInitFunc) NULL,
|
|
(GBaseFinalizeFunc) NULL,
|
|
(GClassInitFunc) gimp_data_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (GimpData),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) gimp_data_init,
|
|
};
|
|
|
|
data_type = g_type_register_static (GIMP_TYPE_VIEWABLE,
|
|
"GimpData",
|
|
&data_info, 0);
|
|
}
|
|
|
|
return data_type;
|
|
}
|
|
|
|
static void
|
|
gimp_data_class_init (GimpDataClass *klass)
|
|
{
|
|
GObjectClass *object_class;
|
|
GimpObjectClass *gimp_object_class;
|
|
|
|
object_class = G_OBJECT_CLASS (klass);
|
|
gimp_object_class = GIMP_OBJECT_CLASS (klass);
|
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
|
|
|
data_signals[DIRTY] =
|
|
g_signal_new ("dirty",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (GimpDataClass, dirty),
|
|
NULL, NULL,
|
|
gimp_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
object_class->finalize = gimp_data_finalize;
|
|
|
|
gimp_object_class->name_changed = gimp_data_name_changed;
|
|
gimp_object_class->get_memsize = gimp_data_get_memsize;
|
|
|
|
klass->dirty = gimp_data_real_dirty;
|
|
klass->save = NULL;
|
|
klass->get_extension = NULL;
|
|
klass->duplicate = NULL;
|
|
}
|
|
|
|
static void
|
|
gimp_data_init (GimpData *data,
|
|
GimpDataClass *data_class)
|
|
{
|
|
data->filename = NULL;
|
|
data->writable = TRUE;
|
|
data->deletable = TRUE;
|
|
data->dirty = TRUE;
|
|
data->internal = FALSE;
|
|
|
|
/* look at the passed class pointer, not at GIMP_DATA_GET_CLASS(data)
|
|
* here, because the latter is always GimpDataClass itself
|
|
*/
|
|
if (! data_class->save)
|
|
data->writable = FALSE;
|
|
}
|
|
|
|
static void
|
|
gimp_data_finalize (GObject *object)
|
|
{
|
|
GimpData *data = GIMP_DATA (object);
|
|
|
|
if (data->filename)
|
|
{
|
|
g_free (data->filename);
|
|
data->filename = NULL;
|
|
}
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gimp_data_name_changed (GimpObject *object)
|
|
{
|
|
if (GIMP_OBJECT_CLASS (parent_class)->name_changed)
|
|
GIMP_OBJECT_CLASS (parent_class)->name_changed (object);
|
|
|
|
gimp_data_dirty (GIMP_DATA (object));
|
|
}
|
|
|
|
static gint64
|
|
gimp_data_get_memsize (GimpObject *object,
|
|
gint64 *gui_size)
|
|
{
|
|
GimpData *data = GIMP_DATA (object);
|
|
gint64 memsize = 0;
|
|
|
|
if (data->filename)
|
|
memsize += strlen (data->filename) + 1;
|
|
|
|
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
|
gui_size);
|
|
}
|
|
|
|
gboolean
|
|
gimp_data_save (GimpData *data,
|
|
GError **error)
|
|
{
|
|
gboolean success = FALSE;
|
|
|
|
g_return_val_if_fail (GIMP_IS_DATA (data), FALSE);
|
|
g_return_val_if_fail (data->writable == TRUE, FALSE);
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
if (data->internal)
|
|
{
|
|
data->dirty = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
g_return_val_if_fail (data->filename != NULL, FALSE);
|
|
|
|
if (GIMP_DATA_GET_CLASS (data)->save)
|
|
success = GIMP_DATA_GET_CLASS (data)->save (data, error);
|
|
|
|
if (success)
|
|
data->dirty = FALSE;
|
|
|
|
return success;
|
|
}
|
|
|
|
void
|
|
gimp_data_dirty (GimpData *data)
|
|
{
|
|
g_return_if_fail (GIMP_IS_DATA (data));
|
|
|
|
g_signal_emit (data, data_signals[DIRTY], 0);
|
|
}
|
|
|
|
static void
|
|
gimp_data_real_dirty (GimpData *data)
|
|
{
|
|
data->dirty = TRUE;
|
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (data));
|
|
}
|
|
|
|
gboolean
|
|
gimp_data_delete_from_disk (GimpData *data,
|
|
GError **error)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_DATA (data), FALSE);
|
|
g_return_val_if_fail (data->filename != NULL, FALSE);
|
|
g_return_val_if_fail (data->deletable == TRUE, FALSE);
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
if (data->internal)
|
|
return TRUE;
|
|
|
|
if (unlink (data->filename) == -1)
|
|
{
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_DELETE,
|
|
_("Could not delete '%s': %s"),
|
|
gimp_filename_to_utf8 (data->filename), g_strerror (errno));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
const gchar *
|
|
gimp_data_get_extension (GimpData *data)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_DATA (data), NULL);
|
|
|
|
if (GIMP_DATA_GET_CLASS (data)->get_extension)
|
|
return GIMP_DATA_GET_CLASS (data)->get_extension (data);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
gimp_data_set_filename (GimpData *data,
|
|
const gchar *filename,
|
|
gboolean writable)
|
|
{
|
|
g_return_if_fail (GIMP_IS_DATA (data));
|
|
g_return_if_fail (filename != NULL);
|
|
g_return_if_fail (g_path_is_absolute (filename));
|
|
|
|
if (data->internal)
|
|
return;
|
|
|
|
if (data->filename)
|
|
g_free (data->filename);
|
|
|
|
data->filename = g_strdup (filename);
|
|
data->writable = FALSE;
|
|
data->deletable = FALSE;
|
|
|
|
/* if the data is supposed to be writable, still check if it really is */
|
|
if (writable)
|
|
{
|
|
gchar *dirname = g_path_get_dirname (filename);
|
|
|
|
if ((access (filename, F_OK) == 0 && /* check if the file exists */
|
|
access (filename, W_OK) == 0) || /* and is writable */
|
|
(access (filename, F_OK) != 0 && /* OR doesn't exist */
|
|
access (dirname, W_OK) == 0)) /* and we can write to its dir */
|
|
{
|
|
data->writable = TRUE;
|
|
data->deletable = TRUE;
|
|
}
|
|
|
|
g_free (dirname);
|
|
|
|
/* if we can't save, we are not writable */
|
|
if (! GIMP_DATA_GET_CLASS (data)->save)
|
|
data->writable = FALSE;
|
|
}
|
|
}
|
|
|
|
void
|
|
gimp_data_create_filename (GimpData *data,
|
|
const gchar *basename,
|
|
const gchar *dest_dir)
|
|
{
|
|
gchar *filename;
|
|
gchar *fullpath;
|
|
gchar *safe_name;
|
|
gint i;
|
|
gint unum = 1;
|
|
|
|
g_return_if_fail (GIMP_IS_DATA (data));
|
|
g_return_if_fail (basename != NULL);
|
|
g_return_if_fail (dest_dir != NULL);
|
|
g_return_if_fail (g_path_is_absolute (dest_dir));
|
|
|
|
safe_name = g_strdup (basename);
|
|
if (safe_name[0] == '.')
|
|
safe_name[0] = '-';
|
|
for (i = 0; safe_name[i]; i++)
|
|
if (safe_name[i] == G_DIR_SEPARATOR || g_ascii_isspace (safe_name[i]))
|
|
safe_name[i] = '-';
|
|
|
|
filename = g_strconcat (safe_name, gimp_data_get_extension (data), NULL);
|
|
|
|
fullpath = g_build_filename (dest_dir, filename, NULL);
|
|
|
|
g_free (filename);
|
|
|
|
while (g_file_test (fullpath, G_FILE_TEST_EXISTS))
|
|
{
|
|
g_free (fullpath);
|
|
|
|
filename = g_strdup_printf ("%s-%d%s",
|
|
safe_name,
|
|
unum++,
|
|
gimp_data_get_extension (data));
|
|
|
|
fullpath = g_build_filename (dest_dir, filename, NULL);
|
|
|
|
g_free (filename);
|
|
}
|
|
|
|
g_free (safe_name);
|
|
|
|
gimp_data_set_filename (data, fullpath, TRUE);
|
|
|
|
g_free (fullpath);
|
|
}
|
|
|
|
GimpData *
|
|
gimp_data_duplicate (GimpData *data,
|
|
gboolean stingy_memory_use)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_DATA (data), NULL);
|
|
|
|
if (GIMP_DATA_GET_CLASS (data)->duplicate)
|
|
return GIMP_DATA_GET_CLASS (data)->duplicate (data, stingy_memory_use);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
gimp_data_make_internal (GimpData *data)
|
|
{
|
|
g_return_if_fail (GIMP_IS_DATA (data));
|
|
|
|
if (data->filename)
|
|
{
|
|
g_free (data->filename);
|
|
data->filename = NULL;
|
|
}
|
|
|
|
data->internal = TRUE;
|
|
data->writable = FALSE;
|
|
data->deletable = FALSE;
|
|
}
|
|
|
|
GQuark
|
|
gimp_data_error_quark (void)
|
|
{
|
|
static GQuark quark = 0;
|
|
|
|
if (! quark)
|
|
quark = g_quark_from_static_string ("gimp-data-error-quark");
|
|
|
|
return quark;
|
|
}
|