[rkward-cvs] SF.net SVN: rkward-code:[4628] branches/development_branches/ rkward_graphpics_device/rkward/rbackend/rkwarddevice

tfry at users.sf.net tfry at users.sf.net
Mon Mar 25 18:18:18 UTC 2013


Revision: 4628
          http://sourceforge.net/p/rkward/code/4628
Author:   tfry
Date:     2013-03-25 18:18:17 +0000 (Mon, 25 Mar 2013)
Log Message:
-----------
More bits on the graphics device.
- All drawing ops are now implemented (although I have not tested some things, importantly plotmath)
- Interaction ops, including resizing are still unimplemented
- The QGraphicsScene shows its performance limitations: Everything works smoothly up to around 10,000 points / items. At 100,000 items, the thing becomes completely unusable.
   - I played with optimiazation flags and delayed updates to no real avail
   - One successful attempt was rendering every 5k or 10k items to a pixmap.
   - Of course this begs the question: Why not render everything to a pixmap in the first place? And so that's what I'll try, next.
     - Text selection might be added later, on top of this, if that seems important enough.

Modified Paths:
--------------
    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_backendtransmitter.h
    branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
    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/rbackend/rkwarddevice/rkgraphicsdevice.cpp
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp	2013-03-24 19:29:41 UTC (rev 4627)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp	2013-03-25 18:18:17 UTC (rev 4628)
@@ -31,14 +31,23 @@
 
 #include "../../debug.h"
 
+#define UPDATE_INTERVAL 100
+
 QHash<int, RKGraphicsDevice*> RKGraphicsDevice::devices;
 
 RKGraphicsDevice::RKGraphicsDevice (double width, double height) : QObject () {
 	RK_TRACE (GRAPHICS_DEVICE);
 	scene = new QGraphicsScene (0, 0, width, height, this);
 	view = new QGraphicsView (scene);
+//	view->setOptimizationFlags (QGraphicsView::DontSavePainterState);
+//	view->setRenderHints (QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+//	scene->setItemIndexMethod (QGraphicsScene::NoIndex);
+//	scene->setBspTreeDepth (16);
+//	view->setViewportUpdateMode (QGraphicsView::NoViewportUpdate);
+	connect (&updatetimer, SIGNAL (timeout ()), this, SLOT (updateNow ()));
 	view->show ();
 	item_z = clip_z = 0;
+	clip = 0;
 	setClip (scene->sceneRect ());
 }
 
@@ -47,6 +56,19 @@
 	delete view;
 }
 
+void RKGraphicsDevice::triggerUpdate () {
+	view->setUpdatesEnabled (false);
+	updatetimer.start (UPDATE_INTERVAL);
+}
+
+void RKGraphicsDevice::updateNow () {
+//	QList<QRectF> dummy;
+//	dummy.append (scene->sceneRect ());
+//	view->updateScene (dummy);
+	view->setUpdatesEnabled (true);
+	view->update ();
+}
+
 RKGraphicsDevice* RKGraphicsDevice::newDevice (int devnum, double width, double height) {
 	RK_TRACE (GRAPHICS_DEVICE);
 
@@ -66,61 +88,142 @@
 	devices.take (devnum)->deleteLater ();
 }
 
+void RKGraphicsDevice::clear (const QBrush& bg) {
+	RK_TRACE (GRAPHICS_DEVICE);
+
+	scene->clear ();
+	clip = 0;
+	setClip (scene->sceneRect ());
+	rect (scene->sceneRect (), QPen (Qt::NoPen), bg);
+	view->show ();
+	updatetimer.start (UPDATE_INTERVAL);
+}
+
 void RKGraphicsDevice::setClip (const QRectF& new_clip) {
 	RK_TRACE (GRAPHICS_DEVICE);
+
+//	QGraphicsItem* old_clip = clip;
 	clip = scene->addRect (new_clip, QPen (Qt::NoPen));
 	clip->setZValue (clip_z += .1);
 	clip->setFlags (QGraphicsItem::ItemClipsChildrenToShape);
 	item_z = 0;
+//	if (old_clip) old_clip->setCacheMode (QGraphicsItem::DeviceCoordinateCache);
 }
 
