
How to do member functions and callbacks in a generic fashion without
needing #ifdefs in the wxextend library for different languages, and
without subclassing?

Let's register a C function for each member callback, and then use these C
functions to call CLIPS/Python/whatever.

So, in initialization of the specific extension language, e.g. wxCLIPS,
wxPython, we register C functions that will process callbacks:

  wxRegisterExtensionCallback(WXTYPE type, char *event, ExtensionFunction cFunction);

and this C function is _always_ called with known arguments by
the extension library.

e.g.

  wxRegisterExtensionCallback(wxTYPE_CANVAS, "OnPaint", ClipsImplementOnPaint);

So, the extension library calls 'language implementation' callbacks on a
per CLASS basis; but the language-specific function (e.g.
my-clips-on-paint) is called on a per OBJECT basis.

It is up to this function to determine the correct per-object function
to call, e.g. by retrieving the callback list from this particular
object and seeing if it includes an entry for this member function (e.g.
OnPaint).

For each class, there can't be some static data for the implementation
callbacks, because a generic registration function would not know about
this data. Instead, we use whatever efficient algorithms we can (e.g.
hashed on type, then a list of event/function structures for each type).

Note that there is another kind of registration handler, currently
in use: register-event-handler in wxCLIPS is called by the person
writing CLIPS code, to register a CLIPS handler for the event (e.g.
OnPaint). It is this function that must be found and executed
by the _specific_ language implementation function, e.g.
ClipsImplementOnPaint below.


//// Here's the extension library implementation: implemented
//// in the wxextend library, once and for all. NEVER changed
//// by wxPython or wxCLIPS.
void wxExtensionCanvas::OnPaint(void)
{
  // Finds the function for this type or subtype. There should ALWAYS
  // be a func registered for this member function, or the language
  // binding will be incomplete.
  wxExtensionFunction func = wxFindExtensionCallback(wxTYPE_CANVAS, "OnPaint");
  if (func)
  {
    (* (void (*)(long)) func) ((long)this);
  }
}

//// Using CLIPS as the extension language. This code goes in wxCLIPS.

//// This is the implementation for a SPECIFIC extension language: CLIPS
void ClipsImplementOnPaint(long id)
{
  wxWindow *win = (wxWindow *)id;
  ClipsFunctionTable *table = (ClipsFunctionTable *)win->GetClientData();
  if (table)
  {
    // Find the CLIPS function that has been registered
    // for THIS specific object, THIS message.
    ClipsFunction func = table->Find("OnPaint");
    if (func)
    {
      char buf[100];
      sprintf(buf, "(%s %ld)", func, id);
      clipsEchoOn = FALSE;
      RouteCommand(buf);
      clipsEchoOn = TRUE;
    }
  }
}

void wxClipsInitialize(void)
{ 
  ...
  //// Register this callback.
  wxRegisterExtensionCallback(wxTYPE_CANVAS, "OnPaint", (ExtensionFunction)ClipsImplementOnPaint);
  ...
}

//// Now for using C as the extension language: this code is in an imaginary
//// wxC directory.

//// This is the implementation for a SPECIFIC extension language: C
void CImplementOnPaint(long id)
{
  wxWindow *win = (wxWindow *)id;
  CFunctionTable *table = (CFunctionTable *)win->GetClientData();
  if (table)
  {
    CFunction func = table->Find("OnPaint");
    if (func)
    {
      (* (void (*)(long)) func) (id);
    }
  }
}

void wxCInitialize(void)
{ 
  ...
  //// Register this callback.
  wxRegisterExtensionCallback(wxTYPE_CANVAS, "OnPaint", (ExtensionFunction)CImplementOnPaint);
  ...
}

Problem: how do we note the fact, in the extension library, that
there is no specific object handler, and we should call the default
handler instead? Perhaps this fact should be returned in an extra (e.g.
first) argument to the event handler.

ALSO, all arguments sent to the handler should follow wxWindows
convention as far as possible, not CLIPS: this mapping can be
done within each implementation. So, change the types.

Does this apply to the bitlist, e.g. creating a frame?
Yes: we can simply do the parsing in the CLIPS implementation
wrapper. BUT, this does pose a problem for automated translation,
because some CLIPS function arguments will be posed in terms of strings, whereas
the directly-called C function arguments will be in terms of integers.

Perhaps the translator can have a table of argument-translation
functions; so for a given function call and argument position, the
type will be converted appropriately (ie. the argument generated
by CLIPS2C will be wrapped up in a conversion function which is
implemented in the clipslib support library).

How will this work with callbacks, if e.g. message-box returns a string
in CLIPS and an integer in C? Where does translation take place? The
function e.g. wxcMessageBox can again be wrapped up in a conversion
routine to convert from integer to string. Or -- the string-using function
is also implemented, so no translation is required.

---------------------------------------------------------------

Implementation of a language binding: you may need to define
overloaded versions of all widget creation functions, in order
to supply a callback in the language-specific manner.
This may only really need be done for the C interface, because
other implementations will need to redefine these functions anyway,
and will do the 2-step creation: create the widget, then associate
a callback with it

DELETION of objects. In the original version of wxCLIPS, callback
structures are deleted in the constructor. In the new version,
we don't have access to the constructor, so the client data
(or whatever is used to hold per-object callbacks) doesn't get a chance
to be deleted. SO, we need to have an OnDelete event which all objects
can handle. We may require only one OnDelete handler for wxWindow's if we know
all wxWindow client data is going to be a wxObject.

HOW THIS DISTINCTION HELPS

Say the writer of wxPython added 15 handlers in wxExtend.
The writer of wxCLIPS may need only add code to handle (say) 5
of these because some are for the same message and can be dealt
with using the same function. Ie., OnSize must be intercepted
multiple times in wxExtend, once for each subwindow and frame;
but only one function is needed in wxCLIPS to handle the OnSize
message, since the CLIPS calling method is the same for any
class of window.
