[rkward-cvs] SF.net SVN: rkward:[3159] branches/2010_10_18_backend_restructuring_branch/ rkward

tfry at users.sourceforge.net tfry at users.sourceforge.net
Thu Oct 28 11:42:21 UTC 2010


Revision: 3159
          http://rkward.svn.sourceforge.net/rkward/?rev=3159&view=rev
Author:   tfry
Date:     2010-10-28 11:42:21 +0000 (Thu, 28 Oct 2010)

Log Message:
-----------
This surprisingly large diff narrows the event passing to only a single type of events.
In effect, this gets us a lot closer to a fully serializable communication between frontend and backend.
- Also remove useless .rk.set.reply(NULL)-subcommands.
- Also make file.show() asynchronous.

Modified Paths:
--------------
    branches/2010_10_18_backend_restructuring_branch/rkward/agents/showedittextfileagent.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/agents/showedittextfileagent.h
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rpackages/rkward/R/internal.R
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandeditorwindow.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandeditorwindow.h
    branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkworkplace.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkworkplace.h

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/agents/showedittextfileagent.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/agents/showedittextfileagent.cpp	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/agents/showedittextfileagent.cpp	2010-10-28 11:42:21 UTC (rev 3159)
@@ -19,6 +19,7 @@
 
 #include <klocale.h>
 #include <kdialog.h>
+#include <kmessagebox.h>
 
 #include <qlabel.h>
 #include <qlayout.h>
@@ -34,10 +35,10 @@
 
 #include "../debug.h"
 
