get rid of the old barriers around GUI event dispatch

since, on further reflection, it doesn't seem needed, and a simple
 prompt seems to make everything work right
This commit is contained in:
Matthew Flatt 2011-01-17 09:21:50 -07:00
parent 7545d7d18f
commit 36155e913e
3 changed files with 39 additions and 102 deletions

View File

@ -390,31 +390,21 @@
(define event-dispatch-handler (make-parameter really-dispatch-event))
(define (handle-event thunk e)
(let/ec esc ; used to disable continuation aborts/jumps past here
(let ([done? #f])
(dynamic-wind
void
(lambda ()
(call-with-continuation-barrier
(lambda ()
(call-with-continuation-prompt ; to delimit continuations
(lambda ()
(call-with-continuation-prompt ; to delimit search for dispatch-event-key
(lambda ()
;; communicate the thunk to `really-dispatch-event':
(let ([b (box thunk)])
;; use the event-dispatch handler:
(with-continuation-mark dispatch-event-key b
((event-dispatch-handler) e))
;; if the event-dispatch handler doesn't chain
;; to the original one, then do so now:
(when (unbox b)
(set-box! b #f)
(thunk))))
dispatch-event-prompt)))))
(set! done? #t))
(lambda ()
(unless done? (esc (void))))))))
(call-with-continuation-prompt ; to delimit continuations
(lambda ()
(call-with-continuation-prompt ; to delimit search for dispatch-event-key
(lambda ()
;; communicate the thunk to `really-dispatch-event':
(let ([b (box thunk)])
;; use the event-dispatch handler:
(with-continuation-mark dispatch-event-key b
((event-dispatch-handler) e))
;; if the event-dispatch handler doesn't chain
;; to the original one, then do so now:
(when (unbox b)
(set-box! b #f)
(thunk))))
dispatch-event-prompt))))
(define yield
(case-lambda

View File

@ -923,86 +923,31 @@ An eventspace is a @techlink[#:doc reference-doc]{synchronizable
parent. (Note that the blocking state of an eventspace is unrelated
to whether an event is ready for dispatching.)
@subsection[#:tag "evtcontjump"]{Exceptions, Continuations, and Jumps}
@subsection[#:tag "evtcontjump"]{Continuations and Event Dispatch}
Whenever the system dispatches an event, the call to the handler is
wrapped with a @deftech{continuation prompt} that delimits
continuations captured by the handler (see
@racket[call-with-continuation-prompt]). For example, if a button
callback captures a continuation, then applying the continuation
later reinstalls only the work to be done by the handler up until the
point that it returns; the dispatch machinery to invoke the button
callback is not included in the continuation. The delimited
continuation prompt is installed outside the call to the @tech{event
dispatch handler}, so any captured continuation includes the
invocation of the @tech{event dispatch handler}.
wrapped with a @deftech{continuation prompt} (see
@racket[call-with-continuation-prompt]) that delimits continuation
aborts (such as when an exception is raised) and continuations
captured by the handler. The delimited continuation prompt is
installed outside the call to the @tech{event dispatch handler}, so
any captured continuation includes the invocation of the @tech{event
dispatch handler}.
An event-handling callback (and the @tech{event dispatch handler}) is
further wrapped with a @deftech{continuation barrier} and a
@racket[dynamic-wind] that blocks jumps (using continuation prompts
other than the default one) that escape past the dispatch site. The
following @scheme[block] procedure illustrates how the system blocks
escape continuation jumps:
@def+int[
(define (block f)
(code:comment @#,t{calls @scheme[f] and returns void if @scheme[f] tries to escape})
(let ([done? #f])
(let/ec k
(dynamic-wind
void
(lambda () (begin0 (f) (set! done? #t)))
(lambda () (unless done? (k (void))))))))
(block (lambda () 5))
(let/ec k (block (lambda () (k 10))))
(let/ec k ((lambda () (k 10))) 11)
(let/ec k (block (lambda () (k 10))) 11)
]
This blocking of continuation jumps complicates the interaction
between @scheme[with-handlers] and @scheme[yield] (or the default
@tech{event dispatch handler}). For example, in evaluating the expression
@schemeblock[
(with-handlers ([(lambda (x) #t)
(lambda (x) (error "error during yield"))])
(yield))
]
the @scheme["error during yield"] handler is @italic{never} called,
even if a callback procedure invoked by @scheme[yield] raises an
exception. The @scheme[with-handlers] expression installs an
exception handler that tries to jump back to the context of the
@scheme[with-handlers] expression before invoking a handler
procedure; this jump is blocked by the dispatch within
@scheme[yield], so @scheme["error during yield"] is never
printed. Exceptions during @scheme[yield] are ``handled'' in the
sense that control jumps out of the event handler, but @scheme[yield]
may dispatch another event rather than escaping or returning.
The following expression demonstrates a more effective way to handle
exceptions within @scheme[yield], for the rare cases where such
handling is useful:
@schemeblock[
(let/ec k
(call-with-exception-handler
(lambda (x)
(error "error during yield")
(k))
(lambda ()
(yield))))
]
This expression installs an exception handler that prints an error
message @italic{before} trying to escape. Like the continuation escape
associated with @scheme[with-handlers], the escape to @scheme[k] never
succeeds. Nevertheless, if an exception is raised by an event
handler during the call to @scheme[yield], an error message is
printed before control returns to the event dispatcher within
@scheme[yield].
For example, if a button callback raises an exception, than the abort
performed by the default exception handler returns to the event-dispatch
point, rather than terminating the program or escaping past an enclosing
@racket[(yield)]. If @racket[with-handlers] wraps a @racket[(yield)] that
leads to an exception raised by a button callback, however, the exception
can be captured by the @racket[with-handlers].
Along similar lines, if a button callback captures a continuation
(using the default continuation prompt tag), then applying the
continuation re-installs only the work to be done by the handler up
until the point that it returns; the dispatch machinery to invoke the
button callback is not included in the continuation. A continuation
captured during a button callback is therefore potentially useful
outside of the same callback.
@section[#:tag "animation"]{Animation in Canvases}

View File

@ -151,7 +151,9 @@ into the control.
Event callbacks are delimited by a continuation prompt using the
default continuation prompt tag. As a result, continuations can be
usufully captured during one event callback and applied during other
callbacks or outside of an even callback.
callbacks or outside of an even callback. The continuation barrier and
jump-defeating `dynamic-wind' that formerly guarded callbacks has been
removed.
Removed Functions