+void RKGraphicsDevice::addItem (QGraphicsItem* item) {
+	if (item_z > 1000) {
+		updatetimer.stop ();
+		QGraphicsItem *old_clip = clip;
+		QRectF brect = clip->rect ().normalized ();
+		QPixmap cache (brect.width () + 1, brect.height () + 1);
+		cache.fill (QColor (0, 0, 0, 0));
+		QPainter painter;
+		painter.begin (&cache);
+		scene->render (&painter, cache.rect (), brect);
+		painter.end ();
+		setClip (brect);
+		QGraphicsPixmapItem *cached = new QGraphicsPixmapItem (cache);
+		cached->setPos (brect.x (), brect.y ());
+		addItem (cached);
+		delete old_clip;
+	}
+	item->setZValue (item_z += .1);
+	item->setParentItem (clip);
+	triggerUpdate ();
+}
+
 void RKGraphicsDevice::circle (double x, double y, double r, const QPen& pen, const QBrush& brush) {
-	QGraphicsEllipseItem* circle = new QGraphicsEllipseItem (x - r, y - r, r+r, r+r, clip);
+	RK_TRACE (GRAPHICS_DEVICE);
+
+	QGraphicsEllipseItem* circle = new QGraphicsEllipseItem (x - r, y - r, r+r, r+r);
 	circle->setPen (pen);
 	circle->setBrush (brush);
-	circle->setZValue (item_z += .1);
+	addItem (circle);
 }
 
 void RKGraphicsDevice::line (double x1, double y1, double x2, double y2, const QPen& pen) {
-	QGraphicsLineItem* line = new QGraphicsLineItem (x1, y1, x2, y2, clip);
+	RK_TRACE (GRAPHICS_DEVICE);
+
+	QGraphicsLineItem* line = new QGraphicsLineItem (x1, y1, x2, y2);
 	line->setPen (pen);
-	line->setZValue (item_z += .1);
+	addItem (line);
 }
 
+void RKGraphicsDevice::rect (const QRectF& rec, const QPen& pen, const QBrush& brush) {
+	RK_TRACE (GRAPHICS_DEVICE);
+
+	QGraphicsRectItem* rect = new QGraphicsRectItem (rec);
+	rect->setPen (pen);
+	rect->setBrush (brush);
+	addItem (rect);
+}
+
 double RKGraphicsDevice::strWidth (const QString& text, const QFont& font) {
-	QGraphicsSimpleTextItem t (text, 0);
+	RK_TRACE (GRAPHICS_DEVICE);
+
+	QGraphicsTextItem t (text);
 	t.setFont (font);
 	return t.boundingRect ().width ();
 }
 
 void RKGraphicsDevice::text (double x, double y, const QString& _text, double rot, double hadj, const QColor& col, const QFont& font) {
-	QGraphicsTextItem *text = new QGraphicsTextItem (clip);
+	RK_TRACE (GRAPHICS_DEVICE);
+
+	QGraphicsTextItem *text = new QGraphicsTextItem ();
 	text->setPlainText (_text);
 	text->setFont (font);
-	QRectF brect = text->boundingRect();
+	text->setDefaultTextColor (col);
+	QRectF brect = text->boundingRect ();
 	text->rotate (-rot);
 	text->translate (-hadj * brect.width (), - QFontMetricsF (font).height ());
 	text->setPos (x, y);
-	text->setZValue (item_z += .1);
 	text->setTextInteractionFlags (Qt::TextSelectableByMouse);
+	addItem (text);
 }
 
 void RKGraphicsDevice::metricInfo (const QChar& c, const QFont& font, double* ascent, double* descent, double* width) {
+	RK_TRACE (GRAPHICS_DEVICE);
+
 	QFontMetricsF fm (font);
 	*ascent = fm.ascent ();	// TODO: or should we return the metrics of this particular char (similar to strWidth)
 	*descent = fm.descent ();
 	*width = fm.width (c);
+/*	QGraphicsTextItem t;
+	t.setPlainText (QString (c));
+	t.setFont (font);
+	*ascent = t.boundingRect().height();
+	*descent = 0;
+	*width = t.boundingRect().width(); */
 }
 
 void RKGraphicsDevice::polygon (const QPolygonF& pol, const QPen& pen, const QBrush& brush) {
-	QGraphicsPolygonItem *poli = new QGraphicsPolygonItem (pol, clip);
+	RK_TRACE (GRAPHICS_DEVICE);
+
+	QGraphicsPolygonItem *poli = new QGraphicsPolygonItem (pol);
 	poli->setPen (pen);
 	poli->setBrush (brush);
-	poli->setZValue (item_z += .1);
+	addItem (poli);
 }
 
 void RKGraphicsDevice::polyline (const QPolygonF& pol, const QPen& pen) {
-	QGraphicsPolygonItem *poli = new QGraphicsPolygonItem (pol, clip);
+	RK_TRACE (GRAPHICS_DEVICE);
+// Qt insistes that all QGraphicsPolygonItems must be closed. So the this does not work:
+// QGraphicsPolygonItem *poli = new QGraphicsPolygonItem (pol, clip);
+	if (pol.isEmpty ()) return;
+
+	QPainterPath path;
+	path.moveTo (pol[0]);
+	for (int i = 1; i < pol.size (); ++i) {
+		path.lineTo (pol[i]);
+	}
+	QGraphicsPathItem *poli = new QGraphicsPathItem (path);
 	poli->setPen (pen);
-	poli->setZValue (item_z += .1);
+	addItem (poli);
 }
