unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Marius Vollmer <mvo@zagadka.ping.de>
Cc: guile-user@gnu.org
Subject: Re: Continuations: possible newbie question
Date: 19 Dec 2002 01:41:24 +0100	[thread overview]
Message-ID: <87n0n2hmbv.fsf@zagadka.ping.de> (raw)
In-Reply-To: <20021218175155.B25665@metro.immute.net>

Matt Hellige <matt@immute.net> writes:

> On the other hand, I'll probably still not end up using this technique
> to implement my call-backs, given the performance penalties and so on.
> I hope I can just shuffle things around a bit in my native code...

I would not worry about performance too early.  If you invoke one
continuation for every key press by the user, that should be no
problem.

Here is a little Gtk+ program that shows off continuations.  I still
find it quite instructive...

;; This is an example of how to use continuations with the Gtk event
;; loop.  It implements a dialog box that looks to the programmer like
;; it was modal, and to the user like it was non-modal.  The function
;; `yes-or-no?' that implements this dialog box only returns to the
;; caller when the user has aswered the dialog.  The user however can
;; pop up any number of these dialog boxes and answer them in any
;; order he likes.  The main application stays alive as well.

(use-modules (gtk gtk))

;; The callbacks that have been delayed

(define callbacks '())

;; Our own event-loop.  We remove the callbacks before invoking them
;; so that we don't get confused when the callback reenters the
;; event-loop.

(define (event-loop)
  (cond
   ((not (null? callbacks))
    (let ((c (car callbacks)))
      (set! callbacks (cdr callbacks))
	 (c)
	 (event-loop)))
   ((not (zero? (gtk-main-iteration)))
    (event-loop))))

;; Connect to a signal and arrange for PROC to be consed onto
;; CALLBACKS when the signal is emitted.

(define (gtk-signal-connect-delayed obj sig proc)
  (gtk-signal-connect obj sig 
		      (lambda () (set! callbacks (cons proc callbacks)))))

;; Now for the continuation part.  To implement the non-modal dialog box
;; that can be used from your code like a modal one, we save the
;; continuation of the YES-OR-NO? invokation and reenter the event-loop
;; (after popping up the window).  When a button has been clicked, we
;; destroy the window and invoke the saved continuation with the
;; appropriate return value.

(define (yes-or-no? title)
  (call-with-current-continuation
   (lambda (cont)
     ;; Now CONT is the part of the program that receives our
     ;; return value.

     (let* ((d (gtk-window-new 'dialog))
	    (v (gtk-vbox-new #f 0))
	    (h (gtk-hbox-new #t 0))
	    (l (gtk-label-new title))
	    (s (gtk-hseparator-new))
	    (y (gtk-button-new-with-label "Yes"))
	    (n (gtk-button-new-with-label "No"))

	    (answer (lambda (val)
		      (gtk-widget-destroy d)

		      ;; Here we return to our caller after the
		      ;; dialog has been destroyed.
		      (cont val))))

       (gtk-container-add d v)
       (gtk-box-pack-start v l #f #f 0)
       (gtk-box-pack-start v s #f #f 0)
       (gtk-box-pack-start v h #f #f 0)
       (gtk-box-pack-start h y #f #f 0)
       (gtk-box-pack-start h n #f #f 0)
       (gtk-widget-show-all d)

       ;; Bind ANSWER to the "clicked" signals of the action
       ;; buttons.
       (gtk-signal-connect-delayed y "clicked" (lambda () (answer #t)))
       (gtk-signal-connect-delayed n "clicked" (lambda () (answer #f)))

       ;; Reenter the event-loop.  You can think of this as a goto.
       (event-loop)))))

(define w (gtk-window-new 'toplevel))
(define b (gtk-button-new-with-label "Ok!"))
(gtk-container-add w b)

(gtk-signal-connect-delayed 
 b "clicked" 
 (let ((i 0))
   (lambda () 
     (set! i (1+ i))
     ;; capture I in a local environment so that nobody can alter
     ;; it while YES-OR-NO? does its thing.
     (let ((i i))
       ;; Use YES-OR-NO? as if it were a modal dialog.
       (pk i (yes-or-no? (string-append (number->string i)
					": Really?")))))))

(gtk-signal-connect w "destroy" gtk-exit)

(gtk-widget-show b)
(gtk-widget-show w)

(event-loop)

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-user


  reply	other threads:[~2002-12-19  0:41 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-12-18 17:27 Continuations: possible newbie question Thien-Thi Nguyen
2002-12-18 18:14 ` Matt Hellige
2002-12-18 20:04   ` Neil Jerram
2002-12-18 23:51     ` Matt Hellige
2002-12-19  0:41       ` Marius Vollmer [this message]
2002-12-19  2:42         ` Matt Hellige
  -- strict thread matches above, loose matches on Subject: below --
2002-12-18 18:42 Thien-Thi Nguyen
2002-12-18  0:14 Matt Hellige

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87n0n2hmbv.fsf@zagadka.ping.de \
    --to=mvo@zagadka.ping.de \
    --cc=guile-user@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).