mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-29 08:20:20 +02:00
Experimental hacks emulating the Guile-iii Tk interface.
This commit is contained in:
parent
7dd98e0b20
commit
c7ec19832b
3 changed files with 549 additions and 0 deletions
377
ice-9/gtcl.scm
Normal file
377
ice-9/gtcl.scm
Normal file
|
@ -0,0 +1,377 @@
|
|||
;;;; Copyright (C) 1996, 1997 Mikael Djurfeldt
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or modify
|
||||
;;;; it under the terms of the GNU General Public License as published by
|
||||
;;;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;;;; any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this software; see the file COPYING. If not, write to
|
||||
;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
;;;;
|
||||
;;;; The author can be reached at djurfeldt@nada.kth.se
|
||||
;;;; Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN
|
||||
;;;;
|
||||
|
||||
;;; *******************************
|
||||
;;; * Experimental hack *
|
||||
;;; * Shouldn't go into snapshots *
|
||||
;;; * Don't distribute! *
|
||||
;;; *******************************
|
||||
|
||||
(define-module (ice-9 gtcl) :use-module (ice-9 debug))
|
||||
|
||||
(define-public TCL_VERSION "7.4")
|
||||
(define-public TCL_MAJOR_VERSION 7)
|
||||
(define-public TCL_MINOR_VERSION 4)
|
||||
|
||||
;;; When a TCL command returns, the string pointer interp->result points to
|
||||
;;; a string containing return information from the command. In addition,
|
||||
;;; the command procedure returns an integer value, which is one of the
|
||||
;;; following:
|
||||
;;;
|
||||
;;; TCL_OK Command completed normally; interp->result contains
|
||||
;;; the command's result.
|
||||
;;; TCL_ERROR The command couldn't be completed successfully;
|
||||
;;; interp->result describes what went wrong.
|
||||
;;; TCL_RETURN The command requests that the current procedure
|
||||
;;; return; interp->result contains the procedure's
|
||||
;;; return value.
|
||||
;;; TCL_BREAK The command requests that the innermost loop
|
||||
;;; be exited; interp->result is meaningless.
|
||||
;;; TCL_CONTINUE Go on to the next iteration of the current loop;
|
||||
;;; interp->result is meaningless.
|
||||
;;;
|
||||
|
||||
(define-public TCL_OK 0)
|
||||
(define-public TCL_ERROR 1)
|
||||
(define-public TCL_RETURN 2)
|
||||
(define-public TCL_BREAK 3)
|
||||
(define-public TCL_CONTINUE 4)
|
||||
|
||||
;;; Flag values passed to variable-related procedures.
|
||||
;;;
|
||||
|
||||
(define-public TCL_GLOBAL_ONLY 1)
|
||||
(define-public TCL_APPEND_VALUE 2)
|
||||
(define-public TCL_LIST_ELEMENT 4)
|
||||
(define-public TCL_TRACE_READS #x10)
|
||||
(define-public TCL_TRACE_WRITES #x20)
|
||||
(define-public TCL_TRACE_UNSETS #x40)
|
||||
(define-public TCL_TRACE_DESTROYED #x80)
|
||||
(define-public TCL_INTERP_DESTROYED #x100)
|
||||
(define-public TCL_LEAVE_ERR_MSG #x200)
|
||||
|
||||
;;; Flag values to pass to TCL_DoOneEvent to disable searches
|
||||
;;; for some kinds of events:
|
||||
;;;
|
||||
|
||||
(define-public TCL_DONT_WAIT 2)
|
||||
(define-public TCL_X_EVENTS 4)
|
||||
(define-public TCL_FILE_EVENTS 8)
|
||||
(define-public TCL_TIMER_EVENTS #x10)
|
||||
(define-public TCL_IDLE_EVENTS #x20)
|
||||
(define-public TCL_ALL_EVENTS -3)
|
||||
|
||||
;; A convenience function for combining flag bits. Like logior, but
|
||||
;; handles the cases of 0 and 1 arguments.
|
||||
;;
|
||||
(define (flags . args)
|
||||
(cond
|
||||
((null? args) 0)
|
||||
((null? (cdr args)) (car args))
|
||||
(else (apply logior args))))
|
||||
|
||||
|
||||
;; MDJ 961023 <djurfeldt@nada.kth.se>
|
||||
(define-public (tcl-eval . strings)
|
||||
; (pk 'cmd strings)
|
||||
(let* ((cmd (tcl-merge the-interpreter (map ->tcl-arg-string strings)))
|
||||
(status (tcl-global-eval the-interpreter cmd)))
|
||||
(if (zero? (car status))
|
||||
(cdr status)
|
||||
(error (cdr status)))))
|
||||
|
||||
(define uniq-command
|
||||
(let ((cnt 0))
|
||||
(lambda (prefix)
|
||||
(set! cnt (+ cnt 1))
|
||||
(string-append prefix (number->string cnt)))))
|
||||
|
||||
(define (closure->tcl-name p)
|
||||
;(let ((tcl-name (procedure-property p 'tcl-name)))
|
||||
;(or #f tcl-name
|
||||
(let ((name (uniq-command ;(or (procedure-property p 'name)
|
||||
"*__guile#"))
|
||||
;(template (procedure-property p 'tcl-calling-convention)))
|
||||
)
|
||||
(tcl-create-command the-interpreter name p)
|
||||
;(set-procedure-property! p 'tcl-name name)
|
||||
name))
|
||||
|
||||
(define (->tcl-arg-string v)
|
||||
(cond
|
||||
((symbol? v) v)
|
||||
((keyword? v) (keyword-dash-symbol v))
|
||||
((string? v) v)
|
||||
((number? v) (number->string v))
|
||||
((eq? #f v) "0")
|
||||
((eq? #t v) "1")
|
||||
((closure? v)
|
||||
(let ((cc (procedure-property v 'tcl-calling-convention)))
|
||||
(if cc
|
||||
(string-append (closure->tcl-name v) " " cc)
|
||||
(closure->tcl-name v))))
|
||||
(else "")))
|
||||
|
||||
(define (tcl-args args)
|
||||
(cond ((null? args) '())
|
||||
((symbol? (car args))
|
||||
(cons (car args) (tcl-args (cdr args))))
|
||||
((keyword? (car args))
|
||||
(cons (keyword-dash-symbol (car args)) (tcl-args (cdr args))))
|
||||
((string? (car args))
|
||||
(cons (car args) (tcl-args (cdr args))))
|
||||
((number? (car args))
|
||||
(cons (number->string (car args)) (tcl-args (cdr args))))
|
||||
((eq? #f (car args))
|
||||
(cons "0" (tcl-args (cdr args))))
|
||||
((eq? #t (car args))
|
||||
(cons "1" (tcl-args (cdr args))))
|
||||
((closure? (car args))
|
||||
(let ((cc (procedure-property (car args) 'tcl-calling-convention)))
|
||||
(if cc
|
||||
(cons (string-append (closure->tcl-name (car args)) " " cc)
|
||||
(tcl-args (cdr args)))
|
||||
(cons (closure->tcl-name (car args))
|
||||
(tcl-args (cdr args))))))
|
||||
(else "")))
|
||||
|
||||
;; MDJ 961023 <djurfeldt@nada.kth.se>
|
||||
(define-public (tcl-command interp name)
|
||||
(let ((proc
|
||||
(lambda args
|
||||
(let ((status (tcl-global-eval
|
||||
the-interpreter
|
||||
(tcl-merge interp (map ->tcl-arg-string
|
||||
(cons name args))))))
|
||||
(if (zero? (car status))
|
||||
(cdr status)
|
||||
(throw 'tcl-error (cdr status)))))))
|
||||
(set-procedure-property! proc 'name name)
|
||||
proc))
|
||||
|
||||
;; Reifying a Tcl command as a Scheme procedure.
|
||||
;;
|
||||
;(define-public (reify-tcl-command interp name)
|
||||
; (let ((command-object (tcl-command interp name)))
|
||||
; (and command-object
|
||||
; (let ((reified
|
||||
; (lambda args
|
||||
; (let ((answer
|
||||
; (tcl-apply-command command-object
|
||||
; (map (lambda (a)
|
||||
; (or (procedure-property a 'tk-command)
|
||||
; a))
|
||||
; args))))
|
||||
; (if (eq? 0 (car answer))
|
||||
; (tcl-string-> (cdr answer))
|
||||
; (throw 'tcl-error (cdr answer)))))))
|
||||
; (set-procedure-property! reified 'tk-command name)
|
||||
; reified))))
|
||||
(define-public reify-tcl-command tcl-command)
|
||||
|
||||
(define-public (tcl-command? p)
|
||||
(and (procedure? p) (procedure-property 'tcl-command)))
|
||||
|
||||
;; Evaluate some code in the scope of a TCL-ERROR handler.
|
||||
;; The handler returns a conventional Tcl error value (i.e. (cons 1 message))
|
||||
;; Some type conversion is automaticly done on the return value to put it
|
||||
;; in a form Tcl will like.
|
||||
;;
|
||||
(defmacro-public with-tcl-error-handling body
|
||||
`(catch 'tcl-error
|
||||
(lambda () (->tcl-string (begin ,@body)))
|
||||
(lambda (tag . message)
|
||||
(cons 1 (apply errcat message)))))
|
||||
|
||||
(define (errcat . args)
|
||||
(apply string-append
|
||||
(map (lambda (x)
|
||||
(call-with-output-string
|
||||
(lambda (p)
|
||||
((if (string? x) display write) x p)
|
||||
(display " " p))))
|
||||
args)))
|
||||
|
||||
;; If this is defined to be an unary function, it gets to extend the
|
||||
;; default type conversion rules for arguments (it is passed otherwise
|
||||
;; unhandled values).
|
||||
;;
|
||||
(define-public tcl-type-converter #f)
|
||||
|
||||
;; Default conversions from Scheme to Tcl strings.
|
||||
;;
|
||||
(define-public (->tcl-string val)
|
||||
(cond
|
||||
((string? val) val)
|
||||
((symbol? val) val)
|
||||
((number? val) (number->string val))
|
||||
((eq? #f val) "0")
|
||||
((eq? #t val) "1")
|
||||
((keyword? val) (keyword->symbol val))
|
||||
(#t "")))
|
||||
|
||||
(define (that x) x)
|
||||
|
||||
;; Default conversions from Tcl strings to Scheme.
|
||||
;;
|
||||
(define-public (tcl-string-> val)
|
||||
(cond
|
||||
((string->number val) => that)
|
||||
((equal? "" val) #f)
|
||||
(#t val)))
|
||||
|
||||
|
||||
;;; {An Implicit Default Interpreter}
|
||||
;;;
|
||||
;;; For programs like "wish" in which there is one designated default
|
||||
;;; interpreter.
|
||||
;;;
|
||||
|
||||
(define-public the-interpreter #f)
|
||||
|
||||
|
||||
;; Use defined-tcl-command to extend the global namespace
|
||||
;; with commands from the default Tcl interpreter.
|
||||
;;
|
||||
;(define-public (use-default-tcl-commands)
|
||||
; (set! *top-level-lookup-thunk* defined-tcl-command))
|
||||
|
||||
;; If there is a defined variable called NAME, return it.
|
||||
;; If not, but there is a Tcl command in the default interpreter
|
||||
;; called NAME, create a variable an initialize it to point to the
|
||||
;; reified Tcl command.
|
||||
;;
|
||||
;; Finally, always return a variable, perhaps undefined, if DEFINING?
|
||||
;; is a true value.
|
||||
;;
|
||||
(define-public (make-tcl-binder interp)
|
||||
(lambda (m s define?)
|
||||
(if define?
|
||||
(let ((b (make-undefined-variable s)))
|
||||
(module-obarray-set! (module-obarray m) s b)
|
||||
(if (tcl-defined? the-interpreter s)
|
||||
(variable-set! b (tcl-command interp s)))
|
||||
b)
|
||||
(and (tcl-defined? interp s)
|
||||
(let ((b (make-undefined-variable s)))
|
||||
(module-obarray-set! (module-obarray m) s b)
|
||||
(variable-set! b (tcl-command interp s))
|
||||
b)))))
|
||||
|
||||
;; Used to define Scheme procedures which are also Tcl commands.
|
||||
;; The declarations syntax is;
|
||||
;;
|
||||
;; (proc name (?<calling-convention>? ?.? <formals>) <body>)
|
||||
;;
|
||||
;; which is expanded in terms of tcl-lambda.
|
||||
;;
|
||||
(defmacro-public proc (name . spec)
|
||||
`(begin
|
||||
(define ,name (tcl-lambda ,@ spec))
|
||||
(tcl-create-command the-interpreter ',name ,name)))
|
||||
|
||||
|
||||
;; Used to define an anonymous Scheme procedure which is suitable
|
||||
;; for use as a Tcl command.
|
||||
;;
|
||||
;; The declaration syntax is:
|
||||
;;
|
||||
;; (tcl-lambda (?<calling-convention>? ?.? <formals>) <body>)
|
||||
;;
|
||||
;; A <calling-convention> is a string that describes how the procedure
|
||||
;; should be called when it is used as a Tcl command.
|
||||
;; If the procedure hash the tcl-name PROC, and the calling convention
|
||||
;; "%x %y", then the procedure will be called as:
|
||||
;;
|
||||
;; PROC %x %y
|
||||
;;
|
||||
;; Such calling conventions are useful in cases such as binding a Scheme
|
||||
;; procedure to Tk event.
|
||||
;;
|
||||
;; Formals specifications are as usual except that non-rest parameters
|
||||
;; can have declarations. Declarations are arbitrary expressions in which
|
||||
;; the name of the formal is in the second position. The expressions are
|
||||
;; evaluated in the scope of the formals, and may modify the formals by
|
||||
;; side effect. Declarations should return a false value to cause an error
|
||||
;; to be thrown, a true value otherwise.
|
||||
;;
|
||||
(defmacro-public tcl-lambda (formals . body)
|
||||
(let* ((calling-convention (if (and (pair? formals)
|
||||
(string? (car formals)))
|
||||
(let ((a (car formals)))
|
||||
(set! formals (cdr formals))
|
||||
a)
|
||||
#f))
|
||||
(args (tcl-formals-vars formals))
|
||||
(full-body `(begin
|
||||
,@(tcl-type-checks formals 1)
|
||||
,@body)))
|
||||
`(let ((proc (lambda ,args
|
||||
(with-tcl-error-handling ,full-body))))
|
||||
,@(if calling-convention
|
||||
`((set-procedure-property! proc
|
||||
'tcl-calling-convention
|
||||
,calling-convention)
|
||||
proc)
|
||||
`(proc)))))
|
||||
|
||||
|
||||
;; From a list of formals, perhaps with declarations, return the
|
||||
;; formals <<e.g. (a (tcl->int b) . c) => (a b . c) >>
|
||||
;;
|
||||
(define-public (tcl-formals-vars formals)
|
||||
(if (not (pair? formals))
|
||||
formals
|
||||
(cons (if (pair? (car formals))
|
||||
(cadar formals)
|
||||
(car formals))
|
||||
(tcl-formals-vars (cdr formals)))))
|
||||
|
||||
(define-public (tcl-error . args)
|
||||
(apply throw (cons 'tcl-error args)))
|
||||
|
||||
|
||||
(define-public (tcl-type-checks formals pos)
|
||||
(cond
|
||||
((not (pair? formals)) '())
|
||||
((not (pair? (car formals)))
|
||||
(tcl-type-checks (cdr formals) (+ 1 pos)))
|
||||
(#t (cons (tcl-type-check (car formals))
|
||||
(tcl-type-checks (cdr formals) (+ 1 pos))))))
|
||||
|
||||
(define-public tcl-type-converters
|
||||
`( (number . ,(lambda (x) (tcl->number x))) ))
|
||||
|
||||
(define (tcl-type-check x)
|
||||
(let ((a (assoc (car x) tcl-type-converters)))
|
||||
(if (not a)
|
||||
(error "Unsupported declaration" x)
|
||||
(list 'set! (cadr x) (cons (cdr a) (cdr x))))))
|
||||
|
||||
(define-public (tcl->number x)
|
||||
(cond ((string? x) (string->number x))
|
||||
((integer? x) x)
|
||||
(#t (tcl-error "Expected integer but got" x))))
|
||||
|
||||
;;; To support stack handling:
|
||||
|
||||
(define v (builtin-variable 'tk-stack-mark))
|
||||
|
||||
(variable-set! v ->tcl-string)
|
90
ice-9/gwish.scm
Normal file
90
ice-9/gwish.scm
Normal file
|
@ -0,0 +1,90 @@
|
|||
;;;; Copyright (C) 1996, 1997 Mikael Djurfeldt
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or modify
|
||||
;;;; it under the terms of the GNU General Public License as published by
|
||||
;;;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;;;; any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this software; see the file COPYING. If not, write to
|
||||
;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
;;;;
|
||||
;;;; The author can be reached at djurfeldt@nada.kth.se
|
||||
;;;; Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN
|
||||
;;;;
|
||||
|
||||
|
||||
;;; *******************************
|
||||
;;; * Experimental hack *
|
||||
;;; * Shouldn't go into snapshots *
|
||||
;;; * Don't distribute! *
|
||||
;;; *******************************
|
||||
|
||||
(define-module (ice-9 gwish)
|
||||
:use-module (guile)
|
||||
:use-module (ice-9 threads)
|
||||
:use-module (ice-9 nonblocking)
|
||||
:use-module (ice-9 gtcl))
|
||||
|
||||
|
||||
;;; {The Interpreter}
|
||||
;;;
|
||||
|
||||
(set! the-interpreter (tcl-create-interp))
|
||||
|
||||
(define gtcl-module (local-ref '(app modules ice-9 gtcl)))
|
||||
(define tcl-binder (make-tcl-binder the-interpreter))
|
||||
|
||||
(set-module-binder! (module-public-interface gtcl-module) tcl-binder)
|
||||
|
||||
;;; {Namespace cleaning}
|
||||
;;;
|
||||
|
||||
;; These are the names of procedures already defined
|
||||
;; in Scheme but which, in this context, ought to refer
|
||||
;; to Tcl/Tk commands.
|
||||
|
||||
(define override-scheme-list '(bind))
|
||||
|
||||
(for-each
|
||||
(lambda (name)
|
||||
(eval `(set! ,name (reify-tcl-command the-interpreter ',name))))
|
||||
override-scheme-list)
|
||||
|
||||
;;; {Non-blocking ports}
|
||||
|
||||
(define stdin-avail #t)
|
||||
|
||||
(proc set-stdin-flag args (set! stdin-avail #t) "")
|
||||
|
||||
(define wait TCL_ALL_EVENTS)
|
||||
(define dont-wait (+ wait TCL_DONT_WAIT))
|
||||
|
||||
(set! handle-input-events
|
||||
(lambda ()
|
||||
(cond ((single-active-thread?) (tcl-do-one-event wait))
|
||||
((zero? (tcl-do-one-event dont-wait))
|
||||
(yield)
|
||||
))
|
||||
(if stdin-avail
|
||||
(begin
|
||||
(set! stdin-avail #f)
|
||||
(signal-condition-variable repl-input-port-condvar)))))
|
||||
|
||||
(fileevent 'stdin 'readable 'set-stdin-flag)
|
||||
|
||||
(activate-non-blocking-input)
|
||||
|
||||
;;; {The application window}
|
||||
|
||||
(let ((init-status (tk-init-main-window the-interpreter
|
||||
(or (getenv "DISPLAY") ":0")
|
||||
"gwish"
|
||||
"Gwish")))
|
||||
(if (not (eq? #t init-status))
|
||||
(error init-status)))
|
82
ice-9/nonblocking.scm
Normal file
82
ice-9/nonblocking.scm
Normal file
|
@ -0,0 +1,82 @@
|
|||
;;;; Copyright (C) 1996 Mikael Djurfeldt
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or modify
|
||||
;;;; it under the terms of the GNU General Public License as published by
|
||||
;;;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;;;; any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this software; see the file COPYING. If not, write to
|
||||
;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
;;;;
|
||||
;;;; The author can be reached at djurfeldt@nada.kth.se
|
||||
;;;; Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN
|
||||
;;;;
|
||||
|
||||
|
||||
;;; *******************************
|
||||
;;; * Experimental hack *
|
||||
;;; * Shouldn't go into snapshots *
|
||||
;;; * Don't distribute! *
|
||||
;;; *******************************
|
||||
|
||||
;;; {Non-blocking ports}
|
||||
;;;
|
||||
|
||||
(define-module (ice-9 nonblocking)
|
||||
:use-module (ice-9 threads))
|
||||
|
||||
(define mu (make-mutex))
|
||||
(define-public repl-input-port-condvar (make-condition-variable))
|
||||
|
||||
(define non-blocking-input #f)
|
||||
|
||||
(define-public (make-non-blocking-port wait-port read-port)
|
||||
(letrec ((read-char-fn (lambda args
|
||||
(if (char-ready? wait-port)
|
||||
(read-char read-port)
|
||||
(begin
|
||||
(wait-condition-variable repl-input-port-condvar
|
||||
mu)
|
||||
(unlock-mutex mu)
|
||||
(read-char-fn))))))
|
||||
(make-soft-port
|
||||
(vector #f #f #f
|
||||
read-char-fn
|
||||
(lambda () (close-port orig-port)))
|
||||
"r")))
|
||||
|
||||
(define-public repl-input-port (current-input-port))
|
||||
(define-public basic-repl-input-port repl-input-port)
|
||||
|
||||
(define-public handle-input-events
|
||||
(lambda ()
|
||||
(if (single-active-thread?)
|
||||
(select (list basic-repl-input-port) '() '()))
|
||||
(if (char-ready? basic-repl-input-port)
|
||||
(signal-condition-variable repl-input-port-condvar)
|
||||
(yield))))
|
||||
|
||||
(define (kick)
|
||||
(call-with-new-thread
|
||||
(lambda ()
|
||||
(error-catching-loop
|
||||
(lambda ()
|
||||
(let loop ()
|
||||
(handle-input-events)
|
||||
(loop)))))
|
||||
(lambda args args)))
|
||||
|
||||
(define-public (activate-non-blocking-input)
|
||||
(if (not non-blocking-input)
|
||||
(begin
|
||||
(set! repl-input-port (make-non-blocking-port basic-repl-input-port
|
||||
(current-input-port)))
|
||||
(set-current-input-port repl-input-port)
|
||||
(kick)
|
||||
(set! non-blocking-input #t))))
|
Loading…
Add table
Add a link
Reference in a new issue