[education/rkward] /: Fix some synchronization bugs around closing devices.

Thomas Friedrichsmeier null at kde.org
Sat Mar 19 21:57:45 GMT 2022


Git commit 9d8ed3bb51643d80afff5e7cc669007a077a1e1f by Thomas Friedrichsmeier.
Committed on 19/03/2022 at 21:57.
Pushed by tfry into branch 'master'.

Fix some synchronization bugs around closing devices.

M  +2    -1    ChangeLog
M  +1    -1    VERSION.cmake
M  +2    -2    rkward/rbackend/rkrbackend.cpp
M  +7    -3    rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
M  +3    -2    rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
M  +17   -6    rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
M  +2    -2    rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
M  +10   -6    rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
M  +92   -29   rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
M  +1    -1    rkward/rbackend/rpackages/rkward/DESCRIPTION
M  +4    -2    rkward/rbackend/rpackages/rkward/R/internal_graphics.R
M  +1    -1    rkward/windows/rkwindowcatcher.cpp

https://invent.kde.org/education/rkward/commit/9d8ed3bb51643d80afff5e7cc669007a077a1e1f

diff --git a/ChangeLog b/ChangeLog
index 023df0e8..25e031a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,10 +1,11 @@
 TODO:
-- RKDClose needs to be synchronous to avoid race-condition while closing device
+- Fix initial graphics window size
 
 TODOS for autotests:
   - Check and update the standards files
   - Use options(warn=1), in order to get warnings into the test?
 
+- Fix some buglets around closing on-screen devices
 - Implement new R graphics functions: gradients, patterns, clip paths
 - Add icons to settings dialog for quick visual orientation
 - Merge ktexteditor (script) settings into the main settings dialog
diff --git a/VERSION.cmake b/VERSION.cmake
index 7e7d01ee..adb07cee 100644
--- a/VERSION.cmake
+++ b/VERSION.cmake
@@ -1,3 +1,3 @@
 # DO NOT CHANGE THIS FILE MANUALLY!
 # It will be overwritten by scripts/set_dist_version.sh
-SET(RKVERSION_NUMBER 0.7.2z+0.7.3+devel2)
+SET(RKVERSION_NUMBER 0.7.2z+0.7.3+devel4)
diff --git a/rkward/rbackend/rkrbackend.cpp b/rkward/rbackend/rkrbackend.cpp
index f27968ea..4fd5fefb 100644
--- a/rkward/rbackend/rkrbackend.cpp
+++ b/rkward/rbackend/rkrbackend.cpp
@@ -1067,7 +1067,7 @@ SEXP doCaptureOutput (SEXP mode, SEXP capture_messages, SEXP capture_output, SEX
 }
 
 SEXP RKStartGraphicsDevice (SEXP width, SEXP height, SEXP pointsize, SEXP family, SEXP bg, SEXP title, SEXP antialias);
-SEXP RKD_AdjustSize (SEXP devnum);
+SEXP RKD_AdjustSize (SEXP devnum, SEXP id);
 SEXP doWs (SEXP name);
 void doPendingPriorityCommands ();
 
