Updating packages for 2.7.0 =========================== Package maintainers should be aware of the following changes scheduled to appear in 2.7.0 sometime in April 2008. Graphics Devices ================ This section applies to graphics devices in packages. The standard package 'grDevices' and the X11 device in src/modules/X11 provide reference examples. The API has been changed, and although the old API is currently still supported (but probably not for 2.8.x), please update to the new and cleaner API. There is a (new) description in the 'R Internals' manual. 1) The only graphics header required is #include (which includes GraphicsDevice.h>). Rgraphics.h is part of the base graphics system, and should not be included. Nor should Rdevices.h. 2) 'newDevStruct' has been removed from both a NewDevDesc and a GEDevDesc, and must not be initialized. The following elements of the NewDevDesc are no longer present (most were already unused): canResizePlot canChangeFont canRotateText canResizeText asp dot() hold() open() displayList savedSnapshot DLlastElt Packages almost certainly need an 'open' function themselves, but it is never called by the R engine.) It was long unnecessary to initialize displayList or savedSnapshot. There new pointer types pGEDevDesc and pDevDesc (to what is currently called NewDevDesc), and these are preferred to explicit pointers. 3) Define R_USE_PROTOTYPES to 1 to check the prototypes in the callbacks set in the NewDevDesc. (This is optional as some users have passed pointers to their own structures rather than a pDevDesc -- this may not continue to work, but defining R_USE_PROTOTYPES to 0 removes the check.) By release time R_USE_PROTOTYPES=1 will be the default. 4) There should be no references to DevDesc in the package code. This is likely to need replacement calls as follows: old new -------------------------- addDevice GEaddDevice GetDevice GEgetDevice KillDevice GEkillDevice CurrentDevice GEcurrentDevice all of the RHS taking a pGEDevDesc as an argument, and devNumber ndevNumber which takes a pDevDesc as an argument. 5) A frequent construction is to find the GEDevDesc corresponding to a NewDevDesc, for example to replay the display list or to kill the device. This used to be of the form KillDevice((DevDesc*) GetDevice(devNumber((DevDesc*) dd))); (from devX11.c), which was particularly egregious as a NewDevDesc* was being cast to a DevDesc*. This has been replaced by killDevice(ndevNumber(dd)); but there is a convenience function pGEDevDesc desc2GEDesc(pDevDesc dd) to find the enclosing GEDevDesc. 6) BEGIN_SUSPEND_INTERRUPTS and END_SUSPEND_INTERRUPTS are defined in GraphicsDevice.h and should be used to surround the code creating and adding the device. 7) The metricInfo function should take account of MBCS locales, so be something like static void NULL_MetricInfo(int c, pGEcontext gc, double* ascent, double* descent, double* width, pDevDesc dev) { Rboolean Unicode = mbcslocale; if (c < 0) { Unicode = TRUE; c = -c; } /* used if hasTextUTF8=TRUE */ if(Unicode && gc->fontface != 5 && c >= 128) { /* Unicode case */ ; } else { /* single-byte case */ ; } } 8) Some packages work hard to provide overall metric information for the font when the metricInfo() callback is called with c=0. This is no longer used (and was only used in recent times to test if any font metric information was available). 9) Some packages are able to handle UTF-8/Unicode text even in a non-UTF-8 locale, and others really want only UTF-8 text. The graphics engine can be asked to send all but symbol text in UTF-8 via dd->hasTextUTF8 = TRUE; dd->textUTF8 = UTF8_text_function; dd->strWidthUTF8 = UTF8_strwidth_function; when ordinary text will be sent to the UTF8 functions and symbols to the standard functions. If you want even symbols sent in UTF-8, also define dd->wantSymbolUTF8 = TRUE; (Fonts containing the complete Adobe Symbol set in UTF-8 are rare, though.) If you do this the metricInfo function will need to be something like static void My_MetricInfo(int c, pGEcontext gc, double* ascent, double* descent, double* width, pDevDesc dev) { Rboolean Unicode = mbcslocale; char str[16]; if (c < 0) { Unicode = TRUE; c = -c; } /* used if hasTextUTF8=TRUE */ if(Unicode && c >= 128) { /* Unicode case */ Rf_ucstoutf8(str, c); } else { /* ASCII case */ ; str[0] = c; str[1] = '\0'; } /* Do something with str */ }