Re: [Geany-devel] Threaded file handling

2009-07-27 Thread Enrico Tröger
On Mon, 27 Jul 2009 11:21:41 +0200, Jonas wrote:

Hi there,

I'd like to see threaded file handling (read, write, ...) in Geany 
because I'm mostly working directly on servers and waiting for one of 
that dozens of files to save (or open) becomes a torture quite fast.

Instead of waiting for one file to get saved I could work on another 
file which logically speaking saves time.

Some time ago, I worked on this and if I didn't post the patch
somewhere on the net (mailing list, bug tracker, I don't remember) I
probably have it laying around on my hard disk somewhere.

The main problem with threaded or asynchronous file operations is that
you don't have any feedback of the result of the requested operation.
That is, for file opening is almost completely useless because at the
very first we need the contents of the file to continue opening it,
obviously. So, when the user chooses to open a file from a remote
server which may take a few seconds, with asynchronous read nothing
would happen in Geany. The file open dialog would be closed and Geany
would wait for the server to respond while the user just don't see
anything and thinks something went wrong. Then, a few seconds later the
server finally responds and Geany starts opening the document while the
user is doing something else and is even more confused what's
happening.
Sorry, I don't see how this could be an improvement.


Regarding file saving:
this is more or less easier to realise and also more useful but also
for plain file saving, i.e. when the user clicks the Save button or hit
Ctrl-S. But we do most save operations implicitly in Geany e.g. when
compiling/building/running the current file. At this point we need
synchronous saving otherwise the whole point in saving a file prior to
an operation which relies on it becomes useless.


Regards,
Enrico

-- 
Get my GPG key from http://www.uvena.de/pub.asc


pgpl9HxCljtl5.pgp
Description: PGP signature
___
Geany-devel mailing list
Geany-devel@uvena.de
http://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel


Re: [Geany-devel] Threaded file handling

2009-07-27 Thread Jonas Haag

Am 27.07.2009 13:59, schrieb Enrico Tröger:

Sorry, I don't see how this could be an improvement.
Well just open some new tab and set its label to Loading foo.ext... 
and you're done ;-)



[...]e.g. when
compiling/building/running the current file. At this point we need
synchronous saving otherwise the whole point in saving a file prior to
an operation which relies on it becomes useless.

Yes, but that's the only case in that you need synchronous saving.

Regards,
Jonas
___
Geany-devel mailing list
Geany-devel@uvena.de
http://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel


Re: [Geany-devel] Threaded file handling

2009-07-27 Thread Enrico Tröger
On Mon, 27 Jul 2009 14:34:36 +0200, Jonas wrote:

Am 27.07.2009 13:59, schrieb Enrico Tröger:
 Sorry, I don't see how this could be an improvement.
Well just open some new tab and set its label to Loading foo.ext... 
and you're done ;-)

Hmm ok. Not sure I would like this but it could be at least a start of
a solution for the mentioned problems.


 [...]e.g. when
 compiling/building/running the current file. At this point we need
 synchronous saving otherwise the whole point in saving a file prior
 to an operation which relies on it becomes useless.
Yes, but that's the only case in that you need synchronous saving.

There was another case as well but I can't remember it right now,
unfortunately.
Anyway, attached is the patch I mentioned. It's a few months old so it
probably won't apply cleanly anymore against trunk but it should be
easily possible to manually replay the changes.
Note that the patch is in an early alpha state, I only tested it
shortly and there might be still tons of problems.
But if anyone wants to work on this, feel free to do it. I can't spend
any time on this in the next few weeks, sorry.


Regards,
Enrico

-- 
Get my GPG key from http://www.uvena.de/pub.asc
diff --git a/configure.in b/configure.in
index f94a741..00e03a7 100644
--- a/configure.in
+++ b/configure.in
@@ -128,7 +128,7 @@ fi


 # GTK checks
-gtk_modules=gtk+-2.0 = 2.6.0
+gtk_modules=gtk+-2.0 = 2.6.0 gthread-2.0
 PKG_CHECK_MODULES(GTK, [$gtk_modules])
 AC_SUBST(GTK_CFLAGS)
 AC_SUBST(GTK_LIBS)
diff --git a/src/callbacks.c b/src/callbacks.c
index 688c910..377b86c 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -182,7 +182,7 @@ on_save1_activate  (GtkMenuItem *menuitem,
 		if (doc-file_name == NULL)
 			dialogs_show_save_as();
 		else
-			document_save_file(doc, FALSE);
+			document_save_file_async(doc, FALSE);
 	}
 }