@@ -1157,7 +1157,7 @@ bool RKRBackend::startR () {
 		{ "rk.update.locale", (DL_FUNC) (void*) &doUpdateLocale, 0 },
 		{ "rk.capture.output", (DL_FUNC) (void*) &doCaptureOutput, 5 },
 		{ "rk.graphics.device", (DL_FUNC) (void*) &RKStartGraphicsDevice, 7},
-		{ "rk.graphics.device.resize", (DL_FUNC) (void*) &RKD_AdjustSize, 1},
+		{ "rk.graphics.device.resize", (DL_FUNC) (void*) &RKD_AdjustSize, 2},
 		{ 0, 0, 0 }
 	};
 	R_registerRoutines (R_getEmbeddingDllInfo(), NULL, callMethods, NULL, NULL);
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
index c0b59e1f..9ed62900 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
@@ -50,6 +50,7 @@ RKGraphicsDevice::RKGraphicsDevice (double width, double height, const QString &
 
 	interaction_opcode = -1;
 	dialog = 0;
+	id = 0;
 	recording_path = false;
 	view = new QLabel ();
 	view->installEventFilter (this);
@@ -163,7 +164,7 @@ int RKGraphicsDevice::finalizeTilingPattern(int extend) {
 void RKGraphicsDevice::viewKilled () {
 	RK_TRACE (GRAPHICS_DEVICE);
 	view = 0;
-	closeDevice (devices.key (this));
+//	closeDevice(devices.key(this));  // Do not do this, here. Don't mark the device as dead until R thinks so, too, and tells us about it.
 }
 
 void RKGraphicsDevice::triggerUpdate () {
@@ -204,12 +205,13 @@ void RKGraphicsDevice::forceSync() {
 
 void RKGraphicsDevice::checkSize() {
 	RK_TRACE (GRAPHICS_DEVICE);
+	if(!view) return;
 	if (view->size () != area.size ()) {
-		RKGlobals::rInterface ()->issueCommand (new RCommand ("rkward:::RK.resize (" + QString::number (devices.key (this) + 1) + ')', RCommand::PriorityCommand));
+		RKGlobals::rInterface()->issueCommand(new RCommand ("rkward:::RK.resize(" + QString::number(devices.key(this) + 1) + ',' + QString::number(id) + ')', RCommand::PriorityCommand));
 	}
 }
 
-RKGraphicsDevice* RKGraphicsDevice::newDevice (int devnum, double width, double height, const QString &title, bool antialias) {
+RKGraphicsDevice* RKGraphicsDevice::newDevice (int devnum, double width, double height, const QString &title, bool antialias, quint32 id) {
 	RK_TRACE (GRAPHICS_DEVICE);
 
 	if (devices.contains (devnum)) {
@@ -217,6 +219,7 @@ RKGraphicsDevice* RKGraphicsDevice::newDevice (int devnum, double width, double
 		closeDevice (devnum);
 	}
 	RKGraphicsDevice* dev = new RKGraphicsDevice (width, height, title.isEmpty () ? i18n ("Graphics Device Number %1", QString::number (devnum+1)) : title, antialias);
+	dev->id = id;
 	devices.insert (devnum, dev);
 	return (dev);
 }
@@ -479,6 +482,7 @@ QImage RKGraphicsDevice::capture () const {
 void RKGraphicsDevice::setActive (bool active) {
 	RK_TRACE (GRAPHICS_DEVICE);
 
+	if (!view) return;
 	if (active) view->setWindowTitle (i18nc ("Window title", "%1 (Active)", base_title));
 	else view->setWindowTitle (i18nc ("Window title", "%1 (Inactive)", base_title));
 	emit (activeChanged (active));
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h b/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
index 4ebbc72a..0b9650b5 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
@@ -51,7 +51,7 @@ protected:
 	RKGraphicsDevice (double width, double height, const QString &title, bool antialias);
 	~RKGraphicsDevice ();
 public:
-	static RKGraphicsDevice* newDevice (int devnum, double width, double height, const QString &title, bool antialias);
+	static RKGraphicsDevice* newDevice (int devnum, double width, double height, const QString &title, bool antialias, quint32 id);
 	static void closeDevice (int devnum);
 	static QHash<int, RKGraphicsDevice*> devices;
 
@@ -89,7 +89,7 @@ public:
 	void stopGettingEvents ();
 
  	QWidget* viewPort () const { return view; };
-	QSizeF currentSize () const { return view->size (); }
+	QSizeF currentSize () const { return view ? view->size() : QSizeF(); }
 	void setAreaSize (const QSize &size);
 
 /** Patterns / gradients are registered per device in R */
@@ -139,6 +139,7 @@ private:
 	bool recording_path;
 
 	int interaction_opcode;	/**< Current interactive operation (from RKDOpcodes enum), or -1 is there is no current interactive operation */
+	quint32 id;
 
 	QList<StoredEvent> stored_events;
 
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
index 72c0163e..fa20803f 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
@@ -245,8 +245,9 @@ void RKGraphicsDeviceFrontendTransmitter::newData () {
 			double width, height;
 			QString title;
 			bool antialias;
-			streamer.instream >> width >> height >> title >> antialias;
-			device = RKGraphicsDevice::newDevice (devnum, width, height, title, antialias);
+			quint32 id;
+			streamer.instream >> width >> height >> title >> antialias >> id;
+			device = RKGraphicsDevice::newDevice (devnum, width, height, title, antialias, id);
 			RKWorkplace::mainWorkplace ()->newRKWardGraphisWindow (device, devnum+1);
 			connect (device, &RKGraphicsDevice::locatorDone, this, &RKGraphicsDeviceFrontendTransmitter::locatorDone);
 			connect (device, &RKGraphicsDevice::newPageConfirmDone, this, &RKGraphicsDeviceFrontendTransmitter::newPageConfirmDone);
@@ -331,7 +332,8 @@ void RKGraphicsDeviceFrontendTransmitter::newData () {
 		} else if (opcode == RKDNewPage) {
 			device->clear(readBrush(streamer.instream, device));
 		} else if (opcode == RKDClose) {
-			RKGraphicsDevice::closeDevice (devnum);
+			RKGraphicsDevice::closeDevice(devnum);
+			sendDummyReply(devnum);
 		} else if (opcode == RKDActivate) {
 			device->setActive (true);
 		} else if (opcode == RKDDeActivate) {
@@ -378,7 +380,7 @@ void RKGraphicsDeviceFrontendTransmitter::newData () {
 		} else if (opcode == RKDSetClipPath) {
 			qint32 index;
 			streamer.instream >> index;
-			bool ok = device->setClipToCachedPath(index);
+			qint8 ok = device->setClipToCachedPath(index) ? 1 : 0;
 			streamer.outstream << ok;
 			streamer.writeOutBuffer();
 		} else if (opcode == RKDReleaseClipPath) {
@@ -442,8 +444,7 @@ void RKGraphicsDeviceFrontendTransmitter::newData () {
 			device->confirmNewPage ();
 		} else if (opcode == RKDForceSync) {
 			device->forceSync();
-			streamer.outstream << (qint8) 0;
-			streamer.writeOutBuffer();
+			sendDummyReply(devnum);
 		} else {
 			RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Unhandled operation of type %d for device number %d. Skipping.", opcode, devnum+1);
 		}
@@ -472,10 +473,20 @@ void RKGraphicsDeviceFrontendTransmitter::sendDummyReply (quint8 opcode) {
 	} else if (opcode == RKDStrWidthUTF8) {
 		double width = 1;
 		streamer.outstream << width;
+	} else if (opcode == RKDCapture) {
+		streamer.outstream << (quint32) 0 << (quint32) 0;
+//	} else if (opcode == RKDQueryResolution) {
+//		streamer.outstream << (qint32) 0;
 	} else if (opcode == RKDGetSize) {
 		streamer.outstream << QSizeF ();
+	} else if (opcode == RKDSetPattern || opcode == RKDEndRecordTilingPattern || opcode == RKDEndRecordClipPath) {
+		streamer.outstream << (qint32) -1;
+	} else if (opcode == RKDSetClipPath) {
+		streamer.outstream << (qint32) 0;
 	} else if (opcode == RKDFetchNextEvent) {
 		streamer.outstream << (qint8) RKDNothing;
+	} else if (opcode == RKDClose || opcode == RKDForceSync) {
+		streamer.outstream << (qint8) RKDNothing;
 	} else {
 		return;	// nothing to write
 	}
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
index afadb26f..12daa58d 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
@@ -96,14 +96,13 @@ enum RKDOpcodes {
 	RKDRect,
 	RKDTextUTF8,
 	RKDNewPage,
-	RKDClose,
+	RKDStartGettingEvents,
 	RKDActivate,           // 10
 	RKDDeActivate,
 	RKDClip,
 	RKDMode,
 	RKDRaster,
 	RKDSetSize,            // 15
-	RKDStartGettingEvents,
 	RKDStopGettingEvents,
 	RKDReleasePattern,
 	RKDStartRecordTilingPattern,      // part of setPattern in R
@@ -124,6 +123,7 @@ enum RKDOpcodes {
 	RKDSetClipPath,       // 110
 	RKDEndRecordClipPath,
 	RKDForceSync,
+	RKDClose,
 
 	// Protocol operations
 	RKDCancel              = 200
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
index da9e47a0..a91f8127 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
@@ -44,6 +44,7 @@
 struct RKGraphicsDeviceDesc {
 	bool init (pDevDesc dev, double pointsize, const QStringList &family, rcolor bg);
 	int devnum;
+	quint32 id;
 	double width, height;
 	int dpix, dpiy;
 	QString getFontFamily (bool symbolfont) const {
@@ -66,6 +67,7 @@ struct RKGraphicsDeviceDesc {
 #define RKGD_DPI 72.0
 
 void RKStartGraphicsDevice (double width, double height, double pointsize, const QStringList &family, rcolor bg, const char* title, bool antialias) {
+	static quint32 id = 0;
 	if (width <= 0 || height <= 0) {
 		Rf_error ("Invalid width or height: (%g, %g)", width, height);
 	}
@@ -89,12 +91,14 @@ void RKStartGraphicsDevice (double width, double height, double pointsize, const
 			delete (desc);
 			desc = 0;
 		} else {
-			desc->devnum = 0;	// graphics engine will send an Activate-event, before we were even
-								// able to see our own devnum and call RKD_Create. Therefore, initialize
-								// devnum to 0, so as not to confuse the frontend
-			pGEDevDesc gdd = GEcreateDevDesc (dev);
+			desc->devnum = 0;  // graphics engine will send an Activate-event, before we were even
+			                   // able to see our own devnum and call RKD_Create. Therefore, initialize
+			                   // devnum to 0, so as not to confuse the frontend
+			desc->id = id++;   // extra identifier to make sure, R and the frontend are really talking about the same device
+			                   // in case of potentially out-of-sync operations (notably RKDADjustSize)
+			pGEDevDesc gdd = GEcreateDevDesc(dev);
 			gdd->displayList = R_NilValue;
-			GEaddDevice2 (gdd, "RKGraphicsDevice");
+			GEaddDevice2(gdd, "RKGraphicsDevice");
 #ifdef _MSC_VER
 			// See RKD_Close()
 			desc->rgdevdesc = gdd;
@@ -104,7 +108,7 @@ void RKStartGraphicsDevice (double width, double height, double pointsize, const
 
 	if (desc) {
 		desc->devnum = curDevice ();
-		RKD_Create (desc->width, desc->height, dev, title, antialias);
+		RKD_Create (desc->width, desc->height, dev, title, antialias, desc->id);
 	} else {
 		Rf_error("unable to start device");
 	}
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
index f82b5d87..a537abaa 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
@@ -2,7 +2,7 @@
                           rkgraphicsdevice_stubs  -  description
                              -------------------
     begin                : Mon Mar 18 20:06:08 CET 2013
-    copyright            : (C) 2013-2021 by Thomas Friedrichsmeier
+    copyright            : (C) 2013-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -25,6 +25,22 @@
 #include "../rkreventloop.h"
 #include "../../debug.h"
 
+#undef RK_TRACE
+#define RK_TRACE(flags)
+/*
+#define RK_TRACE(flags) RKFullTrace _rk_full_trace(__FILE__, __FUNCTION__, __LINE__);
+class RKFullTrace {
+public:
+	RKFullTrace(char *file, const char *function, int line) : _function(function){
+		qDebug("Trace enter: %s - function %s line %d", file, _function, line);
+	};
+	~RKFullTrace() {
+		qDebug("Trace leave: function %s", _function);
+	};
+	const char *_function;
+}; */
+
+
 #include <R_ext/GraphicsEngine.h>
 
 #define RKD_IN_STREAM RKGraphicsDeviceBackendTransmitter::streamer.instream
@@ -177,6 +193,7 @@ public:
 	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_QueryResolution (int *dpix, int *dpiy) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
 		WRITE_HEADER_NUM (RKDQueryResolution, 0);
@@ -189,11 +206,12 @@ static void RKD_QueryResolution (int *dpix, int *dpiy) {
 	}
 }
 
-static void RKD_Create (double width, double height, pDevDesc dev, const char *title, bool antialias) {
+static void RKD_Create (double width, double height, pDevDesc dev, const char *title, bool antialias, quint32 id) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	{
 		RKGraphicsDataStreamWriteGuard guard;
 		WRITE_HEADER (RKDCreate, dev);
-		RKD_OUT_STREAM << width << height << QString::fromUtf8 (title) << antialias;
+		RKD_OUT_STREAM << width << height << QString::fromUtf8 (title) << antialias << id;
 	}
 	{
 		// Reading a reply in order to force this to be synchronous. .rk.with.placement.hint() may run into race conditions, otherwise.
@@ -204,6 +222,7 @@ static void RKD_Create (double width, double height, pDevDesc dev, const char *t
 }
 
 static void RKD_Size (double *left, double *right, double *top, double *bottom, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 // NOTE: This does *not* query the frontend for the current size. This is only done on request
 	*left = dev->left;
 	*top = dev->top;
@@ -212,36 +231,57 @@ static void RKD_Size (double *left, double *right, double *top, double *bottom,
 }
 
 static void RKD_SetSize (pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	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);
+static void RKD_Activate (pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
+	RKGraphicsDataStreamWriteGuard guard;
+	WRITE_HEADER (RKDActivate, dev);
+}
+
+static void RKD_Deactivate (pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
+	RKGraphicsDataStreamWriteGuard guard;
+	WRITE_HEADER (RKDDeActivate, dev);
+}
+
+SEXP RKD_AdjustSize(SEXP _devnum, SEXP _id) {
+	RK_TRACE(GRAPHICS_DEVICE);
+	int devnum = Rf_asInteger(_devnum);
+	quint32 id = Rf_asInteger(_id);
+	pGEDevDesc gdev = GEgetDevice(devnum);
+	if (!gdev) Rf_error("No such device %d", devnum);
 	pDevDesc dev = gdev->dev;
+	// This is called from rkward:::RK.resize(), which in turn may be out of sync with R's device list. Before doing anything,
+	// double check that this is really the device we think it is.
+	if (dev->activate != RKD_Activate) Rf_error("Not an RKWard device", devnum);
+	if (static_cast<RKGraphicsDeviceDesc*>(dev->deviceSpecific)->id != id) Rf_error("Graphics device mismatch", devnum);
+
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
-		WRITE_HEADER (RKDGetSize, dev);
+		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);
+	if (size.isNull()) Rf_error("Could not determine current size of device %d. Device closed?", devnum);
 	dev->left = dev->top = 0;
-	dev->right = size.width ();
-	dev->bottom = size.height ();
+	dev->right = size.width();
+	dev->bottom = size.height();
 
-	RKD_SetSize (dev);    // This adjusts the rendering area in the frontend
-	GEplayDisplayList (gdev);
+	RKD_SetSize(dev);    // This adjusts the rendering area in the frontend
+	if(gdev->dirty) GEplayDisplayList(gdev);
 	return R_NilValue;
 }
 
 static void RKD_Circle (double x, double y, double r, R_GE_gcontext *gc, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	RKGraphicsDataStreamWriteGuard guard;
 	WRITE_HEADER (RKDCircle, dev);
 	RKD_OUT_STREAM << x << y << r;
@@ -250,6 +290,7 @@ static void RKD_Circle (double x, double y, double r, R_GE_gcontext *gc, pDevDes
 }
 
 static void RKD_Line (double x1, double y1, double x2, double y2, R_GE_gcontext *gc, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	RKGraphicsDataStreamWriteGuard guard;
 	WRITE_HEADER (RKDLine, dev);
 	RKD_OUT_STREAM << x1 << y1 << x2 << y2;
@@ -258,6 +299,7 @@ static void RKD_Line (double x1, double y1, double x2, double y2, R_GE_gcontext
 }
 
 static void RKD_Polygon (int n, double *x, double *y, R_GE_gcontext *gc, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	RKGraphicsDataStreamWriteGuard guard;
 	WRITE_HEADER (RKDPolygon, dev);
 	quint32 _n = qMin (n, 1 << 25);	// skip stuff exceeding reasonable limits to keep protocol simple
@@ -271,6 +313,7 @@ static void RKD_Polygon (int n, double *x, double *y, R_GE_gcontext *gc, pDevDes
 }
 
 static void RKD_Polyline (int n, double *x, double *y, R_GE_gcontext *gc, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	RKGraphicsDataStreamWriteGuard guard;
 	WRITE_HEADER (RKDPolyline, dev);
 	quint32 _n = qMin (n, 1 << 25);	// skip stuff exceeding reasonable limits to keep protocol simple
@@ -283,6 +326,7 @@ static void RKD_Polyline (int n, double *x, double *y, R_GE_gcontext *gc, pDevDe
 }
 
 static void RKD_Path (double *x, double *y, int npoly, int *nper, Rboolean winding, R_GE_gcontext *gc, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	RKGraphicsDataStreamWriteGuard guard;
 	WRITE_HEADER (RKDPath, dev);
 	quint32 total_points = 0;
@@ -303,6 +347,7 @@ static void RKD_Path (double *x, double *y, int npoly, int *nper, Rboolean windi
 }
 
 static void RKD_Rect (double x0, double y0, double x1, double y1, R_GE_gcontext *gc, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	RKGraphicsDataStreamWriteGuard guard;
 	WRITE_HEADER (RKDRect, dev);
 	RKD_OUT_STREAM << QRectF (x0, y0, x1-x0, y1-y0);
@@ -312,6 +357,7 @@ static void RKD_Rect (double x0, double y0, double x1, double y1, R_GE_gcontext
 }
 
 static void RKD_TextUTF8 (double x, double y, const char *str, double rot, double hadj, R_GE_gcontext *gc, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	RKGraphicsDataStreamWriteGuard guard;
 	WRITE_HEADER (RKDTextUTF8, dev);
 	RKD_OUT_STREAM << x << y << QString::fromUtf8 (str) << rot << hadj;	// NOTE: yes, even Symbols are sent as UTF-8, here.
@@ -320,6 +366,7 @@ static void RKD_TextUTF8 (double x, double y, const char *str, double rot, doubl
 }
 
 static double RKD_StrWidthUTF8 (const char *str, R_GE_gcontext *gc, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	{
 		RKGraphicsDataStreamWriteGuard guard;
 		WRITE_HEADER (RKDStrWidthUTF8, dev);
@@ -335,12 +382,14 @@ static double RKD_StrWidthUTF8 (const char *str, R_GE_gcontext *gc, pDevDesc dev
 }
 
 static void RKD_NewPage (R_GE_gcontext *gc, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	RKGraphicsDataStreamWriteGuard guard;
 	WRITE_HEADER (RKDNewPage, dev);
 	WRITE_FILL ();
 }
 
 static void RKD_MetricInfo (int c, R_GE_gcontext *gc, double* ascent, double* descent, double* width, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
 		WRITE_HEADER (RKDMetricInfo, dev);
@@ -363,8 +412,10 @@ static void RKD_MetricInfo (int c, R_GE_gcontext *gc, double* ascent, double* de
 }
 
 static void RKD_Close (pDevDesc dev) {
-	RKGraphicsDataStreamWriteGuard guard;
-	WRITE_HEADER (RKDClose, dev);
+	RK_TRACE(GRAPHICS_DEVICE);
+	{
+		RKGraphicsDataStreamWriteGuard guard;
+		WRITE_HEADER (RKDClose, dev);
 #ifdef _MSC_VER
 	// Ok, this is a terribly crude HACK, obviously, and it's just waiting to come back to bite us. However:
 	// We had to allocate the DevDesc in our own (MSVC-compiled) code (that's the way it is done), but if we allow R to delete
@@ -374,23 +425,20 @@ static void RKD_Close (pDevDesc dev) {
 	// If (or when) this breaks, we could try to just call some other device's init-routine, then hijack that device. Or out-source
 	// the RKGraphicsDevice backend init code into an R package...
 	// Or can we use R's Calloc/Malloc, instead? -> Manual caution not to use free() (only Free()), on that, though.
-	static_cast<RKGraphicsDeviceDesc*> (dev->deviceSpecific)->rgdevdesc->dev = NULL;
+		static_cast<RKGraphicsDeviceDesc*> (dev->deviceSpecific)->rgdevdesc->dev = NULL;
 	free (dev);
 #endif
-	delete static_cast<RKGraphicsDeviceDesc*> (dev->deviceSpecific);
-}
-
-static void RKD_Activate (pDevDesc dev) {
-	RKGraphicsDataStreamWriteGuard guard;
-	WRITE_HEADER (RKDActivate, dev);
-}
-
-static void RKD_Deactivate (pDevDesc dev) {
-	RKGraphicsDataStreamWriteGuard guard;
-	WRITE_HEADER (RKDDeActivate, dev);
+		delete static_cast<RKGraphicsDeviceDesc*> (dev->deviceSpecific);
+	}
+	{
+		RKGraphicsDataStreamWriteGuard rguard;
+		qint8 dummy;
+		RKD_IN_STREAM >> dummy;
+	}
 }
 
 static void RKD_Clip (double left, double right, double top, double bottom, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	dev->clipLeft = left;
 	dev->clipRight = right;
 	dev->clipTop = top;
@@ -401,6 +449,7 @@ static void RKD_Clip (double left, double right, double top, double bottom, pDev
 }
 
 static void RKD_Mode (int mode, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	Q_UNUSED (mode);
 	Q_UNUSED (dev);
 /* Left empty for now. 1 is start signal, 0 is stop signal. Might be useful for flushing, though.
@@ -411,6 +460,7 @@ static void RKD_Mode (int mode, pDevDesc dev) {
 }
 
 static void RKD_Raster (unsigned int *raster, int w, int h, double x, double y, double width, double height, double rot, Rboolean interpolate, const pGEcontext gc, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	Q_UNUSED (gc);
 
 	RKGraphicsDataStreamWriteGuard wguard;
@@ -430,6 +480,7 @@ static void RKD_Raster (unsigned int *raster, int w, int h, double x, double y,
 }
 
 static SEXP RKD_Capture (pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
 		WRITE_HEADER (RKDCapture, dev);
@@ -471,6 +522,7 @@ static SEXP RKD_Capture (pDevDesc dev) {
 }
 
 static Rboolean RKD_Locator (double *x, double *y, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
 		WRITE_HEADER (RKDLocator, dev);
@@ -485,6 +537,7 @@ static Rboolean RKD_Locator (double *x, double *y, pDevDesc dev) {
 }
 
 static Rboolean RKD_NewFrameConfirm (pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
 		WRITE_HEADER (RKDNewPageConfirm, dev);
@@ -501,6 +554,7 @@ static Rboolean RKD_NewFrameConfirm (pDevDesc dev) {
 
 #if R_VERSION >= R_Version (2, 12, 0)
 void RKD_EventHelper (pDevDesc dev, int code) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
 		if (code == 1) {
@@ -576,6 +630,7 @@ void RKD_EventHelper (pDevDesc dev, int code) {
 }
 
 void RKD_onExit (pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	if (rkd_suppress_on_exit > 0) {
 		--rkd_suppress_on_exit;
 		return;
@@ -590,6 +645,7 @@ void RKD_onExit (pDevDesc dev) {
 
 #if R_VERSION >= R_Version (2, 14, 0)
 int RKD_HoldFlush (pDevDesc dev, int level) {
+	RK_TRACE(GRAPHICS_DEVICE);
 #ifdef __GNUC__
 #warning implement me
 #endif
@@ -614,7 +670,8 @@ SEXP makeInt(int val) {
 }
 
 void forceSync(pDevDesc dev) {
-// NOTE: See commen7 in RKGraphicsDevice::forceSync();
+	RK_TRACE(GRAPHICS_DEVICE);
+// NOTE: See comment in RKGraphicsDevice::forceSync();
 // KF6 TODO: Still neded with Qt6?
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
@@ -628,6 +685,7 @@ void forceSync(pDevDesc dev) {
 }
 
 SEXP RKD_SetPattern (SEXP pattern, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	auto ptype = R_GE_patternType(pattern);
 	if ((ptype == R_GE_linearGradientPattern) || (ptype == R_GE_radialGradientPattern)) {
 		RKGraphicsDataStreamWriteGuard wguard;
@@ -691,6 +749,7 @@ SEXP RKD_SetPattern (SEXP pattern, pDevDesc dev) {
 }
 
 void RKD_ReleasePattern (SEXP ref, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	qint32 index;
 	if (Rf_isNull(ref)) index = 0;  // means: destroy all patterns
 	else index = INTEGER(ref)[0];
@@ -702,6 +761,7 @@ void RKD_ReleasePattern (SEXP ref, pDevDesc dev) {
 }
 
 SEXP RKD_SetClipPath (SEXP path, SEXP ref, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	qint32 index = -1;
 	if (!Rf_isNull(ref)) index = INTEGER(ref)[0];
 	// NOTE: just because we have a reference, doesn't mean, it's also valid, according to R sources
@@ -713,7 +773,7 @@ SEXP RKD_SetClipPath (SEXP path, SEXP ref, pDevDesc dev) {
 		}
 		{
 			RKGraphicsDataStreamReadGuard rguard;
-			bool ok;
+			qint8 ok;
 			RKD_IN_STREAM >> ok;
 			if (!ok) Rf_warning("Invalid reference to clipping path");
 			else return R_NilValue;
@@ -751,6 +811,7 @@ SEXP RKD_SetClipPath (SEXP path, SEXP ref, pDevDesc dev) {
 }
 
 void RKD_ReleaseClipPath (SEXP ref, pDevDesc dev) {
+	RK_TRACE(GRAPHICS_DEVICE);
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
 		WRITE_HEADER(RKDReleaseClipPath, dev);
@@ -767,6 +828,7 @@ void RKD_ReleaseClipPath (SEXP ref, pDevDesc dev) {
 }
 
 SEXP RKD_SetMask (SEXP path, SEXP ref, pDevDesc dd) {
+	RK_TRACE(GRAPHICS_DEVICE);
 #ifdef __GNUC__
 #warning implement me
 #endif
@@ -774,6 +836,7 @@ SEXP RKD_SetMask (SEXP path, SEXP ref, pDevDesc dd) {
 }
 
 void RKD_ReleaseMask (SEXP ref, pDevDesc dd) {
+	RK_TRACE(GRAPHICS_DEVICE);
 #ifdef __GNUC__
 #warning implement me
 #endif
diff --git a/rkward/rbackend/rpackages/rkward/DESCRIPTION b/rkward/rbackend/rpackages/rkward/DESCRIPTION
index c816fd30..d6eb97db 100755
--- a/rkward/rbackend/rpackages/rkward/DESCRIPTION
+++ b/rkward/rbackend/rpackages/rkward/DESCRIPTION
@@ -18,7 +18,7 @@ Authors at R: c(person(given="Thomas", family="Friedrichsmeier",
         role=c("aut")), person(given="the RKWard team",
         email="rkward-devel at kde.org", role=c("cre","ctb")))
 Version: 0.7.3
-Date: 2022-03-10
+Date: 2022-03-19
 RoxygenNote: 7.1.2
 Collate: 
     'base_overrides.R'
diff --git a/rkward/rbackend/rpackages/rkward/R/internal_graphics.R b/rkward/rbackend/rpackages/rkward/R/internal_graphics.R
index 3c027184..d4020d4b 100644
--- a/rkward/rbackend/rpackages/rkward/R/internal_graphics.R
+++ b/rkward/rbackend/rpackages/rkward/R/internal_graphics.R
@@ -14,9 +14,11 @@
 }
 
 # Fetch the current size of the given RK() device from the frontend, and redraw
-"RK.resize" <- function (devnum) {
+"RK.resize" <- function (devnum, id) {
 	# Note: RK.resize() often fails, if something is currently being plotted. That's usually benign, and should not produce warning messages.
-	try (.Call ("rk.graphics.device.resize", as.integer (devnum)-1, PACKAGE="(embedding)"), silent=TRUE)
+	suppressWarnings(
+		try (.Call ("rk.graphics.device.resize", as.integer (devnum)-1, as.integer(id), PACKAGE="(embedding)"), silent=TRUE)
+	)
 }
 
 #' @include internal.R
diff --git a/rkward/windows/rkwindowcatcher.cpp b/rkward/windows/rkwindowcatcher.cpp
index 78dcd023..0371669d 100644
--- a/rkward/windows/rkwindowcatcher.cpp
+++ b/rkward/windows/rkwindowcatcher.cpp
@@ -368,7 +368,7 @@ void RKCaughtX11Window::commonClose(bool in_destructor) {
 	if (rk_native_device) rk_native_device->stopInteraction();
 
 	QString status = i18n("Closing device (saving history)");
-	if (!close_attempted) {
+	if (!(close_attempted || killed_in_r)) {
 		RCommand* c = new RCommand("dev.off (" + QString::number(device_number) + ')', RCommand::App, i18n("Shutting down device number %1", device_number));
 		if (!in_destructor) setStatusMessage(status, c);
 		RKGlobals::rInterface()->issueCommand(c);


More information about the rkward-tracker mailing list