+
+void RKGraphicsDevice::setActive (bool active) {
+	RK_TRACE (GRAPHICS_DEVICE);
+	emit (activeChanged (active));
+}
+
+#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-24 19:29:41 UTC (rev 4627)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h	2013-03-25 18:18:17 UTC (rev 4628)
@@ -20,13 +20,16 @@
 
 #include <QHash>
 #include <QPen>
+#include <QTimer>
 
 class QGraphicsRectItem;
 class QGraphicsView;
 class QGraphicsScene;
+class QGraphicsItem;
 
 /** This is the class that actually does all the drawing for the RKGraphicsDevice */
 class RKGraphicsDevice : public QObject {
+	Q_OBJECT
 protected:
 	RKGraphicsDevice (double width, double height);
 	~RKGraphicsDevice ();
@@ -37,13 +40,23 @@
 
 	void circle (double x, double y, double r, const QPen& pen, const QBrush& brush);
 	void line (double x1, double y1, double x2, double y2, const QPen& pen);
+	void rect (const QRectF& rec, const QPen& pen, const QBrush& brush);
 	double strWidth (const QString &text, const QFont& font);
 	void text (double x, double y, const QString &text, double rot, double hadj, const QColor& col, const QFont& font);
 	void metricInfo (const QChar& c, const QFont& font, double *ascent, double *descent, double *width);
 	void setClip (const QRectF& new_clip);
 	void polygon (const QPolygonF& pol, const QPen& pen, const QBrush &brush);
 	void polyline (const QPolygonF& pol, const QPen& pen);
+	void clear (const QBrush& bg);
+	void setActive (bool active);
+	void triggerUpdate ();
+signals:
+	void activeChanged (bool);
+private slots:
+	void updateNow ();
 private:
+	void addItem (QGraphicsItem *item);
+	QTimer updatetimer;
 	QGraphicsScene* scene;
 	QGraphicsView* view;
 	QGraphicsRectItem* clip;

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-24 19:29:41 UTC (rev 4627)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.cpp	2013-03-25 18:18:17 UTC (rev 4628)
@@ -29,7 +29,7 @@
 QMutex RKGraphicsDeviceBackendTransmitter::mutex;
 RKGraphicsDeviceBackendTransmitter* RKGraphicsDeviceBackendTransmitter::_instance = 0;
 
-RKGraphicsDeviceBackendTransmitter::RKGraphicsDeviceBackendTransmitter (QIODevice* _connection) : QThread () {
+RKGraphicsDeviceBackendTransmitter::RKGraphicsDeviceBackendTransmitter (QIODevice* _connection, bool is_q_local_socket) : QThread () {
 	RK_TRACE (GRAPHICS_DEVICE);
 
 	RK_ASSERT (!connection);
@@ -37,6 +37,7 @@
 	connection = _connection;
 	streamer.setIODevice (connection);
 	alive = true;
+	is_local_socket = is_q_local_socket;
 	start ();
 }
 
@@ -56,12 +57,18 @@
 		con->write (RKRBackendTransmitter::instance ()->connectionToken ().toLocal8Bit ().data ());
 		con->write ("\n");
 		con->waitForBytesWritten (1000);
-		_instance = new RKGraphicsDeviceBackendTransmitter (con);
+		_instance = new RKGraphicsDeviceBackendTransmitter (con, true);
 		return _instance;
 	}
 	return 0;
 }
 
