Implement asynchronous ^G detection for X, using the real-time
authorChris Hanson <org/chris-hanson/cph>
Mon, 29 Apr 1991 10:43:18 +0000 (10:43 +0000)
committerChris Hanson <org/chris-hanson/cph>
Mon, 29 Apr 1991 10:43:18 +0000 (10:43 +0000)
interrupt.  New procedures X-TIMER-INTERVAL and SET-X-TIMER-INTERVAL!
allow control over the interrupt's interval, which is initially one
second.

v7/src/edwin/edwin.pkg
v7/src/edwin/make.scm
v7/src/edwin/xterm.scm

index 4c9a809a11857d93c9eaeb559d8ce1348afc7d9c..b33cb57ed0d071b84c82ec6f11c1d56473bb3c9c 100644 (file)
@@ -1,6 +1,6 @@
 #| -*-Scheme-*-
 
-$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/edwin.pkg,v 1.33 1991/04/26 03:11:56 cph Exp $
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/edwin.pkg,v 1.34 1991/04/29 10:42:35 cph Exp $
 
 Copyright (c) 1989-91 Massachusetts Institute of Technology
 
@@ -258,7 +258,9 @@ MIT in each case. |#
   (files "xterm")
   (parent (edwin))
   (export (edwin)
-         x-display-type)
+         set-x-timer-interval!
+         x-display-type
+         x-timer-interval)
   (export (edwin x-commands)
          screen-xterm)
   (initialization (initialize-package!)))
index 2004bdc15f2bf5b7cc6ec057a2f0bcf14e65f97f..1d85a65c2369247768cded35646166cd24660a10 100644 (file)
@@ -1,6 +1,6 @@
 #| -*-Scheme-*-
 
-$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/make.scm,v 3.39 1991/04/26 05:27:24 cph Exp $
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/make.scm,v 3.40 1991/04/29 10:43:18 cph Exp $
 
 Copyright (c) 1989-91 Massachusetts Institute of Technology
 
@@ -37,4 +37,4 @@ MIT in each case. |#
 (declare (usual-integrations))
 
 (package/system-loader "edwin" '() 'QUERY)