-ShowEditTextFileAgent::ShowEditTextFileAgent (RCallbackArgs *args, const QString &text, const QString &caption) : QObject (RKWardMainWindow::getMain ()) {
+ShowEditTextFileAgent::ShowEditTextFileAgent (RBackendRequest *request, const QString &text, const QString &caption) : QObject (RKWardMainWindow::getMain ()) {
 	RK_TRACE (APP);
 
-	ShowEditTextFileAgent::args = args;
+	ShowEditTextFileAgent::request = request;
 
 	dialog = new KDialog (0);
 
@@ -56,7 +57,7 @@
 
 	dialog->setButtonText (KDialog::Ok, i18n ("Done"));
 
-	connect (dialog, SIGNAL (finished ()), this, SLOT (done ()));
+	connect (dialog, SIGNAL (finished ()), this, SLOT (deleteLater ()));
 
 	// do it
 	dialog->show ();
@@ -65,38 +66,23 @@
 
 ShowEditTextFileAgent::~ShowEditTextFileAgent () {
 	RK_TRACE (APP);
+
+	request->completed ();
+	dialog->deleteLater ();
 }
 
 // static
-void ShowEditTextFileAgent::showEditFiles (RCallbackArgs *args) {
+void ShowEditTextFileAgent::showEditFiles (RBackendRequest *request) {
 	RK_TRACE (APP);
-	if (!args) return;
+	if (!request) return;
 
-	QString caption;
-	QString message;
-	QString message_snip1 = i18n (" For that reason processing has been stopped for now. Press the \"Done\"-button, or close this dialog once you think it is safe to resume.\n\n");
-	QString message_snip2 = i18n ("The file(s) have been opened in text-windows. The following is a list of the file(s) in question:\n\n");
-
-	QStringList files = args->params["files"].toStringList ();
-	QStringList titles = args->params["titles"].toStringList ();
-	QString wtitle = args->params["wtitle"].toString ();
+	QStringList files = request->params["files"].toStringList ();
+	QStringList titles = request->params["titles"].toStringList ();
+	QString wtitle = request->params["wtitle"].toString ();
 	int count = files.count ();
 	RK_ASSERT (titles.count () == count);
 
-	QString bad_files_list;
-	bool r_highlighting = false;
-	bool read_only = true;
-	if (args->type == RCallbackArgs::RShowFiles) {
-		caption = i18n ("Showing file(s)");
-		message = i18n ("A command running in the R-engine wants you to see one or more file(s). RKWard can not determine, whether it is safe to continue processing R commands, before you have read the file(s) in question.") + message_snip1 + message_snip2;
-	} else if (args->type == RCallbackArgs::REditFiles) {
-		caption = i18n ("Edit file(s)");
-		message = i18n ("A command running in the R-engine wants you to edit one or more file(s). RKWard can not determine, whether it is safe to continue processing R commands, before you have read/edited (and saved) the file(s) in question.") + message_snip1 + message_snip2;
-
-		r_highlighting = true;
-		read_only = false;
-	}
-
+	QStringList display_titles;
 	for (int n = 0; n < count; ++n) {
 		QString title;
 		if (!titles[n].isEmpty ()) title = titles[n];
@@ -105,39 +91,31 @@
 			if (!title.isEmpty ()) title.prepend (": ");
 			title.prepend (wtitle);
 		}
-
-		message.append (title + "\n");
-
-		bool ok = RKWorkplace::mainWorkplace ()->openScriptEditor (KUrl::fromLocalFile (files[n]), QString (), r_highlighting, read_only, title);
-
-		if (!ok)  {
-			bad_files_list.append ("- ").append (title).append (" (").append (files[n]).append (")\n");
-		}
+		display_titles.append (title);
 	}
 
-	if (!bad_files_list.isEmpty ()) {
-		message.append (i18n ("\n\nThe following of the above files were not readable and have not been opened:\n\n"));
-		message.append (bad_files_list);
-	}
+	bool r_highlighting = false;
+	bool read_only = true;
+	bool delete_files = false;
+	if (request->type == RBackendRequest::ShowFiles) {
+		RK_ASSERT (!request->synchronous);
 
-	new ShowEditTextFileAgent (args, message, caption);
-}
+		KMessageBox::informationList (RKWardMainWindow::getMain (), i18n ("A command running in the R-engine wants you to see the following file(s):\n"), display_titles, i18n ("Showing file(s)"), "show_files");
 
-void ShowEditTextFileAgent::done () {
-	RK_TRACE (APP);
-	dialog->deleteLater ();
+		delete_files = request->params["delete"].toBool ();
+		request->completed ();
+	} else if (request->type == RBackendRequest::EditFiles) {
+		new ShowEditTextFileAgent (request, i18n ("A command running in the R-engine wants you to edit one or more file(s). Please look at these files, edit them as appriopriate, and save them. When done, press the \"Done\"-button, or close this dialog to resume.\n\n") + display_titles.join ("\n"), i18n ("Edit file(s)"));
 
-	QStringList files = args->params["files"].toStringList ();
-	if ((args->type == RCallbackArgs::RShowFiles) && args->params["delete"].toBool ()) {
-		for (int n = 0; n < files.count (); ++n) {
-			RK_ASSERT (QFile::remove (QString (files[n])));
-		}
+		r_highlighting = true;
+		read_only = false;
+	} else {
+		RK_ASSERT (false);
 	}
 
-	// this line is what causes the backend-thread to resume processing:
-	args->done = true;
-
-	deleteLater ();
+	// do this last, as it may produce error messages, if some of the files could not be opened.
+	for (int n = 0; n < count; ++n) {
+		RKWorkplace::mainWorkplace ()->openScriptEditor (KUrl::fromLocalFile (files[n]), QString (), r_highlighting, read_only, display_titles[n], delete_files);
+	}
 }
 
-#include "showedittextfileagent.moc"

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/agents/showedittextfileagent.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/agents/showedittextfileagent.h	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/agents/showedittextfileagent.h	2010-10-28 11:42:21 UTC (rev 3159)
@@ -2,7 +2,7 @@
                           showedittextfileagent  -  description
                              -------------------
     begin                : Tue Sep 13 2005
-    copyright            : (C) 2005 by Thomas Friedrichsmeier
+    copyright            : (C) 2005, 2010 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -20,7 +20,7 @@
 
 #include <qobject.h>
 
-struct RCallbackArgs;
+struct RBackendRequest;
 class KDialog;
 
 /** The purpose of this agent is to display text files for showing and/or editing on request of the R backend. Technically speaking, it gets invoked, whenever the standard R callbacks (ptr_)R_ShowFiles, (ptr_)R_EditFiles, or (ptr_)R_EditFile are called. While the task of simply opening such files for display/editing is rather simple, there is one slightly more difficult issue involved (and hence this class to handle it): In standard R, all these calls are blocking further processing, until the user has closed the shown/edited files. In some cases this may be necessary (for instance if R wants to use with the edited files immediately), in some cases this is an unnecessary nuisance (such as when R simply wants to display a help page or some other purely informational text).
@@ -32,24 +32,20 @@
 @author Thomas Friedrichsmeier
 */
 class ShowEditTextFileAgent : public QObject {
-	Q_OBJECT
 public:
 /** constructor. Do not use directly. Use the static showEditFiles () instead.
 @param args The corresponding RCallbackArgs-record
 @param text Text to display in the dialog. */
-	ShowEditTextFileAgent (RCallbackArgs *args, const QString &text, const QString &caption);
+	ShowEditTextFileAgent (RBackendRequest *request, const QString &text, const QString &caption);
 
-/** destructor */
+/** destructor. Called when the user presses the done button (or closes the notification dialog). Resumes processing in the backend, deletes the agent */
 	~ShowEditTextFileAgent ();
 
 /** This gets called by RInterface, in order to show/edit the files in question. The RCallbackArgs-struct is passed in raw form, and only this function sorts
 out, what exactly needs to be done. Note that this is a static member. It will take care of creating/deleting an agent on its own. */
-	static void showEditFiles (RCallbackArgs *args);
-public slots:
-/** this slot gets called, when the user presses the done button (or closes the notification dialog). Resumes processing in the backend, deletes the agent */
-	void done ();
+	static void showEditFiles (RBackendRequest *request);
 private:
-	RCallbackArgs *args;
+	RBackendRequest *request;
 	KDialog *dialog;
 };
 

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp	2010-10-28 11:42:21 UTC (rev 3159)
@@ -112,10 +112,9 @@
 void RSuicide (const char* message) {
 	RK_TRACE (RBACKEND);
 
-	RCallbackArgs args;
-	args.type = RCallbackArgs::RBackendExit;
-	args.params["message"] = QVariant (i18n ("The R engine has encountered a fatal error:\n%1").arg (message));
-	RThread::this_pointer->handleStandardCallback (&args);
+	RBackendRequest request (true, RBackendRequest::BackendExit);
+	request.params["message"] = QVariant (i18n ("The R engine has encountered a fatal error:\n%1").arg (message));
+	RThread::this_pointer->handleRequest (&request);
 	RThread::this_pointer->killed = true;
 }
 
@@ -186,8 +185,6 @@
 	RK_ASSERT (RThread::repl_status.eval_depth >= 0);
 	if (RThread::repl_status.eval_depth == 0) {
 		while (1) {
-			if (RThread::this_pointer->killed) return 0;
-
 			if (RThread::repl_status.user_command_status == RThread::RKReplStatus::NoUserCommand) {
 				RCommandProxy *command = RThread::this_pointer->fetchNextCommand ();
 				if (!command) {
@@ -265,21 +262,19 @@
 
 	// here, we handle readline() calls and such, i.e. not the regular prompt for code
 	// browser() also takes us here. TODO: give browser() special handling! May be identifiable due to hist==true
-	RCallbackArgs args;
-	args.type = RCallbackArgs::RReadLine;
-	args.params["prompt"] = QVariant (prompt);
-	args.params["cancelled"] = QVariant (false);
+	RBackendRequest request (true, RBackendRequest::ReadLine);
+	request.params["prompt"] = QVariant (prompt);
+	request.params["cancelled"] = QVariant (false);
 
-	RThread::this_pointer->handleStandardCallback (&args);
-// default implementation seems to return 1 on success, 0 on failure, contrary to some documentation. see unix/std-sys.c
-	if (args.params["cancelled"].toBool ()) {
+	RThread::this_pointer->handleRequest (&request);
+	if (request.params["cancelled"].toBool ()) {
 		if (RThread::this_pointer->current_command) RThread::this_pointer->current_command->status |= RCommand::Canceled;
 		RK_doIntr();
-		// threoretically, the above should have got us out, but for good measure:
+		// threoretically, the above should have got us out of the loop, but for good measure:
 		Rf_error ("cancelled");
 	}
 
-	QByteArray localres = RThread::this_pointer->current_locale_codec->fromUnicode (args.params["result"].toString ());
+	QByteArray localres = RThread::this_pointer->current_locale_codec->fromUnicode (request.params["result"].toString ());
 	// need to append a newline, here. TODO: theoretically, RReadConsole comes back for more, if \0 was encountered before \n.
 	qstrncpy ((char *) buf, localres.left (buflen - 2).append ('\n').data (), buflen);
 
@@ -327,10 +322,9 @@
 
 	if (saveact != SA_SUICIDE) {
 		if (!RThread::this_pointer->isKilled ()) {
-			RCallbackArgs args;
-			args.type = RCallbackArgs::RBackendExit;
-			args.params["message"] = QVariant (i18n ("The R engine has shut down with status: %1").arg (status));
-			RThread::this_pointer->handleStandardCallback (&args);
+			RBackendRequest request (true, RBackendRequest::BackendExit);
+			request.params["message"] = QVariant (i18n ("The R engine has shut down with status: %1").arg (status));
+			RThread::this_pointer->handleRequest (&request);
 		}
 
 		if(saveact == SA_DEFAULT) saveact = SA_SAVE;
@@ -368,13 +362,12 @@
 int RChooseFile (int isnew, char *buf, int len) {
 	RK_TRACE (RBACKEND);
 
-	RCallbackArgs args;
-	args.type = RCallbackArgs::RChooseFile;
-	args.params["new"] = QVariant ((bool) isnew);
+	RBackendRequest request (true, RBackendRequest::ChooseFile);
+	request.params["new"] = QVariant ((bool) isnew);
 
-	RThread::this_pointer->handleStandardCallback (&args);
+	RThread::this_pointer->handleRequest (&request);
 
-	QByteArray localres = RThread::this_pointer->current_locale_codec->fromUnicode (args.params["result"].toString ());
+	QByteArray localres = RThread::this_pointer->current_locale_codec->fromUnicode (request.params["result"].toString ());
 	qstrncpy ((char *) buf, localres.data (), len);
 
 // return length of filename (strlen (buf))
@@ -384,35 +377,33 @@
 /* There are about one million possible entry points to editing / showing files. We try to cover them all, using the
 following bunch of functions (REditFilesHelper() and doShowEditFiles() are helpers, only) */
 
-void REditFilesHelper (QStringList files, QStringList titles, QString wtitle, RCallbackArgs::RCallbackType edit, bool delete_files) {
+void REditFilesHelper (QStringList files, QStringList titles, QString wtitle, RBackendRequest::RCallbackType edit, bool delete_files) {
 	RK_TRACE (RBACKEND);
 
-	RCallbackArgs args;
-	if (edit == RCallbackArgs::REditFiles) args.type = RCallbackArgs::REditFiles;
-	else {
-		RK_ASSERT (edit == RCallbackArgs::RShowFiles);
-		args.type = RCallbackArgs::RShowFiles;
-		args.params["delete"] = QVariant (delete_files);
+	RK_ASSERT ((edit == RBackendRequest::ShowFiles) || (edit == RBackendRequest::EditFiles));
+	RBackendRequest request (edit != RBackendRequest::ShowFiles, edit);		// editing is synchronous, showing is asynchronous
+	if (edit == RBackendRequest::ShowFiles) {
+		request.params["delete"] = QVariant (delete_files);
 	}
 	// see ?file.show() for what appears to be the intended meaning of these first three parameters
 	// (which seem to be inconsistently named even in R itself...)
-	args.params["files"] = QVariant (files);
-	args.params["titles"] = QVariant (titles);
-	args.params["wtitle"] = QVariant (wtitle);
+	request.params["files"] = QVariant (files);
+	request.params["titles"] = QVariant (titles);
+	request.params["wtitle"] = QVariant (wtitle);
 
-	RThread::this_pointer->handleStandardCallback (&args);
+	RThread::this_pointer->handleRequest (&request);
 }
 
 int REditFiles (int nfile, const char **file, const char **title, const char *wtitle) {
 	RK_TRACE (RBACKEND);
 
-	REditFilesHelper (charPArrayToQStringList (file, nfile), charPArrayToQStringList (title, nfile), wtitle, RCallbackArgs::REditFiles, false);
+	REditFilesHelper (charPArrayToQStringList (file, nfile), charPArrayToQStringList (title, nfile), wtitle, RBackendRequest::EditFiles, false);
 
 // default implementation seems to return 1 if nfile <= 0, else 1. No idea, what for. see unix/std-sys.c
 	return (nfile <= 0);
 }
 
-SEXP doShowEditFiles (SEXP files, SEXP titles, SEXP wtitle, SEXP del, RCallbackArgs::RCallbackType edit) {
+SEXP doShowEditFiles (SEXP files, SEXP titles, SEXP wtitle, SEXP del, RBackendRequest::RCallbackType edit) {
 	RK_TRACE (RBACKEND);
 
 	// this function would be much shorter, if SEXPToStringList would simply return a QStringList...
@@ -443,7 +434,7 @@
 }
 
 SEXP doEditFiles (SEXP files, SEXP titles, SEXP wtitle) {
-	return (doShowEditFiles (files, titles, wtitle, R_NilValue, RCallbackArgs::REditFiles));
+	return (doShowEditFiles (files, titles, wtitle, R_NilValue, RBackendRequest::EditFiles));
 }
 
 int REditFile (const char *buf) {
@@ -457,13 +448,13 @@
 }
 
 SEXP doShowFiles (SEXP files, SEXP titles, SEXP wtitle, SEXP delete_files) {
-	return (doShowEditFiles (files, titles, wtitle, delete_files, RCallbackArgs::RShowFiles));
+	return (doShowEditFiles (files, titles, wtitle, delete_files, RBackendRequest::ShowFiles));
 }
 
 int RShowFiles (int nfile, const char **file, const char **headers, const char *wtitle, Rboolean del, const char */* pager */) {
 	RK_TRACE (RBACKEND);
 
-	REditFilesHelper (charPArrayToQStringList (file, nfile), charPArrayToQStringList (headers, nfile), QString (wtitle), RCallbackArgs::RShowFiles, (bool) del);
+	REditFilesHelper (charPArrayToQStringList (file, nfile), charPArrayToQStringList (headers, nfile), QString (wtitle), RBackendRequest::ShowFiles, (bool) del);
 
 // default implementation seems to returns 1 on success, 0 on failure. see unix/std-sys.c
 	return 1;
@@ -474,20 +465,20 @@
 int doDialogHelper (QString caption, QString message, QString button_yes, QString button_no, QString button_cancel, bool wait) {
 	RK_TRACE (RBACKEND);
 
-	RCallbackArgs args;
-	args.type = RCallbackArgs::RShowMessage;
-	args.params["caption"] = QVariant (caption);
-	args.params["message"] = QVariant (message);
-	args.params["button_yes"] = QVariant (button_yes);
-	args.params["button_no"] = QVariant (button_no);
-	args.params["button_cancel"] = QVariant (button_cancel);
-	if (wait) args.params["wait"] = "1";
+	RBackendRequest request (wait, RBackendRequest::ShowMessage);
+	request.params["caption"] = QVariant (caption);
+	request.params["message"] = QVariant (message);
+	request.params["button_yes"] = QVariant (button_yes);
+	request.params["button_no"] = QVariant (button_no);
+	request.params["button_cancel"] = QVariant (button_cancel);
 
-	RThread::this_pointer->handleStandardCallback (&args);
-
-	QString ret = args.params["result"].toString ();
-	if (ret == "yes") return 1;
-	if (ret == "no") return -1;
+	RThread::this_pointer->handleRequest (&request);
+ 
+	if (wait) {
+		QString ret = request.params["result"].toString ();
+		if (ret == "yes") return 1;
+		if (ret == "no") return -1;
+	}
 	return 0;
 }
 
@@ -682,8 +673,22 @@
 	for (unsigned int i = 0; i < count; ++i) {
 		list.append (strings[i]);
 	}
-	RThread::this_pointer->handleSubstackCall (list);
 	delete [] strings;
+
+	// handle symbol updates inline
+	if (list.count () == 2) {		// schedule symbol update for later
+		if (list[0] == "ws") {
+			// always keep in mind: No current command can happen for tcl/tk events.
+			if ((!RThread::this_pointer->current_command) || (RThread::this_pointer->current_command->type & RCommand::ObjectListUpdate) || (!(RThread::this_pointer->current_command->type & RCommand::Sync))) {		// ignore Sync commands that are not flagged as ObjectListUpdate
+				if (!RThread::this_pointer->changed_symbol_names.contains (list[1])) RThread::this_pointer->changed_symbol_names.append (list[1]);
+			}
+			return R_NilValue;
+		}
+	}
+
+#warning TODO: extend this by sychronity parameter
+	RThread::this_pointer->handleHistoricalSubstackRequest (list);
+
 	return R_NilValue;
 }
 
@@ -954,30 +959,34 @@
 
 	if (ctype & RCommand::DirectToOutput) runDirectCommand (".rk.capture.messages()");
 
-	repl_status.eval_depth++;
-	SEXP parsed = parseCommand (command->command, &error);
-	if (error == NoError) {
-		SEXP exp;
-		PROTECT (exp = runCommandInternalBase (parsed, &error));
+	if (ctype & RCommand::QuitCommand) {
+		killed = true;
+	} else if (!(ctype & RCommand::EmptyCommand)) {
+		repl_status.eval_depth++;
+		SEXP parsed = parseCommand (command->command, &error);
 		if (error == NoError) {
-			if (ctype & RCommand::GetStringVector) {
-				retdata.datatype = RData::StringVector;
-				retdata.data = RKRSupport::SEXPToStringList (exp, &(retdata.length));
-			} else if (ctype & RCommand::GetRealVector) {
-				retdata.datatype = RData::RealVector;
-				retdata.data = RKRSupport::SEXPToRealArray (exp, &(retdata.length));
-			} else if (ctype & RCommand::GetIntVector) {
-				retdata.datatype = RData::IntVector;
-				retdata.data = RKRSupport::SEXPToIntArray (exp, &(retdata.length));
-			} else if (ctype & RCommand::GetStructuredData) {
-				RData *dummy = RKRSupport::SEXPToRData (exp);
-				retdata.setData (*dummy);
-				delete dummy;
+			SEXP exp;
+			PROTECT (exp = runCommandInternalBase (parsed, &error));
+			if (error == NoError) {
+				if (ctype & RCommand::GetStringVector) {
+					retdata.datatype = RData::StringVector;
+					retdata.data = RKRSupport::SEXPToStringList (exp, &(retdata.length));
+				} else if (ctype & RCommand::GetRealVector) {
+					retdata.datatype = RData::RealVector;
+					retdata.data = RKRSupport::SEXPToRealArray (exp, &(retdata.length));
+				} else if (ctype & RCommand::GetIntVector) {
+					retdata.datatype = RData::IntVector;
+					retdata.data = RKRSupport::SEXPToIntArray (exp, &(retdata.length));
+				} else if (ctype & RCommand::GetStructuredData) {
+					RData *dummy = RKRSupport::SEXPToRData (exp);
+					retdata.setData (*dummy);
+					delete dummy;
+				}
 			}
+			UNPROTECT (1); // exp
 		}
-		UNPROTECT (1); // exp
+		repl_status.eval_depth--;
 	}
-	repl_status.eval_depth--;
 
 	if (ctype & RCommand::DirectToOutput) runDirectCommand (".rk.print.captured.messages()");
 	if (!(ctype & RCommand::Internal)) {

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h	2010-10-28 11:42:21 UTC (rev 3159)
@@ -36,80 +36,80 @@
 }
 #endif
 
-/** This struct is used to pass the standard callbacks from R to the main thread (if needed; some are handled in the backend thread). Note that for the callbacks that need to be passed to the main
-thread, we can be quite wasteful both in terms of cycles and memory, since these are usually
-requests for user interaction. Hence we use a QVariantMap to accommodate all the different needed
-parameters, easily, and in a readable way. */
-struct RCallbackArgs {
-/** is main thread done with the callback, yet? Initialized to false inside the true handler: RThread::doStandardCallback () */
-	bool done;
-/** type of the callback */
+class RBackendRequest {
+public:
 	enum RCallbackType {
-		RBackendExit,
-		RShowMessage,
-		RShowFiles,
-		RChooseFile,
-		REditFiles,
-		RReadLine
-       } type;
-/** All the parameters sent in either direction */
+		BackendExit,
+		ShowMessage,
+		ShowFiles,
+		ChooseFile,
+		EditFiles,
+		ReadLine,
+		CommandOut,
+		Started,
+		EvalRequest,
+		CallbackRequest,
+		StartupError,
+		HistoricalSubstackRequest,
+		OtherRequest		/**< Any other type of request. Note: which requests are in the enum, and which are not has mostly historical reasons. @see params */
+	};
+
+	RBackendRequest (bool synchronous, RCallbackType type) {
+		RBackendRequest::synchronous = synchronous;
+		RBackendRequest::type = type;
+		done = false;
+		command = 0;
+	}
+	~RBackendRequest () {};
+
+	RBackendRequest *duplicate () {
+		RBackendRequest* ret = new RBackendRequest (synchronous, type);
+		ret->done = done;
+		ret->command = command;
+		ret->params = params;
+		return ret;
+	}
+
+	void completed () {
+		if (!synchronous) delete this;
+		else done = true;
+	}
+
+/** Should this request be handled synchronously? False by default. */
+	bool synchronous;
+/** For synchronous requests, only: The frontend-thread will set this to true (using completed()), once the request has been "completed". Important: The backend thread MUST NOT touch a request after it has been sent, and before "done" has been set to true. */
+	bool done;
+	RCallbackType type;
+/** For synchronous requests, only: If the the frontend wants any commands to be executed, it will place the next one in this slot. The backend thread should keep executing commands (in a sub-eventloop) while this is non-zero. Also, the backend-thread may place here any command that has just finished. */
+	RCommandProxy *command;
+/** Any other parameters, esp. for RCallbackType::OtherRequest. Can be used in both directions. */
 	QVariantMap params;
 };
 
 class QStringList;
 class QTextCodec;
 class RInterface;
-struct RCallbackArgs;
 struct ROutput;
 
-/** this struct is used to pass on eval-requests (i.e. request for RKWard to do something, which may involve issuing further commands) from the
-backend-thread to the main thread. Do not use outside the backend-classes. */
-struct REvalRequest {
-private:
-friend class RInterface;
-friend class RThread;
-	QStringList call;
-};
-
-/** Used to request the next command from the front-end */
-struct RNextCommandRequest {
-private:
-friend class RInterface;
-friend class RThread;
-	bool *done;
-	RCommandProxy *command;
-};
-
 /** Simple event class to relay information from the RThread to the main thread. This is basically like QCustomEvent in Qt3*/
 class RKRBackendEvent : public QEvent {
 public:
 	enum EventType {
-		Base = QEvent::User + 1,
-		RNextCommandRequest,
-		RCommandOut,
-		RCommandOutput,
-		RStarted,
-		REvalRequest,
-		RCallbackRequest,
-		RStartupError
+		RKWardEvent = QEvent::User + 1
 	};
-
-	RKRBackendEvent (EventType type, void* data=0) : QEvent ((QEvent::Type) type) { _data = data; };
+	RKRBackendEvent (RBackendRequest* data=0) : QEvent ((QEvent::Type) RKWardEvent) { _data = data; };
 	RKRBackendEvent ();
 
-	EventType etype () { return ((EventType) type ()); };
-	void* data () { return _data; };
+	RBackendRequest* data () { return _data; };
 private:
-	void* _data;
+	RBackendRequest* _data;
 };
 
 /** This class represents the thread the R backend is running in. So to speak, this is where the "eventloop" of R is running. The main thing happening
-in this class, is that an infinite loop is running. Whenever there are commands to be executed, those get evaluated. Also, at regular intervals,
+in this class, is that it enters R's REPL (Read-evaluate-parse-loop). Whenever there are commands to be executed, those get evaluated. When there are not,
 processing of X11-Events in R is triggered. The rest of the time the thread sleeps.
 
-Actually, there are really two copies of the main loop: The regular one, and a second one which gets run when the R backend has requested some
-task to be carried out (@see handleSubstackCall). In this case, we might have to run some further child commands in the backend, before we proceed with the commands in
-the main queque. Some thing like:
+Actually, there is also a custom sub-eventloop, which gets called when the R backend has requested something. See handleRequest(). In this case, we might have to run some further child commands in the backend, before we proceed with the commands in the main queque. Some thing like:
 
 - Run some RCommand s
 	- R backend asks for some information / action
@@ -119,7 +119,7 @@
 	- R backend request completed
 - Run some more RCommand s
 
-This subordinate/nested eventloop is done in handleSubstackCall ().
+This subordinate/nested eventloop is done in handleRequest ().
 
 A closely related class is RInterface: RThread communicates with RInterface by placing QCustomEvent s, when commands are done
 or when the backend needs information from the frontend. For historical reasons, the definitions of RThread class-members are currently spread over different files.
@@ -159,7 +159,7 @@
 
 /** initializes the R-backend. Returns an error-code that consists of a bit-wise or-conjunction of the RThread::InitStatus -enum, RThread::Ok on success.
 Note that you should call initialize only once in a application */
-	int initialize ();
+	QString initialize ();
 
 	void enterEventLoop ();
 protected:
@@ -189,15 +189,11 @@
 @param forcibly: if true, will always flush the output. If false, will flush the output only if the mutex can be locked without waiting. */
 	ROutputList flushOutput (bool forcibly=false);
 
-/** This is a sub-eventloop, being run when the backend request information from the frontend. See \ref RThread for a more detailed description */
-	void handleSubstackCall (QStringList &call);
+	void handleRequest (RBackendRequest *request) { handleRequest (request, true); };
+/** A relic of history. Eventually most of these will be replaced by dedicated RBackendRequests. */
+	void handleHistoricalSubstackRequest (const QStringList &list);
+	RCommandProxy* fetchNextCommand ();
 
-/** This is a minimal sub-eventloop, being run, when the backend requests simple information from the frontend. It differs from handleSubstack in two
-points:
-1) it does not create a full-fledged substack for additional R commands
-2) it may return information via the args parameter immediately */
-	void handleStandardCallback (RCallbackArgs *args);
-
 /** The command currently being executed. */
 	RCommandProxy *current_command;
 
@@ -237,16 +233,17 @@
 	};
 	static RKReplStatus repl_status;
 
-	// fetch next command (and do event processing while waiting)
-	RCommandProxy *fetchNextCommand ();
 	void commandFinished (bool check_object_updates_needed=true);
 /** thread is killed. Should exit as soon as possible. @see kill */
 	bool killed;
+/** A list of symbols that have been assigned new values during the current command */
+	QStringList changed_symbol_names;
 protected:
 /** On pthread systems this is the pthread_id of the backend thread. It is needed to send SIGINT to the R backend */
 	Qt::HANDLE thread_id;
 /** If the length of the current output buffer is too long, this will pause any further output until the main thread has had a chance to catch up. */
 	void waitIfOutputBufferExceeded ();
+	RCommandProxy* handleRequest (RBackendRequest *request, bool mayHandleSubstack);
 private:
 /** set up R standard callbacks */
 	void setupCallbacks ();
@@ -262,8 +259,6 @@
 	QStringList toplevel_env_names;
 /** A copy of the names of the toplevel symbols in the .GlobalEnv. */
 	QStringList global_env_toplevel_names;
-/** A list of symbols that have been assigned new values during the current command */
-	QStringList changed_symbol_names;
 /** check wether the object list / global environment / individual symbols have changed, and updates them, if needed */
 	void checkObjectUpdatesNeeded (bool check_list);
 	QList<RCommandProxy*> all_current_commands;
@@ -274,6 +269,9 @@
 	QMutex output_buffer_mutex;
 /** current length of output. If the backlog of output which has not yet been processed by the frontend becomes too long, output will be paused, automatically */
 	int out_buf_len;
+
+	/** The previously executed command. Only non-zero until a new command has been requested. */
+	RCommandProxy *previous_command;
 };
  
 #endif

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp	2010-10-28 11:42:21 UTC (rev 3159)
@@ -76,7 +76,6 @@
 	RCommandStack::regular_stack = new RCommandStack (0);
 	running_command_canceled = 0;
 	command_logfile_mode = NotRecordingCommands;
-	command_request = 0;
 	previously_idle = false;
 	locked = 0;
 
@@ -152,14 +151,9 @@
 	r_thread->start ();
 }
 
-RCommand *RInterface::runningCommand () {
-	 if (all_current_commands.isEmpty ()) return 0;
-	 return (all_current_commands.last ());
-}
-
 void RInterface::tryNextCommand () {
 	RK_TRACE (RBACKEND);
-	if (!command_request) return;
+	if (!currentCommandRequest ()) return;
 
 	RCommandStack *stack = RCommandStack::currentStack ();
 	bool main_stack = (stack == RCommandStack::regular_stack);
@@ -170,18 +164,12 @@
 		if (command) {
 			all_current_commands.append (command);
 
-			if ((command->type () & RCommand::EmptyCommand) || (command->status & RCommand::Canceled) || (command->type () & RCommand::QuitCommand)) {
-				// some commands are not actually run by R, but handled inline, here
-				if (command->status & RCommand::Canceled) {
-					command->status |= RCommand::Failed;
-				}
-				if (command->type () & RCommand::QuitCommand) {
-					r_thread->kill ();
-				}
-				stack->pop ();
+			if (command->status & RCommand::Canceled) {
+				// avoid passing cancelled commands to R
+				command->status |= RCommand::Failed;
+
 				// notify ourselves...
-				RKRBackendEvent* event = new RKRBackendEvent (RKRBackendEvent::RCommandOut, new RCommandProxy (command));
-				qApp->postEvent (this, event);
+				handleCommandOut (new RCommandProxy (command));
 				return;
 			}
 
@@ -203,8 +191,56 @@
 	}
 }
 
+void RInterface::handleCommandOut (RCommandProxy *proxy) {
+	RK_TRACE (RBACKEND);
+
+	RK_ASSERT (proxy);
+	RK_ASSERT (!all_current_commands.isEmpty ());
+	RCommand *command = all_current_commands.takeLast ();
+	RCommandStack::currentStack ()->pop ();
+	proxy->mergeAndDelete (command);
+
+	#ifdef RKWARD_DEBUG
+		int dl = DL_WARNING;		// failed application commands are an issue worth reporting, failed user commands are not
+		if (command->type () & RCommand::User) dl = DL_DEBUG;
+		if (command->failed ()) {
+			command->status |= RCommand::WasTried | RCommand::Failed;
+			if (command->status & RCommand::ErrorIncomplete) {
+				RK_DO (qDebug ("Command failed (incomplete)"), RBACKEND, dl);
+			} else if (command->status & RCommand::ErrorSyntax) {
+				RK_DO (qDebug ("Command failed (syntax)"), RBACKEND, dl);
+			} else if (command->status & RCommand::Canceled) {
+				RK_DO (qDebug ("Command failed (interrupted)"), RBACKEND, dl);
+			} else {
+				RK_DO (qDebug ("Command failed (other)"), RBACKEND, dl);
+			}
+			RK_DO (qDebug ("failed command was: '%s'", qPrintable (command->command ())), RBACKEND, dl);
+			RK_DO (qDebug ("- error message was: '%s'", qPrintable (command->error ())), RBACKEND, dl);
+		}
+	#endif
+
+	if (command->status & RCommand::Canceled) {
+		command->status |= RCommand::HasError;
+		ROutput *out = new ROutput;
+		out->type = ROutput::Error;
+		out->output = ("--- interrupted ---");
+		command->output_list.append (out);
+		command->newOutput (out);
+		if (running_command_canceled) {
+			RK_ASSERT (command == running_command_canceled);
+			running_command_canceled = 0;
+			r_thread->interruptProcessing (false);
+			locked -= locked & Cancel;
+		}
+	}
+	command->finished ();
+	RCommandStackModel::getModel ()->itemChange (command);
+	delete command;
+}
+
 void RInterface::doNextCommand (RCommand *command) {
 	RK_TRACE (RBACKEND);
+	RBackendRequest* command_request = currentCommandRequest ();
 	RK_ASSERT (command_request);
 
 	flushOutput (true);
@@ -227,8 +263,8 @@
 	}
 
 	command_request->command = proxy;
-	*(command_request->done) = true;
-	command_request = 0;
+	command_request->completed ();
+	command_requests.pop_back ();
 	QThread::yieldCurrentThread ();
 }
 
@@ -236,87 +272,32 @@
 	RK_TRACE (RBACKEND);
 
 	RKRBackendEvent *ev;
-	if (((int) e->type ()) >= ((int) RKRBackendEvent::Base)) {
+	if (((int) e->type ()) == ((int) RKRBackendEvent::RKWardEvent)) {
 		ev = static_cast<RKRBackendEvent*> (e);
 	} else {
 		RK_ASSERT (false);
 		return;
 	}
 
-	if (ev->etype () == RKRBackendEvent::RNextCommandRequest) {
-		RK_ASSERT (!command_request);
-		command_request = static_cast<RNextCommandRequest*> (ev->data ());
-		tryNextCommand ();
-	} else if (ev->etype () == RKRBackendEvent::RCommandOut) {
-		flushOutput (true);
+	flushOutput (true);
+	RBackendRequest *request = ev->data ();
+	if (request->type == RBackendRequest::CommandOut) {
+		RCommandProxy *cproxy = request->command;
 
-		RCommandProxy *cproxy = static_cast <RCommandProxy *> (ev->data ());
-		RK_ASSERT (!all_current_commands.isEmpty ());
-		RCommand *command = all_current_commands.takeLast ();
-		RCommandStack::currentStack ()->pop ();
-		cproxy->mergeAndDelete (command);
+		if (cproxy) handleCommandOut (cproxy);
+		// else: cproxy should only even be 0 in the very first cycle
 
-		#ifdef RKWARD_DEBUG
-			int dl = DL_WARNING;		// failed application commands are an issue worth reporting, failed user commands are not
-			if (command->type () & RCommand::User) dl = DL_DEBUG;
-			if (command->failed ()) {
-				command->status |= RCommand::WasTried | RCommand::Failed;
-				if (command->status & RCommand::ErrorIncomplete) {
-					RK_DO (qDebug ("Command failed (incomplete)"), RBACKEND, dl);
-				} else if (command->status & RCommand::ErrorSyntax) {
-					RK_DO (qDebug ("Command failed (syntax)"), RBACKEND, dl);
-				} else if (command->status & RCommand::Canceled) {
-					RK_DO (qDebug ("Command failed (interrupted)"), RBACKEND, dl);
-				} else {
-					RK_DO (qDebug ("Command failed (other)"), RBACKEND, dl);
-				}
-				RK_DO (qDebug ("failed command was: '%s'", qPrintable (command->command ())), RBACKEND, dl);
-				RK_DO (qDebug ("- error message was: '%s'", qPrintable (command->error ())), RBACKEND, dl);
-			}
-		#endif
-
-		if (command->status & RCommand::Canceled) {
-			command->status |= RCommand::HasError;
-			ROutput *out = new ROutput;
-			out->type = ROutput::Error;
-			out->output = ("--- interrupted ---");
-			command->output_list.append (out);
-			command->newOutput (out);
-			if (running_command_canceled) {
-				RK_ASSERT (command == running_command_canceled);
-				running_command_canceled = 0;
-				r_thread->interruptProcessing (false);
-				locked -= locked & Cancel;
-			}
-		}
-		command->finished ();
-		RCommandStackModel::getModel ()->itemChange (command);
-		delete command;
-	} else if ((ev->etype () == RKRBackendEvent::REvalRequest)) {
-		processREvalRequest (static_cast<REvalRequest *> (ev->data ()));
-	} else if ((ev->etype () == RKRBackendEvent::RCallbackRequest)) {
-		processRCallbackRequest (static_cast<RCallbackArgs *> (ev->data ()));
-	} else if ((ev->etype () == RKRBackendEvent::RStarted)) {
-		bool* ok_to_proceed = static_cast<bool*> (ev->data ());
-		*ok_to_proceed = true;
+		command_requests.append (request);
+		tryNextCommand ();
+	} else if (request->type == RBackendRequest::HistoricalSubstackRequest) {
+		processHistoricalSubstackRequest (request);
+	} else if ((request->type == RBackendRequest::Started)) {
+		request->completed ();
 		RKWardMainWindow::discardStartupOptions ();
-	} else if ((ev->etype () == RKRBackendEvent::RStartupError)) {
-		flushOutput (true);
-		int* err_p = static_cast<int*> (ev->data ());
-		int err = *err_p;
-		delete err_p;
+	} else if ((request->type == RBackendRequest::StartupError)) {
 		QString message = i18n ("<p>There was a problem starting the R backend. The following error(s) occurred:</p>\n");
-		if (err & RThread::LibLoadFail) {
-			message.append (i18n ("</p>\t- The 'rkward' R-library either could not be loaded at all, or not in the correct version. This may lead to all sorts of errors, from single missing features to complete failure to function. The most likely cause is that the last installation did not place all files in the correct place. However, in some cases, left-overs from a previous installation that was not cleanly removed may be the cause.</p>\
-			<p><b>You should quit RKWard, now, and fix your installation</b>. For help with that, see <a href=\"http://p.sf.net/rkward/compiling\">http://p.sf.net/rkward/compiling</a>.</p>\n"));
-		}
-		if (err & RThread::SinkFail) {
-			message.append (i18n ("<p>\t-There was a problem setting up the communication with R. Most likely this is due to an incorrect version of the 'rkward' R-library or failure to find that at all. This indicates a broken installation.</p>\
-			<p><b>You should quit RKWard, now, and fix your installation</b>. For help with that, see <a href=\"http://p.sf.net/rkward/compiling\">http://p.sf.net/rkward/compiling</a>.</p></p>\n"));
-		}
-		if (err & RThread::OtherFail) {
-			message.append (i18n ("<p>\t-An unspecified error occurred that is not yet handled by RKWard. Likely RKWard will not function properly. Please check your setup.</p>\n"));
-		}
+		message.append (request->params["message"].toString ());
+
 		QString details = runningCommand()->fullOutput();
 		if (!details.isEmpty ()) {
 			// WORKAROUND for stupid KMessageBox behavior. (kdelibs 4.2.3)
@@ -324,8 +305,10 @@
 			details = details.replace('<', "<").replace('\n', "<br>").leftJustified (513);
 		}
 		KMessageBox::detailedError (0, message, details, i18n ("Error starting R"), KMessageBox::Notify | KMessageBox::AllowLink);
+
+		request->completed ();
 	} else {
-		RK_ASSERT (false);
+		processRBackendRequest (request);
 	}
 }
 
@@ -432,40 +415,41 @@
 	else locked -= locked & User;
 }
 
-void RInterface::processREvalRequest (REvalRequest *request) {
+void RInterface::processHistoricalSubstackRequest (RBackendRequest* request) {
 	RK_TRACE (RBACKEND);
 
+	command_requests.append (request);
 	RK_ASSERT (!all_current_commands.isEmpty ());
 	RCommandStack *reply_stack = new RCommandStack (all_current_commands.last ());
 	RCommandChain *in_chain = reply_stack->startChain (reply_stack);
 
-	// clear reply object
-	issueCommand (".rk.set.reply (NULL)", RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);
-	if (request->call.isEmpty ()) {
+	QStringList calllist = request->params["call"].toStringList ();
+
+	if (calllist.isEmpty ()) {
 		RK_ASSERT (false);
 		closeChain (in_chain);
 		return;
 	}
-	
-	QString call = request->call[0];
+
+	QString call = calllist[0];
 	if (call == "get.tempfile.name") {
-		if (request->call.count () >= 3) {
-			QString file_prefix = request->call[1];
-			QString file_extension = request->call[2];
+		if (calllist.count () >= 3) {
+			QString file_prefix = calllist[1];
+			QString file_extension = calllist[2];
 
 			issueCommand (".rk.set.reply (\"" + RKCommonFunctions::getUseableRKWardSavefileName (file_prefix, file_extension) + "\")", RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);
 		} else {
 			issueCommand (".rk.set.reply (\"Too few arguments in call to get.tempfile.name.\")", RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);
 		}
 	} else if (call == "set.output.file") {
-		RK_ASSERT (request->call.count () == 2);
+		RK_ASSERT (calllist.count () == 2);
 
-		RKOutputWindowManager::self ()->setCurrentOutputPath (request->call[1]);
+		RKOutputWindowManager::self ()->setCurrentOutputPath (calllist[1]);
 	} else if (call == "sync") {
-		RK_ASSERT (request->call.count () >= 2);
+		RK_ASSERT (calllist.count () >= 2);
 
-		for (int i = 1; i < request->call.count (); ++i) {
-			QString object_name = request->call[i];
+		for (int i = 1; i < calllist.count (); ++i) {
+			QString object_name = calllist[i];
 			RObject *obj = RObjectList::getObjectList ()->findObject (object_name);
 			if (obj) {
 				RK_DO (qDebug ("triggering update for symbol %s", object_name.toLatin1 ().data()), RBACKEND, DL_DEBUG);
@@ -477,18 +461,18 @@
 		}
 	} else if (call == "syncenvs") {
 		RK_DO (qDebug ("triggering update of object list"), RBACKEND, DL_DEBUG);
-		RObjectList::getObjectList ()->updateFromR (in_chain, request->call.mid (1));
+		RObjectList::getObjectList ()->updateFromR (in_chain, calllist.mid (1));
 	} else if (call == "syncglobal") {
 		RK_DO (qDebug ("triggering update of globalenv"), RBACKEND, DL_DEBUG);
-		RObjectList::getGlobalEnv ()->updateFromR (in_chain, request->call.mid (1));
+		RObjectList::getGlobalEnv ()->updateFromR (in_chain, calllist.mid (1));
 	} else if (call == "edit") {
-		RK_ASSERT (request->call.count () >= 2);
+		RK_ASSERT (calllist.count () >= 2);
 
-		QStringList object_list = request->call.mid (1);
+		QStringList object_list = calllist.mid (1);
 		new RKEditObjectAgent (object_list, in_chain);
 	} else if (call == "require") {
-		if (request->call.count () >= 2) {
-			QString lib_name = request->call[1];
+		if (calllist.count () >= 2) {
+			QString lib_name = calllist[1];
 			KMessageBox::information (0, i18n ("The R-backend has indicated that in order to carry out the current task it needs the package '%1', which is not currently installed. We will open the package-management tool, and there you can try to locate and install the needed package.", lib_name), i18n ("Require package '%1'", lib_name));
 			RKLoadLibsDialog::showInstallPackagesModal (0, in_chain, lib_name);
 			issueCommand (".rk.set.reply (\"\")", RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);
@@ -502,21 +486,21 @@
 #ifndef DISABLE_RKWINDOWCATCHER
  	} else if (call == "startOpenX11") {
 		// TODO: error checking/handling (wrong parameter count/type)
-		if (request->call.count () >= 2) {
-			window_catcher->start (QString (request->call[1]).toInt ());
+		if (calllist.count () >= 2) {
+			window_catcher->start (QString (calllist[1]).toInt ());
 		}
  	} else if (call == "endOpenX11") {
 		// TODO: error checking/handling (wrong parameter count/type)
-		if (request->call.count () >= 2) {
-			window_catcher->stop (QString (request->call[1]).toInt ());
+		if (calllist.count () >= 2) {
+			window_catcher->stop (QString (calllist[1]).toInt ());
 		}
 	} else if (call == "updateDeviceHistory") {
-		if (request->call.count () >= 2) {
-			window_catcher->updateHistory (request->call.mid (1));
+		if (calllist.count () >= 2) {
+			window_catcher->updateHistory (calllist.mid (1));
 		}
 	} else if (call == "killDevice") {
-		if (request->call.count () >= 2) {
-			window_catcher->killDevice (request->call[1].toInt ());
+		if (calllist.count () >= 2) {
+			window_catcher->killDevice (calllist[1].toInt ());
 		}
 #endif // DISABLE_RKWINDOWCATCHER
 	} else if (call == "wdChange") {
@@ -527,17 +511,15 @@
 			issueCommand (".rk.set.reply (FALSE)", RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);
 		}
 	} else if (call == "doPlugin") {
-		if (request->call.count () >= 3) {
+		if (calllist.count () >= 3) {
 			QString message;
 			bool ok;
 			RKComponentMap::ComponentInvocationMode mode = RKComponentMap::ManualSubmit;
-			if (request->call[2] == "auto") mode = RKComponentMap::AutoSubmit;
-			else if (request->call[2] == "submit") mode = RKComponentMap::AutoSubmitOrFail;
-			ok = RKComponentMap::invokeComponent (request->call[1], request->call.mid (3), mode, &message, in_chain);
+			if (calllist[2] == "auto") mode = RKComponentMap::AutoSubmit;
+			else if (calllist[2] == "submit") mode = RKComponentMap::AutoSubmitOrFail;
+			ok = RKComponentMap::invokeComponent (calllist[1], calllist.mid (3), mode, &message, in_chain);
 
-			if (message.isEmpty ()) {
-				issueCommand (".rk.set.reply (NULL)", RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);
-			} else {
+			if (!message.isEmpty ()) {
 				QString type = "warning";
 				if (!ok) type = "error";
 				issueCommand (".rk.set.reply (list (type=\"" + type + "\", message=\"" + RKCommonFunctions::escape (message) + "\"))", RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);
@@ -546,24 +528,24 @@
 			RK_ASSERT (false);
 		}
 	} else if (call == "listPlugins") {
-		if (request->call.count () == 1) {
+		if (calllist.count () == 1) {
 			QStringList list = RKComponentMap::getMap ()->allComponentIds ();
 			issueCommand (".rk.set.reply (c (\"" + list.join ("\", \"") + "\"))\n", RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);
 		} else {
 			RK_ASSERT (false);
 		}
 	} else if (call == "showHTML") {
-		if (request->call.count () == 2) {
-			RKWorkplace::mainWorkplace ()->openHelpWindow (request->call[1]);
+		if (calllist.count () == 2) {
+			RKWorkplace::mainWorkplace ()->openHelpWindow (calllist[1]);
 		} else {
 			RK_ASSERT (false);
 		}
 	} else if (call == "select.list") {
-		QString title = request->call[1];
-		bool multiple = (request->call[2] == "multi");
-		int num_preselects = request->call[3].toInt ();
-		QStringList preselects = request->call.mid (4, num_preselects);
-		QStringList choices = request->call.mid (4 + num_preselects);
+		QString title = calllist[1];
+		bool multiple = (calllist[2] == "multi");
+		int num_preselects = calllist[3].toInt ();
+		QStringList preselects = calllist.mid (4, num_preselects);
+		QStringList choices = calllist.mid (4 + num_preselects);
 
 		QStringList results = RKSelectListDialog::doSelect (0, title, choices, preselects, multiple);
 		if (results.isEmpty ()) results.append ("");	// R wants to have it that way
@@ -577,9 +559,9 @@
 
 		issueCommand (command, RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);
 	} else if (call == "recordCommands") {
-		if (request->call.count () == 3) {
-			QString filename = request->call[1];
-			bool with_sync = (request->call[2] == "include.sync");
+		if (calllist.count () == 3) {
+			QString filename = calllist[1];
+			bool with_sync = (calllist[2] == "include.sync");
 
 			if (filename.isEmpty ()) {
 				command_logfile_mode = NotRecordingCommands;
@@ -608,18 +590,18 @@
 	closeChain (in_chain);
 }
 
-void RInterface::processRCallbackRequest (RCallbackArgs *args) {
+void RInterface::processRBackendRequest (RBackendRequest *request) {
 	RK_TRACE (RBACKEND);
 
 	// first, copy out the type. Allows for easier typing below
-	RCallbackArgs::RCallbackType type = args->type;
+	RBackendRequest::RCallbackType type = request->type;
 
-	if (type == RCallbackArgs::RShowMessage) {
-		QString caption = args->params["caption"].toString ();
-		QString message = args->params["message"].toString ();
-		QString button_yes = args->params["button_yes"].toString ();;
-		QString button_no = args->params["button_no"].toString ();;
-		QString button_cancel = args->params["button_cancel"].toString ();;
+	if (type == RBackendRequest::ShowMessage) {
+		QString caption = request->params["caption"].toString ();
+		QString message = request->params["message"].toString ();
+		QString button_yes = request->params["button_yes"].toString ();;
+		QString button_no = request->params["button_no"].toString ();;
+		QString button_cancel = request->params["button_cancel"].toString ();;
 
 		KGuiItem button_yes_item = KStandardGuiItem::yes ();
 		if (button_yes != "yes") button_yes_item.setText (button_yes);
@@ -628,26 +610,24 @@
 		KGuiItem button_cancel_item = KStandardGuiItem::cancel ();
 		if (button_cancel != "cancel") button_cancel_item.setText (button_cancel);
 
-		bool shown = false;
 		KMessageBox::DialogType dialog_type = KMessageBox::QuestionYesNoCancel;
 		if (button_cancel.isEmpty ()) dialog_type = KMessageBox::QuestionYesNo;
 		if (button_no.isEmpty () && button_cancel.isEmpty ()) {
 			dialog_type = KMessageBox::Information;
-			if (args->params["wait"].toString () != "1") {	// non-modal dialogs are not supported out of the box by KMessageBox;
+			if (!request->synchronous) {	// non-modal dialogs are not supported out of the box by KMessageBox;
 				KDialog* dialog = new KDialog ();
 				KMessageBox::createKMessageBox (dialog, QMessageBox::Information, message, QStringList (), QString (), 0, KMessageBox::Notify | KMessageBox::NoExec);
 				dialog->setWindowTitle (caption);
 				dialog->setAttribute (Qt::WA_DeleteOnClose);
 				dialog->setButtons (KDialog::Ok);
 				dialog->show();
-				shown = true;
+
+				request->completed ();
+				return;
 			}
 		}
 
-		int result = KMessageBox::Ok;
-		if (!shown) {
-			result = KMessageBox::messageBox (0, dialog_type, message, caption, button_yes_item, button_no_item, button_cancel_item);
-		}
+		int result = KMessageBox::messageBox (0, dialog_type, message, caption, button_yes_item, button_no_item, button_cancel_item);
 
 		QString result_string;
 		if ((result == KMessageBox::Yes) || (result == KMessageBox::Ok)) result_string = "yes";
@@ -655,8 +635,8 @@
 		else if (result == KMessageBox::Cancel) result_string = "cancel";
 		else RK_ASSERT (false);
 
-		args->params["result"] = result_string;
-	} else if (type == RCallbackArgs::RReadLine) {
+		request->params["result"] = result_string;
+	} else if (type == RBackendRequest::ReadLine) {
 		QString result;
 
 		// yes, readline *can* be called outside of a current command (e.g. from tcl/tk)
@@ -667,30 +647,30 @@
 			dummy_command = true;
 		}
 
-		bool ok = RKReadLineDialog::readLine (0, i18n ("R backend requests information"), args->params["prompt"].toString (), command, &result);
-		args->params["result"] = QVariant (result);
+		bool ok = RKReadLineDialog::readLine (0, i18n ("R backend requests information"), request->params["prompt"].toString (), command, &result);
+		request->params["result"] = QVariant (result);
 
 		if (dummy_command) delete command;
-		if (!ok) args->params["cancelled"] = QVariant (true);
-	} else if ((type == RCallbackArgs::RShowFiles) || (type == RCallbackArgs::REditFiles)) {
-		ShowEditTextFileAgent::showEditFiles (args);
+		if (!ok) request->params["cancelled"] = QVariant (true);
+	} else if ((type == RBackendRequest::ShowFiles) || (type == RBackendRequest::EditFiles)) {
+		ShowEditTextFileAgent::showEditFiles (request);
 		return;		// we are not done, yet!
-	} else if (type == RCallbackArgs::RChooseFile) {
+	} else if (type == RBackendRequest::ChooseFile) {
 		QString filename;
-		if (args->params["new"].toBool ()) {
+		if (request->params["new"].toBool ()) {
 			filename = KFileDialog::getSaveFileName ();
 		} else {
 			filename = KFileDialog::getOpenFileName ();
 		}
-		args->params["result"] = QVariant (filename);
-	} else if (type == RCallbackArgs::RBackendExit) {
-		QString message = args->params["message"].toString ();
+		request->params["result"] = QVariant (filename);
+	} else if (type == RBackendRequest::BackendExit) {
+		QString message = request->params["message"].toString ();
 		message += i18n ("\nIt will be shut down immediately. This means, you can not use any more functions that rely on the R backend. I.e. you can do hardly anything at all, not even save the workspace (but if you're lucky, R already did that). What you can do, however, is save any open command-files, the output, or copy data out of open data editors. Quit RKWard after that.\nSince this should never happen, please write a mail to rkward-devel at lists.sourceforge.net, and tell us, what you were trying to do, when this happened. Sorry!");
 		KMessageBox::error (0, message, i18n ("R engine has died"));
 		r_thread->kill ();
 	}
 
-	args->done = true;
+	request->completed ();
 }
 
 #include "rinterface.moc"

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h	2010-10-28 11:42:21 UTC (rev 3159)
@@ -26,13 +26,11 @@
 
 class RCommand;
 class RKWardMainWindow;
-struct RCallbackArgs;
 class QTimer;
 class RThread;
 class RCommandReceiver;
-struct REvalRequest;
 struct RKWardStartupOptions;
-struct RNextCommandRequest;
+struct RBackendRequest;
 
 /** This class provides the main interface to the R-processor.
 
@@ -72,7 +70,7 @@
 	void pauseProcessing (bool pause);
 
 /** returns the command currently running in the thread. Be careful when using the returned pointer! */
-	RCommand *runningCommand ();
+	RCommand *runningCommand () const { return (all_current_commands.isEmpty () ? 0 : all_current_commands.last ()); };
 
 	bool backendIsDead ();
 	bool backendIsIdle ();
@@ -101,17 +99,17 @@
 		RecordingCommandsWithSync
 	} command_logfile_mode;
 
-/** See \ref RThread::doSubstack (). Does the actual job. */
-	void processREvalRequest (REvalRequest *request);
-//	void processRGetValueRequest (RGetValueRequest);
-/** See \ref RThread::doStandardCallback (). Does the actual job. */
-	void processRCallbackRequest (RCallbackArgs *args);
+	void processHistoricalSubstackRequest (RBackendRequest *request);
+	void processRBackendRequest (RBackendRequest *request);
 
 /** A list of all commands that have entered, and not yet left, the backend thread */
 	QList<RCommand*> all_current_commands;
-	RNextCommandRequest *command_request;
+/** NOTE: processsing R events while waiting for the next command may, conceivably, lead to new requests, which may also wait for sub-commands! Thus we keep a simple stack of requests. */
+	QList<RBackendRequest*> command_requests;
+	RBackendRequest* currentCommandRequest () const { return (command_requests.isEmpty () ? 0 : command_requests.last ()); };
 	void tryNextCommand ();
 	void doNextCommand (RCommand *command);
+	void handleCommandOut (RCommandProxy *proxy);
 	bool previously_idle;
 
 /** @see locked */

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rpackages/rkward/R/internal.R
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rpackages/rkward/R/internal.R	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rpackages/rkward/R/internal.R	2010-10-28 11:42:21 UTC (rev 3159)
@@ -60,13 +60,13 @@
 	}
 }
 
+".rk.rkreply" <- NULL
+".rk.set.reply" <- function (x) .rk.rkreply <<- x
+
 ".rk.do.call" <- function (x, args=NULL) {
+	.rk.set.reply (NULL)
 	.Call ("rk.do.command", c (x, args));
-	if (exists (".rk.rkreply")) {
-		return (.rk.rkreply)
-	} else {
-		return (NULL)
-	}
+	return (.rk.rkreply)
 }
 
 # package information formats may - according to the help - be subject to change. Hence this function to cope with "missing" values
@@ -294,15 +294,11 @@
 
 ".rk.output.html.file" <- NULL
 
-".rk.rkreply" <- NULL
-
-".rk.set.reply" <- function (x) .rk.rkreply <<- x
-
 "Sys.setlocale" <- function (category = "LC_ALL", locale = "", ...) {
 	if (category == "LC_ALL" || category == "LC_CTYPE" || category == "LANG") {
-		.rk.do.call ("preLocaleChange", NULL);
-		if (!is.null (.rk.rkreply)) {
-			if (.rk.rkreply == FALSE) stop ("Changing the locale was cancelled by user");
+		allow <- .rk.do.call ("preLocaleChange", NULL);
+		if (!is.null (allow)) {
+			if (allow == FALSE) stop ("Changing the locale was cancelled by user");
 		}
 
 		ret <- base::Sys.setlocale (category, locale, ...)

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp	2010-10-28 11:42:21 UTC (rev 3159)
@@ -56,32 +56,32 @@
 	RK_TRACE (RBACKEND);
 	thread_id = currentThreadId ();
 	killed = false;
-	int err;
+	previous_command = 0;
 
 	// in RInterface::RInterface() we have created a fake RCommand to capture all the output/errors during startup. Fetch it
+	repl_status.eval_depth++;
 	fetchNextCommand ();
 
-	if ((err = initialize ())) {
-		int* err_c = new int;
-		*err_c = err;
-		qApp->postEvent (RKGlobals::rInterface (), new RKRBackendEvent (RKRBackendEvent::RStartupError, err_c));
+	QString err = initialize ();
+	if (!err.isEmpty ()) {
+		RBackendRequest req (true, RBackendRequest::StartupError);
+		req.params["message"] = err;
+		handleRequest (&req);
 	}
-	bool startup_was_handled = false;
-	qApp->postEvent (RKGlobals::rInterface (), new RKRBackendEvent (RKRBackendEvent::RStarted, &startup_was_handled));
 
 	// wait until RKWard is set to go (esp, it has handled any errors during startup, etc.)
-	while (!startup_was_handled) {
-		msleep (10);
-	}
+	RBackendRequest* req = new RBackendRequest (true, RBackendRequest::Started);
+	handleRequest (req);
+	delete req;
 
 	commandFinished ();		// the fake startup command
+	repl_status.eval_depth--;
 
 	enterEventLoop ();
 }
 
 void RThread::commandFinished (bool check_object_updates_needed) {
 	RK_TRACE (RBACKEND);
-
 	RK_DO (qDebug ("done running command"), RBACKEND, DL_DEBUG);
 
 	current_command->status -= (current_command->status & RCommand::Running);
@@ -91,39 +91,64 @@
 		checkObjectUpdatesNeeded (current_command->type & (RCommand::User | RCommand::ObjectListUpdate));
 	}
 
-	RKRBackendEvent* event = new RKRBackendEvent (RKRBackendEvent::RCommandOut, current_command);
-	qApp->postEvent (RKGlobals::rInterface (), event);		// command may be deleted after this!
+	previous_command = current_command;
 
 	all_current_commands.pop_back();
 	if (!all_current_commands.isEmpty ()) current_command = all_current_commands.last ();
 }
 
-RCommandProxy* RThread::fetchNextCommand () {
+RCommandProxy* RThread::handleRequest (RBackendRequest *_request, bool mayHandleSubstack) {
 	RK_TRACE (RBACKEND);
+	RK_ASSERT (_request);
 
-	RNextCommandRequest req;
-	bool done = false;
-	req.done = &done;
-	req.command = 0;
+	RBackendRequest* request = _request;
+	bool synchronous = request->synchronous;	// It's important to *copy* this. For async requests, the request instance may be deleted right after sending.
+	if (!synchronous) request = request->duplicate ();	// will remain in the frontend, and be deleted, there
 
-	RKRBackendEvent* event = new RKRBackendEvent (RKRBackendEvent::RNextCommandRequest, &req);
+	RKRBackendEvent* event = new RKRBackendEvent (request);
 	qApp->postEvent (RKGlobals::rInterface (), event);
 
-	while (!done) {
+	if (!synchronous) {
+		RK_ASSERT (mayHandleSubstack);	// i.e. not called from fetchNextCommand
+		_request->done = true;	// for aesthetics
+		return 0;
+	}
+
+	while (!request->done) {
 		if (killed) return 0;
+		// NOTE: processX11Events() may, conceivably, lead to new requests, which may also wait for sub-commands!
 		processX11Events ();
-		if (!done) msleep (10);
+		if (!request->done) msleep (10);
 	}
 
-	RCommandProxy *command = req.command;
-	if (command) {
-		all_current_commands.append (command);
-		current_command = command;
-	}
+	RCommandProxy* command = request->command;
+	if (!command) return 0;
 
-	return command;
+	all_current_commands.append (command);
+	current_command = command;
+
+	if (!mayHandleSubstack) return command;
+	
+	while (command) {
+		runCommand (command);
+		commandFinished (false);
+
+		command = fetchNextCommand ();
+	};
+
+	return 0;
 }
 
+RCommandProxy* RThread::fetchNextCommand () {
+	RK_TRACE (RBACKEND);
+
+	RBackendRequest req (true, RBackendRequest::CommandOut);
+	req.command = previous_command;
+	previous_command = 0;
+
+	return (handleRequest (&req, false));
+}
+
 void RThread::waitIfOutputBufferExceeded () {
 	// don't trace
 	while (out_buf_len > MAX_BUF_LENGTH) {
@@ -132,10 +157,10 @@
 }
 
 void RThread::handleOutput (const QString &output, int buf_length, ROutput::ROutputType output_type) {
+	if (!buf_length) return;
 	RK_TRACE (RBACKEND);
 
-	if (!buf_length) return;
-	RK_DO (qDebug ("Output type %d: ", output_type, qPrintable (output)), RBACKEND, DL_DEBUG);
+	RK_DO (qDebug ("Output type %d: %s", output_type, qPrintable (output)), RBACKEND, DL_DEBUG);
 	waitIfOutputBufferExceeded ();
 
 	output_buffer_mutex.lock ();
@@ -180,52 +205,17 @@
 	return ret;
 }
 
-void RThread::handleSubstackCall (QStringList &call) {
+void RThread::handleHistoricalSubstackRequest (const QStringList &list) {
 	RK_TRACE (RBACKEND);
 
-	if (call.count () == 2) {		// schedule symbol update for later
-		if (call[0] == "ws") {
-			// always keep in mind: No current command can happen for tcl/tk events.
-			if ((!current_command) || (current_command->type & RCommand::ObjectListUpdate) || (!(current_command->type & RCommand::Sync))) {		// ignore Sync commands that are not flagged as ObjectListUpdate
-				if (!changed_symbol_names.contains (call[1])) changed_symbol_names.append (call[1]);
-			}
-			return;
-		}
-	}
+	RBackendRequest request (true, RBackendRequest::HistoricalSubstackRequest);
+	request.params["call"] = list;
+	handleRequest (&request);
+}                                                                        
 
-	REvalRequest request;
-	request.call = call;
-	RKRBackendEvent* event = new RKRBackendEvent (RKRBackendEvent::REvalRequest, &request);
-	qApp->postEvent (RKGlobals::rInterface (), event);
-
-	RCommandProxy *c;
-	while ((c = fetchNextCommand ())) {
-		runCommand (c);
-		commandFinished (false);
-	}
-}
-
-void RThread::handleStandardCallback (RCallbackArgs *args) {
+QString RThread::initialize () {
 	RK_TRACE (RBACKEND);
 
-	args->done = false;
-
-	RKRBackendEvent* event = new RKRBackendEvent (RKRBackendEvent::RCallbackRequest, args);
-	qApp->postEvent (RKGlobals::rInterface (), event);
-	
-	bool *done = &(args->done);
-	while (!(*done)) {
-		msleep (10); // callback not done yet? Sleep for a while
-
-		if (!(RInterface::backendIsLocked () || killed)) processX11Events ();
-	}
-
-	RK_DO (qDebug ("standard callback done"), RBACKEND, DL_DEBUG);
-}
-
-int RThread::initialize () {
-	RK_TRACE (RBACKEND);
-
 	int argc = 2;
 	char* argv[2] = { qstrdup ("--slave"), qstrdup ("--no-save") };
 	RKWardStartupOptions *options = RKWardMainWindow::getStartupOptions ();
@@ -271,7 +261,20 @@
 	if (!runDirectCommand ("options (error=quote (.rk.do.error ()))\n")) status |= SinkFail;
 	if (!runDirectCommand ("rk.set.output.html.file (\"" + RKSettingsModuleGeneral::filesPath () + "/rk_out.html\")\n")) status |= SinkFail;
 
-	return status;
+	QString error_messages;
+	if (status & LibLoadFail) {
+		error_messages.append (i18n ("</p>\t- The 'rkward' R-library either could not be loaded at all, or not in the correct version. This may lead to all sorts of errors, from single missing features to complete failure to function. The most likely cause is that the last installation did not place all files in the correct place. However, in some cases, left-overs from a previous installation that was not cleanly removed may be the cause.</p>\
+		<p><b>You should quit RKWard, now, and fix your installation</b>. For help with that, see <a href=\"http://p.sf.net/rkward/compiling\">http://p.sf.net/rkward/compiling</a>.</p>\n"));
+	}
+	if (status & SinkFail) {
+		error_messages.append (i18n ("<p>\t-There was a problem setting up the communication with R. Most likely this is due to an incorrect version of the 'rkward' R-library or failure to find that at all. This indicates a broken installation.</p>\
+		<p><b>You should quit RKWard, now, and fix your installation</b>. For help with that, see <a href=\"http://p.sf.net/rkward/compiling\">http://p.sf.net/rkward/compiling</a>.</p></p>\n"));
+	}
+	if (status & OtherFail) {
+		error_messages.append (i18n ("<p>\t-An unspecified error occurred that is not yet handled by RKWard. Likely RKWard will not function properly. Please check your setup.</p>\n"));
+	}
+
+	return error_messages;
 }
 
 void RThread::checkObjectUpdatesNeeded (bool check_list) {
@@ -332,12 +335,12 @@
 		if (search_update_needed) {	// this includes an update of the globalenv, even if not needed
 			QStringList call = toplevel_env_names;
 			call.prepend ("syncenvs");	// should be faster than the reverse
-			handleSubstackCall (call);
+			handleHistoricalSubstackRequest (call);
 		} 
 		if (globalenv_update_needed) {
 			QStringList call = global_env_toplevel_names;
 			call.prepend ("syncglobal");	// should be faster than the reverse
-			handleSubstackCall (call);
+			handleHistoricalSubstackRequest (call);
 		}
 	}
 
@@ -349,7 +352,7 @@
 	if (!changed_symbol_names.isEmpty ()) {
 		QStringList call = changed_symbol_names;
 		call.prepend (QString ("sync"));	// should be faster than reverse
-		handleSubstackCall (call);
+		handleHistoricalSubstackRequest (call);
 		changed_symbol_names.clear ();
 	}
 }

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandeditorwindow.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandeditorwindow.cpp	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandeditorwindow.cpp	2010-10-28 11:42:21 UTC (rev 3159)
@@ -158,6 +158,7 @@
 	RK_TRACE (COMMANDEDITOR);
 	delete hinter;
 	delete m_doc;
+	if (!delete_on_close.isEmpty ()) KIO::del (delete_on_close)->start ();
 }
 
 void RKCommandEditorWindow::fixupPartGUI () {
@@ -331,7 +332,7 @@
 	m_doc->setReadWrite (!ro);
 }
 
-bool RKCommandEditorWindow::openURL (const KUrl &url, const QString& encoding, bool use_r_highlighting, bool read_only){
+bool RKCommandEditorWindow::openURL (const KUrl &url, const QString& encoding, bool use_r_highlighting, bool read_only, bool delete_on_close){
 	RK_TRACE (COMMANDEDITOR);
 
 	// encoding must be set *before* loading the file
@@ -342,6 +343,14 @@
 
 		updateCaption ();
 
+		if (delete_on_close) {
+			if (!read_only) {
+				RK_ASSERT (false);
+				return true;
+			}
+			RKCommandEditorWindow::delete_on_close=url;
+		}
+
 		return true;
 	}
 	return false;

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandeditorwindow.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandeditorwindow.h	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandeditorwindow.h	2010-10-28 11:42:21 UTC (rev 3159)
@@ -143,8 +143,9 @@
 /** open given URL. 
 @param use_r_highlighting Initialize the view to use R syntax highlighting. Use, if you're going to edit an R syntax file
 @param encoding encoding to use. If QString (), the default encoding is used.
- at param read_only Open the file in read-only mode */
-	bool openURL (const KUrl &url, const QString& encoding=QString (), bool use_r_highlighting=true, bool read_only=false);
+ at param read_only Open the file in read-only mode
+ at param delete_on_close File should be deleted when closing the window. Only respected with read_only=true. */
+	bool openURL (const KUrl &url, const QString& encoding=QString (), bool use_r_highlighting=true, bool read_only=false, bool delete_on_close=false);
 /** returns, whether the document was modified since the last save */
 	bool isModified ();
 /** insert the given text into the document at the current cursor position. Additionally, focuses the view */
@@ -261,6 +262,8 @@
 
 	KUrl previous_autosave_url;
 	QTimer* autosave_timer;
+
+	KUrl delete_on_close;
 };
 
 #endif

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkworkplace.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkworkplace.cpp	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkworkplace.cpp	2010-10-28 11:42:21 UTC (rev 3159)
@@ -216,7 +216,7 @@
 	return false;
 }
 
-bool RKWorkplace::openScriptEditor (const KUrl &url, const QString& encoding, bool use_r_highlighting, bool read_only, const QString &force_caption) {
+bool RKWorkplace::openScriptEditor (const KUrl &url, const QString& encoding, bool use_r_highlighting, bool read_only, const QString &force_caption, bool delete_on_close) {
 	RK_TRACE (APP);
 
 // is this url already opened?
@@ -234,7 +234,7 @@
 	RKCommandEditorWindow *editor = new RKCommandEditorWindow (view (), use_r_highlighting);
 
 	if (!url.isEmpty ()) {
-		if (!editor->openURL (url, encoding, use_r_highlighting, read_only)) {
+		if (!editor->openURL (url, encoding, use_r_highlighting, read_only, delete_on_close)) {
 			delete editor;
 			KMessageBox::messageBox (view (), KMessageBox::Error, i18n ("Unable to open \"%1\"", url.prettyUrl ()), i18n ("Could not open command file"));
 			return false;

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkworkplace.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkworkplace.h	2010-10-27 18:47:46 UTC (rev 3158)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkworkplace.h	2010-10-28 11:42:21 UTC (rev 3159)
@@ -100,7 +100,7 @@
 @param read_only Open the document read only? Default is false, i.e. Read-write
 @param force_caption Usually the caption is determined from the url of the file. If you specify a non-empty string here, that is used instead.
 @returns false if a local url could not be opened, true for all remote urls, and on success */
-	bool openScriptEditor (const KUrl &url=KUrl (), const QString& encoding=QString (), bool use_r_highlighting=true, bool read_only=false, const QString &force_caption = QString::null);
+	bool openScriptEditor (const KUrl &url=KUrl (), const QString& encoding=QString (), bool use_r_highlighting=true, bool read_only=false, const QString &force_caption = QString::null, bool delete_on_close=false);
 /** Opens a new help window, starting at the given url
 @param url URL to open
 @param only_once if true, checks whether any help window already shows this URL. If so, raise it, but do not open a new window. Else show the new window */


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the rkward-tracker mailing list