+bool RKGraphicsDeviceBackendTransmitter::connectionAlive () {
+	if (!_instance) return false;
+	if (!_instance->is_local_socket) return true;
+	return static_cast<QLocalSocket*> (_instance->connection)->state () == QLocalSocket::ConnectedState;
+}
+
 void RKGraphicsDeviceBackendTransmitter::run () {
 	RK_TRACE (GRAPHICS_DEVICE);
 

Modified: branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.h
===================================================================
--- branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.h	2013-03-24 19:29:41 UTC (rev 4627)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_backendtransmitter.h	2013-03-25 18:18:17 UTC (rev 4628)
@@ -28,10 +28,11 @@
  Also it provides the namespace for some statics.
  As the protocol is really quite simple (only the backend send requests, only one request at a time), so is the transmitter. */
 class RKGraphicsDeviceBackendTransmitter : public QThread {
-	RKGraphicsDeviceBackendTransmitter (QIODevice *connection);
+	RKGraphicsDeviceBackendTransmitter (QIODevice *connection, bool is_q_local_socket);
 	~RKGraphicsDeviceBackendTransmitter ();
 public:
 	static void kill ();
+	static bool connectionAlive ();
 	static RKGraphicsDeviceBackendTransmitter* instance ();
 	static RKAsyncDataStreamHelper streamer;
 	static QIODevice* connection;
@@ -39,6 +40,7 @@
 private:
 	static RKGraphicsDeviceBackendTransmitter* _instance;
 	bool alive;
+	bool is_local_socket;
 	void run ();
 };
 

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-24 19:29:41 UTC (rev 4627)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp	2013-03-25 18:18:17 UTC (rev 4628)
@@ -81,15 +81,35 @@
 	connect (connection, SIGNAL (readyRead ()), this, SLOT (newData ()));
 }
 
+static QColor readColor (QDataStream &instream) {
+	quint8 r, g, b, a;
+	instream >> r >> g >> b >> a;
+	if (a == 0x00) return QColor ();
+	return QColor (r, g, b, a);
+}
+
 static QPen readSimplePen (QDataStream &instream) {
-	quint8 r, g, b, a;
+	QColor col = readColor (instream);
 	double lwd;
 	qint32 lty;
-	instream >> r >> g >> b >> a >> lwd >> lty;
-#warning: Line style!
+	instream >> lwd >> lty;
+	if (!col.isValid () || (lty == -1L)) return QPen (Qt::NoPen);
+
+	lwd = qMax (1.0001, lwd);	// minimum 1 px (+rounding margin!) as in X11 device
 	QPen ret;
+	if (lty != 0) {	// solid
+		QVector<qreal> dashes;
+		quint32 nlty = lty;
+		for (int i = 0; i < 8; ++i) {
+			if (!nlty) break;
+			quint8 j = nlty & 0xF;
+			dashes.append (j * lwd * 96/72 + .5);	// 96/72: value taken from X11 device
+			nlty >>= 4;
+		}
+		if (!dashes.isEmpty ()) ret.setDashPattern (dashes);
+	}
 	ret.setWidthF (lwd);
-	ret.setColor (QColor (r, g, b, a));
+	ret.setColor (col);
 	return ret;
 }
 
@@ -98,22 +118,27 @@
 	quint8 lends, ljoin;
 	double lmitre;
 	instream >> lends >> ljoin >> lmitre;
-#warning: Apply attribs!
+	ret.setCapStyle (lends == RoundLineCap ? Qt::RoundCap : (lends == ButtLineCap ? Qt::FlatCap : Qt::SquareCap));
+	ret.setJoinStyle (ljoin == RoundJoin ? Qt::RoundJoin : (ljoin == BevelJoin ? Qt::BevelJoin : Qt::MiterJoin));
+	ret.setMiterLimit (lmitre);
 	return ret;
 }
 
 static QBrush readBrush (QDataStream &instream) {
-#warning: Read brush!
-	return QBrush ();
+	QColor col = readColor (instream);
+	if (!col.isValid ()) return QBrush ();
+	return QBrush (col);
 }
 
 static QFont readFont (QDataStream &instream) {
-#warning: Handle all attribs!
 	double cex, ps, lineheight;
 	quint8 fontface;
 	QString fontfamily;
 	instream >> cex >> ps >> lineheight >> fontface >> fontfamily;
+#warning TODO deal with line-height
 	QFont ret (fontfamily);
+	if (fontface == 2 || fontface == 4) ret.setWeight (QFont::Bold);
+	if (fontface == 3 || fontface == 4) ret.setItalic (true);
 	ret.setPointSizeF (cex*ps);
 	return ret;
 }
@@ -123,7 +148,7 @@
 	instream >> n;
 	QVector<QPointF> points;
 	points.reserve (n + (close ? 1 : 0));
-	for (int i = 0; i < n; ++i) {
+	for (quint32 i = 0; i < n; ++i) {
 		double x, y;
 		instream >> x >> y;
 		points.append (QPointF (x, y));
@@ -156,32 +181,34 @@
 			}
 		}
 