-(add-system! (make-system "Edwin" 3 39 '()))
\ No newline at end of file
+(add-system! (make-system "Edwin" 3 40 '()))
\ No newline at end of file
index 0dbae74a6639ad48902b03836fcaebb6c7e48fd7..0aafad75ba01135ca395d41943c34df382e7f861 100644 (file)
@@ -1,6 +1,6 @@
 ;;; -*-Scheme-*-
 ;;;
-;;;    $Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/xterm.scm,v 1.17 1991/04/26 05:27:14 cph Exp $
+;;;    $Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/xterm.scm,v 1.18 1991/04/29 10:42:11 cph Exp $
 ;;;
 ;;;    Copyright (c) 1989-91 Massachusetts Institute of Technology
 ;;;
@@ -47,6 +47,8 @@
 (declare (usual-integrations))
 \f
 (define-primitives
+  (real-timer-clear 0)
+  (real-timer-set 2)
   (x-open-display 1)
   (x-close-all-displays 0)
   (x-close-display 1)
 \f
 ;;;; Event Handling
 
-(define (get-xterm-input-operations screen)
-  (let ((display (screen-display screen))
+(define (get-xterm-input-operations)
+  (let ((display x-display-data)
+       (queue x-display-events)
        (string false)
        (start 0)
        (end 0)
        (pending-event false))
-    (let ((get-next-event
-          (lambda (time-limit)
-            (if pending-event
-                (let ((event pending-event))
-                  (set! pending-event false)
-                  event)
-                (x-display-process-events display time-limit))))
-         (process-key-press-event
+    (let ((process-key-press-event
           (lambda (event)
             (set! string (vector-ref event 2))
             (set! start 0)
                   (if i
                       (begin
                         (set! start (fix:+ i 1))
-                        (signal-interrupt!)))))))
-         (process-special-event
-          (lambda (event)
-            (let ((handler (vector-ref event-handlers (vector-ref event 0)))
-                  (screen (xterm->screen (vector-ref event 1))))
-              (if (and handler screen)
-                  (handler screen event))))))
-      (let ((guarantee-input
-            (lambda ()
-              (let loop ()
-                (let ((event (get-next-event false)))
-                  (cond ((not event)
-                         (error "#F returned from blocking read"))
-                        ((eq? true event)
-                         false)
-                        ((eq? event-type:key-press (vector-ref event 0))
-                         (process-key-press-event event)
-                         (if (fix:< start end) true (loop)))
-                        (else
-                         (process-special-event event)
-                         (loop))))))))
-       (values
-        (lambda ()                     ;halt-update?
-          (if (or (fix:< start end) pending-event)
-              true
-              (let ((event (get-next-event 0)))
-                (and event
-                     (begin
-                       (set! pending-event event)
-                       true)))))
-        (lambda ()                     ;char-ready?
-          (if (fix:< start end)
-              true
-              (let loop ()
+                        (signal-interrupt!))))))))
+      (let ((get-next-event
+            (lambda (time-limit)
+              (if pending-event
+                  (let ((event pending-event))
+                    (set! pending-event false)
+                    event)
+                  (read-event queue display time-limit)))))
+       (let ((guarantee-input
+              (lambda ()
+                (let loop ()
+                  (let ((event (get-next-event false)))
+                    (cond ((not event)
+                           (error "#F returned from blocking read"))
+                          ((eq? true event)
+                           false)
+                          ((fix:= event-type:key-press (vector-ref event 0))
+                           (process-key-press-event event)
+                           (if (fix:< start end) true (loop)))
+                          (else
+                           (process-special-event event)
+                           (loop))))))))
+         (values
+          (lambda ()                   ;halt-update?
+            (if (or (fix:< start end) pending-event)
+                true
                 (let ((event (get-next-event 0)))
-                  (cond ((or (not event) (eq? true event))
-                         false)
-                        ((eq? event-type:key-press (vector-ref event 0))
-                         (process-key-press-event event)
-                         (if (fix:< start end) true (loop)))
-                        (else
-                         (process-special-event event)
-                         (loop)))))))
-        (lambda ()                     ;peek-char
-          (and (or (fix:< start end) (guarantee-input))
-               (string-ref string start)))
-        (lambda ()                     ;read-char
-          (and (or (fix:< start end) (guarantee-input))
-               (let ((char (string-ref string start)))
-                 (set! start (fix:+ start 1))
-                 char))))))))
+                  (and event
+                       (begin
+                         (set! pending-event event)
+                         true)))))
+          (lambda ()                   ;char-ready?
+            (if (fix:< start end)
+                true
+                (let loop ()
+                  (let ((event (get-next-event 0)))
+                    (cond ((or (not event) (eq? true event))
+                           false)
+                          ((fix:= event-type:key-press (vector-ref event 0))
+                           (process-key-press-event event)
+                           (if (fix:< start end) true (loop)))
+                          (else
+                           (process-special-event event)
+                           (loop)))))))
+          (lambda ()                   ;peek-char
+            (and (or (fix:< start end) (guarantee-input))
+                 (string-ref string start)))
+          (lambda ()                   ;read-char
+            (and (or (fix:< start end) (guarantee-input))
+                 (let ((char (string-ref string start)))
+                   (set! start (fix:+ start 1))
+                   char)))))))))
+\f
+(define (read-event queue display time-limit)
+  ;; If no time-limit, we're reading from the keyboard.  In that case,
+  ;; make sure that asynchronous input is reenabled afterwards.
+  (let ((reenable? (if time-limit allow-asynchronous-input? true)))
+    (set! allow-asynchronous-input? false)
+    (let loop ()
+      (let ((event
+            (if (queue-empty? queue)
+                (x-display-process-events display time-limit)
+                (dequeue!/unsafe queue))))
+       (if (and (vector? event)
+                (fix:= event-type:expose (vector-ref event 0)))
+           (begin
+             (process-expose-event event)
+             (loop))
+           (begin
+             (set! allow-asynchronous-input? reenable?)
+             event))))))
+
+(define (timer-interrupt-handler)
+  (if (and allow-asynchronous-input?
+          (buffer-events x-display-events x-display-data signal-interrupts?))
+      (begin
+       ;; Don't allow further asynchronous input until the command
+       ;; loop has restarted (actually, until next attempt to read
+       ;; from the keyboard).
+       (set! allow-asynchronous-input? false)
+       (signal-interrupt!))))
+
+(define allow-asynchronous-input?)
+
+(define (buffer-events queue display allow-interrupts?)
+  (let loop ()
+    (let ((event (x-display-process-events display 0)))
+      (cond ((not event)
+            false)
+           ((eq? true event)
+            (accept-process-output)
+            (notify-process-status-changes)
+            (loop))
+           ((and allow-interrupts?
+                 (fix:= event-type:key-press (vector-ref event 0))
+                 (string-find-next-char (vector-ref event 2) #\BEL))
+            ;; Flush keyboard and mouse events from the input
+            ;; queue.  Other events are harmless and must be
+            ;; processed regardless.
+            (do ((events
+                  (let loop ()
+                    (if (queue-empty? queue)
+                        '()
+                        (let ((event (dequeue!/unsafe queue)))
+                          (if (let ((type (vector-ref event 0)))
+                                (or (fix:= type event-type:button-down)
+                                    (fix:= type event-type:button-up)
+                                    (fix:= type event-type:key-press)
+                                    (fix:= type event-type:motion)))
+                              (loop)
+                              (cons event (loop))))))
+                  (cdr events)))
+                ((null? events))
+              (enqueue!/unsafe queue (car events)))
+            true)
+           (else
+            (enqueue!/unsafe queue event)
+            (loop))))))
 \f
 ;;; The values of these flags must be equal to the corresponding event
 ;;; types in "microcode/x11base.c"
 (define-integrable (define-event-handler event-type handler)
   (vector-set! event-handlers event-type handler))
 
+(define (process-special-event event)
+  (let ((handler (vector-ref event-handlers (vector-ref event 0)))
+       (screen (xterm->screen (vector-ref event 1))))
+    (if (and handler screen)
+       (handler screen event))))
+
+(define (process-expose-event event)
+  (xterm-dump-rectangle (vector-ref event 1)
+                       (vector-ref event 2)
+                       (vector-ref event 3)
+                       (vector-ref event 4)
+                       (vector-ref event 5)))
+
 (define-event-handler event-type:configure
   (lambda (screen event)
     (let ((xterm (screen-xterm screen))
              (set-screen-size! screen x-size y-size)
              (update-screen! screen true)))))))
 