@@ -214,7 +214,7 @@ on_save_all1_activate  (GtkMenuItem *menuitem,
 			dialogs_show_save_as();
 		}
 		else
-			document_save_file(doc, FALSE);
+			document_save_file_async(doc, FALSE);
 	}
 	treeviews_update_tag_list(cur_doc, TRUE);
 	ui_set_window_title(cur_doc);
diff --git a/src/document.c b/src/document.c
index 6711282..b314233 100644
--- a/src/document.c
+++ b/src/document.c
@@ -1430,52 +1430,125 @@ _(An error occurred while converting the file from UTF-8 in \%s\. The file re
 }


-static gint write_data_to_disk(GeanyDocument *doc, const gchar *data, gint len)
+typedef struct
+{
+	GeanyDocument *doc;
+	gchar *text;
+	gsize len;
+	gint err;
+	gboolean async;
+} SaveData;
+
+
+/* Callback which is called from the saving thread when it is finished, to do GTK stuff */
+static gboolean save_file_finished(gpointer data)
 {
+	SaveData *sd = data;
+	gboolean async = sd-async; /* cache the async flag as we need it after we freed 'sd' */
+
+	if (sd-err != 0)
+	{
+		ui_set_statusbar(TRUE, _(Error saving file (%s).), g_strerror(sd-err));
+		dialogs_show_msgbox_with_secondary(GTK_MESSAGE_ERROR,
+			_(Error saving file.), g_strerror(sd-err));
+		utils_beep();
+		sd-doc-priv-save_in_progress = FALSE;
+		return FALSE;
+	}
+
+	/* store the opened encoding for undo/redo */
+	store_saved_encoding(sd-doc);
+
+	/* ignore the following things if we are quitting */
+	if (! main_status.quitting)
+	{
+		sci_set_savepoint(sd-doc-editor-sci);
+
+		/* stat the file to get the timestamp, otherwise on Windows the actual
+		 * timestamp can be ahead of time(NULL) */
+		if (file_prefs.disk_check_timeout  0)
+			document_update_timestamp(sd-doc);
+
+		/* update filetype-related things */
+		/** TODO possibly refactor document_set_filetype() to move separate updating the
+		 *  tm_file in the threaded code and keep the GUI updating outside */
+		document_set_filetype(sd-doc, sd-doc-file_type);
+
+		tm_workspace_update(TM_WORK_OBJECT(app-tm_workspace), TRUE, TRUE, FALSE);
+
+		document_update_tab_label(sd-doc);
+
+		msgwin_status_add(_(File %s saved.), sd-doc-file_name);
+		ui_update_statusbar(sd-doc, -1);
+#ifdef HAVE_VTE
+		vte_cwd(sd-doc-file_name, FALSE);
+#endif
+	}
+	sd-doc-priv-save_in_progress = FALSE;
+	g_signal_emit_by_name(geany_object, document-save, sd-doc);
+
+	g_free(sd-text);
+	g_free(sd);
+
+	return (async) ? FALSE : TRUE;
+}
+
+
+/* Saving thread to write the data to the file on disk.
+ * Don't do any GTK stuff in here. save_file_finished() is called at the end as an idle function
+ * to update GUI things in the GTK main thread.
+ * If called asynchronously, it returns always NULL.
+ * If called synchronously, it returns NULL on any error or non-NULL on success. */
+static gpointer save_file_start(gpointer data)
+{
+	SaveData *sd = data;
 	FILE *fp;
-	gint bytes_written;
+	gsize bytes_written;
 	gchar *locale_filename = NULL;
-	gint err = 0;

-	g_return_val_if_fail(data != NULL, EINVAL);
+	g_return_val_if_fail(data != NULL  sd-text != NULL, NULL);

-	locale_filename = utils_get_locale_from_utf8(doc-file_name);
+	locale_filename = utils_get_locale_from_utf8(sd-doc-file_name);