[rkward-cvs] SF.net SVN: rkward-code:[4639] branches/development_branches/ rkward_graphpics_device/rkward

tfry at users.sf.net tfry at users.sf.net
Thu Mar 28 17:51:55 UTC 2013


Revision: 4639
          http://sourceforge.net/p/rkward/code/4639
Author:   tfry
Date:     2013-03-28 17:51:54 +0000 (Thu, 28 Mar 2013)
Log Message:
-----------
Handle more device creation params. Fix debug flags. Implement locator(), and cancellation of interactive ops.

Modified Paths:
--------------
    branches/development_branches/rkward_graphpics_device/rkward/debug.h
    branches/development_branches/rkward_graphpics_device/rkward/main.cpp
    branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkrbackendprotocol_backend.cpp
    branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
    branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
    branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.cpp
    branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
    branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.h
    branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
    branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
    branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp

Modified: branches/development_branches/rkward_graphpics_device/rkward/debug.h
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/debug.h	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/debug.h	2013-03-28 17:51:54 UTC (rev 4639)
@@ -44,13 +44,13 @@
 #define OUTPUT 1 << 10
 #define XML 1 << 11
 #define GRAPHICS_DEVICE 1 << 12
-#define ALL (APP | PLUGIN | PHP | OBJECTS | EDITOR | RBACKEND | COMMANDEDITOR | MISC | DIALOGS | OUTPUT | XML)
+#define DEBUG_ALL (APP | PLUGIN | PHP | OBJECTS | EDITOR | RBACKEND | COMMANDEDITOR | MISC | DIALOGS | OUTPUT | XML | GRAPHICS_DEVICE)
 
 #ifdef RKWARD_DEBUG
 // Debug functions 
 #	define RK_DO(expr,flags,level) if ((flags & RK_Debug_Flags) && (level >= RK_Debug_Level)) { expr; }
 #	define RK_DEBUG(flags,level,...) { if ((flags & RK_Debug_Flags) && (level >= RK_Debug_Level)) RKDebug (flags,level,__VA_ARGS__); }
-#	define RK_ASSERT(x) if (!(x)) RK_DEBUG (ALL, DL_FATAL, "Assert '%s' failed at %s - function %s line %d", #x, __FILE__, __FUNCTION__, __LINE__);
+#	define RK_ASSERT(x) if (!(x)) RK_DEBUG (DEBUG_ALL, DL_FATAL, "Assert '%s' failed at %s - function %s line %d", #x, __FILE__, __FUNCTION__, __LINE__);
 #	ifndef RKWARD_NO_TRACE
 #		define RK_TRACE(flags) RK_DEBUG (flags, DL_TRACE, "Trace: %s - function %s line %d", __FILE__, __FUNCTION__, __LINE__);
 #	else

Modified: branches/development_branches/rkward_graphpics_device/rkward/main.cpp
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/main.cpp	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/main.cpp	2013-03-28 17:51:54 UTC (rev 4639)
@@ -78,7 +78,7 @@
 #include "version.h"
 
 int RK_Debug_Level = 0;
-int RK_Debug_Flags = ALL;
+int RK_Debug_Flags = DEBUG_ALL;
 int RK_Debug_CommandStep = 0;
 QMutex RK_Debug_Mutex;
 
@@ -120,7 +120,7 @@
 #endif */
 	options.add ("evaluate <Rcode>", ki18n ("After starting (and after loading the specified workspace, if applicable), evaluate the given R code."), 0);
 	options.add ("debug-level <level>", ki18n ("Verbosity of debug messages (0-5)"), "2");
-	options.add ("debug-flags <flags>", ki18n ("Mask for components to debug (see debug.h)"), "8191");
+	options.add ("debug-flags <flags>", ki18n ("Mask for components to debug (see debug.h)"), QString::number (DEBUG_ALL).toLocal8Bit ());
 	options.add ("debugger <command>", ki18n ("Debugger (enclose any debugger arguments in single quotes ('') together with the command)"), "");
 	options.add ("+[File]", ki18n ("R workspace file to open"), 0);
 
