Jon,
Just in case you are not aware your problem is easy to solve if you use
sdl [1] instead of glut to setup your gl context and handle input. Sdl
doesn't own your main loop, you can poll or wait for events and then
continue with your own code.
This simplifies a lot the interaction with the toplevel. For example,
you can enter a function from the toplevel which will handle user input
until the user presses escape to return to the toplevel and reenter the
function later again. Or you can just initialize the context and then
paint your window from the toplevel without handling the input in the
window.
The features you loose with respect to glut is menus and multiple
windows. But with sdl you don't need threads to solve your problem, you
control the loop and this may be simpler for students (unless you want
to introduce them to concurrency at the same time...).
A more brittle path to follow (with glut or whatever) which I did not
investigate deeply is to use the (hidden) Toploop module and to try to
render and control the toplevel in one of your glut window. However I
don't know enough about Toploop to be sure you can get to the expected
result.
Daniel
[1] <http://ocamlsdl.sourceforge.net/>