[education/rkward] /: Implement capabilities report for RK()-device

Thomas Friedrichsmeier null at kde.org
Tue Jul 30 17:00:07 BST 2024


Git commit 1ca0fed0b7377f80b8664766a25ee663db4504e5 by Thomas Friedrichsmeier.
Committed on 30/07/2024 at 15:59.
Pushed by tfry into branch 'master'.

Implement capabilities report for RK()-device

M  +1    -0    ChangeLog
M  +1    -0    rkward/rbackend/rkrapi.h
M  +1    -1    rkward/rbackend/rkrbackendprotocol_backend.cpp
M  +72   -3    rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
M  +2    -2    rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
M  +4    -0    rkward/rkward.cpp

https://invent.kde.org/education/rkward/-/commit/1ca0fed0b7377f80b8664766a25ee663db4504e5

diff --git a/ChangeLog b/ChangeLog
index bb0ef5bf4..a3d126f76 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,5 @@
 --- Version 0.8.1 - UNRELEASED
+- Fixed: Implement capbilities report for RK() device (may fix graphics limitation, but also potential crashes with R >= 4.2.0)
 - Fixed: Adjustments to changes in R devel (for compatibility with the future R 4.5.x)
 - Fixed: Potential crash on "spontaneous" R output (originating from event handlers such as tcl)
 - Fixed: commandArgs() would show incorrect options
diff --git a/rkward/rbackend/rkrapi.h b/rkward/rbackend/rkrapi.h
index e72f817e2..80e7fef3e 100644
--- a/rkward/rbackend/rkrapi.h
+++ b/rkward/rbackend/rkrapi.h
@@ -282,6 +282,7 @@ IMPORT_R_API(SET_TAG);
 IMPORT_R_API(SET_TYPEOF);
 IMPORT_R_API(STRING_ELT);
 IMPORT_R_API(SET_STRING_ELT);
+IMPORT_R_API(SET_VECTOR_ELT);
 IMPORT_R_API(SET_PRENV);
 IMPORT_R_API(SET_PRVALUE);
 IMPORT_R_API(TYPEOF);
diff --git a/rkward/rbackend/rkrbackendprotocol_backend.cpp b/rkward/rbackend/rkrbackendprotocol_backend.cpp
index 4289d3591..efb310cf4 100644
--- a/rkward/rbackend/rkrbackendprotocol_backend.cpp
+++ b/rkward/rbackend/rkrbackendprotocol_backend.cpp
@@ -88,7 +88,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
 		setvbuf(stdout, nullptr, _IONBF, 0);
 		setvbuf(stderr, nullptr, _IONBF, 0);
 
-		RK_Debug::RK_Debug_Flags = RBACKEND;
+		RK_Debug::RK_Debug_Flags = RBACKEND | GRAPHICS_DEVICE;
 		if (RK_Debug::setupLogFile (QDir::tempPath () + "/rkward.rbackend")) qInstallMessageHandler (RKDebugMessageOutput);
 
 		QString servername, rkd_server_name;
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
index b55e578b7..86f80fdf6 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
@@ -34,6 +34,7 @@ struct RKGraphicsDeviceDesc {
 };
 
 #include "rkgraphicsdevice_stubs.cpp"
+static SEXP RKD_capabilities(SEXP capabilities);
 
 // No, I do not really understand what this is for.
 // Mostly trying to mimick the X11 device's behavior, here.
