[rkward-cvs] SF.net SVN: rkward-code:[4708] trunk/rkward/rkward

tfry at users.sf.net tfry at users.sf.net
Mon Apr 22 19:02:19 UTC 2013


Revision: 4708
          http://sourceforge.net/p/rkward/code/4708
Author:   tfry
Date:     2013-04-22 19:02:17 +0000 (Mon, 22 Apr 2013)
Log Message:
-----------
Finish initial implementation of priority commands, and implement RK() device resize-handling on top of this.
So far this uses R_PolledEvents() for our hook into R's event loop. However, this is not perfect at least on Unix.
E.g. R_PolledEvents() does not get called during Sys.sleep() (and probably other select()s).

On Unix, it may be a better idea to use an input handler listening on a pipe. Not tested on Windows, yet.

Modified Paths:
--------------
    trunk/rkward/rkward/rbackend/rinterface.cpp
    trunk/rkward/rkward/rbackend/rinterface.h
    trunk/rkward/rkward/rbackend/rkbackendtransmitter.cpp
    trunk/rkward/rkward/rbackend/rkrbackend.cpp
    trunk/rkward/rkward/rbackend/rkrbackend.h
    trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.cpp
    trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h
    trunk/rkward/rkward/rbackend/rktransmitter.cpp
    trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
    trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
    trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
    trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
    trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
    trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal_graphics.R
    trunk/rkward/rkward/settings/rksettingsmodulewatch.cpp

Modified: trunk/rkward/rkward/rbackend/rinterface.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.cpp	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rinterface.cpp	2013-04-22 19:02:17 UTC (rev 4708)
@@ -151,6 +151,22 @@
 	return 0;
 }
 