+/* WARNING: No fixed evaluation order of function arguments. Do not use several readXYZ() calls in the same function call! Use dummy variables, instead. */
 		if (opcode == RKDCircle) {
 			double x, y, r;
 			streamer.instream >> x >> y >> r;
-			device->circle (x, y, r, readSimplePen (streamer.instream), readBrush (streamer.instream));
-			continue;
+			QPen pen = readSimplePen (streamer.instream);
+			device->circle (x, y, r, pen, readBrush (streamer.instream));
 		} else if (opcode == RKDLine) {
 			double x1, y1, x2, y2;
 			streamer.instream >> x1 >> y1 >> x2 >> y2;
 			device->line (x1, y1, x2, y2, readPen (streamer.instream));
-			continue;
 		} else if (opcode == RKDPolygon) {
 			QPolygonF pol (readPoints (streamer.instream, true));
-			device->polygon (pol, readPen (streamer.instream), readBrush (streamer.instream));
-			continue;
+			QPen pen = readPen (streamer.instream);
+			device->polygon (pol, pen, readBrush (streamer.instream));
 		} else if (opcode == RKDPolyline) {
 			QPolygonF pol (readPoints (streamer.instream, false));
 			device->polyline (pol, readPen (streamer.instream));
-			continue;
 		} else if (opcode == RKDRect) {
+			QRectF rect;
+			streamer.instream >> rect;
+			QPen pen = readPen (streamer.instream);
+			device->rect (rect, pen, readBrush (streamer.instream));
 		} else if (opcode == RKDStrWidthUTF8) {
 			QString out;
 			streamer.instream >> out;
 			double w = device->strWidth (out, readFont (streamer.instream));
 			streamer.outstream << w;
 			streamer.writeOutBuffer ();
-			continue;
 		} else if (opcode == RKDMetricInfo) {
 			QChar c;
 			double ascent, descent, width;
@@ -189,29 +216,41 @@
 			device->metricInfo (c, readFont (streamer.instream), &ascent, &descent, &width);
 			streamer.outstream << ascent << descent << width;
 			streamer.writeOutBuffer ();
-			continue;
 		} else if (opcode == RKDTextUTF8) {
 			double x, y, rot, hadj;
 			QString out;
-			QRgb col;
-			streamer.instream >> x >> y >> out >> rot >> hadj >> col;
+			streamer.instream >> x >> y >> out >> rot >> hadj;
+			QColor col = readColor (streamer.instream);
 			device->text (x, y, out, rot, hadj, col, readFont (streamer.instream));
-			continue;
 		} else if (opcode == RKDNewPage) {
+			device->clear (readBrush (streamer.instream));
 		} else if (opcode == RKDClose) {
+			RKGraphicsDevice::closeDevice (devnum);
 		} else if (opcode == RKDActivate) {
+			RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Unhandled operation of type %d for device number %d. Skippping.", opcode, devnum);
 		} else if (opcode == RKDDeActivate) {
+			RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Unhandled operation of type %d for device number %d. Skippping.", opcode, devnum);
 		} else if (opcode == RKDClip) {
+			QRectF clip;
+			streamer.instream >> clip;
+			device->setClip (clip);
 		} else if (opcode == RKDMode) {
+			quint8 m;
+			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);
 		} 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 {
+			RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Unhandled operation of type %d for device number %d. Skippping.", opcode, devnum);
 		}
 
-		RK_ASSERT (streamer.instream.atEnd ());
-		RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Unhandled operation of type %d for device number %d. Skippping.", opcode, devnum);
-
-#warning TODO: Actually handle the data!
-		sendDummyReply (opcode);
+		if (!streamer.instream.atEnd ()) {
+			RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Failed to read all data for operation of type %d on device number %d.", opcode, devnum);
+		}
 	}
 }
 