@@ -160,7 +160,7 @@
 	RK_Debug_Level = DL_FATAL - QString (args->getOption ("debug-level")).toInt ();
 	RK_Debug_Flags = QString (args->getOption ("debug-flags")).toInt ();
 	if (!args->getOption ("debugger").isEmpty ()) {
-		RK_DEBUG (ALL, DL_ERROR, "--debugger option should have been handled by wrapper script. Ignoring.");
+		RK_DEBUG (DEBUG_ALL, DL_ERROR, "--debugger option should have been handled by wrapper script. Ignoring.");
 	}
 
 	RKWardStartupOptions *stoptions = new RKWardStartupOptions;

Modified: branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkrbackendprotocol_backend.cpp
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkrbackendprotocol_backend.cpp	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkrbackendprotocol_backend.cpp	2013-03-28 17:51:54 UTC (rev 4639)
@@ -85,7 +85,7 @@
 
 	extern "C" void RK_setupGettext (const char*);
 	int RK_Debug_Level = 2;
-	int RK_Debug_Flags = ALL;
+	int RK_Debug_Flags = DEBUG_ALL;
 	QMutex RK_Debug_Mutex;
 	QTemporaryFile* RK_Debug_File;
 

Modified: branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp	2013-03-28 17:51:54 UTC (rev 4639)
@@ -20,22 +20,31 @@
 #include <QGraphicsScene>
 #include <QGraphicsView>
 #include <QGraphicsRectItem>
-#include <qmath.h>
+#include <QPushButton>
+#include <QHBoxLayout>
+#include <QMouseEvent>
 #include <klocale.h>
+#include <sys/stat.h>
 
+#include "rkgraphicsdevice_protocol_shared.h"
+
 #include "../../debug.h"
 
 #define UPDATE_INTERVAL 100
 
 QHash<int, RKGraphicsDevice*> RKGraphicsDevice::devices;
 