+RCommandChain* RInterface::openSubcommandChain (RCommand* parent_command) {
+	RK_TRACE (RBACKEND);
+
+	current_commands_with_subcommands.append (parent_command);
+	return RCommandStack::startChain (parent_command);
+}
+
+void RInterface::closeSubcommandChain (RCommand* parent_command) {
+	RK_TRACE (RBACKEND);
+
+	if (current_commands_with_subcommands.contains (parent_command)) {
+		current_commands_with_subcommands.removeAll (parent_command);
+		doNextCommand (0);
+	}
+}
+
 void RInterface::tryNextCommand () {
 	RK_TRACE (RBACKEND);
 	RCommand *command = RCommandStack::currentCommand ();
@@ -164,8 +180,8 @@
 	bool priority = command && (command->type () & RCommand::PriorityCommand);
 	bool on_top_level = all_current_commands.isEmpty ();
 	if (!(on_top_level && locked && !(priority))) {                                     // do not respect locks for sub-commands
-		if (!on_top_level && all_current_commands.contains (command)) {  // all sub-commands of the current command have finished
-			doNextCommand (0);
+		if ((!on_top_level) && all_current_commands.contains (command)) {  // all sub-commands of the current command have finished, it became the top-most item of the RCommandStack, again
+			closeSubcommandChain (command);
 			return;
 		}
 
@@ -352,7 +368,7 @@
 		// The reason for doing it this way, instead of the reverse, is that this allows the backend thread / process to continue working, concurrently
 		// NOTE: cproxy should only ever be 0 in the very first cycle
 		if (cproxy) command = popPreviousCommand (cproxy->id);
-		command_requests.append (request);
+		if (request->synchronous) command_requests.append (request);
 		tryNextCommand ();
 		if (cproxy) {
 			RK_ASSERT (command);
@@ -371,7 +387,7 @@
 		startup_errors = request->params["message"].toString ();
 
 		command_requests.append (request);
-		RCommandChain *chain = RCommandStack::startChain (runningCommand ());
+		RCommandChain *chain = openSubcommandChain (runningCommand ());
 
 		issueCommand ("paste (R.version[c (\"major\", \"minor\")], collapse=\".\")\n", RCommand::GetStringVector | RCommand::App | RCommand::Sync, QString (), this, GET_R_VERSION, chain);
 		// find out about standard library locations
@@ -657,7 +673,7 @@
 		current_command = new RCommand (QString (), RCommand::App | RCommand::EmptyCommand | RCommand::Sync);
 		issueCommand (current_command);
 	}
-	in_chain = startChain (current_command);
+	in_chain = openSubcommandChain (current_command);
 
 	QString call = calllist.value (0);
 	if (call == "sync") {

Modified: trunk/rkward/rkward/rbackend/rinterface.h
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.h	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rinterface.h	2013-04-22 19:02:17 UTC (rev 4708)
@@ -105,6 +105,10 @@
 	void handleCommandOut (RCommand *command);
 	bool previously_idle;
 
+	RCommandChain* openSubcommandChain (RCommand *parent_command);
+	QList<RCommand *> current_commands_with_subcommands;
+	void closeSubcommandChain (RCommand *parent_command);
+
 /** @see locked */
 	enum LockType {
 		User=1		/**< locked on user request */

Modified: trunk/rkward/rkward/rbackend/rkbackendtransmitter.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkbackendtransmitter.cpp	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rkbackendtransmitter.cpp	2013-04-22 19:02:17 UTC (rev 4708)
@@ -2,7 +2,7 @@
                           rkbackendtransmitter  -  description
                              -------------------
     begin                : Thu Nov 18 2010
-    copyright            : (C) 2010 by Thomas Friedrichsmeier
+    copyright            : (C) 2010, 2013 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -90,14 +90,25 @@
 	// first check for requests which originated in the frontend
 	if (request->type == RBackendRequest::Interrupt) {
 		RKRBackend::this_pointer->interruptCommand (request->params.value ("commandid", -1).toInt ());
-	// requests which originated in the backend below this line
-	} else {
+	} else if (request->type == RBackendRequest::PriorityCommand) {
+		RKRBackend::this_pointer->setPriorityCommand (request->takeCommand ());
+	} else {    // requests which originated in the backend below this line
 		if (current_sync_requests.isEmpty ()) {
 			RK_ASSERT (false);
 			return;
 		}
 
-		RBackendRequest* current_sync_request = current_sync_requests.takeFirst ();
+		// "Synchronous" requests are not necessarily answered in the order they have been queued
+		int id = request->id;
+		RBackendRequest* current_sync_request = 0;
+		for (int i = current_sync_requests.size () - 1; i >= 0; --i) {
+			RBackendRequest *candidate = current_sync_requests[i];
+			if (id == candidate->id) {
+				current_sync_request = current_sync_requests.takeAt (i);
+				break;
+			}
+		}
+		RK_ASSERT (current_sync_request);
 		if (current_sync_request->type == RBackendRequest::Output) {
 			delete current_sync_request;	// this was just our internal request
 		} else {

Modified: trunk/rkward/rkward/rbackend/rkrbackend.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackend.cpp	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rkrbackend.cpp	2013-04-22 19:02:17 UTC (rev 4708)
@@ -2,7 +2,7 @@
                           rkrbackend  -  description
                              -------------------
     begin                : Sun Jul 25 2004
-    copyright            : (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 by Thomas Friedrichsmeier
+    copyright            : (C) 2004 - 2013 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -456,6 +456,7 @@
 
 void RWriteConsoleEx (const char *buf, int buflen, int type) {
 	RK_TRACE (RBACKEND);
+	RK_DEBUG (RBACKEND, DL_DEBUG, "raw output type %d, size %d: %s", type, buflen, buf);
 
 	// output while nothing else is running (including handlers?) -> This may be a syntax error.
 	if ((RKRBackend::repl_status.eval_depth == 0) && (!RKRBackend::repl_status.browser_context) && (!RKRBackend::this_pointer->isKilled ())) {
@@ -751,6 +752,7 @@
 	r_running = false;
 
 	current_command = 0;
+	pending_priority_command = 0;
 	stdout_stderr_fd = -1;
 
 	RK_ASSERT (this_pointer == 0);
@@ -997,6 +999,9 @@
 }
 
 SEXP RKStartGraphicsDevice (SEXP width, SEXP height, SEXP pointsize, SEXP family, SEXP bg, SEXP title, SEXP antialias);
+SEXP RKD_AdjustSize (SEXP devnum);
+void doPendingPriorityCommands ();
+void (* old_R_PolledEvents)(void);
 
 bool RKRBackend::startR () {
 	RK_TRACE (RBACKEND);
@@ -1019,7 +1024,8 @@
 #ifndef Q_OS_WIN
 	// re-direct stdout / stderr to a pipe, so we can read output from system() calls
 	int pfd[2];
-	pipe (pfd);
+	int error = pipe (pfd);
+	RK_ASSERT (!error);	// mostly to silence compile time warning about unused return value
 	dup2 (pfd[1], STDOUT_FILENO);
 	dup2 (pfd[1], STDERR_FILENO);		// forward both to a single channel to avoid interleaving hell, for now.
 	close (pfd[1]);
@@ -1072,12 +1078,15 @@
 		{ "rk.update.locale", (DL_FUNC) &doUpdateLocale, 0 },
 		{ "rk.locale.name", (DL_FUNC) &doLocaleName, 0 },
 		{ "rk.graphics.device", (DL_FUNC) &RKStartGraphicsDevice, 7},
+		{ "rk.graphics.device.resize", (DL_FUNC) &RKD_AdjustSize, 1},
 		{ 0, 0, 0 }
 	};
 	R_registerRoutines (R_getEmbeddingDllInfo(), NULL, callMethods, NULL, NULL);
 
 	connectCallbacks();
 	RKInsertToplevelStatementFinishedCallback (0);
+	old_R_PolledEvents = R_PolledEvents;
+	R_PolledEvents = doPendingPriorityCommands;
 	default_global_context = R_GlobalContext;
 
 	// get info on R runtime version
@@ -1324,6 +1333,37 @@
 	}
 }
 
+void RKRBackend::setPriorityCommand (RCommandProxy* command) {
+	RK_TRACE (RBACKEND);
+	QMutexLocker lock (&priority_command_mutex);
+	RK_ASSERT (!(command && pending_priority_command));      // for the time being, we support only one priority command at a time
+	pending_priority_command = command;
+}
+
+void doPendingPriorityCommands () {
+	RK_TRACE (RBACKEND);
+
+	RCommandProxy *command = RKRBackend::this_pointer->pending_priority_command;
+	if (command) {
+		RK_DEBUG (RBACKEND, DL_DEBUG, "running priority command %s", qPrintable (command->command));
+		RKRBackend::this_pointer->setPriorityCommand (0);
+		{
+			QMutexLocker lock (&RKRBackend::this_pointer->all_current_commands_mutex);
+			RKRBackend::this_pointer->all_current_commands.append (command);
+			RKRBackend::this_pointer->current_command = command;
+		}
+
+		RKRBackend::this_pointer->runCommand (command);
+		RKRBackend::this_pointer->commandFinished (false);
+		// TODO: Oh boy, what a mess. Sending notifications should be split from fetchNextCommand() (which is not appropriate, here)
+		RBackendRequest req (false, RBackendRequest::CommandOut);      // NOTE: We do *NOT* want a reply to this one, and in particular, we do *NOT* want to do 
+		                                                               // (recursive) event processing while handling this.
+		req.command = command;
+		RKRBackend::this_pointer->handleRequest (&req);
+	}
+	if (old_R_PolledEvents) old_R_PolledEvents ();
+}
+
 // On Windows, using runDirectCommand (".rk.cat.output ...") is not safe during some places where we call this, e.g. in RBusy.
 // Not a problem on Linux with R 2.13.0, though
 void RKRBackend::catToOutputFile (const QString &out) {
@@ -1440,6 +1480,8 @@
 		if (!request->done) RKRBackendProtocolBackend::msleep (++i < 200 ? 10 : 50);
 	}
 
+	while (pending_priority_command) processX11Events ();  // Probably not needed, but make sure to process priority commands first at all times.
+
 	RCommandProxy* command = request->takeCommand ();
 	if (!command) return 0;
 

Modified: trunk/rkward/rkward/rbackend/rkrbackend.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackend.h	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rkrbackend.h	2013-04-22 19:02:17 UTC (rev 4708)
@@ -2,7 +2,7 @@
                           rkrbackend  -  description
                              -------------------
     begin                : Sun Jul 25 2004
-    copyright            : (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 by Thomas Friedrichsmeier
+    copyright            : (C) 2004 - 2013 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -194,6 +194,10 @@
 	bool fetchStdoutStderr (bool forcibly);
 /** public for technical reasons */
 	QMutex stdout_stderr_mutex;
+
+	void setPriorityCommand (RCommandProxy *command);
+	RCommandProxy *pending_priority_command;
+	QMutex priority_command_mutex;
 private:
 	void clearPendingInterrupt ();
 protected:

Modified: trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.cpp	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.cpp	2013-04-22 19:02:17 UTC (rev 4708)
@@ -2,7 +2,7 @@
                           rkrbackendprotocol  -  description
                              -------------------
     begin                : Thu Nov 04 2010
-    copyright            : (C) 2010, 2011 by Thomas Friedrichsmeier
+    copyright            : (C) 2010, 2011, 2013 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -35,11 +35,13 @@
 }
 
 
+int RBackendRequest::_id = 0;
 RBackendRequest::RBackendRequest (bool synchronous, RCallbackType type) {
 	RK_TRACE (RBACKEND);
 
 	RBackendRequest::synchronous = synchronous;
 	RBackendRequest::type = type;
+	id = ++_id;
 	done = false;
 	command = 0;
 	output = 0;
@@ -55,6 +57,7 @@
 void RBackendRequest::mergeReply (RBackendRequest *reply) {
 	RK_TRACE (RBACKEND);
 
+	RK_ASSERT (reply->id == id);
 	command = reply->command;
 	params = reply->params;
 	output = reply->output;
@@ -66,6 +69,8 @@
 	RK_TRACE (RBACKEND);
 
 	RBackendRequest* ret = new RBackendRequest (synchronous, type);
+	--_id;   // for pretty, consecutive numbering
+	ret->id = id;
 	ret->done = done;
 	ret->command = command;
 	ret->params = params;

Modified: trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h	2013-04-22 19:02:17 UTC (rev 4708)
@@ -2,7 +2,7 @@
                           rkrbackendprotocol  -  description
                              -------------------
     begin                : Thu Nov 04 2010
-    copyright            : (C) 2010, 2011 by Thomas Friedrichsmeier
+    copyright            : (C) 2010, 2011, 2013 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -32,17 +32,17 @@
 		ShowFiles,
 		ChooseFile,
 		EditFiles,
-		ReadLine,
+		ReadLine,      // 5
 		CommandOut,
 		Started,
 		EvalRequest,
 		CallbackRequest,
-		HistoricalSubstackRequest,
+		HistoricalSubstackRequest,   // 10
 		PlainGenericRequest,
 		SetParamsFromBackend,
 		Debugger,
 		CommandLineIn,	/**< The next line of the current user command has been submitted in the backend. */
-		Output,		/**< A piece of output. Note: If the backend runs in a single process, output is handled in a pull fashion, instead of using requests. */
+		Output,		/**< A piece of output. Note: If the backend runs in a single process, output is handled in a pull fashion, instead of using requests. */  //15
 		Interrupt,	/**< Interrupt evaluation. This request type originates in the frontend, not the backend. */
 		PriorityCommand, /**< Send a command to be run during R's event processing. This request type originates in the frontend, not the backend. */
 		OutputStartedNotification, /**< Only used in the frontend: Notification that a new bit of output has arrived. Used to trigger flushing after a timeout. */
@@ -68,6 +68,8 @@
 	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 volatile done;
+	int id;
+	static int _id;
 	RCallbackType type;
 /** For synchronous requests, only: If 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;

Modified: trunk/rkward/rkward/rbackend/rktransmitter.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rktransmitter.cpp	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rktransmitter.cpp	2013-04-22 19:02:17 UTC (rev 4708)
@@ -22,6 +22,7 @@
 void RKRBackendSerializer::serialize (const RBackendRequest &request, QDataStream &stream) {
 	RK_TRACE (RBACKEND);
 
+	stream << (qint16) request.id;
 	stream << (qint8) request.type;
 	stream << request.synchronous;
 	stream << request.done;		// well, not really needed, but...
@@ -45,9 +46,13 @@
 	RK_TRACE (RBACKEND);
 
 	RBackendRequest *request = new RBackendRequest (false, RBackendRequest::OtherRequest);		// will be overwritten
+	RBackendRequest::_id--;
 
 	bool dummyb;
 	qint8 dummy8;
+	qint16 dummy16;
+	stream >> dummy16;
+	request->id = dummy16;
 	stream >> dummy8;
 	request->type = (RBackendRequest::RCallbackType) dummy8;
 	stream >> request->synchronous;

Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp	2013-04-22 19:02:17 UTC (rev 4708)
@@ -28,6 +28,8 @@
 #include <kdialog.h>
 
 #include "rkgraphicsdevice_protocol_shared.h"
+#include "../rinterface.h"
+#include "../../rkglobals.h"
 
 #include "../../debug.h"
 
@@ -40,13 +42,14 @@
 
 	interaction_opcode = -1;
 	dialog = 0;
-	if (antialias) painter.setRenderHints (QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
 	view = new QLabel ();
 	view->installEventFilter (this);
+	view->setScaledContents (true);    // this is just for preview during scaling. The area will be re-sized and re-drawn from R.
 	connect (view, SIGNAL (destroyed(QObject*)), this, SLOT (viewKilled()));
 	connect (&updatetimer, SIGNAL (timeout ()), this, SLOT (updateNow ()));
 	updatetimer.setSingleShot (true);
 	clear ();
+	if (antialias) painter.setRenderHints (QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
 	setActive (true);	// sets window title
 }
 
@@ -74,6 +77,9 @@
 		view->resize (area.size ());
 		view->show ();
 	}
+	if (view->size () != area.size ()) {
+		RKGlobals::rInterface ()->issueCommand (new RCommand ("rkward:::RK.resize (" + QString::number (devices.key (this) + 1) + ")", RCommand::PriorityCommand));
+	}
 	painter.begin (&area);
 }
 
@@ -106,6 +112,13 @@
 	setClip (area.rect ());	// R's devX11.c resets clip on clear, so we do this, too.
 }
 
+void RKGraphicsDevice::setAreaSize (const QSize& size) {
+	if (painter.isActive ()) painter.end ();
+	RK_DEBUG (GRAPHICS_DEVICE, DL_WARNING, "New Size %d, %d (view size is %d, %d)", size.width (), size.height (), view->width (), view->height ());
+	area = QPixmap (size.width (), size.height ());
+	clear ();
+}
+
 void RKGraphicsDevice::setClip (const QRectF& new_clip) {
 	RK_TRACE (GRAPHICS_DEVICE);
 
@@ -270,6 +283,7 @@
 			return true;
 		}
 	}
+	if (event->type () == QEvent::Resize) triggerUpdate ();
 
 	return false;
 }

Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h	2013-04-22 19:02:17 UTC (rev 4708)
@@ -56,6 +56,8 @@
 	void confirmNewPage ();
 
  	QWidget* viewPort () const { return view; };
+	QSizeF currentSize () const { return view->size (); }
+	void setAreaSize (const QSize &size);
 public slots:
 	void stopInteraction ();
 signals:

Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp	2013-04-22 19:02:17 UTC (rev 4708)
@@ -288,6 +288,13 @@
 				}
 			}
 			streamer.writeOutBuffer ();
+		} else if (opcode == RKDGetSize) {
+			streamer.outstream << device->currentSize ();
+			streamer.writeOutBuffer ();
+		} else if (opcode == RKDSetSize) {
+			QSize size;
+			streamer.instream >> size;
+			device->setAreaSize (size);
 		} else if (opcode == RKDLocator) {
 			device->locator ();
 #warning TODO keep track of status
@@ -322,6 +329,8 @@
 	} else if (opcode == RKDStrWidthUTF8) {
 		double width = 1;
 		streamer.outstream << width;
+	} else if (opcode == RKDGetSize) {
+		streamer.outstream << QSizeF ();
 	} else {
 		return;	// nothing to write
 	}

Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h	2013-04-22 19:02:17 UTC (rev 4708)
@@ -62,31 +62,33 @@
 
 enum RKDOpcodes {
 	// Asynchronous operations
-	RKDCreate,     // 0
+	RKDCreate,          // 0
 	RKDCircle,
 	RKDLine,
 	RKDPolygon,
 	RKDPolyline,
-	RKDRect,       // 5
+	RKDRect,            // 5
 	RKDTextUTF8,
 	RKDNewPage,
 	RKDClose,
 	RKDActivate,
-	RKDDeActivate, // 10
+	RKDDeActivate,      // 10
 	RKDClip,
 	RKDMode,
 	RKDRaster,
+	RKDSetSize,
 
 	// Synchronous operations
-	RKDStrWidthUTF8,
-	RKDMetricInfo, // 15
+	RKDStrWidthUTF8,    // 15
+	RKDMetricInfo, 
 	RKDLocator,
 	RKDNewPageConfirm,
 	RKDCapture,
-	RKDQueryResolution,
+	RKDQueryResolution, // 20
+	RKDGetSize,    
 
 	// Protocol operations
-	RKDCancel      // 20
+	RKDCancel
 };
 
 #include <QtGlobal>

Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp	2013-04-22 19:02:17 UTC (rev 4708)
@@ -120,6 +120,7 @@
 };
 
 #include <QRectF>
+#include <QSizeF>
 
 // This ought to be optimized away by the compiler:
 #define SAFE_LINE_END(lend) (quint8) (lend == GE_ROUND_CAP ? RoundLineCap : (lend == GE_BUTT_CAP ? ButtLineCap : SquareLineCap))
@@ -165,14 +166,44 @@
 	RKD_OUT_STREAM << width << height << QString::fromUtf8 (title) << antialias;
 }
 
-// TODO: Handle resizes
 static void RKD_Size (double *left, double *right, double *top, double *bottom, pDevDesc dev) {
+// NOTE: This does *not* query the frontend for the current size. This is only done on request
 	*left = dev->left;
 	*top = dev->top;
 	*right = dev->right;
 	*bottom = dev->bottom;
 }
 
+static void RKD_SetSize (pDevDesc dev) {
+	RKGraphicsDataStreamWriteGuard wguard;
+	WRITE_HEADER (RKDSetSize, dev);
+	RKD_OUT_STREAM << QSize (qAbs (dev->right - dev->left) + .2, qAbs (dev->bottom - dev->top) + .2);
+}
+
+SEXP RKD_AdjustSize (SEXP _devnum) {
+	int devnum = Rf_asInteger (_devnum);
+	pGEDevDesc gdev = GEgetDevice (devnum);
+	if (!gdev) Rf_error ("No such device %d", devnum);
+	pDevDesc dev = gdev->dev;
+	{
+		RKGraphicsDataStreamWriteGuard wguard;
+		WRITE_HEADER (RKDGetSize, dev);
+	}
+	QSizeF size;
+	{
+		RKGraphicsDataStreamReadGuard rguard;
+		RKD_IN_STREAM >> size;
+	}
+	if (size.isNull ()) Rf_error ("Could not determine current size of device %d. Not an RK device?", devnum);
+	dev->left = dev->top = 0;
+	dev->right = size.width ();
+	dev->bottom = size.height ();
+
+	RKD_SetSize (dev);    // This adjusts the rendering area in the frontend
+	GEplayDisplayList (gdev);
+	return R_NilValue;
+}
+
 static void RKD_Circle (double x, double y, double r, R_GE_gcontext *gc, pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
 	WRITE_HEADER (RKDCircle, dev);

Modified: trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal_graphics.R
===================================================================
--- trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal_graphics.R	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal_graphics.R	2013-04-22 19:02:17 UTC (rev 4708)
@@ -32,6 +32,11 @@
 	invisible (x)
 }
 
+# Fetch the current size of the given RK() device from the frontend, and redraw
+"RK.resize" <- function (devnum) {
+	.Call ("rk.graphics.device.resize", as.integer (devnum)-1, PACKAGE="(embedding)")
+}
+
 #' @export
 "x11" <- rk.screen.device
 

Modified: trunk/rkward/rkward/settings/rksettingsmodulewatch.cpp
===================================================================
--- trunk/rkward/rkward/settings/rksettingsmodulewatch.cpp	2013-04-21 18:26:22 UTC (rev 4707)
+++ trunk/rkward/rkward/settings/rksettingsmodulewatch.cpp	2013-04-22 19:02:17 UTC (rev 4708)
@@ -45,7 +45,7 @@
 
 	if (command->type () & RCommand::EmptyCommand) return false;
 	
-	if (command->type () & RCommand::Sync) {
+	if (command->type () & (RCommand::Sync | RCommand::PriorityCommand)) {
 		return (sync_filter & ShowInput);
 	} else if (command->type () & RCommand::User) {
 		return (user_filter & ShowInput);
@@ -66,7 +66,7 @@
 	if (command->type () & RCommand::EmptyCommand) return false;
 	if (!shouldShowInput (command)) return false;
 
-	if (command->type () & RCommand::Sync) {
+	if (command->type () & (RCommand::Sync | RCommand::PriorityCommand)) {
 		return (sync_filter & ShowOutput);
 	} else if (command->type () & RCommand::User) {
 		return (user_filter & ShowOutput);
@@ -84,7 +84,7 @@
 bool RKSettingsModuleWatch::shouldShowError (RCommand *command) {
 	RK_TRACE (SETTINGS);
 
-	if (command->type () & RCommand::Sync) {
+	if (command->type () & (RCommand::Sync | RCommand::PriorityCommand)) {
 		return (sync_filter & ShowError);
 	} else if (command->type () & RCommand::User) {
 		return (user_filter & ShowError);
@@ -101,7 +101,7 @@
 bool RKSettingsModuleWatch::shouldRaiseWindow (RCommand *command) {
 	RK_TRACE (SETTINGS);
 
-	if (command->type () & RCommand::Sync) {
+	if (command->type () & (RCommand::Sync | RCommand::PriorityCommand)) {
 		return (sync_filter & RaiseWindow);
 	} else if (command->type () & RCommand::User) {
 		return (user_filter & RaiseWindow);





More information about the rkward-tracker mailing list