Next Previous Contents

6. Multi-Toolkit Development

Multi-toolkit development can be achieved using a mechanism almost identical to that used for Dialogs. A two tiered arrangement of signalling classes is used. The Popups class is still used by the rest of LyX to access the GUI frontend. However, since the new toolkit port isn't complete we must substitute an existing ports dialogs where necessary. This involves a second class similar to Popups which we'll name according to the incomplete port. This will allow multiple incomplete ports to be developed simultaneously.

Let's assume that we are porting to a GUI toolkit called A and that we'll be using the XForms port to provide those dialogs not yet implemented by the A port. The intermediate class is only used by the A port (say APopups) which is the equivalent of Popups but hides the XForms stuff from the A port. The APopups implementation will be in the XForms directory -- this looks confusing but its called APopups because it holds the XForms popups used by the A port, we'd have a QtPopups for the Qt port and so on.

Multiple Toolkits for Dialogs Overview

The idea is that APopups might start out with all the XForms dialogs and as dialogs are ported the XForms dialogs are removed from APopups. So over time APopups gets smaller and smaller until we eventually remove it. Thus we have temporary intermediate class called APopups and it would contain only those dialogs from the reference port that were required. The A port's implementation of the Popups class has an instance of APopups that it uses. So the Popups constructor must connect the various APopups signals to the Popups signals of the same name. This will ensure that the signals are propagated to the XForms dialogs. A very short example of how the A port's Popups implementation might look is given below:

#include "Communicator.h"
#include "Popups.h"
#include "APopups.h"

static APopups *apopup = 0;

Popups::Popups(const Communicator & comm)
    some_A_Port_Dialog = new someAPortDialog(comm, this);
    /* and some more of this sort of thing */

    // Everything from here down will be removed 
    // once a port is complete
    if (!apopup) {
        apopup = new APopups(comm); 
    /* followed by whichever others are needed */

This implementation only allows one APopups instance to be shared amongst possibly several Popups instances. This would simply mean that the XForms dialogs are shared between all LyXViews instead of having one set per LyXView. For a work in progress this should be okay but if we really wanted per-LyXView dialogs all the time we'd need to make apopup a member of Popups which makes things rather awkward (if config.h were #included into Popups.h we could use the preprocessor to include an APopups instance).

We must then do a bit of preprocessor trickery to make it all work. This is necessary because the XForms dialogs all expect that they will be accessed via the Popups class. The preprocessor trickery simply involves renaming Popups to APopups within the XForms code. An example of the sort of thing needed in the start of an XForms dialog's implementation is shown below:

#ifdef WITH_A 
#include "APopups.h" 
#define Popups APopups 
#include "Popups.h" 

It should also be possible to replace the #define with an equivalent typedef. The main need here is to get the linker linking against the correct implementation.

The APopups constructor should probably be made responsible for ensuring that the reference toolkit's GUI initialisation is performed. This too will probably require a little preprocessor magic because every implementation has its own GUI_initialize function. SMiyata is working on a multi-toolkit GUI_runtime and event handler.

All that remains is a little (!!) Makefile magic to hold it all together. The makefiles have to be setup to compile all the appropriate sources depending upon which of many different toolkits the user wants to use (and allow for the inclusion of multiple toolkits). Probably the simplest way to do this is to use a separate target in the Makefiles. We could assign target "all: kde" in the makefiles when compiling "with-kde" and have separate SUBSYS_o_SOURCES lists. Others will probably have a better idea of what to do here.

A similar scheme could also be used to access the XForms LyXView implementation to get all the dialogs ported and then worry about the LyXView later. Although in the case of the LyXView/Frame its unlikely you'd be able to port one part at a time.

Next Previous Contents