[rkward-cvs] rkward/rkward/rbackend rcommand.h,1.15,1.16 rembed.cpp,1.22,1.23 rembed.h,1.9,1.10 rinterface.cpp,1.27,1.28 rthread.cpp,1.17,1.18 rthread.h,1.14,1.15

Thomas Friedrichsmeier tfry at users.sourceforge.net
Fri Sep 23 17:19:32 UTC 2005


Update of /cvsroot/rkward/rkward/rkward/rbackend
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3446/rkward/rbackend

Modified Files:
	rcommand.h rembed.cpp rembed.h rinterface.cpp rthread.cpp 
	rthread.h 
Log Message:
Merged REmbed into RThread

Index: rthread.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rthread.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -C2 -d -r1.14 -r1.15
*** rthread.h	12 Sep 2005 17:09:59 -0000	1.14
--- rthread.h	23 Sep 2005 17:19:30 -0000	1.15
***************
*** 22,27 ****
  #include "rcommand.h"
  #include "rcommandstack.h"
  
- class REmbed;
  class RInterface;
  struct RCallbackArgs;
--- 22,27 ----
  #include "rcommand.h"
  #include "rcommandstack.h"
+ #include "rembedinternal.h"
  
  class RInterface;
  struct RCallbackArgs;
***************
*** 55,70 ****
  This subordinate/nested eventloop is done in doSubstack ().
  
! Internally, this class is closely related to REmbed and REmbedInternal, which is where the "real work" is being done. RThread basically just takes care of delegating the work. Also related is RInterface: RThread communicates with RInterface by placing QCustomEvent s, when commands are done
! or when the backend needs information from the frontend.
  
! Unless you really want to modify the internal workings of the backend, you will want to look at RInterface and use the functions there.
  
  @see RInterface
- @see REmbed
  @see REmbedInternal
  
  @author Thomas Friedrichsmeier
  */