@@ -192,8 +193,9 @@ bool RKGraphicsDeviceDesc::init (pDevDesc dev, double pointsize, const QStringLi
 	dev->holdflush = RKD_HoldFlush;
 
 #if R_VERSION >= R_Version (4, 1, 0)
+	static_assert(RKD_RGE_VERSION >= 13);
 	// NOTE: We need both a compiletime and a runtime check, in order to support running with an R older than what was used at compile time
-	if (RFn::R_GE_getVersion() >=  15) {
+	if (RFn::R_GE_getVersion() >=  13) {
 		// patterns and gradients
 		dev->setPattern = RKD_SetPattern;
 		dev->releasePattern = RKD_ReleasePattern;
@@ -204,12 +206,15 @@ bool RKGraphicsDeviceDesc::init (pDevDesc dev, double pointsize, const QStringLi
 		dev->setMask = RKD_SetMask;
 		dev->releaseMask = RKD_ReleaseMask;
 		dev->deviceVersion = qMin(qMin(15, R_GE_version), RFn::R_GE_getVersion());
-		dev->deviceClip = TRUE; // for now
+		if (RFn::R_GE_getVersion() >=  14) {
+			dev->deviceClip = TRUE; // for now
+		}
 	}
 #endif
 
 #if R_VERSION >= R_Version (4, 2, 0)
-	if (RFn::R_GE_getVersion() >=  16) {
+	static_assert(RKD_RGE_VERSION >= 15);
+	if (RFn::R_GE_getVersion() >=  15) {
 		// groups
 		dev->defineGroup = RKD_DefineGroup;
 		dev->useGroup = RKD_UseGroup;
@@ -219,7 +224,71 @@ bool RKGraphicsDeviceDesc::init (pDevDesc dev, double pointsize, const QStringLi
 		dev->stroke = RKD_Stroke;
 		dev->fill = RKD_Fill;
 		dev->fillStroke = RKD_FillStroke;
+		dev->capabilities = RKD_capabilities;
 	}
 #endif
+
+	// NOTE: When extending support don't forget to adjust dev->devicVersion, above!
+
 	return true;
 }
+
+#if R_VERSION >= R_Version (4, 2, 0)
+static void setCapabilityStruct(SEXP capabilities, int category, std::initializer_list<int> values) {
+	SEXP sub;
+	RFn::Rf_protect(sub = RFn::Rf_allocVector(INTSXP, values.size()));
+	int i = 0;
+	for (auto it = values.begin(); it != values.end(); ++i, ++it) {
+		RFn::INTEGER(sub)[i] = *it;
+	}
+	RFn::SET_VECTOR_ELT(capabilities, category, sub);
+	RFn::Rf_unprotect(1);
+}
+
+static SEXP RKD_capabilities(SEXP capabilities) {
+	RK_TRACE(GRAPHICS_DEVICE);
+
+	setCapabilityStruct(capabilities, R_GE_capability_patterns, {
+		R_GE_linearGradientPattern,
+		R_GE_radialGradientPattern,
+		R_GE_tilingPattern
+	});
+	setCapabilityStruct(capabilities, R_GE_capability_clippingPaths, { 1 });
+	setCapabilityStruct(capabilities, R_GE_capability_masks, { R_GE_luminanceMask });
+	setCapabilityStruct(capabilities, R_GE_capability_compositing, {
+		R_GE_compositeMultiply,
+		R_GE_compositeScreen,
+		R_GE_compositeOverlay,
+		R_GE_compositeDarken,
+		R_GE_compositeLighten,
+		R_GE_compositeColorDodge,
+		R_GE_compositeColorBurn,
+		R_GE_compositeHardLight,
+		R_GE_compositeSoftLight,
+		R_GE_compositeDifference,
+		R_GE_compositeExclusion,
+		R_GE_compositeClear,
+		R_GE_compositeSource,
+		R_GE_compositeOver,
+		R_GE_compositeIn,
+		R_GE_compositeOut,
+		R_GE_compositeAtop,
+		R_GE_compositeDest,
+		R_GE_compositeDestOver,
+		R_GE_compositeDestIn,
+		R_GE_compositeDestOut,
+		R_GE_compositeDestAtop,
+		R_GE_compositeXor,
+		R_GE_compositeAdd,
+		//R_GE_compositeSaturate // not supported in QPainter
+	});
+	setCapabilityStruct(capabilities, R_GE_capability_transformations, { 1 });
+	setCapabilityStruct(capabilities, R_GE_capability_paths, { 1 });
+/*
+#if RKD_RGE_VERSION >= 16  // R >= 4.3.0
+	setCapabilityStruct(capabilities, R_GE_capability_glyphs, { 1 });
+#endif
+*/
+	return capabilities;
+}
+#endif
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
index 06467ad46..3b513b97a 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
@@ -247,8 +247,8 @@ SEXP RKD_AdjustSize(SEXP _devnum, SEXP _id) {
 	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) RFn::Rf_error("Not an RKWard device", devnum);
-	if (static_cast<RKGraphicsDeviceDesc*>(dev->deviceSpecific)->id != id) RFn::Rf_error("Graphics device mismatch", devnum);
+	if (dev->activate != RKD_Activate) RFn::Rf_error("Not an RKWard device %d", devnum);
+	if (static_cast<RKGraphicsDeviceDesc*>(dev->deviceSpecific)->id != id) RFn::Rf_error("Graphics device mismatch %d", devnum);
 
 	{
 		RKGraphicsDataStreamWriteGuard wguard;
diff --git a/rkward/rkward.cpp b/rkward/rkward.cpp
index a9976fb26..de116d2ca 100644
--- a/rkward/rkward.cpp
+++ b/rkward/rkward.cpp
@@ -964,6 +964,10 @@ void RKWardMainWindow::setRStatus (int status) {
 		if (rstatus_message) rstatus_message->hide();
 		setIndictatorColor(statusbar_r_status, KColorScheme::NeutralText, KColorScheme::NeutralBackground);
 		statusbar_r_status->setToolTip(i18n("The <b>R</b> engine is being initialized."));
+		if (rstatus_message) {
+			delete rstatus_message;
+			rstatus_message = nullptr;
+		}
 	} else {
 		setIndictatorColor(statusbar_r_status, KColorScheme::NegativeText, KColorScheme::NegativeBackground);
 		statusbar_r_status->setToolTip(i18n("The <b>R</b> engine is unavailable."));


More information about the rkward-tracker mailing list