@@ -219,7 +258,7 @@
 	RK_TRACE (GRAPHICS_DEVICE);
 
 	if (opcode == RKDLocator) {
-		bool ok = true;
+		bool ok = false;
 		double x, y;
 		x = y = 0;
 		streamer.outstream << ok << x << y;
@@ -228,7 +267,7 @@
 		ascent = descent = width = 0.1;
 		streamer.outstream << ascent << descent << width;
 	} else if (opcode == RKDNewPageConfirm) {
-		bool ok = true;
+		bool ok = false;
 		streamer.outstream << ok;
 	} else if (opcode == RKDStrWidthUTF8) {
 		double width = 1;

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-24 19:29:41 UTC (rev 4627)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h	2013-03-25 18:18:17 UTC (rev 4628)
@@ -38,6 +38,22 @@
  * 
  */
 
+/** This enum simply repeats R's line end definitions. It is used to ensure compatiblity, without the need to include
+ * any R headers in the frontend. */
+enum RKLineEndStyles {
+	RoundLineCap = 1,
+	ButtLineCap = 2,
+	SquareLineCap = 3
+};
+
+/** This enum simply repeats R's line join definitions. It is used to ensure compatiblity, without the need to include
+ * any R headers in the frontend. */
+enum RKLineJoinStyles {
+	RoundJoin = 1,
+	MitreJoin = 2,
+	BevelJoin = 3
+};
+
 enum RKDOpcodes {
 	// Asynchronous operations
 	RKDCreate,     // 0

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-24 19:29:41 UTC (rev 4627)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp	2013-03-25 18:18:17 UTC (rev 4628)
@@ -114,8 +114,8 @@
 	dev->right  = dev->clipRight  = width;
 	dev->bottom = dev->clipBottom = height;
 	dev->top    = dev->clipTop    = 0;
-	dev->cra[0] = 0.9 * pointsize;
-	dev->cra[1] = 1.2 * pointsize;
+	dev->cra[0] = 0.9 * pointsize * 96/72;
+	dev->cra[1] = 1.2 * pointsize * 96/72;
 	dev->xCharOffset = 0.4900;
 	dev->yCharOffset = 0.3333;
 	dev->yLineBias = 0.1;

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-24 19:29:41 UTC (rev 4627)
+++ branches/development_branches/rkward_graphpics_device/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp	2013-03-25 18:18:17 UTC (rev 4628)
@@ -42,13 +42,23 @@
 		QIODevice* connection = RKGraphicsDeviceBackendTransmitter::connection;
 		BEGIN_SUSPEND_INTERRUPTS {
 			while (connection->bytesToWrite ()) {
-				connection->waitForBytesWritten (10);
+				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");
+					}
+				}
 #warning TODO: Use R_CheckUserInterrupt(), instead?
 				if (connection->bytesToWrite ()) RKRBackend::processX11Events ();
 			}
 			while (!RKGraphicsDeviceBackendTransmitter::streamer.readInBuffer ()) {
 				RKRBackend::processX11Events ();
-				connection->waitForReadyRead (10);
+				if (!connection->waitForReadyRead (10)) {
+					if (!RKGraphicsDeviceBackendTransmitter::connectionAlive ()) {
+						RKGraphicsDeviceBackendTransmitter::mutex.unlock ();
+						Rf_error ("RKWard Graphics connection has shut down");
+					}
+				}
 			}
 		} END_SUSPEND_INTERRUPTS;
 	}
@@ -72,80 +82,89 @@
 
 #include <QRectF>
 
-#define RK_TEST_COL 0xABCDEF01
-#if not ((R_RED(RK_TEST_COL) == 0x01) && (R_GREEN(RK_TEST_COL) == 0xEF) && (R_BLUE(RK_TEST_COL) == 0xCD) && (R_ALPHA(RK_TEST_COL) == 0xAB))
-#error R color format has changed!
-#endif
+// 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))
+// This ought to be optimized away by the compiler:
+#define SAFE_LINE_JOIN(ljoin) (quint8) (ljoin == GE_ROUND_JOIN ? RoundJoin : (ljoin == GE_BEVEL_JOIN ? BevelJoin : MitreJoin))
 
 // I'd love to convert to QColor, directly, but that's in QtGui, not QtCore. QRgb used different byte ordering
-#define WRITE_COLOR_BYTES(col) (quint8) R_RED (col) << (quint8) R_GREEN (col) << (quint8) R_BLUE (col) << (quint8) R_ALPHA (col)
-#define WRITE_HEADER(x,dev) (qint8) x << (quint8) static_cast<RKGraphicsDeviceDesc*> (dev->deviceSpecific)->devnum
-#define WRITE_COL() WRITE_COLOR_BYTES (gc->col)
-#define WRITE_PEN() WRITE_COL() << (double) gc->lwd << (qint32) gc->lty
-#define WRITE_LINE_ENDS() (quint8) gc->lend << (quint8) gc->ljoin << gc->lmitre
-#define WRITE_FILL() WRITE_COLOR_BYTES (gc->fill)
-#define WRITE_FONT(dev) gc->cex << gc->ps << gc->lineheight << (quint8) gc->fontface << (gc->fontfamily[0] ? QString (gc->fontfamily) : (static_cast<RKGraphicsDeviceDesc*> (dev->deviceSpecific)->default_family))
+#define WRITE_COLOR_BYTES(col) \
+	if (col == NA_INTEGER) RKD_OUT_STREAM << (quint8) 0xFF << (quint8) 0xFF << (quint8) 0xFF << (quint8) 0x00; \
+	else RKD_OUT_STREAM << (quint8) R_RED (col) << (quint8) R_GREEN (col) << (quint8) R_BLUE (col) << (quint8) R_ALPHA (col)
+#define WRITE_HEADER(x,dev) \
+	RKD_OUT_STREAM << (qint8) x << (quint8) static_cast<RKGraphicsDeviceDesc*> (dev->deviceSpecific)->devnum
+#define WRITE_COL() \
+	WRITE_COLOR_BYTES (gc->col)
+#define WRITE_PEN() \
+	WRITE_COL(); RKD_OUT_STREAM << (double) gc->lwd << (qint32) gc->lty
+// actually lmitre is only needed if linejoin is GE_MITRE_JOIN, so we could optimize a bit
+#define WRITE_LINE_ENDS() \
+	RKD_OUT_STREAM << SAFE_LINE_END (gc->lend) << SAFE_LINE_JOIN (gc->ljoin) << gc->lmitre
+#define WRITE_FILL() \
+	WRITE_COLOR_BYTES (gc->fill)
+#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)->default_family))
 
 static void RKD_Create (double width, double height, pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDCreate, dev);