! class RThread : public QThread {
  public:
  /** constructor. You need to specify a pointer to the RInterface, so the thread knows where to post its events. Only one RThread should ever be
--- 55,70 ----
  This subordinate/nested eventloop is done in doSubstack ().
  
! 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. Also RThread and REmbedInternal are only separate for technical reasons (R-includes and Qt-includes clashing).
  
! Only one RThread-object can be used in an application.
! Don't use this class in RKWard directly. Unless you really want to modify the internal workings of the backend, you will want to look at RInterface and use the functions there.
  
  @see RInterface
  @see REmbedInternal
  
  @author Thomas Friedrichsmeier
  */
! class RThread : public QThread, public REmbedInternal {
  public:
  /** constructor. You need to specify a pointer to the RInterface, so the thread knows where to post its events. Only one RThread should ever be
***************
*** 83,98 ****
  	void kill () { killed = true; };
  
! /** this is a sub-eventloop, being run when the backend request information from the frontend. See \ref RThread for a more detailed description
  
! @see REmbed::handleSubstackCall () */
! 	void doSubstack (char **call, int call_length);
  
! /** this is a minimal sub-eventloop, being run, when the backend requests simple information from the frontend. It differs from doSubstack 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
  
! @see REmbed::handleStandardCallback () */
! 	void doStandardCallback (RCallbackArgs *args);
  
  /** The command currently being executed. This is used from RInterface::cancelCommand to find out, whether the command to be cancelled is
--- 83,125 ----
  	void kill () { killed = true; };
  
! /** An enum describing whether initialization of the embedded R-process went well, or what errors occurred. */
! 	enum InitStatus {
! 		Ok=0,					/**< No error */
! 		LibLoadFail=1,		/**< Error while trying to load the rkward R package */
! 		SinkFail=2,			/**< Error while redirecting R's stdout and stderr to files to be read from rkward */
! 		OtherFail=4			/**< Other error while initializing the embedded R-process */
! 	};
  
! /** 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 ();
  
! /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
! generates standard output. @see REmbedInternal::handleOutput () */
! 	void handleOutput (char *buf, int buf_length);
! 
! /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
! signals a condition. @see REmbedInternal::handleCondition () */
! //	void handleCondition (char **call, int call_length);
! 
! /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
! reports an error. @see REmbedInternal::handleError () */
! 	void handleError (char **call, int call_length);
! 
! /** This function is public for technical reasons, only. Don't use except from REmbedInternal!
! 
! This is a sub-eventloop, being run when the backend request information from the frontend. See \ref RThread for a more detailed description
! @see REmbedInternal::handleSubstackCall () */
! 	void handleSubstackCall (char **call, int call_length);
! 
! /** This function is public for technical reasons, only. Don't use except from REmbedInternal!
! 
! 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
  
! @see REmbedInternal::handleStandardCallback () */
! 	void handleStandardCallback (RCallbackArgs *args);
  
  /** The command currently being executed. This is used from RInterface::cancelCommand to find out, whether the command to be cancelled is
***************
*** 104,111 ****
  private:
  	RInterface *inter;
! /** This is the function in which an RCommand actually gets processed. Basically it passes the command to REmbed::doCommand () and sends
! RInterface some events about what is currently happening. */
  	void doCommand (RCommand *command);
- 	REmbed *embeddedR;
  	
  	bool locked;
--- 131,136 ----
  private:
  	RInterface *inter;
! /** This is the function in which an RCommand actually gets processed. Basically it passes the command to REmbedInteranl::runCommandInternal () and sends RInterface some events about what is currently happening. */
  	void doCommand (RCommand *command);
  	
  	bool locked;

Index: rembed.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembed.cpp,v
retrieving revision 1.22
retrieving revision 1.23
diff -C2 -d -r1.22 -r1.23
*** rembed.cpp	23 Sep 2005 14:29:47 -0000	1.22
--- rembed.cpp	23 Sep 2005 17:19:30 -0000	1.23
***************
*** 15,18 ****
--- 15,20 ----
   *                                                                         *
   ***************************************************************************/
+ #if 0
+ 
  #include "rembed.h"
  
***************
*** 20,25 ****
  #include <dcopclient.h>
  
- #include <qfile.h>
- #include <qtextstream.h>
  #include <qstring.h>
  
--- 22,25 ----
***************
*** 46,51 ****
  REmbed::~REmbed () {
  	RK_TRACE (RBACKEND);
- 	outfile.close ();
- 	errfile.close ();
  }
  
--- 46,49 ----
***************
*** 159,165 ****
  	// TODO: error-handling?
  
- 	outfile_offset = 0;
- 	errfile_offset = 0;
- 
  	return status;
  }
--- 157,160 ----
***************
*** 224,225 ****
--- 219,223 ----
  	}
  }
+ 
+ #endif
+ 

Index: rembed.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembed.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -C2 -d -r1.9 -r1.10
*** rembed.h	23 Sep 2005 14:29:47 -0000	1.9
--- rembed.h	23 Sep 2005 17:19:30 -0000	1.10
***************
*** 15,18 ****
--- 15,19 ----
   *                                                                         *
   ***************************************************************************/
+ #if 0
  #ifndef REMBED_H
  #define REMBED_H
***************
*** 33,37 ****
  
  	Don't use this class in RKWard directly. Use the interface provided by RInterface, instead.
- 	REmbed could really be merged with RThread. Don't wonder about strange up-and-down calls.
  	Also REmbed and REmbedInternal are only separate for technical reasons (R-includes and Qt-includes clashing).
  
--- 34,37 ----
***************
*** 81,92 ****
  	void handleStandardCallback (RCallbackArgs *args);
  private:
- 	QIODevice::Offset outfile_offset;
- 	QIODevice::Offset errfile_offset;
- 	
- 	QFile outfile;
- 	QFile errfile;
- 	
  	RThread *thread;
  };
  
  #endif
--- 81,87 ----
  	void handleStandardCallback (RCallbackArgs *args);
  private:
  	RThread *thread;
  };
  
  #endif
+ #endif

