add current-get-interaction-input-port' and adjust racket/gui'

so that GUI events are dispatched while a REPL is blocked on input
This commit is contained in:
Matthew Flatt 2011-01-24 16:57:40 -07:00
parent ce2d6030c7
commit 069a7c2b48
12 changed files with 811 additions and 682 deletions

View File

@ -3,6 +3,7 @@
racket/draw/private/utils racket/draw/private/utils
ffi/unsafe/atomic ffi/unsafe/atomic
racket/class racket/class
racket/port
"rbtree.rkt" "rbtree.rkt"
"../../lock.rkt" "../../lock.rkt"
"handlers.rkt" "handlers.rkt"
@ -358,6 +359,12 @@
(define main-eventspace (make-eventspace* (current-thread))) (define main-eventspace (make-eventspace* (current-thread)))
(define current-eventspace (make-parameter main-eventspace)) (define current-eventspace (make-parameter main-eventspace))
;; So we can get from a thread to the eventspace that
;; it handles (independent of the `current-eventspace'
;; parameter):
(define handler-thread-of (make-thread-cell #f))
(thread-cell-set! handler-thread-of main-eventspace)
(define make-new-eventspace (define make-new-eventspace
(let ([make-eventspace (let ([make-eventspace
(lambda () (lambda ()
@ -367,8 +374,9 @@
(thread (thread
(lambda () (lambda ()
(sync pause) (sync pause)
(parameterize ([current-eventspace es]) (thread-cell-set! handler-thread-of es)
(yield (make-semaphore))))))]) (current-eventspace es)
(yield (make-semaphore)))))])
(semaphore-post pause) (semaphore-post pause)
es))]) es))])
make-eventspace)) make-eventspace))
@ -578,3 +586,28 @@
(lambda (v) (lambda (v)
(yield main-eventspace) (yield main-eventspace)
(old-eyh v)))) (old-eyh v))))
;; When using a REPL in a thread that has an eventspace,
;; yield to events when the port would block.
(current-get-interaction-input-port
(let ([orig (current-get-interaction-input-port)])
(lambda ()
(let ([e (thread-cell-ref handler-thread-of)])
(if e
(let ([filter (lambda (v)
(cond
[(eq? v 0) (yield) 0]
[(evt? v)
(parameterize ([current-eventspace e])
(yield))
(choice-evt v
(wrap-evt (eventspace-event-evt e)
(lambda (_) 0)))]
[else v]))])
(filter-read-input-port
(orig)
(lambda (str v)
(filter v))
(lambda (s skip evt v)
(filter v))))
(orig))))))

View File

@ -49,6 +49,7 @@ Both parts of the toolbox rely extensively on the
@include-section["wxme.scrbl"] @include-section["wxme.scrbl"]
@include-section["prefs.scrbl"] @include-section["prefs.scrbl"]
@include-section["dynamic.scrbl"] @include-section["dynamic.scrbl"]
@include-section["startup.scrbl"]
@;------------------------------------------------------------------------ @;------------------------------------------------------------------------

View File

@ -0,0 +1,37 @@
#lang scribble/doc
@(require "common.ss"
(for-label racket/gui/dynamic))
@title{Startup Actions}
The @racketmodname[racket/gui/base] module can be instantiated only
once per operating-system process, because it sets hooks in the Racket
run-time system to coordinate between Racket thread scheduling and GUI
events. Attempting to instantiate it a second time results in an
exception.
Loading @racketmodname[racket/gui/base] sets two parameters:
@itemlist[
@item{@racket[executable-yield-handler] --- The executable yield
handler is set to evaluate @racket[(yield _initial-eventspace)]
before chaining to the previously installed handler. As a
result, the Racket process will normally wait until all
top-level windows are closed, all callbacks are invoked, and all
timers are stopped in the initial eventspace before the process
exits.}
@item{@racket[current-get-interaction-input-port] --- The interaction
port handler is set to wrap the previously installed handler's
result to yield to GUI events when the input port blocks on
reading. This extension of the default handler's behavior is
triggered only when the current thread is the handler thread of
some eventspace, in which case @racket[current-eventspace] is
set to the eventspace before invoking @racket[yield]. As a
result, GUI events normally can be handled while
@racket[read-eval-print-loop] (such as run by the plain Racket
executable) is blocked on input.}
]

View File

@ -317,19 +317,36 @@ the @racket[current-prompt-read], @racket[current-eval], and
A parameter that determines a @deftech{prompt read handler}, which is A parameter that determines a @deftech{prompt read handler}, which is
a procedure that takes no arguments, displays a prompt string, and a procedure that takes no arguments, displays a prompt string, and
returns a top-level form to evaluate. The prompt read handler is returns a top-level form to evaluate. The prompt read handler is
called by @racket[read-eval-print-loop], and the handler typically called by @racket[read-eval-print-loop], and after printing a prompt,
should call the @tech{read interaction handler} (as determined by the the handler typically should call the @tech{read interaction handler}
@racket[current-read-interaction] parameter) after printing a prompt. (as determined by the @racket[current-read-interaction] parameter)
with the port produced by the @tech{interaction port handler}
(as determined by the @racket[current-get-interaction-input-port] parameter).
The default prompt read handler prints @litchar{> } and returns the The default prompt read handler prints @litchar{> } and returns the
result of result of
@racketblock[ @racketblock[
(let ([in (current-input-port)]) (let ([in ((current-get-interaction-input-port))])
((current-read-interaction) (object-name in) in)) ((current-read-interaction) (object-name in) in))
]} ]}
@defparam[current-get-interaction-input-port proc (-> input-port?)]{
A parameter that determines the @deftech{interaction port handler},
which returns a port to use for @racket[read-eval-print-loop] inputs.
The default interaction port handler returns the current input port.
In addition, if that port is the initial current input port,
the initial current output and error ports are flushed.
The @racketmodname[racket/gui/base] library adjusts this parameter's
value by extending the current value. The extension wraps the result
port so that GUI events can be handled when reading from the port
blocks.}
@defparam[current-read-interaction proc (any/c input-port? -> any)]{ @defparam[current-read-interaction proc (any/c input-port? -> any)]{
A parameter that determines the current @deftech{read interaction A parameter that determines the current @deftech{read interaction

View File

@ -1,3 +1,7 @@
5.0.99.7
add `current-get-interaction-input-port', which enables
`racket/gui' events to be dispatched while a REPL is blocked
5.0.99.2 5.0.99.2
proxy => impersonator proxy => impersonator
equal? equates C pointers when they refer to the same address equal? equates C pointers when they refer to the same address

View File

@ -1191,6 +1191,7 @@ enum {
MZCONFIG_PRINT_HANDLER, MZCONFIG_PRINT_HANDLER,
MZCONFIG_PROMPT_READ_HANDLER, MZCONFIG_PROMPT_READ_HANDLER,
MZCONFIG_READ_HANDLER, MZCONFIG_READ_HANDLER,
MZCONFIG_READ_INPUT_PORT_HANDLER,
MZCONFIG_READTABLE, MZCONFIG_READTABLE,
MZCONFIG_READER_GUARD, MZCONFIG_READER_GUARD,

File diff suppressed because it is too large Load Diff

View File

@ -183,6 +183,7 @@ Scheme_Object *scheme_values(int argc, Scheme_Object *argv[]);
static Scheme_Object *current_print(int argc, Scheme_Object **argv); static Scheme_Object *current_print(int argc, Scheme_Object **argv);
static Scheme_Object *current_prompt_read(int, Scheme_Object **); static Scheme_Object *current_prompt_read(int, Scheme_Object **);
static Scheme_Object *current_read(int, Scheme_Object **); static Scheme_Object *current_read(int, Scheme_Object **);
static Scheme_Object *current_get_read_input_port(int, Scheme_Object **);
static Scheme_Object *write_compiled_closure(Scheme_Object *obj); static Scheme_Object *write_compiled_closure(Scheme_Object *obj);
static Scheme_Object *read_compiled_closure(Scheme_Object *obj); static Scheme_Object *read_compiled_closure(Scheme_Object *obj);
@ -571,6 +572,11 @@ scheme_init_fun (Scheme_Env *env)
"current-read-interaction", "current-read-interaction",
MZCONFIG_READ_HANDLER), MZCONFIG_READ_HANDLER),
env); env);
scheme_add_global_constant("current-get-interaction-input-port",
scheme_register_parameter(current_get_read_input_port,
"current-get-interaction-input-port",
MZCONFIG_READ_INPUT_PORT_HANDLER),
env);
scheme_install_type_writer(scheme_unclosed_procedure_type, scheme_install_type_writer(scheme_unclosed_procedure_type,
write_compiled_closure); write_compiled_closure);
@ -9601,6 +9607,15 @@ current_read(int argc, Scheme_Object **argv)
2, NULL, NULL, 0); 2, NULL, NULL, 0);
} }
static Scheme_Object *
current_get_read_input_port(int argc, Scheme_Object **argv)
{
return scheme_param_config("current-get-interaction-input-port",
scheme_make_integer(MZCONFIG_READ_INPUT_PORT_HANDLER),
argc, argv,
0, NULL, NULL, 0);
}
Scheme_Object * Scheme_Object *
scheme_default_print_handler(int argc, Scheme_Object *argv[]) scheme_default_print_handler(int argc, Scheme_Object *argv[])
{ {
@ -9623,22 +9638,37 @@ scheme_default_print_handler(int argc, Scheme_Object *argv[])
return scheme_void; return scheme_void;
} }
Scheme_Object *
scheme_default_read_input_port_handler(int argc, Scheme_Object *argv[])
{
Scheme_Object *inport;
inport = scheme_get_param(scheme_current_config(), MZCONFIG_INPUT_PORT);
if (inport == scheme_orig_stdin_port)
scheme_flush_orig_outputs();
return inport;
}
Scheme_Object * Scheme_Object *
scheme_default_prompt_read_handler(int argc, Scheme_Object *argv[]) scheme_default_prompt_read_handler(int argc, Scheme_Object *argv[])
{ {
Scheme_Config *config; Scheme_Config *config;
Scheme_Object *port, *reader; Scheme_Object *port, *reader, *getter;
Scheme_Object *inport, *name, *a[2]; Scheme_Object *inport, *name, *a[2];
config = scheme_current_config(); config = scheme_current_config();
port = scheme_get_param(config, MZCONFIG_OUTPUT_PORT); port = scheme_get_param(config, MZCONFIG_OUTPUT_PORT);
inport = scheme_get_param(config, MZCONFIG_INPUT_PORT);
scheme_write_byte_string("> ", 2, port); scheme_write_byte_string("> ", 2, port);
scheme_flush_output(port); scheme_flush_output(port);
if (inport == scheme_orig_stdin_port) getter = scheme_get_param(config, MZCONFIG_READ_INPUT_PORT_HANDLER);
scheme_flush_orig_outputs(); inport = _scheme_apply(getter, 0, NULL);
if (!SCHEME_INPORTP(inport))
scheme_wrong_type("default-prompt-read-hander", "input port", -1, -1, &inport);
name = (Scheme_Object *)scheme_port_record(inport); name = (Scheme_Object *)scheme_port_record(inport);
name = ((Scheme_Input_Port *)name)->name; name = ((Scheme_Input_Port *)name)->name;

View File

@ -13,7 +13,7 @@
#define USE_COMPILED_STARTUP 1 #define USE_COMPILED_STARTUP 1
#define EXPECTED_PRIM_COUNT 1017 #define EXPECTED_PRIM_COUNT 1018
#define EXPECTED_UNSAFE_COUNT 76 #define EXPECTED_UNSAFE_COUNT 76
#define EXPECTED_FLFXNUM_COUNT 68 #define EXPECTED_FLFXNUM_COUNT 68
#define EXPECTED_FUTURES_COUNT 5 #define EXPECTED_FUTURES_COUNT 5

View File

@ -1992,6 +1992,7 @@ Scheme_Object *scheme_default_eval_handler(int, Scheme_Object *[]);
Scheme_Object *scheme_default_compile_handler(int, Scheme_Object *[]); Scheme_Object *scheme_default_compile_handler(int, Scheme_Object *[]);
Scheme_Object *scheme_default_print_handler(int, Scheme_Object *[]); Scheme_Object *scheme_default_print_handler(int, Scheme_Object *[]);
Scheme_Object *scheme_default_prompt_read_handler(int, Scheme_Object *[]); Scheme_Object *scheme_default_prompt_read_handler(int, Scheme_Object *[]);
Scheme_Object *scheme_default_read_input_port_handler(int argc, Scheme_Object *[]);
Scheme_Object *scheme_default_read_handler(int argc, Scheme_Object *[]); Scheme_Object *scheme_default_read_handler(int argc, Scheme_Object *[]);
extern Scheme_Object *scheme_default_global_print_handler; extern Scheme_Object *scheme_default_global_print_handler;

View File

@ -13,12 +13,12 @@
consistently.) consistently.)
*/ */
#define MZSCHEME_VERSION "5.0.99.6" #define MZSCHEME_VERSION "5.0.99.7"
#define MZSCHEME_VERSION_X 5 #define MZSCHEME_VERSION_X 5
#define MZSCHEME_VERSION_Y 0 #define MZSCHEME_VERSION_Y 0
#define MZSCHEME_VERSION_Z 99 #define MZSCHEME_VERSION_Z 99
#define MZSCHEME_VERSION_W 6 #define MZSCHEME_VERSION_W 7
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y) #define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W) #define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)

View File

@ -6945,6 +6945,11 @@ static void make_initial_config(Scheme_Thread *p)
0, 0); 0, 0);
init_param(cells, paramz, MZCONFIG_PROMPT_READ_HANDLER, ph); init_param(cells, paramz, MZCONFIG_PROMPT_READ_HANDLER, ph);
ph = scheme_make_prim_w_arity(scheme_default_read_input_port_handler,
"default-get-interaction-input-port",
0, 0);
init_param(cells, paramz, MZCONFIG_READ_INPUT_PORT_HANDLER, ph);
ph = scheme_make_prim_w_arity(scheme_default_read_handler, ph = scheme_make_prim_w_arity(scheme_default_read_handler,
"default-read-interaction-handler", "default-read-interaction-handler",
2, 2); 2, 2);