-(define-event-handler event-type:expose
-  (lambda (screen event)
-    (xterm-dump-rectangle (screen-xterm screen)
-                         (vector-ref event 2)
-                         (vector-ref event 3)
-                         (vector-ref event 4)
-                         (vector-ref event 5))))
-
 (define-event-handler event-type:button-down
   (lambda (screen event)
     (let ((xterm (screen-xterm screen)))
 \f
 (define signal-interrupts?)
 (define pending-interrupt?)
+(define timer-interval 1000)
 
 (define (signal-interrupt!)
   (editor-beep)
 
 (define (with-editor-interrupts-from-x receiver)
   (fluid-let ((signal-interrupts? true)
-             (pending-interrupt? false))
-    (receiver (lambda (thunk) (thunk)))))
+             (pending-interrupt? false)
+             (timer-interrupt timer-interrupt-handler))
+    (dynamic-wind start-timer-interrupt
+                 (lambda ()
+                   (receiver
+                    (lambda (thunk)
+                      (dynamic-wind real-timer-clear
+                                    thunk
+                                    start-timer-interrupt))))
+                 real-timer-clear)))
+
+(define (set-x-timer-interval! interval)
+  (if (not (or (false? interval)
+              (and (exact-integer? interval)
+                   (positive? interval))))
+      (error:wrong-type-argument interval false 'SET-X-TIMER-INTERVAL!))
+  (set! timer-interval interval)
+  (start-timer-interrupt))
+
+(define (x-timer-interval)
+  timer-interval)
+
+(define (start-timer-interrupt)
+  (if timer-interval
+      (real-timer-set timer-interval timer-interval)
+      (real-timer-clear)))
 
 (define (with-x-interrupts-enabled thunk)
   (bind-signal-interrupts? true thunk))
                    (set! signal-interrupts? old-mask)
                    (if (and old-mask pending-interrupt?)
                        (signal-interrupt!))))))
-
+\f
 (define x-display-type)
 (define x-display-data)
+(define x-display-events)
 
 (define (get-x-display)
   ;; X-OPEN-DISPLAY hangs, uninterruptibly, when the X server is
   (or x-display-data
       (let ((display (x-open-display false)))
        (set! x-display-data display)
+       (set! x-display-events (make-queue))
+       (set! allow-asynchronous-input? true)
        display)))
 
 (define (initialize-package!)
                           true
                           get-x-display
                           make-xterm-screen
-                          get-xterm-input-operations
+                          (lambda (screen)
+                            screen     ;ignore
+                            (get-xterm-input-operations))
                           with-editor-interrupts-from-x
                           with-x-interrupts-enabled
                           with-x-interrupts-disabled))
   (set! x-display-data false)
+  (set! x-display-events)
   unspecific)
\ No newline at end of file