Index: rinterface.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rinterface.cpp,v
retrieving revision 1.27
retrieving revision 1.28
diff -C2 -d -r1.27 -r1.28
*** rinterface.cpp	23 Sep 2005 14:29:47 -0000	1.27
--- rinterface.cpp	23 Sep 2005 17:19:30 -0000	1.28
***************
*** 156,166 ****
  		int err = e->type () - RSTARTUP_ERROR_EVENT;
  		QString message = i18n ("There was a problem starting the R backend. The following error(s) occurred:\n");
! 		if (err & REmbed::LibLoadFail) {
  			message.append (i18n ("\t- The 'rkward' R-library could not be loaded. This library is needed for communication between R and RKWard and many things will not work properly if this library is not present. Likely RKWard will even crash. The 'rkward' R-library should have been included in your distribution or RKWard, and should have been set up when you ran 'make install'. Please try 'make install' again and check for any errors. You should quit RKWard now.\n"));
  		}
! 		if (err & REmbed::SinkFail) {
  			message.append (i18n ("\t-There was a problem opening the files needed for communication with R. Most likely this is due to an incorrect setting for the location of these files. Check whether you have correctly configured the location of the log-files (Settings->Configure Settings->Logfiles) and restart RKWard.\n"));
  		}
! 		if (err & REmbed::OtherFail) {
  			message.append (i18n ("\t-An unspecified error occured that is not yet handled by RKWard. Likely RKWard will not function properly. Please check your setup.\n"));
  		}
--- 156,166 ----
  		int err = e->type () - RSTARTUP_ERROR_EVENT;
  		QString message = i18n ("There was a problem starting the R backend. The following error(s) occurred:\n");
! 		if (err & RThread::LibLoadFail) {
  			message.append (i18n ("\t- The 'rkward' R-library could not be loaded. This library is needed for communication between R and RKWard and many things will not work properly if this library is not present. Likely RKWard will even crash. The 'rkward' R-library should have been included in your distribution or RKWard, and should have been set up when you ran 'make install'. Please try 'make install' again and check for any errors. You should quit RKWard now.\n"));
  		}
! 		if (err & RThread::SinkFail) {
  			message.append (i18n ("\t-There was a problem opening the files needed for communication with R. Most likely this is due to an incorrect setting for the location of these files. Check whether you have correctly configured the location of the log-files (Settings->Configure Settings->Logfiles) and restart RKWard.\n"));
  		}
! 		if (err & RThread::OtherFail) {
  			message.append (i18n ("\t-An unspecified error occured that is not yet handled by RKWard. Likely RKWard will not function properly. Please check your setup.\n"));
  		}

Index: rthread.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rthread.cpp,v
retrieving revision 1.17
retrieving revision 1.18
diff -C2 -d -r1.17 -r1.18
*** rthread.cpp	14 Sep 2005 16:32:25 -0000	1.17
--- rthread.cpp	23 Sep 2005 17:19:30 -0000	1.18
***************
*** 20,33 ****
  #include "rinterface.h"
  #include "rcommandstack.h"
  
  #include "../debug.h"
  
  #include <qapplication.h>
  
! RThread::RThread (RInterface *parent) : QThread () {
  	RK_TRACE (RBACKEND);
  	inter = parent;
  	current_command = 0;
! //	r_get_value_reply = 0;
  }
  
--- 20,44 ----
  #include "rinterface.h"
  #include "rcommandstack.h"
+ #include "../settings/rksettingsmoduler.h"
+ #include "../settings/rksettingsmodulelogfiles.h"
+ #include "../rkglobals.h"
  
  #include "../debug.h"
  
+ #include <kapplication.h>
+ #include <dcopclient.h>
+ 
+ #include <qstring.h>
  #include <qapplication.h>
  
! 
! RThread::RThread (RInterface *parent) : QThread (), REmbedInternal () {
  	RK_TRACE (RBACKEND);
  	inter = parent;
  	current_command = 0;
! 
! 	RK_ASSERT (this_pointer == 0);
! 	this_pointer = this;
! 	RK_ASSERT (this_pointer);
  }
  