+	WRITE_HEADER (RKDCreate, dev);
 	RKD_OUT_STREAM << width << height;
 }
 
 static void RKD_Circle (double x, double y, double r, R_GE_gcontext *gc, pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDCircle, dev);
+	WRITE_HEADER (RKDCircle, dev);
 	RKD_OUT_STREAM << x << y << r;
-	RKD_OUT_STREAM << WRITE_PEN ();
-	RKD_OUT_STREAM << WRITE_FILL ();
+	WRITE_PEN ();
+	WRITE_FILL ();
 }
 
 static void RKD_Line (double x1, double y1, double x2, double y2, R_GE_gcontext *gc, pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDLine, dev);
+	WRITE_HEADER (RKDLine, dev);
 	RKD_OUT_STREAM << x1 << y1 << x2 << y2;
-	RKD_OUT_STREAM << WRITE_PEN ();
-	RKD_OUT_STREAM << WRITE_LINE_ENDS ();
+	WRITE_PEN ();
+	WRITE_LINE_ENDS ();
 }
 
 static void RKD_Polygon (int n, double *x, double *y, R_GE_gcontext *gc, pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDPolygon, dev);
+	WRITE_HEADER (RKDPolygon, dev);
 	quint32 _n = qMin (n, 1 << 25);	// skip stuff exceeding reasonable limits to keep protocol simple
 	RKD_OUT_STREAM << _n;
 	for (quint32 i = 0; i < _n; ++i) {
 		RKD_OUT_STREAM << x[i] << y[i];
 	}
-	RKD_OUT_STREAM << WRITE_PEN ();
-	RKD_OUT_STREAM << WRITE_LINE_ENDS ();
-	RKD_OUT_STREAM << WRITE_FILL ();
+	WRITE_PEN ();
+	WRITE_LINE_ENDS ();
+	WRITE_FILL ();
 }
 
 static void RKD_Polyline (int n, double *x, double *y, R_GE_gcontext *gc, pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDPolyline, dev);
+	WRITE_HEADER (RKDPolyline, dev);
 	quint32 _n = qMin (n, 1 << 25);	// skip stuff exceeding reasonable limits to keep protocol simple
 	RKD_OUT_STREAM << _n;
 	for (quint32 i = 0; i < _n; ++i) {
 		RKD_OUT_STREAM << x[i] << y[i];
 	}
-	RKD_OUT_STREAM << WRITE_PEN ();
-	RKD_OUT_STREAM << WRITE_LINE_ENDS ();
+	WRITE_PEN ();
+	WRITE_LINE_ENDS ();
 }
 
 static void RKD_Rect (double x0, double y0, double x1, double y1, R_GE_gcontext *gc, pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDPolyline, dev);
+	WRITE_HEADER (RKDRect, dev);
 	RKD_OUT_STREAM << QRectF (x0, y0, x1-x0, y1-y0);
