[Rd] GUI hooks in R [Was: assignInNamespace and new bindings]

Simon Urbanek simon.urbanek at r-project.org
Wed Jun 1 22:02:16 CEST 2011

On Jun 1, 2011, at 1:50 PM, Thomas Friedrichsmeier wrote:

> On Wednesday 01 June 2011, Simon Urbanek wrote:
>> I suppose, yes, it's possible, but I see somewhat of an asymmetry if done
>> that way : GUIs are like plug-ins in that there is a set of functions they
>> have to implement to work properly. In the current state this is done
>> using the C-level hooks, but they are incomplete in that some of the
>> required hooks are not available on all platforms. However, if you
>> introduce an additional layer of R function hooks, there will be two sets
>> of competing ways for the GUI so register and some of them are simply not
>> feasible on the R level (console handling, for example, which is why we
>> have C-level hooks).
> Well we already have both, at least in some parts. See e.g. options() "pager" 
> and "editor" (which have dupes on the C level, some of which are not cross-
> platform, again), and "browser" (which is a likely candidate for GUI-
> customization, and does not have a C equivalent). Possibly options("error"), 
> too, and perhaps some others.
> Options on the R level have some obvious advantages, e.g. it is not quite as 
> impossible to change the function signature at a later point of time. Also 
> keep in mind that GUIs will almost certainly comprise some R code, but do not 
> necessarily have to have C code.

This is a whole different story. So far I have been talking about embedding GUIs which use Read/WriteConsole and that is also what the original question was about. Obviously you can add toolkit packages, but I don't consider those GUIs in the discussed sense. My argument was that we should clean up the embedding GUIs facilities first by making them consistent across platforms. Those should not need to require separate R code.

> Think tcltk or RGtk based UIs, for instance. 

Those are fairly special in that there are embedding GUIs available as examples (although I'm not sure how functional). However you may not have meant that aspect of it so the above applies.

> Why shouldn't these have an easy way to customize select.list(), for instance. 
> Finally, having this in options() will allow power-users to utilize selected 
> GUI elements, whereever they like (or to disable their GUIs graphical dialogs 
> for some features).

Agreed, but this is a separate question and consideration. But I take your point about "pager" option, for example. It would be nice to have concise list of UI-customization in the non-embedded sense that can be used by any UI packages. 

> Also, I can give you a bunch more UI functions that I would like to be able to 
> customize cross-platform. From the top of my head:
> - Yes / no / cancel questions (graphical only on Windows, currently, but why 
> not let the hosting GUI decide?)
> - readline()
> - Progress bars

> - Adding menus (several GUIs bring their own functions for this, but there is 
> no standard API. Thus packages have a hard time integrating with more than 
> just one GUI.)

I definitely agree with this one - each GUI has its own functions for menu handling which is annoying to say the least.

> Do you seriously want to have a C API for all of these?

Not all, see above. However, menus are an interesting example - it can't be quite a vanilla customization, because the implementation of the menu backend is heavily dependent on what embedding GUI is running R, so it is not really a customization as there may not be any choices (e.g., you can't use JGR's menu functions in the Mac GUI)

A while ago I was proposing a different approach when working on iWidgets - there would be a global GUI object that would be used for UI functions so they can dispatch on it. Then methods could be written for the various GUI object classes implementing different GUIs and behaviors so the R-side code would be very simple - just calling generics - whereas the actual implementation of those methods could be in any package that is providing the current GUI. This would leverage method dispatch as the natural selection of behavior. I still like this the best - you could even have packages that specialize other GUIs and create subclasses etc. Also now we actually have the object system supporting GUI-style semantics (reference) in R... Again, this is not for user-side customization but to link UI provides with R's UI functions.

>> It also makes the GUI unnecessary messy, since they
>> will need to provide both C code and R code, where the R code essentially
>> just points to C code, practically replicating what the C-level hooks
>> would do (just more complicated as it requires embedded symbol
>> registrations etc.).
> Personally, I find that easier than even setting the C pointers cross-platform 
> (because the way to set these is platform specific).

Well, it should be consistent :).

>> Currently I'm more inclined to make the hooks cross-platform (maybe
>> conditional on the GUI type set to "custom" or something like that). But
>> if someone wants to devise some nice way of customizing parts using R
>> callback, I won't oppose it.
> Well, if that stands *real* chances of being included, I will happily make a 
> start (and take the discussion to R-SIG-GUI).

I suppose it is a good idea (I'll need to subscribe to SIG-GUI, though ;)).

>> If you have issues with stdout buffer before the pipe, use can use
>> setvbuf() to disable buffering.
> Well, actually I capture the stdout in a separate process (RKWard uses two 
> processes, anyway). Perhaps moving all output capturing to one process might 
> fix my interleaving issues without the need to mess with system[2](). I'll give 
> that a try.

I guess then your issue may be in IPC since your second process may not be in sync with the R process event loop ... Also if you use separate file descriptors then they are by default block-bufferend which won't work so synchronization issues aside you'll need setvbuf() to make them unbuffered.

>> Cautiously I would argue you have to the moment you're outside R,
>> essentially since the built-in graphics devices are not guaranteed to work
>> when embedded. In practice, I think if you write a GUI, you have to
>> provide a GD - that is the only reasonable way you can seamlessly
>> incorporate R graphics into your GUI.
> Not on Windows and X11, at least. Try RKWard on one of these platforms, and 
> see if you can find any seams. Then check your dev.list() to see the underlying 
> devices.
> Admittedly, we do not have support for the Quartz device, yet, and this may be 
> harder than Windows and X11, but I'm still optimistic.

Quartz is fairly nice in that you can provide additional back-ends fairly quickly - see R_ext/QuartzDevice.h - so you could embed it directly into your GUI. (But then I suppose the Mac support is too far away from reality for this to be relevant ;))

>> That said, there is a precedent for graphics hooks. The problem I see is
>> the same that became apparent with grid last time we added hooks - there
>> are potentially multiple ways to get to the same C level point, and they
>> are either easily forgotten, or even hard to enumerate. For example,
>> dev.set() is not the only way to activate a device - it can be activated
>> from the menu and other means via selectDevice() which is at C level, so
>> there is no R code involved at all, thus setting a hook on dev.set() is
>> will work only in a  subset of cases and thus you cannot expect
>> consistency in your GUI.
> Well, in our particular use case, we can query the window manager for 
> everything else we need to know. But of course there are several more use-
> cases, where adding hooks at the R level would not be good enough (one would 
> be multi-device plot history feature).
> However, *if* such hooks are going to be integrated into base R, then it 
> _think_, it should be no problem to root these hooks at the C level, rather 
> than the R level.
>> (Note: none of my comments are specific to RKWard, since it is not even
>> available for OS X so I don't know anything about it)
> Well, I can't blame you for not trying it, since compilation on the Mac does 
> take ages, and we don't promise the result is any useful, ATM. We simply don't 
> have a developer with a Mac in the project. But most of the time, you *can* 
> compile RKWard on Mac OS X, and it is known to work at least some of the time.

I consider it theoretical, because you actually require KDE which doesn't exist natively so far (and building it in X11 is like requiring Linux ;) - it's in fact much easier to run Linux VM than to try to build KDE on OS X :P I did try at some point...). This is OT so feel free to reply in private if you wish -- but why don't you abstract out the interface so that you can use native toolkits (like RStudio does - that's one thing they did well)?


More information about the R-devel mailing list