-RKGraphicsDevice::RKGraphicsDevice (double width, double height) : QObject (), area (qAbs (width) + 1, qAbs (height) + 1) {
+RKGraphicsDevice::RKGraphicsDevice (double width, double height, const QString &title, bool antialias) : QObject (), area (qAbs (width) + 1, qAbs (height) + 1), base_title (title) {
 	RK_TRACE (GRAPHICS_DEVICE);
-	painter.setRenderHints (QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
+
+	interaction_opcode = -1;
+	if (antialias) painter.setRenderHints (QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
 	view = new QLabel ();
+	view->installEventFilter (this);
 	connect (&updatetimer, SIGNAL (timeout ()), this, SLOT (updateNow ()));
 	updatetimer.setSingleShot (true);
 	clear ();
+	setActive (true);	// sets window title
 }
 
 RKGraphicsDevice::~RKGraphicsDevice () {
@@ -58,14 +67,14 @@
 	painter.begin (&area);
 }
 
-RKGraphicsDevice* RKGraphicsDevice::newDevice (int devnum, double width, double height) {
+RKGraphicsDevice* RKGraphicsDevice::newDevice (int devnum, double width, double height, const QString &title, bool antialias) {
 	RK_TRACE (GRAPHICS_DEVICE);
 
 	if (devices.contains (devnum)) {
 		RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Graphics device number %d already exists while trying to create it", devnum);
 		closeDevice (devnum);
 	}
-	RKGraphicsDevice* dev = new RKGraphicsDevice (width, height);
+	RKGraphicsDevice* dev = new RKGraphicsDevice (width, height, title.isEmpty () ? i18n ("Graphics Device Number %1").arg (QString (devnum+1)) : title, antialias);
 	devices.insert (devnum, dev);
 	return (dev);
 }
@@ -171,7 +180,48 @@
 
 void RKGraphicsDevice::setActive (bool active) {
 	RK_TRACE (GRAPHICS_DEVICE);
+
+	if (active) view->setWindowTitle (i18n ("%1 (Active)").arg (base_title));
+	else view->setWindowTitle (i18n ("%1 (Inactive)").arg (base_title));
 	emit (activeChanged (active));
 }
 
+void RKGraphicsDevice::locator () {
+	RK_TRACE (GRAPHICS_DEVICE);
+
+	interaction_opcode = RKDLocator;
+
+	view->setCursor (Qt::CrossCursor);
+	view->setToolTip (i18n ("<h2>Locating point(s)</h2><p>Use left mouse button to select point(s). Any other mouse button to stop.</p>"));
+}
+
+bool RKGraphicsDevice::eventFilter (QObject *watched, QEvent *event) {
+	RK_ASSERT (watched == view);
+
+	if (interaction_opcode == RKDLocator) {
+		if (event->type () == QEvent::MouseButtonRelease) {
+			QMouseEvent *me = static_cast<QMouseEvent*> (event);
+			if (me->button () == Qt::LeftButton) {
+				emit (locatorDone (true, me->x (), me->y ()));
+				interaction_opcode = -1;
+			}
+			stopInteraction ();
+			return true;
+		}
+	}
+
+	return false;
+}
+
+void RKGraphicsDevice::stopInteraction () {
+	RK_TRACE (GRAPHICS_DEVICE);
+
+	if (interaction_opcode == RKDLocator) {
+		emit (locatorDone (false, 0.0, 0.0));
+	}
+	view->setCursor (Qt::ArrowCursor);
+	view->setToolTip (QString ());
+	interaction_opcode = -1;
+}
+
 #include "rkgraphicsdevice.moc"

Modified: branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h	2013-03-28 17:51:54 UTC (rev 4639)
@@ -29,10 +29,10 @@
 class RKGraphicsDevice : public QObject {
 	Q_OBJECT
 protected:
-	RKGraphicsDevice (double width, double height);
+	RKGraphicsDevice (double width, double height, const QString &title, bool antialias);
 	~RKGraphicsDevice ();
 public:
-	static RKGraphicsDevice* newDevice (int devnum, double width, double height);
+	static RKGraphicsDevice* newDevice (int devnum, double width, double height, const QString &title, bool antialias);
 	static void closeDevice (int devnum);
 	static QHash<int, RKGraphicsDevice*> devices;
 
@@ -48,16 +48,24 @@
 	void clear (const QColor& col=QColor());
 	void setActive (bool active);
 	void triggerUpdate ();
+	void locator ();
+public slots:
+	void stopInteraction ();
 signals:
 	void activeChanged (bool);
+	void locatorDone (bool ok, double x, double y);
 private slots:
 	void updateNow ();
 private:
+	bool eventFilter (QObject *watched, QEvent *event);
+
 	QTimer updatetimer;
 	QPixmap area;
 	QPainter painter;
 	QLabel *view;
-	QWidget *status_overlay;
+	QString base_title;
+
+	int interaction_opcode;	/**< Current interactive operation (from RKDOpcodes enum), or -1 is there is no current interactive operation */
 };
 
 #endif

Modified: branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.cpp
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.cpp	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.cpp	2013-03-28 17:51:54 UTC (rev 4639)
@@ -74,9 +74,9 @@
 
 	while (alive) {
 		msleep (10);	// it's ok to be lazy. If a request expects a reply, RKGraphicsDataStreamReadGuard will take care of pushing everything, itself. Essentially, this thread's job is simply to make sure we don't lag *too* far behind.
-		mutex.lock ();
+/*		mutex.lock ();
 		connection->waitForBytesWritten (100);
-		mutex.unlock ();
+		mutex.unlock (); */
 	}
 
 	RK_TRACE (GRAPHICS_DEVICE);

Modified: branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp	2013-03-28 17:51:54 UTC (rev 4639)
@@ -169,8 +169,12 @@
 		RKGraphicsDevice *device = 0;
 		if (devnum && opcode == RKDCreate) {
 			double width, height;
-			streamer.instream >> width >> height;
-			device = RKGraphicsDevice::newDevice (devnum, width, height);
+			QString title;
+			bool antialias;
+			streamer.instream >> width >> height >> title >> antialias;
+			device = RKGraphicsDevice::newDevice (devnum, width, height, title, antialias);
+			connect (device, SIGNAL (locatorDone(bool,double,double)), this, SLOT (locatorDone(bool,double,double)));
+			connect (this, SIGNAL (stopInteraction()), device, SLOT (stopInteraction()));
 		} else if (devnum) {
 			device = RKGraphicsDevice::devices.value (devnum);
 			if (!device) {
@@ -238,11 +242,14 @@
 			streamer.instream >> m;
 			if (m == 0) device->triggerUpdate ();
 		} else if (opcode == RKDLocator) {
-			RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Unhandled operation of type %d for device number %d. Skippping.", opcode, devnum);
-			sendDummyReply (opcode);
+			device->locator ();
+#warning TODO keep track of status
 		} else if (opcode == RKDNewPageConfirm) {
 			RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Unhandled operation of type %d for device number %d. Skippping.", opcode, devnum);
 			sendDummyReply (opcode);
+		} else if (opcode == RKDCancel) {
+			RK_DEBUG (GRAPHICS_DEVICE, DL_WARNING, "Graphics operation cancelled");
+			emit (stopInteraction());
 		} else {
 			RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Unhandled operation of type %d for device number %d. Skippping.", opcode, devnum);
 		}
@@ -278,5 +285,11 @@
 	streamer.writeOutBuffer ();
 }
 
+void RKGraphicsDeviceFrontendTransmitter::locatorDone (bool ok, double x, double y) {
+	RK_TRACE (GRAPHICS_DEVICE);
 
+	streamer.outstream << ok << x << y;
+	streamer.writeOutBuffer ();
+}
+
 #include "rkgraphicsdevice_frontendtransmitter.moc"

Modified: branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.h
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.h	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.h	2013-03-28 17:51:54 UTC (rev 4639)
@@ -34,6 +34,9 @@
 public slots:
 	void newData ();
 	void newConnection ();
+	void locatorDone (bool ok, double x, double y);
+signals:
+	void stopInteraction ();
 private:
 	void setupServer ();
 	void sendDummyReply (quint8 opcode);

Modified: branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h	2013-03-28 17:51:54 UTC (rev 4639)
@@ -28,13 +28,19 @@
  * even when sending many @em small requests.
  * 
  * All communication is initiated from the backend. The backend sends a request, starting with the size of the
- * request in bytes (quint32), then an opcode, then the device number, then all applicable parameters. Most requests
- * are asynchronous, but a few await a reply from the frontend.
+ * request in bytes (quint32), then an opcode (quint8), then the device number (quint8), then all applicable parameters.
+ * Most requests are asynchronous, but a few await a reply from the frontend.
  * 
  * At any time, there can only be one request waiting for a reply, and the request waiting for a reply is always the most
  * recent one. This makes the protocol very simple.
  * 
  * If the frontend has spontaneous need for communication, it will have to use some separate channel.
+ *
+ * How do we handle cancellation of interactive ops (e.g. locator()) from the backend? If an interrupt is pending
+ * in the backend, _while waiting for the reply_, we push an RKD_Cancel request down the line. This tells the frontend to
+ * send a reply to the last request ASAP (if the frontend has already sent the reply, it will ignore the RKD_Cancel). From
+ * there, we simply process the reply as usual, and leave it to R to actually do the interrupt. If the frontend takes more than
+ * fives seconds to respond at this point, the connection will be killed.
  * 
  */
 
@@ -75,7 +81,10 @@
 	RKDStrWidthUTF8,
 	RKDMetricInfo, // 15
 	RKDLocator,
-	RKDNewPageConfirm
+	RKDNewPageConfirm,
+
+	// Protocol operations
+	RKDCancel
 };
 
 #include <QIODevice>

Modified: branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp	2013-03-28 17:51:54 UTC (rev 4639)
@@ -37,6 +37,7 @@
 #include <R_ext/GraphicsEngine.h>
 }
 
+// rcolor typedef added in R 3.0.0
 #ifndef rcolor
 #define rcolor unsigned int
 #endif
@@ -67,7 +68,6 @@
 	desc->height = height * RKGD_DPI;
 	desc->default_family = family.value (0, "Helvetica");
 	desc->default_symbol_family = family.value (0, "Symbol");
-#warning: Title, antialias
 
 	R_GE_checkVersionOrDie (R_GE_version);
 	R_CheckDeviceAvailable ();
@@ -91,7 +91,7 @@
 
 	if (desc) {
 		desc->devnum = curDevice ();
-		RKD_Create (desc->width, desc->height, dev);
+		RKD_Create (desc->width, desc->height, dev, title, antialias);
 	} else {
 		Rf_error("unable to start device");
 	}

Modified: branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp	2013-03-28 17:19:55 UTC (rev 4638)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp	2013-03-28 17:51:54 UTC (rev 4639)
@@ -34,19 +34,12 @@
 class RKGraphicsDataStreamReadGuard {
 public:
 	RKGraphicsDataStreamReadGuard () {
-#warning TODO: handle cancellation
-/* How shall we handle cancellation? If an interrupt is pending, _while waiting for the reply_, we push an RKD_Cancel
- * request down the line. This tells the frontend to send a reply to the last request ASAP (if the frontend has already sent the reply, it will ignore the RKD_Cancel). From there, we simply process the reply as usual, and leave it to R to actually
- * do the interrupt. */
 		RKGraphicsDeviceBackendTransmitter::mutex.lock ();
 		QIODevice* connection = RKGraphicsDeviceBackendTransmitter::connection;
 		BEGIN_SUSPEND_INTERRUPTS {
 			while (connection->bytesToWrite ()) {
 				if (!connection->waitForBytesWritten (10)) {
-					if (!RKGraphicsDeviceBackendTransmitter::connectionAlive ()) {	// Don't go into endless loop, if e.g. frontend has crashed
-						RKGraphicsDeviceBackendTransmitter::mutex.unlock ();
-						Rf_error ("RKWard Graphics connection has shut down");
-					}
+					checkHandleError ();
 				}
 #warning TODO: Use R_CheckUserInterrupt(), instead?
 				if (connection->bytesToWrite ()) RKRBackend::processX11Events ();
@@ -54,10 +47,8 @@
 			while (!RKGraphicsDeviceBackendTransmitter::streamer.readInBuffer ()) {
 				RKRBackend::processX11Events ();
 				if (!connection->waitForReadyRead (10)) {
-					if (!RKGraphicsDeviceBackendTransmitter::connectionAlive ()) {
-						RKGraphicsDeviceBackendTransmitter::mutex.unlock ();
-						Rf_error ("RKWard Graphics connection has shut down");
-					}
+					if (checkHandleInterrupt (connection)) break;
+					checkHandleError ();
 				}
 			}
 		} END_SUSPEND_INTERRUPTS;
@@ -66,6 +57,37 @@
 	~RKGraphicsDataStreamReadGuard () {
 		RKGraphicsDeviceBackendTransmitter::mutex.unlock ();
 	}
+
+private:
+	bool checkHandleInterrupt (QIODevice *connection) {
+		if (!R_interrupts_pending) return false;
+
+		// Tell the frontend to finish whatever it was doing ASAP. Don't process any other events until that has happened
+		RKGraphicsDeviceBackendTransmitter::streamer.outstream << (quint8) RKDCancel << (quint8) 0;
+		RKGraphicsDeviceBackendTransmitter::streamer.writeOutBuffer ();
+		while (connection->bytesToWrite ()) {
+			if (!connection->waitForBytesWritten (10)) {
+				checkHandleError ();
+			}
+		}
+		int loop = 0;
+		while (!RKGraphicsDeviceBackendTransmitter::streamer.readInBuffer ()) {
+			if (!connection->waitForReadyRead (10)) {
+				if (++loop > 500) {
+					connection->close ();	// If frontend is unresponsive, kill connection
+				}
+				checkHandleError ();
+			}
+		}
+		return true;
+	}
+
+	void checkHandleError () {
+		if (!RKGraphicsDeviceBackendTransmitter::connectionAlive ()) {	// Don't go into endless loop, if e.g. frontend has crashed
+			RKGraphicsDeviceBackendTransmitter::mutex.unlock ();
+			Rf_error ("RKWard Graphics connection has shut down");
+		}
+	}
 };
 
 /** This class is essentially like QMutexLocker. In addition, the destructor takes care of pushing anything that was written to the protocol buffer during it lifetime to the transmitter. (Does NOT wait for the transmission itself). */
@@ -105,10 +127,10 @@
 #define WRITE_FONT(dev) \
 	RKD_OUT_STREAM << gc->cex << gc->ps << gc->lineheight << (quint8) gc->fontface << (gc->fontfamily[0] ? QString (gc->fontfamily) : (static_cast<RKGraphicsDeviceDesc*> (dev->deviceSpecific)->getFontFamily (gc->fontface == 5)))
 
-static void RKD_Create (double width, double height, pDevDesc dev) {
+static void RKD_Create (double width, double height, pDevDesc dev, const char *title, bool antialias) {
 	RKGraphicsDataStreamWriteGuard guard;
 	WRITE_HEADER (RKDCreate, dev);
-	RKD_OUT_STREAM << width << height;
+	RKD_OUT_STREAM << width << height << QString::fromUtf8 (title) << antialias;
 }
 
 static void RKD_Circle (double x, double y, double r, R_GE_gcontext *gc, pDevDesc dev) {





More information about the rkward-tracker mailing list