-	RKD_OUT_STREAM << WRITE_PEN ();
-	RKD_OUT_STREAM << WRITE_LINE_ENDS ();
-	RKD_OUT_STREAM << WRITE_FILL ();
+	WRITE_PEN ();
+	WRITE_LINE_ENDS ();
+	WRITE_FILL ();
 }
 
 static QString RToQString (const char *str, bool is_symbol) {
 	if (is_symbol) {
 		int n = strlen (str);
-		char outbuf[n*4 + 4];
+		char outbuf[n*4 + 16];
 		Rf_AdobeSymbol2utf8 (outbuf, str, n*4);
 		return QString::fromUtf8 (outbuf);
 	}
@@ -154,18 +173,18 @@
 
 static void RKD_TextUTF8 (double x, double y, const char *str, double rot, double hadj, R_GE_gcontext *gc, pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDTextUTF8, dev);
+	WRITE_HEADER (RKDTextUTF8, dev);
 	RKD_OUT_STREAM << x << y << RToQString (str, gc->fontface == 5) << rot << hadj;
-	RKD_OUT_STREAM << WRITE_COL ();
-	RKD_OUT_STREAM << WRITE_FONT (dev);
+	WRITE_COL ();
+	WRITE_FONT (dev);
 }
 
 static double RKD_StrWidthUTF8 (const char *str, R_GE_gcontext *gc, pDevDesc dev) {
 	{
 		RKGraphicsDataStreamWriteGuard guard;
-		RKD_OUT_STREAM << WRITE_HEADER (RKDStrWidthUTF8, dev);
+		WRITE_HEADER (RKDStrWidthUTF8, dev);
 		RKD_OUT_STREAM << RToQString (str, gc->fontface == 5);
-		RKD_OUT_STREAM << WRITE_FONT (dev);
+		WRITE_FONT (dev);
 	}
 	double ret;
 	{
@@ -177,14 +196,14 @@
 
 static void RKD_NewPage (R_GE_gcontext *gc, pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDNewPage, dev);
-	RKD_OUT_STREAM << WRITE_FILL ();
+	WRITE_HEADER (RKDNewPage, dev);
+	WRITE_FILL ();
 }
 
 static void RKD_MetricInfo (int c, R_GE_gcontext *gc, double* ascent, double* descent, double* width, pDevDesc dev) {
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
-		RKD_OUT_STREAM << WRITE_HEADER (RKDMetricInfo, dev);
+		WRITE_HEADER (RKDMetricInfo, dev);
 		QChar unichar;
 		if (c < 0) { unichar = QChar (-c); }
 		else if ((gc->fontface == 5) || (!mbcslocale)) {
@@ -198,28 +217,27 @@
 			unichar = QChar (c);
 		}
 		RKD_OUT_STREAM << unichar;
-		RKD_OUT_STREAM << WRITE_FONT (dev);
+		WRITE_FONT (dev);
 	}
 	{
 		RKGraphicsDataStreamReadGuard rguard;
 		RKD_IN_STREAM >> *ascent >> *descent >> *width;
-//qDebug ("for char %d: a %f, d %f, w %f", c, *ascent, *descent, *width);
 	}
 }
 
 static void RKD_Close (pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDClose, dev);
+	WRITE_HEADER (RKDClose, dev);
 }
 
 static void RKD_Activate (pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDActivate, dev);
+	WRITE_HEADER (RKDActivate, dev);
 }
 
 static void RKD_Deactivate (pDevDesc dev) {
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDDeActivate, dev);
+	WRITE_HEADER (RKDDeActivate, dev);
 }
 
 static void RKD_Clip (double left, double right, double top, double bottom, pDevDesc dev) {
@@ -228,7 +246,7 @@
 	dev->clipTop = top;
 	dev->clipBottom = bottom;
 	RKGraphicsDataStreamWriteGuard guard;
-	RKD_OUT_STREAM << WRITE_HEADER (RKDClip, dev);
+	WRITE_HEADER (RKDClip, dev);
 	RKD_OUT_STREAM << QRectF (left, top, right - left, bottom - top);
 }
 
@@ -245,14 +263,12 @@
 static Rboolean RKD_Locator (double *x, double *y, pDevDesc dev) {
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
-		RKD_OUT_STREAM << WRITE_HEADER (RKDLocator, dev);
+		WRITE_HEADER (RKDLocator, dev);
 	}
 	{
 		RKGraphicsDataStreamReadGuard rguard;
 		bool ok;
-		RKD_IN_STREAM >> ok;
-		RKD_IN_STREAM >> *x;
-		RKD_IN_STREAM >> *y;
+		RKD_IN_STREAM >> ok >> *x >> *y;
 		if (ok) return (Rboolean) TRUE;
 		return (Rboolean) FALSE;
 	}
@@ -261,7 +277,7 @@
 static Rboolean RKD_NewFrameConfirm (pDevDesc dev) {
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
-		RKD_OUT_STREAM << WRITE_HEADER (RKDNewPageConfirm, dev);
+		WRITE_HEADER (RKDNewPageConfirm, dev);
 	}
 	{
 		RKGraphicsDataStreamReadGuard rguard;





More information about the rkward-tracker mailing list