[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: guile as extension language
From: |
Neil Jerram |
Subject: |
Re: guile as extension language |
Date: |
07 Apr 2002 15:38:14 +0100 |
User-agent: |
Gnus/5.0808 (Gnus v5.8.8) Emacs/20.7 |
>>>>> "Paul" == Paul Emsley <address@hidden> writes:
Paul> On Sun, 2002-04-07 at 00:47, Matthew R Wette wrote:
>> Matthew R Wette writes ...
>> >
>> > How is Guile intended to be used as an extension language?
>> >
>> My interest here was in exploring the scope of work required to
>> make a Guile extension for Dia (the gnome graphics app).
>>
Paul> This is not a reply really, more of a me-too.
I've replied separately to Matthew's question, and most of what I say
there should apply to your case as well, when it comes to deciding
what you want your script to be able to control, and how to achieve that.
Which just leaves ...
Paul> I have recently written a program in C/C++ using gtk [1] and now want
to
Paul> type a script (say) (or commands) at the console/terminal. I would
like
Paul> this to be interpreted by guile but cannot see how since gtk has the
Paul> control passed completely to it using gtk_main().
This question keeps cropping up, so this time I'll try my best to give
a definitive answer.
1. Do you really want this I/O at the console? You could choose
instead to use a GtkEntry widget for typing in, and a GtkText for
the output, and include these widgets in your overall GUI. Then
everything would be under the control of gtk_main(), so you avoid
the main issue.
If you followed this route, the basic mechanism for getting
commands evaluated would be to add an "activate" signal handler to
the GtkEntry widget that calls scm_c_eval_string to evaluate the
line of input in the widget.
2. If you definitely want I/O at the console, you can use gtk_idle_add
to register a function that gtk_main should call when nothing is
happening in the GUI. The function that you register should
- do a non-blocking select on standard input to find whether
there's anything to read
- read characters 1 at a time into an input buffer
- when newline is read, call scm_c_eval_string to evaluate the
buffered input.
3. However, both the above are suboptimal for two main reasons:
3.1. They only work if the expression entered on a line is always
balanced.
3.2. They don't support the reading of input that is not meant to
be evaluated, or that should be evaluated in a different way.
(e.g. input for the Guile debugger).
What you really want, IMO, to overcome these issues, is for the
GtkEntry widget (case 1) or the console (case 2) to act like input
ports with two properties:
- From the point of view of code like `(top-repl)' (which
implements the standard Guile REPL), they can be used as input
ports just like any others.
- But, whenever there isn't any immediate input available, they
call gtk_main.
The good news is that Scheme continuations make it possible to do
exactly this! Suppose in C that you
- define and export a Scheme primitive `call-gtk-main', which just
calls gtk_main
- define and export a Scheme primitive `store-continuation', which
saves its continuation argument in a global variable
- write a Gtk idle function `check_stdin', which checks for input
available on standard input and, if there is any, calls the
continuation stored above
- use gtk_idle_add to register this idle function with gtk_main.
Now you can make a soft input port with this read-char procedure:
(lambda ()
(call-with-current-continuation
(lambda (cont)
(store-continuation cont)
(call-gtk-main)))
(read-char standard-input))
(This is for case 2. For case 1 you need something a bit trickier,
where the continuation is called from the "activate" handler, and
the read-char procedure uses an input buffer.)
Finally, to get everything rolling, you need to
- do all your usual application initialization
- define the soft port as shown above, and call it, say,
`soft-port'
- evaluate `(set-current-input-port soft-port)'
- evaluate `(top-repl)'.
(Probably the last 3 steps are most conveniently achieved by
loading a Scheme file.)
For a working example of approach 3, using guile-gtk and the GtkEntry
widget, you might like to grab my guile-gui distro from
http://www.ossau.uklinux.net/guile.
Paul> Is scm_init_guile() really the way to do it? I got the impression
that
Paul> it was not, if I wanted portability (and I do).
scm_init_guile is mostly a red herring. Since you have control of
your source code's main function, you can just as easily do the
scm_boot_guile structure:
- main ()
- scm_boot_guile (..., inner_main, ...)
- inner_main ()
- rest of application
as the scm_init_guile structure:
- main ()
- scm_init_guile ()
- rest of application
It may be true that scm_init_guile is marginally less portable; I
don't know for sure.
(scm_init_guile is designed for libraries that don't have access to
main().)
Paul> I initially thought that that guile + gtk (not guile-gtk) would be
Paul> common combination and tried to find examples to see how they did it,
Paul> but I could not. Can you recommend anything?
Bill Schottstaedt has previously posted examples using both Motif and
Gtk, and Ariel Rios has written a `GuileRepl' widget using Gtk. All
of these are examples of case 1 above. I'd guess that Bill's example
is available in the Snd source, and Ariel's in Gnome CVS.
Paul> I thought that converting to guile-gtk, but since I was using glade
and
Paul> gtkglarea, I was a bit nervous about doing that. Should I have been?
Suggest looking at guile-gtk (and perhaps also my guile-gui) to see
what guile-gtk can do for you. Given that you're already using glade,
it might be that the only thing of use to you would be calling
`gtk-main' from Scheme instead of `gtk_main' from C - i.e. not much
difference!
Neil