Add document_save_file_as and document_rename_file to the plugin API.
If GIO is available, use GFileMonitor to watch for file disk changes and indicate them immediately using an orange tab label colour. Break plugin ABI for this and the last commits. git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@3484 ea778897-0a13-0410-b9d1-a72fbfd435f5
This commit is contained in:
parent
8c5c5bb27c
commit
de3d3b42fb
@ -8,6 +8,12 @@
|
|||||||
Remove filetype O-Matrix (probably unused for years).
|
Remove filetype O-Matrix (probably unused for years).
|
||||||
* src/keybindings.c, src/keybindings.h:
|
* src/keybindings.c, src/keybindings.h:
|
||||||
Reorder some keybindings.
|
Reorder some keybindings.
|
||||||
|
* src/dialogs.c, src/document.c, src/document.h, src/documentprivate.h,
|
||||||
|
src/plugindata.h, src/plugins.c, plugins/geanyfunctions.h:
|
||||||
|
Add document_save_file_as and document_rename_file to the plugin API.
|
||||||
|
If GIO is available, use GFileMonitor to watch for file disk changes
|
||||||
|
and indicate them immediately using an orange tab label colour.
|
||||||
|
Break plugin ABI for this and the last commits.
|
||||||
|
|
||||||
|
|
||||||
2009-01-17 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
|
2009-01-17 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
|
||||||
|
1
TODO
1
TODO
@ -30,7 +30,6 @@ Note: features included in brackets have lower priority.
|
|||||||
target...)
|
target...)
|
||||||
o (tango-like icons for the symbol list)
|
o (tango-like icons for the symbol list)
|
||||||
o (show autocompletion symbol icons - see SCI_REGISTERIMAGE)
|
o (show autocompletion symbol icons - see SCI_REGISTERIMAGE)
|
||||||
o (GFileMonitor support, if/when GIO gets merged with GLib)
|
|
||||||
|
|
||||||
|
|
||||||
1.0:
|
1.0:
|
||||||
|
@ -40,6 +40,10 @@
|
|||||||
geany_functions->p_document->close
|
geany_functions->p_document->close
|
||||||
#define document_index \
|
#define document_index \
|
||||||
geany_functions->p_document->index
|
geany_functions->p_document->index
|
||||||
|
#define document_save_file_as \
|
||||||
|
geany_functions->p_document->save_file_as
|
||||||
|
#define document_rename_file \
|
||||||
|
geany_functions->p_document->rename_file
|
||||||
#define editor_get_indent_prefs \
|
#define editor_get_indent_prefs \
|
||||||
geany_functions->p_editor->get_indent_prefs
|
geany_functions->p_editor->get_indent_prefs
|
||||||
#define editor_create_widget \
|
#define editor_create_widget \
|
||||||
|
@ -382,8 +382,7 @@ static void on_save_as_new_tab_toggled(GtkToggleButton *togglebutton, gpointer u
|
|||||||
|
|
||||||
|
|
||||||
#if ! GEANY_USE_WIN32_DIALOG
|
#if ! GEANY_USE_WIN32_DIALOG
|
||||||
static void handle_save_as(const gchar *utf8_filename, gboolean open_new_tab,
|
static void handle_save_as(const gchar *utf8_filename, gboolean open_new_tab, gboolean rename_file)
|
||||||
gboolean rename_file)
|
|
||||||
{
|
{
|
||||||
GeanyDocument *doc = document_get_current();
|
GeanyDocument *doc = document_get_current();
|
||||||
|
|
||||||
@ -400,22 +399,16 @@ static void handle_save_as(const gchar *utf8_filename, gboolean open_new_tab,
|
|||||||
{
|
{
|
||||||
if (rename_file)
|
if (rename_file)
|
||||||
{
|
{
|
||||||
gchar *old_filename = utils_get_locale_from_utf8(doc->file_name);
|
document_rename_file(doc, utf8_filename);
|
||||||
gchar *new_filename = utils_get_locale_from_utf8(utf8_filename);
|
|
||||||
|
|
||||||
g_rename(old_filename, new_filename);
|
|
||||||
g_free(old_filename);
|
|
||||||
g_free(new_filename);
|
|
||||||
}
|
}
|
||||||
/* create a new tm_source_file object otherwise tagmanager won't work correctly */
|
/* create a new tm_source_file object otherwise tagmanager won't work correctly */
|
||||||
tm_workspace_remove_object(doc->tm_file, TRUE, TRUE);
|
tm_workspace_remove_object(doc->tm_file, TRUE, TRUE);
|
||||||
doc->tm_file = NULL;
|
doc->tm_file = NULL;
|
||||||
}
|
}
|
||||||
document_save_file_as(doc, utf8_filename);
|
document_save_file_as(doc, utf8_filename);
|
||||||
}
|
|
||||||
|
|
||||||
if (! open_new_tab)
|
|
||||||
build_menu_update(doc);
|
build_menu_update(doc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
272
src/document.c
272
src/document.c
@ -47,6 +47,10 @@
|
|||||||
/* gstdio.h also includes sys/stat.h */
|
/* gstdio.h also includes sys/stat.h */
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_GIO
|
||||||
|
# include <gio/gio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
#include "documentprivate.h"
|
#include "documentprivate.h"
|
||||||
#include "filetypes.h"
|
#include "filetypes.h"
|
||||||
@ -337,9 +341,7 @@ static void init_doc_struct(GeanyDocument *new_doc)
|
|||||||
new_doc->encoding = NULL;
|
new_doc->encoding = NULL;
|
||||||
new_doc->has_bom = FALSE;
|
new_doc->has_bom = FALSE;
|
||||||
new_doc->editor = NULL;
|
new_doc->editor = NULL;
|
||||||
new_doc->mtime = 0;
|
|
||||||
new_doc->changed = FALSE;
|
new_doc->changed = FALSE;
|
||||||
new_doc->last_check = time(NULL);
|
|
||||||
new_doc->real_path = NULL;
|
new_doc->real_path = NULL;
|
||||||
|
|
||||||
new_doc->priv = g_new0(GeanyDocumentPrivate, 1);
|
new_doc->priv = g_new0(GeanyDocumentPrivate, 1);
|
||||||
@ -384,6 +386,97 @@ static void queue_colourise(GeanyDocument *doc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_GIO
|
||||||
|
static void file_monitor_changed_cb(G_GNUC_UNUSED GFileMonitor *monitor, G_GNUC_UNUSED GFile *file,
|
||||||
|
G_GNUC_UNUSED GFile *other_file, GFileMonitorEvent event, GeanyDocument *doc)
|
||||||
|
{
|
||||||
|
if (file_prefs.disk_check_timeout == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case G_FILE_MONITOR_EVENT_CHANGED:
|
||||||
|
{
|
||||||
|
if (doc->priv->file_disk_status == FILE_IGNORE)
|
||||||
|
{ /* ignore this change completely, used after saving a file */
|
||||||
|
doc->priv->file_disk_status = FILE_OK;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doc->priv->file_disk_status = FILE_CHANGED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case G_FILE_MONITOR_EVENT_DELETED:
|
||||||
|
{
|
||||||
|
doc->priv->file_disk_status = FILE_MISSING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* ignore */
|
||||||
|
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
|
||||||
|
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
|
||||||
|
case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
|
||||||
|
case G_FILE_MONITOR_EVENT_UNMOUNTED:
|
||||||
|
/* we ignore 'created' for now since it causes trouble when renaming files */
|
||||||
|
case G_FILE_MONITOR_EVENT_CREATED:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc->priv->file_disk_status != FILE_OK)
|
||||||
|
{
|
||||||
|
ui_update_tab_status(doc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void document_stop_file_monitoring(GeanyDocument *doc)
|
||||||
|
{
|
||||||
|
g_return_if_fail(doc != NULL);
|
||||||
|
|
||||||
|
if (doc->priv->monitor != NULL)
|
||||||
|
{
|
||||||
|
g_object_unref(doc->priv->monitor);
|
||||||
|
doc->priv->monitor = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void file_monitor_setup(GeanyDocument *doc)
|
||||||
|
{
|
||||||
|
g_return_if_fail(doc != NULL);
|
||||||
|
/* Disable file monitoring completely for remote files (i.e. remote GIO files) as GFileMonitor
|
||||||
|
* doesn't work at all for remote files and legacy polling is too slow. */
|
||||||
|
if (! doc->priv->is_remote)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_GIO
|
||||||
|
gchar *locale_filename;
|
||||||
|
GFile *file;
|
||||||
|
|
||||||
|
/* stop any previous monitoring */
|
||||||
|
document_stop_file_monitoring(doc);
|
||||||
|
|
||||||
|
locale_filename = utils_get_locale_from_utf8(doc->file_name);
|
||||||
|
if (locale_filename != NULL && g_file_test(locale_filename, G_FILE_TEST_EXISTS))
|
||||||
|
{
|
||||||
|
/* get a file monitor and connect to the 'changed' signal */
|
||||||
|
file = g_file_new_for_path(locale_filename);
|
||||||
|
doc->priv->monitor = g_file_monitor_file(file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||||
|
g_signal_connect(doc->priv->monitor, "changed", G_CALLBACK(file_monitor_changed_cb), doc);
|
||||||
|
|
||||||
|
/* we set the rate limit according to the GUI pref but it's most probably not used */
|
||||||
|
g_file_monitor_set_rate_limit(doc->priv->monitor, file_prefs.disk_check_timeout * 1000);
|
||||||
|
|
||||||
|
g_object_unref(file);
|
||||||
|
}
|
||||||
|
g_free(locale_filename);
|
||||||
|
#else
|
||||||
|
doc->priv->last_check = time(NULL);
|
||||||
|
doc->priv->mtime = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
doc->priv->file_disk_status = FILE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Creates a new document and editor, adding a tab in the notebook.
|
/* Creates a new document and editor, adding a tab in the notebook.
|
||||||
* @return The created document */
|
* @return The created document */
|
||||||
static GeanyDocument *document_create(const gchar *utf8_filename)
|
static GeanyDocument *document_create(const gchar *utf8_filename)
|
||||||
@ -438,7 +531,6 @@ static GeanyDocument *document_create(const gchar *utf8_filename)
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the given document.
|
* Close the given document.
|
||||||
*
|
*
|
||||||
@ -497,6 +589,8 @@ gboolean document_remove_page(guint page_num)
|
|||||||
editor_destroy(doc->editor);
|
editor_destroy(doc->editor);
|
||||||
doc->editor = NULL;
|
doc->editor = NULL;
|
||||||
|
|
||||||
|
document_stop_file_monitoring(doc);
|
||||||
|
|
||||||
doc->is_valid = FALSE;
|
doc->is_valid = FALSE;
|
||||||
doc->file_name = NULL;
|
doc->file_name = NULL;
|
||||||
doc->real_path = NULL;
|
doc->real_path = NULL;
|
||||||
@ -571,7 +665,7 @@ GeanyDocument *document_new_file(const gchar *utf8_filename, GeanyFiletype *ft,
|
|||||||
sci_set_undo_collection(doc->editor->sci, TRUE);
|
sci_set_undo_collection(doc->editor->sci, TRUE);
|
||||||
sci_empty_undo_buffer(doc->editor->sci);
|
sci_empty_undo_buffer(doc->editor->sci);
|
||||||
|
|
||||||
doc->mtime = time(NULL);
|
doc->priv->mtime = time(NULL);
|
||||||
|
|
||||||
doc->encoding = g_strdup(encodings[file_prefs.default_new_encoding].charset);
|
doc->encoding = g_strdup(encodings[file_prefs.default_new_encoding].charset);
|
||||||
/* store the opened encoding for undo/redo */
|
/* store the opened encoding for undo/redo */
|
||||||
@ -593,6 +687,8 @@ GeanyDocument *document_new_file(const gchar *utf8_filename, GeanyFiletype *ft,
|
|||||||
sci_set_line_numbers(doc->editor->sci, editor_prefs.show_linenumber_margin, 0);
|
sci_set_line_numbers(doc->editor->sci, editor_prefs.show_linenumber_margin, 0);
|
||||||
sci_goto_pos(doc->editor->sci, 0, TRUE);
|
sci_goto_pos(doc->editor->sci, 0, TRUE);
|
||||||
|
|
||||||
|
file_monitor_setup(doc);
|
||||||
|
|
||||||
/* "the" SCI signal (connect after initial setup(i.e. adding text)) */
|
/* "the" SCI signal (connect after initial setup(i.e. adding text)) */
|
||||||
g_signal_connect(doc->editor->sci, "sci-notify", G_CALLBACK(editor_sci_notify_cb), doc->editor);
|
g_signal_connect(doc->editor->sci, "sci-notify", G_CALLBACK(editor_sci_notify_cb), doc->editor);
|
||||||
|
|
||||||
@ -1082,6 +1178,7 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
|
|||||||
g_return_val_if_fail(doc != NULL, NULL); /* really should not happen */
|
g_return_val_if_fail(doc != NULL, NULL); /* really should not happen */
|
||||||
|
|
||||||
doc->priv->is_remote = utils_is_remote_path(locale_filename);
|
doc->priv->is_remote = utils_is_remote_path(locale_filename);
|
||||||
|
file_monitor_setup(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
sci_set_undo_collection(doc->editor->sci, FALSE); /* avoid creation of an undo action */
|
sci_set_undo_collection(doc->editor->sci, FALSE); /* avoid creation of an undo action */
|
||||||
@ -1099,7 +1196,7 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
|
|||||||
|
|
||||||
sci_set_undo_collection(doc->editor->sci, TRUE);
|
sci_set_undo_collection(doc->editor->sci, TRUE);
|
||||||
|
|
||||||
doc->mtime = filedata.mtime; /* get the modification time from file and keep it */
|
doc->priv->mtime = filedata.mtime; /* get the modification time from file and keep it */
|
||||||
g_free(doc->encoding); /* if reloading, free old encoding */
|
g_free(doc->encoding); /* if reloading, free old encoding */
|
||||||
doc->encoding = filedata.enc;
|
doc->encoding = filedata.enc;
|
||||||
doc->has_bom = filedata.bom;
|
doc->has_bom = filedata.bom;
|
||||||
@ -1252,6 +1349,7 @@ gboolean document_reload_file(GeanyDocument *doc, const gchar *forced_enc)
|
|||||||
|
|
||||||
static gboolean document_update_timestamp(GeanyDocument *doc)
|
static gboolean document_update_timestamp(GeanyDocument *doc)
|
||||||
{
|
{
|
||||||
|
#ifndef HAVE_GIO
|
||||||
struct stat st;
|
struct stat st;
|
||||||
gchar *locale_filename;
|
gchar *locale_filename;
|
||||||
|
|
||||||
@ -1266,8 +1364,9 @@ static gboolean document_update_timestamp(GeanyDocument *doc)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
doc->mtime = st.st_mtime; /* get the modification time from file and keep it */
|
doc->priv->mtime = st.st_mtime; /* get the modification time from file and keep it */
|
||||||
g_free(locale_filename);
|
g_free(locale_filename);
|
||||||
|
#endif
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1326,22 +1425,47 @@ static void replace_header_filename(GeanyDocument *doc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Save the %document, detecting the filetype.
|
* Renames the file in @a doc to @a new_filename. Only the file on disk is actually renamed,
|
||||||
|
* you still have to call @ref document_save_file_as() to change the @a doc object.
|
||||||
|
* It also stops monitoring for file changes to prevent receiving too many file change events
|
||||||
|
* while renaming. File monitoring is setup again in @ref document_save_file_as().
|
||||||
|
*
|
||||||
|
* @param doc The current document which should be renamed.
|
||||||
|
* @param new_filename The new filename in UTF-8 encoding.
|
||||||
|
*/
|
||||||
|
void document_rename_file(GeanyDocument *doc, const gchar *new_filename)
|
||||||
|
{
|
||||||
|
gchar *old_locale_filename = utils_get_locale_from_utf8(doc->file_name);
|
||||||
|
gchar *new_locale_filename = utils_get_locale_from_utf8(new_filename);
|
||||||
|
|
||||||
|
/* stop file monitoring to avoid getting events for deleting/creating files,
|
||||||
|
* it's re-setup in document_save_file_as() */
|
||||||
|
document_stop_file_monitoring(doc);
|
||||||
|
|
||||||
|
g_rename(old_locale_filename, new_locale_filename);
|
||||||
|
|
||||||
|
g_free(old_locale_filename);
|
||||||
|
g_free(new_locale_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the document, detecting the filetype.
|
||||||
*
|
*
|
||||||
* @param doc The document for the file to save.
|
* @param doc The document for the file to save.
|
||||||
* @param utf8_fname The new name for the document, in UTF-8, or NULL.
|
* @param utf8_fname The new name for the document, in UTF-8, or NULL.
|
||||||
* @return @c TRUE if the file was saved or @c FALSE if the file could not be saved.
|
* @return @c TRUE if the file was saved or @c FALSE if the file could not be saved.
|
||||||
|
*
|
||||||
* @see document_save_file().
|
* @see document_save_file().
|
||||||
*/
|
*/
|
||||||
gboolean document_save_file_as(GeanyDocument *doc, const gchar *utf8_fname)
|
gboolean document_save_file_as(GeanyDocument *doc, const gchar *utf8_fname)
|
||||||
{
|
{
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
|
||||||
if (doc == NULL)
|
g_return_val_if_fail(doc != NULL, FALSE);
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (utf8_fname)
|
if (utf8_fname != NULL)
|
||||||
{
|
{
|
||||||
g_free(doc->file_name);
|
g_free(doc->file_name);
|
||||||
doc->file_name = g_strdup(utf8_fname);
|
doc->file_name = g_strdup(utf8_fname);
|
||||||
@ -1365,6 +1489,12 @@ gboolean document_save_file_as(GeanyDocument *doc, const gchar *utf8_fname)
|
|||||||
replace_header_filename(doc);
|
replace_header_filename(doc);
|
||||||
|
|
||||||
ret = document_save_file(doc, TRUE);
|
ret = document_save_file(doc, TRUE);
|
||||||
|
|
||||||
|
/* file monitoring support, add file monitoring after the file has been saved
|
||||||
|
* to ignore any earlier events */
|
||||||
|
file_monitor_setup(doc);
|
||||||
|
doc->priv->file_disk_status = FILE_IGNORE;
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
ui_add_recent_file(doc->file_name);
|
ui_add_recent_file(doc->file_name);
|
||||||
return ret;
|
return ret;
|
||||||
@ -1551,6 +1681,9 @@ gboolean document_save_file(GeanyDocument *doc, gboolean force)
|
|||||||
err = write_data_to_disk(doc, data, len);
|
err = write_data_to_disk(doc, data, len);
|
||||||
g_free(data);
|
g_free(data);
|
||||||
|
|
||||||
|
/* ignore file changed notification after writing the file */
|
||||||
|
doc->priv->file_disk_status = FILE_IGNORE;
|
||||||
|
|
||||||
if (err != 0)
|
if (err != 0)
|
||||||
{
|
{
|
||||||
ui_set_statusbar(TRUE, _("Error saving file (%s)."), g_strerror(err));
|
ui_set_statusbar(TRUE, _("Error saving file (%s)."), g_strerror(err));
|
||||||
@ -2472,6 +2605,7 @@ GdkColor *document_get_status_color(GeanyDocument *doc)
|
|||||||
{
|
{
|
||||||
static GdkColor red = {0, 0xFFFF, 0, 0};
|
static GdkColor red = {0, 0xFFFF, 0, 0};
|
||||||
static GdkColor green = {0, 0, 0x7FFF, 0};
|
static GdkColor green = {0, 0, 0x7FFF, 0};
|
||||||
|
static GdkColor orange = {0, 0xFFFF, 0x7FFF, 0};
|
||||||
GdkColor *color = NULL;
|
GdkColor *color = NULL;
|
||||||
|
|
||||||
if (doc == NULL)
|
if (doc == NULL)
|
||||||
@ -2479,6 +2613,11 @@ GdkColor *document_get_status_color(GeanyDocument *doc)
|
|||||||
|
|
||||||
if (doc->changed)
|
if (doc->changed)
|
||||||
color = &red;
|
color = &red;
|
||||||
|
else if (doc->priv->file_disk_status == FILE_MISSING ||
|
||||||
|
doc->priv->file_disk_status == FILE_CHANGED)
|
||||||
|
{
|
||||||
|
color = &orange;
|
||||||
|
}
|
||||||
else if (doc->readonly)
|
else if (doc->readonly)
|
||||||
color = &green;
|
color = &green;
|
||||||
|
|
||||||
@ -2606,62 +2745,103 @@ static gboolean check_reload(GeanyDocument *doc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean check_resave_missing_file(GeanyDocument *doc)
|
||||||
|
{
|
||||||
|
gboolean want_reload = FALSE;
|
||||||
|
|
||||||
|
/* file is missing - set unsaved state */
|
||||||
|
document_set_text_changed(doc, TRUE);
|
||||||
|
/* don't prompt more than once */
|
||||||
|
setptr(doc->real_path, NULL);
|
||||||
|
|
||||||
|
if (dialogs_show_question_full(NULL, GTK_STOCK_SAVE, GTK_STOCK_CANCEL,
|
||||||
|
_("Try to resave the file?"),
|
||||||
|
_("File \"%s\" was not found on disk!"), doc->file_name))
|
||||||
|
{
|
||||||
|
dialogs_show_save_as();
|
||||||
|
want_reload = TRUE;
|
||||||
|
}
|
||||||
|
return want_reload;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static time_t check_disk_status_real(GeanyDocument *doc, gboolean force)
|
||||||
|
{
|
||||||
|
time_t t = 0;
|
||||||
|
#ifndef HAVE_GIO
|
||||||
|
struct stat st;
|
||||||
|
gchar *locale_filename;
|
||||||
|
|
||||||
|
t = time(NULL);
|
||||||
|
|
||||||
|
if (! force && doc->priv->last_check > (t - file_prefs.disk_check_timeout))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
doc->priv->last_check = t;
|
||||||
|
|
||||||
|
locale_filename = utils_get_locale_from_utf8(doc->file_name);
|
||||||
|
if (g_stat(locale_filename, &st) != 0)
|
||||||
|
{
|
||||||
|
doc->priv->file_disk_status = FILE_MISSING;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (doc->priv->mtime > t || st.st_mtime > t)
|
||||||
|
{
|
||||||
|
g_warning("%s: Something is wrong with the time stamps.", __func__);
|
||||||
|
}
|
||||||
|
else if (doc->priv->mtime < st.st_mtime)
|
||||||
|
{
|
||||||
|
doc->priv->file_disk_status = FILE_CHANGED;
|
||||||
|
/* return st.st_mtime to set it after the file has been possibly reloaded */
|
||||||
|
t = st.st_mtime;
|
||||||
|
}
|
||||||
|
g_free(locale_filename);
|
||||||
|
#endif
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set force to force a disk check, otherwise it is ignored if there was a check
|
/* Set force to force a disk check, otherwise it is ignored if there was a check
|
||||||
* in the last file_prefs.disk_check_timeout seconds.
|
* in the last file_prefs.disk_check_timeout seconds.
|
||||||
* @return @c TRUE if the file has changed. */
|
* @return @c TRUE if the file has changed. */
|
||||||
gboolean document_check_disk_status(GeanyDocument *doc, gboolean force)
|
gboolean document_check_disk_status(GeanyDocument *doc, gboolean force)
|
||||||
{
|
{
|
||||||
struct stat st;
|
|
||||||
time_t t;
|
|
||||||
gchar *locale_filename;
|
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
time_t t;
|
||||||
|
|
||||||
if (file_prefs.disk_check_timeout == 0)
|
if (file_prefs.disk_check_timeout == 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (doc == NULL)
|
if (doc == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
/* ignore documents that have never been saved to disk */
|
/* ignore documents that have never been saved to disk */
|
||||||
if (doc->real_path == NULL) return FALSE;
|
if (doc->real_path == NULL)
|
||||||
|
|
||||||
t = time(NULL);
|
|
||||||
|
|
||||||
if (! force && doc->last_check > (t - file_prefs.disk_check_timeout))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
doc->last_check = t;
|
/* check the file's mtime in case we don't have GIO support, otherwise this is a no-op */
|
||||||
|
t = check_disk_status_real(doc, force);
|
||||||
|
|
||||||
locale_filename = utils_get_locale_from_utf8(doc->file_name);
|
switch (doc->priv->file_disk_status)
|
||||||
if (g_stat(locale_filename, &st) != 0)
|
|
||||||
{
|
{
|
||||||
/* file is missing - set unsaved state */
|
case FILE_CHANGED:
|
||||||
document_set_text_changed(doc, TRUE);
|
|
||||||
/* don't prompt more than once */
|
|
||||||
setptr(doc->real_path, NULL);
|
|
||||||
|
|
||||||
if (dialogs_show_question_full(NULL, GTK_STOCK_SAVE, GTK_STOCK_CANCEL,
|
|
||||||
_("Try to resave the file?"),
|
|
||||||
_("File \"%s\" was not found on disk!"), doc->file_name))
|
|
||||||
{
|
{
|
||||||
dialogs_show_save_as();
|
check_reload(doc);
|
||||||
|
doc->priv->mtime = t;
|
||||||
|
ret = TRUE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
case FILE_MISSING:
|
||||||
else if (doc->mtime > t || st.st_mtime > t)
|
|
||||||
{
|
|
||||||
geany_debug("Strange: Something is wrong with the time stamps.");
|
|
||||||
}
|
|
||||||
else if (doc->mtime < st.st_mtime)
|
|
||||||
{
|
|
||||||
if (check_reload(doc))
|
|
||||||
{
|
{
|
||||||
/* Update the modification time */
|
check_resave_missing_file(doc);
|
||||||
doc->mtime = st.st_mtime;
|
ret = TRUE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
default:
|
||||||
doc->mtime = st.st_mtime; /* Ignore this change on disk completely */
|
break;
|
||||||
|
|
||||||
ret = TRUE; /* file has changed */
|
|
||||||
}
|
}
|
||||||
g_free(locale_filename);
|
|
||||||
|
doc->priv->file_disk_status = FILE_OK;
|
||||||
|
ui_update_tab_status(doc);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,10 +93,6 @@ struct GeanyDocument
|
|||||||
gboolean readonly;
|
gboolean readonly;
|
||||||
/** Whether this %document has been changed since it was last saved. */
|
/** Whether this %document has been changed since it was last saved. */
|
||||||
gboolean changed;
|
gboolean changed;
|
||||||
/** Time of the last disk check. */
|
|
||||||
time_t last_check;
|
|
||||||
/** Modification time of this %document on disk. */
|
|
||||||
time_t mtime;
|
|
||||||
/** The link-dereferenced, locale-encoded file name.
|
/** The link-dereferenced, locale-encoded file name.
|
||||||
* If non-NULL, this indicates the file once existed on disk (not just as an
|
* If non-NULL, this indicates the file once existed on disk (not just as an
|
||||||
* unsaved document with a filename set).
|
* unsaved document with a filename set).
|
||||||
@ -157,6 +153,7 @@ void document_set_text_changed(GeanyDocument *doc, gboolean changed);
|
|||||||
|
|
||||||
void document_set_filetype(GeanyDocument *doc, GeanyFiletype *type);
|
void document_set_filetype(GeanyDocument *doc, GeanyFiletype *type);
|
||||||
|
|
||||||
|
void document_rename_file(GeanyDocument *doc, const gchar *new_filename);
|
||||||
|
|
||||||
GeanyDocument *document_index(gint idx);
|
GeanyDocument *document_index(gint idx);
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#ifndef GEANY_DOCUMENT_PRIVATE_H
|
#ifndef GEANY_DOCUMENT_PRIVATE_H
|
||||||
#define GEANY_DOCUMENT_PRIVATE_H
|
#define GEANY_DOCUMENT_PRIVATE_H
|
||||||
|
|
||||||
|
|
||||||
/* available UNDO actions, UNDO_SCINTILLA is a pseudo action to trigger Scintilla's
|
/* available UNDO actions, UNDO_SCINTILLA is a pseudo action to trigger Scintilla's
|
||||||
* undo management */
|
* undo management */
|
||||||
enum
|
enum
|
||||||
@ -36,6 +37,15 @@ enum
|
|||||||
UNDO_ACTIONS_MAX
|
UNDO_ACTIONS_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
FILE_OK,
|
||||||
|
FILE_CHANGED,
|
||||||
|
FILE_MISSING,
|
||||||
|
FILE_IGNORE
|
||||||
|
}
|
||||||
|
FileDiskStatus;
|
||||||
|
|
||||||
|
|
||||||
typedef struct FileEncoding
|
typedef struct FileEncoding
|
||||||
{
|
{
|
||||||
@ -69,7 +79,16 @@ typedef struct GeanyDocumentPrivate
|
|||||||
gint symbol_list_sort_mode;
|
gint symbol_list_sort_mode;
|
||||||
/* indicates whether a file is on a remote filesystem, works only with GIO/GVFS */
|
/* indicates whether a file is on a remote filesystem, works only with GIO/GVFS */
|
||||||
gboolean is_remote;
|
gboolean is_remote;
|
||||||
}
|
/* File status on disk of the document, can be 'FILE_CHANGED', 'FILE_MISSING' (deleted) or
|
||||||
|
* 'FILE_OK' if there are no known changes */
|
||||||
|
FileDiskStatus file_disk_status;
|
||||||
|
/* Reference to a GFileMonitor object, only used when GIO file monitoring is used. */
|
||||||
|
gpointer monitor;
|
||||||
|
/* Time of the last disk check, only used when legacy file monitoring is used. */
|
||||||
|
time_t last_check;
|
||||||
|
/* Modification time of the document on disk, only used when legacy file monitoring is used. */
|
||||||
|
time_t mtime;
|
||||||
|
}
|
||||||
GeanyDocumentPrivate;
|
GeanyDocumentPrivate;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,13 +45,13 @@
|
|||||||
enum {
|
enum {
|
||||||
/** The Application Programming Interface (API) version, incremented
|
/** The Application Programming Interface (API) version, incremented
|
||||||
* whenever any plugin data types are modified or appended to. */
|
* whenever any plugin data types are modified or appended to. */
|
||||||
GEANY_API_VERSION = 125,
|
GEANY_API_VERSION = 126,
|
||||||
|
|
||||||
/** The Application Binary Interface (ABI) version, incremented whenever
|
/** The Application Binary Interface (ABI) version, incremented whenever
|
||||||
* existing fields in the plugin data types have to be changed or reordered. */
|
* existing fields in the plugin data types have to be changed or reordered. */
|
||||||
/* This should usually stay the same if fields are only appended, assuming only pointers to
|
/* This should usually stay the same if fields are only appended, assuming only pointers to
|
||||||
* structs and not structs themselves are declared by plugins. */
|
* structs and not structs themselves are declared by plugins. */
|
||||||
GEANY_ABI_VERSION = 56
|
GEANY_ABI_VERSION = 57
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Check the plugin can be loaded by Geany.
|
/** Check the plugin can be loaded by Geany.
|
||||||
@ -248,8 +248,10 @@ typedef struct DocumentFuncs
|
|||||||
void (*set_encoding) (struct GeanyDocument *doc, const gchar *new_encoding);
|
void (*set_encoding) (struct GeanyDocument *doc, const gchar *new_encoding);
|
||||||
void (*set_text_changed) (struct GeanyDocument *doc, gboolean changed);
|
void (*set_text_changed) (struct GeanyDocument *doc, gboolean changed);
|
||||||
void (*set_filetype) (struct GeanyDocument *doc, struct GeanyFiletype *type);
|
void (*set_filetype) (struct GeanyDocument *doc, struct GeanyFiletype *type);
|
||||||
gboolean (*close) (GeanyDocument *doc);
|
gboolean (*close) (struct GeanyDocument *doc);
|
||||||
struct GeanyDocument* (*index)(gint idx);
|
struct GeanyDocument* (*index)(gint idx);
|
||||||
|
gboolean (*save_file_as) (struct GeanyDocument *doc, const gchar *utf8_fname);
|
||||||
|
void (*rename_file) (struct GeanyDocument *doc, const gchar *new_filename);
|
||||||
}
|
}
|
||||||
DocumentFuncs;
|
DocumentFuncs;
|
||||||
|
|
||||||
|
@ -131,7 +131,9 @@ static DocumentFuncs doc_funcs = {
|
|||||||
&document_set_text_changed,
|
&document_set_text_changed,
|
||||||
&document_set_filetype,
|
&document_set_filetype,
|
||||||
&document_close,
|
&document_close,
|
||||||
&document_index
|
&document_index,
|
||||||
|
&document_save_file_as,
|
||||||
|
&document_rename_file
|
||||||
};
|
};
|
||||||
|
|
||||||
static EditorFuncs editor_funcs = {
|
static EditorFuncs editor_funcs = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user