***************
*** 38,47 ****
  void RThread::run () {
  	RK_TRACE (RBACKEND);
- 	embeddedR = new REmbed (this);
  	locked = true;
  	killed = false;
  	int err;
  	bool previously_idle = false;
! 	if ((err = embeddedR->initialize ())) {
  		qApp->postEvent (inter, new QCustomEvent (RSTARTUP_ERROR_EVENT + err));
  	}
--- 49,57 ----
  void RThread::run () {
  	RK_TRACE (RBACKEND);
  	locked = true;
  	killed = false;
  	int err;
  	bool previously_idle = false;
! 	if ((err = initialize ())) {
  		qApp->postEvent (inter, new QCustomEvent (RSTARTUP_ERROR_EVENT + err));
  	}
***************
*** 55,59 ****
  	while (1) {
  		MUTEX_LOCK;
! 		embeddedR->processX11Events ();
  
  		if (previously_idle) {
--- 65,69 ----
  	while (1) {
  		MUTEX_LOCK;
! 		processX11Events ();
  
  		if (previously_idle) {
***************
*** 71,79 ****
  				// mutex will be unlocked inside
  				doCommand (command);
! 				embeddedR->processX11Events ();
  			}
  		
  			if (killed) {
! 				embeddedR->shutdown (false);
  				MUTEX_UNLOCK
  				return;
--- 81,89 ----
  				// mutex will be unlocked inside
  				doCommand (command);
! 				processX11Events ();
  			}
  		
  			if (killed) {
! 				shutdown (false);
  				MUTEX_UNLOCK
  				return;
***************
*** 91,95 ****
  		MUTEX_UNLOCK;
  		if (killed) {
! 			embeddedR->shutdown (false);
  			return;
  		}
--- 101,105 ----
  		MUTEX_UNLOCK;
  		if (killed) {
! 			shutdown (false);
  			return;
  		}
***************
*** 100,104 ****
  void RThread::doCommand (RCommand *command) {
  	RK_TRACE (RBACKEND);
! 	// notify GUI-thread that a new command is being tried
  	QCustomEvent *event = new QCustomEvent (RCOMMAND_IN_EVENT);
  	event->setData (command);
--- 110,114 ----
  void RThread::doCommand (RCommand *command) {
  	RK_TRACE (RBACKEND);
! 	// step 1: notify GUI-thread that a new command is being tried and initialize
  	QCustomEvent *event = new QCustomEvent (RCOMMAND_IN_EVENT);
  	event->setData (command);
***************
*** 107,113 ****
  	current_command = command;
  
! 	// mutex will be unlocked inside
! 	embeddedR->runCommand (command);
  
  	current_command = prev_command;
  	// notify GUI-thread that command was finished
--- 117,177 ----
  	current_command = command;
  
! 	// step 2: actual handling
! 	if (command->type () & RCommand::EmptyCommand) return;
! 	if (command->status & RCommand::Canceled) return;
! 	
! 	RKWardRError error;
! 	
! 	int ctype = command->type ();
! 	const char *ccommand = command->command ().latin1 ();
! 	
! 	RK_DO (qDebug ("running command: %s", ccommand), RBACKEND, DL_DEBUG);
! 
! 	if (command->type () & RCommand::DirectToOutput) {
! 		runCommandInternal ("sink (\"" + RKSettingsModuleLogfiles::filesPath () + "/rk_out.html\", append=TRUE, split=TRUE)\n", &error);
! 	}
! 
! 	MUTEX_UNLOCK;
! 
! 	if (ctype & RCommand::GetStringVector) {
! 		command->string_data = getCommandAsStringVector (ccommand, &(command->string_count), &error);
! 	} else if (ctype & RCommand::GetRealVector) {
! 		command->real_data = getCommandAsRealVector (ccommand, &(command->real_count), &error);
! 	} else if (ctype & RCommand::GetIntVector) {
! 		command->integer_data = getCommandAsIntVector (ccommand, &(command->integer_count), &error);
! 	} else {
! 		runCommandInternal (ccommand, &error, ctype & RCommand::User);
! 	}
  
+ 	MUTEX_LOCK;
+ 	
+ 	if (error != NoError) {
+ 		command->status |= RCommand::WasTried | RCommand::Failed;
+ 		if (error == Incomplete) {
+ 			command->status |= RCommand::ErrorIncomplete;
+ 			RK_DO (qDebug ("Command failed (incomplete)"), RBACKEND, DL_WARNING);
+ 		} else if (error == SyntaxError) {
+ 			command->status |= RCommand::ErrorSyntax;
+ 			RK_DO (qDebug ("Command failed (syntax)"), RBACKEND, DL_WARNING);
+ 		} else {
+ 			command->status |= RCommand::ErrorOther;
+ 			RK_DO (qDebug ("Command failed (other)"), RBACKEND, DL_WARNING);
+ 		}
+ 		RK_DO (qDebug ("failed command was: '%s'", command->command ().latin1 ()), RBACKEND, DL_WARNING);
+ 	} else {
+ 		command->status |= RCommand::WasTried;
+ 	}
+ 
+ 	RKWardRError dummy;
+ 	if (command->type () & RCommand::DirectToOutput) {
+ 		runCommandInternal ("sink ()\n", &dummy);
+ 	}
+ 
+ 	if (error) {
+ 		RK_DO (qDebug ("- error message was: '%s'", command->error ().latin1 ()), RBACKEND, DL_WARNING);
+ //		runCommandInternal (".rk.init.handlers ()\n", &dummy);
+ 	}
+ 
+ 	// step 3: cleanup
  	current_command = prev_command;
  	// notify GUI-thread that command was finished
***************
*** 117,121 ****
  }
  
! void RThread::doSubstack (char **call, int call_length) {
  	RK_TRACE (RBACKEND);
  
--- 181,236 ----
  }
  
! void RThread::handleOutput (char *buf, int buf_length) {
! 	RK_TRACE (RBACKEND);
! 
! 	if (!buf_length) return;
! 	if (!current_command) return;
! 
! 	ROutput *out = new ROutput;
! 	out->type = ROutput::Output;
! 	out->output = QString (buf);
! 
! 	current_command->output_list.append (out);
! 	current_command->status |= RCommand::HasOutput;
! 	// TODO: pass a signal to the main thread for real-time update of output
! 
! 	RK_DO (qDebug ("output '%s'", buf), RBACKEND, DL_DEBUG);
! }
! 
! /*
! void RThread::handleCondition (char **call, int call_length) {
! 	RK_TRACE (RBACKEND);
! 
! 	RK_ASSERT (call_length >= 2);
! 	if (!call_length) return;
! 
! 	//RThreadInternal::next_output_is_error = true;
! 	qDebug ("condition '%s', message '%s'", call[0], call[1]);
! } */
! 
! void RThread::handleError (char **call, int call_length) {
! 	RK_TRACE (RBACKEND);
! 
! 	if (!call_length) return;
! 	if (!current_command) return;
! 
! 	// Unfortunately, errors still get printed to the output. We try this crude method for the time being:
! 	current_command->output_list.last ()->type = ROutput::Error;
! 	current_command->status |= RCommand::HasError;
! 
! /*	// for now we ignore everything but the first string.
! 	ROutput *out = new ROutput;
! 	out->type = ROutput::Error;
! 	out->output = QString (call[0]);
! 
! 	thread->current_command->output_list.append (out);
! 	thread->current_command->status |= RCommand::HasError; */
! 	// TODO: pass a signal to the main thread for real-time update of output
! 
! 	//RThreadInternal::next_output_is_error = true;
! 	RK_DO (qDebug ("error '%s'", call[0]), RBACKEND, DL_DEBUG);
! }
! 
! void RThread::handleSubstackCall (char **call, int call_length) {
  	RK_TRACE (RBACKEND);
  
***************
*** 135,139 ****
  	while (!done) {
  		MUTEX_LOCK;
! 		embeddedR->processX11Events ();
  		// while commands are in queue, don't wait
  		while (reply_stack->isActive () && !locked) {
--- 250,254 ----
  	while (!done) {
  		MUTEX_LOCK;
! 		processX11Events ();
  		// while commands are in queue, don't wait
  		while (reply_stack->isActive () && !locked) {
***************
*** 143,147 ****
  				// mutex will be unlocked inside
  				doCommand (command);
! 				embeddedR->processX11Events ();
  			}
  		}
--- 258,262 ----
  				// mutex will be unlocked inside
  				doCommand (command);
! 				processX11Events ();
  			}
  		}
***************
*** 155,163 ****
  		msleep (10);
  	}
! 	
  	delete reply_stack;
  }
  
! void RThread::doStandardCallback (RCallbackArgs *args) {
  	RK_TRACE (RBACKEND);
  
--- 270,278 ----
  		msleep (10);
  	}
! 
  	delete reply_stack;
  }
  
! void RThread::handleStandardCallback (RCallbackArgs *args) {
  	RK_TRACE (RBACKEND);
  
***************
*** 174,178 ****
  
  		MUTEX_LOCK;
! 		embeddedR->processX11Events ();
  
  		if (args->done) {
--- 289,293 ----
  
  		MUTEX_LOCK;
! 		processX11Events ();
  
  		if (args->done) {
***************
*** 182,183 ****
--- 297,345 ----
  	}
  }
+ 
+ int RThread::initialize () {
+ 	RK_TRACE (RBACKEND);
+ 	QString r_home = RKSettingsModuleR::rHomeDir();
+ 
+ 	QStringList arglist = RKSettingsModuleR::getOptionList();
+ 	char *argv[arglist.count ()];
+ 	int argc = 0;
+ 	QStringList::iterator it;
+ 	for (it = arglist.begin (); it != arglist.end (); ++it) {
+ 		argv[argc] = qstrdup ((*it).latin1 ());
+ 		argc++;
+ 	}
+ 	
+ 	startR (r_home, argc, argv);
+ 
+ 	for (--argc; argc >= 0; --argc) {
+ 		delete argv[argc];
+ 	}
+ 
+ 	connectCallbacks ();
+ 
+ 	RKWardRError error;
+ 	int status = 0;
+ 	
+ 	runCommandInternal ("library (\"rkward\")\n", &error);
+ 	if (error) status |= LibLoadFail;
+ 	QStringList list = RKSettingsModuleR::getPackageRepositories ();
+ 	QString command = "options (repos=c(";
+ 	for (QStringList::const_iterator it = list.begin (); it != list.end (); ++it) {
+ 		if (it != list.begin ()) {
+ 			command.append (", ");
+ 		}
+ 		command.append ("\"" + *it + "\"");
+ 	}
+ 	runCommandInternal (command + "))\n", &error);
+ 	if (error) status |= OtherFail;
+ 	runCommandInternal ("options (error=quote (.rk.do.error ()))\n", &error);
+ 	if (error) status |= SinkFail;
+ /*	runCommandInternal (".rk.init.handlers ()\n", &error);
+ 	if (error) status |= SinkFail; */
+ 	runCommandInternal ("options (htmlhelp=TRUE); options (browser=\"dcop " + kapp->dcopClient ()->appId () + " rkwardapp openHTMLHelp \")", &error);
+ 	if (error) status |= OtherFail;
+ 	// TODO: error-handling?
+ 
+ 	return status;
+ }

Index: rcommand.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rcommand.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -C2 -d -r1.15 -r1.16
*** rcommand.h	23 Sep 2005 14:29:47 -0000	1.15
--- rcommand.h	23 Sep 2005 17:19:30 -0000	1.16
***************
*** 202,206 ****
  	int getFlags () { return (_flags); };
  private:
! friend class REmbed;
  friend class RInterface;
  /** internal function will be called by the backend, as the command gets passed through. Takes care of sending this command (back) to its receiver */
--- 202,206 ----
  	int getFlags () { return (_flags); };
  private:
! friend class RThread;
  friend class RInterface;
  /** internal function will be called by the backend, as the command gets passed through. Takes care of sending this command (back) to its receiver */





More information about the rkward-tracker mailing list