medit/moo/mooedit/mooeditfileops.c

1128 lines
30 KiB
C
Raw Normal View History

2006-05-21 16:11:05 -07:00
/*
2005-09-02 16:27:25 -07:00
* mooeditfileops.c
2005-06-22 11:20:32 -07:00
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
2005-06-22 11:20:32 -07:00
*
* 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.
*
* See COPYING file that comes with this distribution.
*/
2006-06-12 22:58:44 -07:00
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2005-06-22 11:20:32 -07:00
#define MOOEDIT_COMPILATION
#include "mooedit/mooedit-private.h"
2005-09-02 16:27:25 -07:00
#include "mooedit/mooeditfileops.h"
2005-06-22 11:20:32 -07:00
#include "mooedit/mooeditdialogs.h"
#include "mooedit/mootextbuffer.h"
2005-09-05 22:36:44 -07:00
#include "mooutils/moocompat.h"
#include "mooutils/moofilewatch.h"
2005-06-22 11:20:32 -07:00
#include <string.h>
2005-11-09 23:15:16 -08:00
#include <sys/types.h>
#include <sys/stat.h>
2006-06-12 22:58:44 -07:00
#ifdef HAVE_UNISTD_H
2005-11-09 23:15:16 -08:00
#include <unistd.h>
2006-06-12 22:58:44 -07:00
#endif
2005-11-09 23:15:16 -08:00
#include <stdio.h>
#include <errno.h>
#if GLIB_CHECK_VERSION(2,6,0)
# include <glib/gstdio.h>
#endif
2005-06-22 11:20:32 -07:00
2005-09-02 16:27:25 -07:00
static MooEditLoader *default_loader = NULL;
static MooEditSaver *default_saver = NULL;
static GSList *UNTITLED = NULL;
static GHashTable *UNTITLED_NO = NULL;
2005-09-02 16:27:25 -07:00
2005-11-01 20:41:09 -08:00
static gboolean moo_edit_load_default (MooEditLoader *loader,
MooEdit *edit,
const char *file,
const char *encoding,
GError **error);
static gboolean moo_edit_reload_default (MooEditLoader *loader,
MooEdit *edit,
GError **error);
static gboolean moo_edit_save_default (MooEditSaver *saver,
MooEdit *edit,
const char *file,
const char *encoding,
2005-11-09 23:15:16 -08:00
MooEditSaveFlags flags,
2005-11-01 20:41:09 -08:00
GError **error);
static gboolean moo_edit_save_copy_default (MooEditSaver *saver,
MooEdit *edit,
const char *file,
const char *encoding,
GError **error);
2005-09-02 16:27:25 -07:00
2005-06-22 11:20:32 -07:00
static void block_buffer_signals (MooEdit *edit);
static void unblock_buffer_signals (MooEdit *edit);
static gboolean focus_in_cb (MooEdit *edit);
static void check_file_status (MooEdit *edit,
2005-06-22 11:20:32 -07:00
gboolean in_focus_only);
static void file_modified_on_disk (MooEdit *edit);
static void file_deleted (MooEdit *edit);
2005-09-02 16:27:25 -07:00
static void add_status (MooEdit *edit,
MooEditStatus s);
2005-06-22 11:20:32 -07:00
2005-11-11 12:09:30 -08:00
MooEditLoader*
_moo_edit_loader_get_default (void)
2005-06-22 11:20:32 -07:00
{
2005-09-02 16:27:25 -07:00
if (!default_loader)
{
default_loader = g_new0 (MooEditLoader, 1);
default_loader->ref_count = 1;
default_loader->load = moo_edit_load_default;
default_loader->reload = moo_edit_reload_default;
}
2005-06-22 11:20:32 -07:00
2005-09-02 16:27:25 -07:00
return default_loader;
}
2005-06-22 11:20:32 -07:00
2005-11-11 12:09:30 -08:00
MooEditSaver*
_moo_edit_saver_get_default (void)
2005-09-02 16:27:25 -07:00
{
if (!default_saver)
{
default_saver = g_new0 (MooEditSaver, 1);
default_saver->ref_count = 1;
default_saver->save = moo_edit_save_default;
2005-11-01 20:41:09 -08:00
default_saver->save_copy = moo_edit_save_copy_default;
2005-06-22 11:20:32 -07:00
}
2005-09-02 16:27:25 -07:00
return default_saver;
}
2005-06-22 11:20:32 -07:00
2005-11-11 12:09:30 -08:00
MooEditLoader*
_moo_edit_loader_ref (MooEditLoader *loader)
2005-09-02 16:27:25 -07:00
{
g_return_val_if_fail (loader != NULL, NULL);
loader->ref_count++;
return loader;
}
2005-11-11 12:09:30 -08:00
MooEditSaver*
_moo_edit_saver_ref (MooEditSaver *saver)
2005-09-02 16:27:25 -07:00
{
g_return_val_if_fail (saver != NULL, NULL);
saver->ref_count++;
return saver;
}
2005-11-11 12:09:30 -08:00
void
_moo_edit_loader_unref (MooEditLoader *loader)
2005-09-02 16:27:25 -07:00
{
if (!loader || --loader->ref_count)
return;
g_free (loader);
if (loader == default_loader)
default_loader = NULL;
}
2005-11-11 12:09:30 -08:00
void
_moo_edit_saver_unref (MooEditSaver *saver)
2005-09-02 16:27:25 -07:00
{
if (!saver || --saver->ref_count)
return;
g_free (saver);
if (saver == default_saver)
default_saver = NULL;
}
2005-11-11 12:09:30 -08:00
gboolean
_moo_edit_loader_load (MooEditLoader *loader,
MooEdit *edit,
const char *filename,
const char *encoding,
GError **error)
2005-09-02 16:27:25 -07:00
{
char *filename_copy, *encoding_copy;
gboolean result;
2005-09-02 16:27:25 -07:00
g_return_val_if_fail (loader != NULL, FALSE);
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
filename_copy = g_strdup (filename);
encoding_copy = g_strdup (encoding);
2005-09-02 16:27:25 -07:00
result = loader->load (loader, edit, filename_copy, encoding_copy, error);
g_free (filename_copy);
g_free (encoding_copy);
return result;
2005-09-02 16:27:25 -07:00
}
2005-11-11 12:09:30 -08:00
gboolean
_moo_edit_loader_reload (MooEditLoader *loader,
MooEdit *edit,
GError **error)
2005-09-02 16:27:25 -07:00
{
g_return_val_if_fail (loader != NULL, FALSE);
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
return loader->reload (loader, edit, error);
}
2005-11-11 12:09:30 -08:00
gboolean
_moo_edit_saver_save (MooEditSaver *saver,
MooEdit *edit,
const char *filename,
const char *encoding,
MooEditSaveFlags flags,
GError **error)
2005-09-02 16:27:25 -07:00
{
char *filename_copy, *encoding_copy;
gboolean result;
2005-09-02 16:27:25 -07:00
g_return_val_if_fail (saver != NULL, FALSE);
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
filename_copy = g_strdup (filename);
encoding_copy = g_strdup (encoding);
2005-09-02 16:27:25 -07:00
2005-11-09 23:15:16 -08:00
result = saver->save (saver, edit, filename_copy, encoding_copy, flags, error);
g_free (filename_copy);
g_free (encoding_copy);
return result;
2005-09-02 16:27:25 -07:00
}
2005-11-01 20:41:09 -08:00
gboolean
_moo_edit_saver_save_copy (MooEditSaver *saver,
MooEdit *edit,
const char *filename,
const char *encoding,
GError **error)
2005-11-01 20:41:09 -08:00
{
char *filename_copy, *encoding_copy;
gboolean result;
g_return_val_if_fail (saver != NULL, FALSE);
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
filename_copy = g_strdup (filename);
encoding_copy = g_strdup (encoding);
result = saver->save_copy (saver, edit, filename_copy, encoding_copy, error);
g_free (filename_copy);
g_free (encoding_copy);
return result;
}
2005-09-02 16:27:25 -07:00
/***************************************************************************/
/* File loading
*/
static gboolean do_load (MooEdit *edit,
const char *file,
const char *encoding,
GError **error);
2006-06-18 01:38:28 -07:00
#if 0
static gboolean load_binary (MooEdit *edit,
const char *file,
GError **error);
#endif
2005-09-02 16:27:25 -07:00
static const char *common_encodings[] = {
"UTF8",
"ISO_8859-15",
"ISO_8859-1"
};
static gboolean
try_load (MooEdit *edit,
const char *file,
const char *encoding,
GError **error)
2005-09-02 16:27:25 -07:00
{
2005-09-06 09:21:05 -07:00
GtkTextBuffer *buffer;
2006-04-26 12:08:58 -07:00
gboolean result, enable_highlight;
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
g_return_val_if_fail (file && file[0], FALSE);
g_return_val_if_fail (encoding && encoding[0], FALSE);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
2006-06-18 01:38:28 -07:00
gtk_text_buffer_set_text (buffer, "", 0);
2006-04-26 12:08:58 -07:00
g_object_get (edit, "enable-highlight", &enable_highlight, NULL);
g_object_set (edit, "enable-highlight", FALSE, NULL);
result = do_load (edit, file, encoding, error);
g_object_set (edit, "enable-highlight", enable_highlight, NULL);
return result;
}
static gboolean
moo_edit_load_default (G_GNUC_UNUSED MooEditLoader *loader,
MooEdit *edit,
const char *file,
const char *encoding,
GError **error)
{
GtkTextIter start;
GtkTextBuffer *buffer;
MooTextView *view;
2005-09-02 16:27:25 -07:00
gboolean undo;
gboolean success = FALSE;
2005-09-02 16:27:25 -07:00
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
g_return_val_if_fail (file && file[0], FALSE);
2005-06-22 11:20:32 -07:00
if (moo_edit_is_empty (edit))
undo = FALSE;
else
undo = TRUE;
view = MOO_TEXT_VIEW (edit);
2005-09-06 09:21:05 -07:00
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
block_buffer_signals (edit);
2005-06-22 11:20:32 -07:00
if (undo)
2005-09-06 09:21:05 -07:00
gtk_text_buffer_begin_user_action (buffer);
2005-06-22 11:20:32 -07:00
else
moo_text_view_begin_not_undoable_action (view);
moo_text_buffer_begin_non_interactive_action (MOO_TEXT_BUFFER (buffer));
2005-06-22 11:20:32 -07:00
if (!encoding)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (common_encodings); ++i)
{
g_clear_error (error);
encoding = common_encodings[i];
success = try_load (edit, file, encoding, error);
if (success)
break;
}
if (!success)
{
const char *locale_charset;
if (!g_get_charset (&locale_charset))
{
g_clear_error (error);
encoding = locale_charset;
success = try_load (edit, file, encoding, error);
}
}
}
else
{
success = try_load (edit, file, encoding, error);
2005-06-22 11:20:32 -07:00
}
2006-06-18 01:38:28 -07:00
#if 0
if (!success)
{
g_clear_error (error);
success = load_binary (edit, file, error);
}
#endif
if (!success)
gtk_text_buffer_set_text (buffer, "", 0);
2005-06-22 11:20:32 -07:00
unblock_buffer_signals (edit);
if (success)
{
2005-11-02 22:47:53 -08:00
/* XXX */
gtk_text_buffer_get_start_iter (buffer, &start);
gtk_text_buffer_place_cursor (buffer, &start);
2005-11-02 22:47:53 -08:00
edit->priv->status = 0;
moo_edit_set_modified (edit, FALSE);
_moo_edit_set_filename (edit, file, encoding);
_moo_edit_start_file_watch (edit);
}
else
{
_moo_edit_stop_file_watch (edit);
}
2005-06-22 11:20:32 -07:00
if (undo)
2005-09-06 09:21:05 -07:00
gtk_text_buffer_end_user_action (buffer);
2005-06-22 11:20:32 -07:00
else
moo_text_view_end_not_undoable_action (view);
2005-06-22 11:20:32 -07:00
moo_text_buffer_end_non_interactive_action (MOO_TEXT_BUFFER (buffer));
return success;
2005-06-22 11:20:32 -07:00
}
static gboolean
do_load (MooEdit *edit,
const char *filename,
const char *encoding,
GError **error)
2005-06-22 11:20:32 -07:00
{
2005-09-02 16:27:25 -07:00
GIOChannel *file = NULL;
GIOStatus status;
2005-09-06 09:21:05 -07:00
GtkTextBuffer *buffer;
MooEditLineEndType le = MOO_EDIT_LINE_END_NONE;
2006-04-28 17:39:30 -07:00
GString *text = NULL;
char *line = NULL;
2005-06-22 11:20:32 -07:00
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (encoding != NULL, FALSE);
2005-06-22 11:20:32 -07:00
2005-09-06 09:21:05 -07:00
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
2005-09-02 16:27:25 -07:00
file = g_io_channel_new_file (filename, "r", error);
2005-06-22 11:20:32 -07:00
2005-09-02 16:27:25 -07:00
if (!file)
return FALSE;
2005-06-22 11:20:32 -07:00
2005-09-06 09:21:05 -07:00
if (g_io_channel_set_encoding (file, encoding, error) != G_IO_STATUS_NORMAL)
2006-04-28 17:39:30 -07:00
goto error_out;
text = g_string_new (NULL);
2005-06-22 11:20:32 -07:00
2005-09-02 16:27:25 -07:00
while (TRUE)
{
gboolean insert_line_term = FALSE;
gsize len, line_term_pos;
MooEditLineEndType le_here = 0;
2005-06-22 11:20:32 -07:00
status = g_io_channel_read_line (file, &line, &len, &line_term_pos, error);
2005-06-22 11:20:32 -07:00
if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_EOF)
2006-04-28 17:39:30 -07:00
goto error_out;
2005-09-02 16:27:25 -07:00
if (line)
2005-07-29 04:51:36 -07:00
{
2005-09-02 16:27:25 -07:00
if (!g_utf8_validate (line, len, NULL))
{
g_set_error (error, G_CONVERT_ERROR,
G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
"Invalid UTF8 data read from file");
2006-04-28 17:39:30 -07:00
goto error_out;
2005-09-02 16:27:25 -07:00
}
if (line_term_pos != len)
{
char *line_term = line + line_term_pos;
insert_line_term = TRUE;
len = line_term_pos;
if (!strcmp ("\xe2\x80\xa9", line_term))
{
insert_line_term = FALSE;
len = len + 3;
}
else if (!strcmp (line_term, "\r"))
{
le_here = MOO_EDIT_LINE_END_MAC;
}
else if (!strcmp (line_term, "\n"))
{
le_here = MOO_EDIT_LINE_END_UNIX;
}
else if (!strcmp (line_term, "\r\n"))
{
le_here = MOO_EDIT_LINE_END_WIN32;
}
if (le_here)
{
if (le && le != le_here)
le = MOO_EDIT_LINE_END_MIX;
else
le = le_here;
}
}
2006-04-28 17:39:30 -07:00
g_string_append_len (text, line, len);
if (insert_line_term)
2006-04-28 17:39:30 -07:00
g_string_append_c (text, '\n');
#define MAX_TEXT_BUF_LEN 1000000
if (text->len > MAX_TEXT_BUF_LEN)
{
gtk_text_buffer_insert_at_cursor (buffer, text->str, text->len);
g_string_truncate (text, 0);
}
#undef MAX_TEXT_BUF_LEN
2005-09-02 16:27:25 -07:00
g_free (line);
2005-07-29 04:51:36 -07:00
}
2005-09-02 16:27:25 -07:00
if (status == G_IO_STATUS_EOF)
2005-07-29 04:51:36 -07:00
{
g_io_channel_shutdown (file, TRUE, NULL);
g_io_channel_unref (file);
break;
2005-07-29 04:51:36 -07:00
}
2005-06-22 11:20:32 -07:00
}
2006-04-28 17:39:30 -07:00
if (text->len)
gtk_text_buffer_insert_at_cursor (buffer, text->str, text->len);
edit->priv->line_end_type = le;
2006-04-28 17:39:30 -07:00
g_string_free (text, TRUE);
2005-09-02 16:27:25 -07:00
g_clear_error (error);
2005-06-22 11:20:32 -07:00
return TRUE;
2006-04-28 17:39:30 -07:00
error_out:
if (text)
g_string_free (text, TRUE);
if (file)
{
g_io_channel_shutdown (file, TRUE, NULL);
g_io_channel_unref (file);
}
g_free (line);
return FALSE;
2005-06-22 11:20:32 -07:00
}
2006-06-18 01:38:28 -07:00
#if 0
#define TEXT_BUF_LEN (1 << 16)
#define REPLACEMENT_CHAR '\1'
#define LINE_LEN 80
static gboolean
load_binary (MooEdit *edit,
const char *filename,
GError **error)
{
GIOChannel *file = NULL;
GIOStatus status;
GtkTextBuffer *buffer;
g_return_val_if_fail (filename != NULL, FALSE);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
file = g_io_channel_new_file (filename, "r", error);
if (!file)
return FALSE;
g_io_channel_set_encoding (file, NULL, NULL);
while (TRUE)
{
gsize len, line_len;
char buf[TEXT_BUF_LEN];
status = g_io_channel_read_chars (file, buf, TEXT_BUF_LEN, &len, error);
if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_EOF)
goto error_out;
if (len)
{
guint i;
for (i = 0, line_len = 0; i < len; ++i, ++line_len)
{
if (buf[i] && !(buf[i] & 0x80))
continue;
if (line_len > LINE_LEN)
{
buf[i] = '\n';
line_len = 0;
}
else
{
buf[i] = REPLACEMENT_CHAR;
}
}
gtk_text_buffer_insert_at_cursor (buffer, buf, len);
}
if (status == G_IO_STATUS_EOF)
{
g_io_channel_shutdown (file, TRUE, NULL);
g_io_channel_unref (file);
break;
}
}
g_clear_error (error);
return TRUE;
error_out:
if (file)
{
g_io_channel_shutdown (file, TRUE, NULL);
g_io_channel_unref (file);
}
return FALSE;
}
#undef TEXT_BUF_LEN
#undef REPLACEMENT_CHAR
#undef LINE_LEN
#endif
2005-11-02 22:47:53 -08:00
/* XXX */
2005-11-11 12:09:30 -08:00
static gboolean
moo_edit_reload_default (MooEditLoader *loader,
MooEdit *edit,
GError **error)
2005-06-22 11:20:32 -07:00
{
GtkTextIter start, end;
2005-09-06 09:21:05 -07:00
GtkTextBuffer *buffer;
2006-04-26 12:08:58 -07:00
gboolean result, enable_highlight;
2005-06-22 11:20:32 -07:00
g_return_val_if_fail (edit->priv->filename != NULL, FALSE);
2005-09-06 09:21:05 -07:00
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
2005-06-22 11:20:32 -07:00
block_buffer_signals (edit);
2005-09-06 09:21:05 -07:00
gtk_text_buffer_begin_user_action (buffer);
2005-06-22 11:20:32 -07:00
2005-09-06 09:21:05 -07:00
gtk_text_buffer_get_bounds (buffer, &start, &end);
gtk_text_buffer_delete (buffer, &start, &end);
2006-04-26 12:08:58 -07:00
g_object_get (edit, "enable-highlight", &enable_highlight, NULL);
g_object_set (edit, "enable-highlight", FALSE, NULL);
2005-06-22 11:20:32 -07:00
result = _moo_edit_loader_load (loader, edit, edit->priv->filename,
edit->priv->encoding, error);
2006-04-26 12:08:58 -07:00
g_object_set (edit, "enable-highlight", enable_highlight, NULL);
gtk_text_buffer_end_user_action (buffer);
unblock_buffer_signals (edit);
if (result)
2005-09-02 16:27:25 -07:00
{
2005-06-22 11:20:32 -07:00
edit->priv->status = 0;
moo_edit_set_modified (edit, FALSE);
_moo_edit_start_file_watch (edit);
2005-09-02 16:27:25 -07:00
g_clear_error (error);
2005-06-22 11:20:32 -07:00
}
return result;
2005-06-22 11:20:32 -07:00
}
2005-09-02 16:27:25 -07:00
/***************************************************************************/
/* File saving
*/
2005-11-09 23:15:16 -08:00
#ifdef __WIN32__
#define BAK_SUFFIX ".bak"
#define DEFAULT_LE_TYPE MOO_EDIT_LINE_END_WIN32
2005-11-09 23:15:16 -08:00
#else
#define BAK_SUFFIX "~"
#define DEFAULT_LE_TYPE MOO_EDIT_LINE_END_UNIX
2005-11-09 23:15:16 -08:00
#endif
2005-09-02 16:27:25 -07:00
static gboolean do_write (MooEdit *edit,
const char *file,
const char *encoding,
GError **error);
2005-11-01 20:41:09 -08:00
static gboolean
moo_edit_save_default (G_GNUC_UNUSED MooEditSaver *saver,
MooEdit *edit,
const char *filename,
const char *encoding,
2005-11-09 23:15:16 -08:00
MooEditSaveFlags flags,
2005-11-01 20:41:09 -08:00
GError **error)
2005-06-22 11:20:32 -07:00
{
2005-09-02 16:27:25 -07:00
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
g_return_val_if_fail (filename && filename[0], FALSE);
if (!encoding)
encoding = "UTF8";
2005-09-02 16:27:25 -07:00
if (!do_write (edit, filename, encoding, error))
return FALSE;
edit->priv->status = 0;
_moo_edit_set_filename (edit, filename, encoding);
moo_edit_set_modified (edit, FALSE);
_moo_edit_start_file_watch (edit);
2005-09-02 16:27:25 -07:00
return TRUE;
}
2005-11-01 20:41:09 -08:00
static gboolean
moo_edit_save_copy_default (G_GNUC_UNUSED MooEditSaver *saver,
MooEdit *edit,
const char *filename,
const char *encoding,
GError **error)
{
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
g_return_val_if_fail (filename && filename[0], FALSE);
return do_write (edit, filename, encoding ? encoding : "UTF8", error);
}
static gboolean
do_write (MooEdit *edit,
const char *filename,
const char *encoding,
GError **error)
2005-09-02 16:27:25 -07:00
{
GIOChannel *file;
GIOStatus status;
GtkTextIter line_start;
2005-09-06 09:21:05 -07:00
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
MooEditLineEndType le_type = DEFAULT_LE_TYPE;
const char *le = "\n";
gssize le_len = 1;
2005-09-02 16:27:25 -07:00
g_return_val_if_fail (filename != NULL, FALSE);
if (encoding && (!g_ascii_strcasecmp (encoding, "UTF-8") || !g_ascii_strcasecmp (encoding, "UTF8")))
2005-09-02 16:27:25 -07:00
encoding = NULL;
file = g_io_channel_new_file (filename, "w", error);
2005-06-22 11:20:32 -07:00
if (!file)
2005-09-02 16:27:25 -07:00
return FALSE;
if (encoding && g_io_channel_set_encoding (file, encoding, error) != G_IO_STATUS_NORMAL)
2005-06-22 11:20:32 -07:00
{
2005-09-02 16:27:25 -07:00
g_io_channel_shutdown (file, TRUE, NULL);
g_io_channel_unref (file);
return FALSE;
2005-06-22 11:20:32 -07:00
}
switch (edit->priv->line_end_type)
{
case MOO_EDIT_LINE_END_NONE:
le_type = DEFAULT_LE_TYPE;
break;
case MOO_EDIT_LINE_END_UNIX:
case MOO_EDIT_LINE_END_WIN32:
case MOO_EDIT_LINE_END_MAC:
le_type = edit->priv->line_end_type;
break;
case MOO_EDIT_LINE_END_MIX:
edit->priv->line_end_type = le_type = DEFAULT_LE_TYPE;
break;
}
switch (le_type)
{
case MOO_EDIT_LINE_END_UNIX:
le = "\n";
le_len = 1;
break;
case MOO_EDIT_LINE_END_WIN32:
le = "\r\n";
le_len = 2;
break;
case MOO_EDIT_LINE_END_MAC:
le = "\r";
le_len = 1;
break;
case MOO_EDIT_LINE_END_MIX:
case MOO_EDIT_LINE_END_NONE:
g_assert_not_reached ();
}
2005-09-06 09:21:05 -07:00
gtk_text_buffer_get_start_iter (buffer, &line_start);
2005-09-02 16:27:25 -07:00
do
2005-06-22 11:20:32 -07:00
{
2005-09-02 16:27:25 -07:00
gsize written;
GtkTextIter line_end = line_start;
if (!gtk_text_iter_ends_line (&line_start))
{
char *line;
gssize len = -1;
gtk_text_iter_forward_to_line_end (&line_end);
line = gtk_text_buffer_get_slice (buffer, &line_start, &line_end, TRUE);
2005-09-02 16:27:25 -07:00
status = g_io_channel_write_chars (file, line, len, &written, error);
g_free (line);
/* XXX */
if (status != G_IO_STATUS_NORMAL)
{
g_io_channel_shutdown (file, TRUE, NULL);
g_io_channel_unref (file);
return FALSE;
}
}
2006-04-05 13:29:45 -07:00
if (!gtk_text_iter_is_end (&line_end))
2005-09-02 16:27:25 -07:00
{
status = g_io_channel_write_chars (file, le, le_len, &written, error);
if (written < (gsize)le_len || status != G_IO_STATUS_NORMAL)
{
g_io_channel_shutdown (file, TRUE, NULL);
g_io_channel_unref (file);
return FALSE;
}
}
2005-06-22 11:20:32 -07:00
}
2005-09-02 16:27:25 -07:00
while (gtk_text_iter_forward_line (&line_start));
2005-06-22 11:20:32 -07:00
/* glib #320668 */
status = g_io_channel_flush (file, error);
if (status != G_IO_STATUS_NORMAL)
{
g_io_channel_shutdown (file, FALSE, NULL);
g_io_channel_unref (file);
return FALSE;
}
2005-09-02 16:27:25 -07:00
status = g_io_channel_shutdown (file, TRUE, error);
2005-06-22 11:20:32 -07:00
2005-09-02 16:27:25 -07:00
if (status != G_IO_STATUS_NORMAL)
{
g_io_channel_unref (file);
return FALSE;
}
g_io_channel_unref (file);
g_clear_error (error);
return TRUE;
2005-06-22 11:20:32 -07:00
}
2005-09-02 16:27:25 -07:00
/***************************************************************************/
/* Aux stuff
*/
static void block_buffer_signals (MooEdit *edit)
2005-06-22 11:20:32 -07:00
{
2005-09-06 09:21:05 -07:00
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
g_signal_handler_block (buffer, edit->priv->modified_changed_handler_id);
2005-06-22 11:20:32 -07:00
}
2005-09-02 16:27:25 -07:00
static void unblock_buffer_signals (MooEdit *edit)
2005-06-22 11:20:32 -07:00
{
2005-09-06 09:21:05 -07:00
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
g_signal_handler_unblock (buffer, edit->priv->modified_changed_handler_id);
2005-06-22 11:20:32 -07:00
}
static void
file_watch_event (G_GNUC_UNUSED MooFileWatch *watch,
MooFileWatchEvent *event,
MooEdit *edit)
{
if (event->monitor_id != edit->priv->file_monitor_id)
return;
g_return_if_fail (edit->priv->filename != NULL);
g_return_if_fail (!(edit->priv->status & MOO_EDIT_CHANGED_ON_DISK));
switch (event->code)
{
case MOO_FILE_WATCH_CHANGED:
edit->priv->modified_on_disk = TRUE;
break;
case MOO_FILE_WATCH_DELETED:
edit->priv->deleted_from_disk = TRUE;
2005-11-16 03:23:49 -08:00
edit->priv->file_monitor_id = 0;
break;
case MOO_FILE_WATCH_CREATED:
case MOO_FILE_WATCH_MOVED:
g_return_if_reached ();
}
check_file_status (edit, TRUE);
}
void
2006-05-02 19:28:25 -07:00
_moo_edit_start_file_watch (MooEdit *edit)
2005-06-22 11:20:32 -07:00
{
MooFileWatch *watch;
GError *error = NULL;
2005-06-22 11:20:32 -07:00
watch = _moo_editor_get_file_watch (edit->priv->editor);
g_return_if_fail (MOO_IS_FILE_WATCH (watch));
if (edit->priv->file_monitor_id)
moo_file_watch_cancel_monitor (watch, edit->priv->file_monitor_id);
edit->priv->file_monitor_id = 0;
2005-06-22 11:20:32 -07:00
2005-09-02 16:27:25 -07:00
g_return_if_fail ((edit->priv->status & MOO_EDIT_CHANGED_ON_DISK) == 0);
2005-06-22 11:20:32 -07:00
g_return_if_fail (edit->priv->filename != NULL);
edit->priv->file_monitor_id = moo_file_watch_monitor_file (watch,
edit->priv->filename,
edit, &error);
if (!edit->priv->file_monitor_id)
{
2006-05-02 19:28:25 -07:00
g_warning ("%s: could not start watch for '%s'",
G_STRLOC, edit->priv->filename);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
}
2006-05-02 19:28:25 -07:00
return;
}
/* XXX watch errors too */
if (!edit->priv->file_watch_event_handler_id)
edit->priv->file_watch_event_handler_id =
g_signal_connect (watch, "event",
G_CALLBACK (file_watch_event), edit);
2005-06-22 11:20:32 -07:00
if (!edit->priv->focus_in_handler_id)
edit->priv->focus_in_handler_id =
g_signal_connect (edit, "focus-in-event",
G_CALLBACK (focus_in_cb),
NULL);
}
void
_moo_edit_stop_file_watch (MooEdit *edit)
2005-06-22 11:20:32 -07:00
{
MooFileWatch *watch;
watch = _moo_editor_get_file_watch (edit->priv->editor);
g_return_if_fail (MOO_IS_FILE_WATCH (watch));
2005-09-02 16:27:25 -07:00
if (edit->priv->file_monitor_id)
moo_file_watch_cancel_monitor (watch, edit->priv->file_monitor_id);
edit->priv->file_monitor_id = 0;
if (edit->priv->file_watch_event_handler_id)
{
g_signal_handler_disconnect (watch, edit->priv->file_watch_event_handler_id);
edit->priv->file_watch_event_handler_id = 0;
}
2005-06-22 11:20:32 -07:00
2005-09-02 16:27:25 -07:00
if (edit->priv->focus_in_handler_id)
{
2005-06-22 11:20:32 -07:00
g_signal_handler_disconnect (edit, edit->priv->focus_in_handler_id);
edit->priv->focus_in_handler_id = 0;
}
}
2005-11-03 17:35:22 -08:00
static gboolean
focus_in_cb (MooEdit *edit)
2005-06-22 11:20:32 -07:00
{
check_file_status (edit, TRUE);
return FALSE;
}
static void
check_file_status (MooEdit *edit,
gboolean in_focus_only)
2005-06-22 11:20:32 -07:00
{
if (in_focus_only && !GTK_WIDGET_HAS_FOCUS (edit))
return;
2005-06-22 11:20:32 -07:00
g_return_if_fail (edit->priv->filename != NULL);
g_return_if_fail (!(edit->priv->status & MOO_EDIT_CHANGED_ON_DISK));
2005-06-22 11:20:32 -07:00
if (edit->priv->deleted_from_disk)
file_deleted (edit);
else if (edit->priv->modified_on_disk)
file_modified_on_disk (edit);
2005-06-22 11:20:32 -07:00
}
2005-11-03 17:35:22 -08:00
static void
file_modified_on_disk (MooEdit *edit)
2005-06-22 11:20:32 -07:00
{
g_return_if_fail (edit->priv->filename != NULL);
edit->priv->modified_on_disk = FALSE;
edit->priv->deleted_from_disk = FALSE;
_moo_edit_stop_file_watch (edit);
2005-09-02 16:27:25 -07:00
add_status (edit, MOO_EDIT_MODIFIED_ON_DISK);
2005-06-22 11:20:32 -07:00
}
2005-11-03 17:35:22 -08:00
static void
file_deleted (MooEdit *edit)
2005-06-22 11:20:32 -07:00
{
g_return_if_fail (edit->priv->filename != NULL);
edit->priv->modified_on_disk = FALSE;
edit->priv->deleted_from_disk = FALSE;
_moo_edit_stop_file_watch (edit);
2005-09-02 16:27:25 -07:00
add_status (edit, MOO_EDIT_DELETED);
2005-06-22 11:20:32 -07:00
}
2005-11-03 17:35:22 -08:00
static void
add_status (MooEdit *edit,
MooEditStatus s)
2005-06-22 11:20:32 -07:00
{
2005-09-02 16:27:25 -07:00
edit->priv->status |= s;
g_signal_emit_by_name (edit, "doc-status-changed", NULL);
2005-06-22 11:20:32 -07:00
}
2005-11-03 17:35:22 -08:00
static void
remove_untitled (gpointer destroyed,
MooEdit *edit)
{
gpointer n = g_hash_table_lookup (UNTITLED_NO, edit);
if (n)
{
UNTITLED = g_slist_remove (UNTITLED, n);
g_hash_table_remove (UNTITLED_NO, edit);
if (!destroyed)
g_object_weak_unref (G_OBJECT (edit),
(GWeakNotify) remove_untitled,
GINT_TO_POINTER (TRUE));
}
}
2005-11-03 17:35:22 -08:00
static int
add_untitled (MooEdit *edit)
{
int n;
if (!(n = GPOINTER_TO_INT (g_hash_table_lookup (UNTITLED_NO, edit))))
{
for (n = 1; ; ++n)
{
if (!g_slist_find (UNTITLED, GINT_TO_POINTER (n)))
{
UNTITLED = g_slist_prepend (UNTITLED, GINT_TO_POINTER (n));
break;
}
}
g_hash_table_insert (UNTITLED_NO, edit, GINT_TO_POINTER (n));
g_object_weak_ref (G_OBJECT (edit),
(GWeakNotify) remove_untitled,
GINT_TO_POINTER (TRUE));
}
return n;
}
2005-11-03 17:35:22 -08:00
void
_moo_edit_set_filename (MooEdit *edit,
const char *file,
const char *encoding)
2005-06-22 11:20:32 -07:00
{
2005-09-02 16:27:25 -07:00
g_free (edit->priv->filename);
g_free (edit->priv->basename);
g_free (edit->priv->display_filename);
g_free (edit->priv->display_basename);
2005-06-22 11:20:32 -07:00
if (!UNTITLED_NO)
UNTITLED_NO = g_hash_table_new (g_direct_hash, g_direct_equal);
2005-09-02 16:27:25 -07:00
if (!file)
2005-06-22 11:20:32 -07:00
{
int n = add_untitled (edit);
2005-09-02 16:27:25 -07:00
edit->priv->filename = NULL;
edit->priv->basename = NULL;
if (n == 1)
edit->priv->display_filename = g_strdup ("Untitled");
else
edit->priv->display_filename = g_strdup_printf ("Untitled %d", n);
edit->priv->display_basename = g_strdup (edit->priv->display_filename);
2005-06-22 11:20:32 -07:00
}
2005-09-02 16:27:25 -07:00
else
{
remove_untitled (NULL, edit);
2005-09-02 16:27:25 -07:00
edit->priv->filename = g_strdup (file);
edit->priv->basename = g_path_get_basename (file);
2005-09-02 16:27:25 -07:00
edit->priv->display_filename =
_moo_edit_filename_to_utf8 (file);
edit->priv->display_basename =
_moo_edit_filename_to_utf8 (edit->priv->basename);
2005-06-22 11:20:32 -07:00
}
2005-09-02 16:27:25 -07:00
g_free (edit->priv->encoding);
edit->priv->encoding = g_strdup (encoding);
2005-06-22 11:20:32 -07:00
2005-09-02 16:27:25 -07:00
g_signal_emit_by_name (edit, "filename-changed", edit->priv->filename, NULL);
moo_edit_status_changed (edit);
2005-06-22 11:20:32 -07:00
}
2005-11-03 17:35:22 -08:00
char*
_moo_edit_filename_to_utf8 (const char *filename)
{
GError *err = NULL;
char *utf_filename;
g_return_val_if_fail (filename != NULL, NULL);
utf_filename = g_filename_to_utf8 (filename, -1, NULL, NULL, &err);
if (!utf_filename)
{
g_critical ("%s: could not convert filename to utf8", G_STRLOC);
if (err)
{
g_critical ("%s: %s", G_STRLOC, err->message);
g_error_free (err);
err = NULL;
}
utf_filename = g_strdup ("<Unknown>");
}
return utf_filename;
}