home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / swat / scheme / mit-xhooks.scm < prev    next >
Text File  |  1995-08-02  |  31KB  |  923 lines

  1. ;;; -*- Scheme -*-
  2.  
  3. #| ******************************
  4.  
  5. MIT-XHOOKS defines the level of the system that handles event
  6. processing, and the manipulation of UITK objects just above the X
  7. level (defined in MIT-XLIB).  This layer will differ between
  8. MIT-Scheme and Scheme-to-C
  9.  
  10. This file tries to include all the functions that actually call X so
  11. that the other parts of the system can be rebuilt on a different
  12. substrate. 
  13.  
  14.   ****************************** |#
  15.  
  16. #|
  17. Not used?
  18.  
  19. (define (with-window display title desired-size context receiver)
  20.   ;; Call RECEIVER with UITKwindow and actual size
  21.   (let* ((window (create-top-level-x-window
  22.           display title desired-size context)))
  23.     (XMapWindow display window)
  24.     (report-window-size display window receiver)))
  25.  
  26. (define (report-window-size display window receiver)
  27.   (get-window-attributes display window
  28.    (lambda (x y width height . others)
  29.      others
  30.      (receiver (make-uitkwindow display window)
  31.            (make-size width height)
  32.            x
  33.            y))))
  34.  
  35.  
  36. (define (create-top-level-x-window display title desired-size context)
  37.   (let ((window
  38.      (XCreateSimpleWindow
  39.       display
  40.       (XDefaultRootWindow display)    ; Parent is root window
  41.       0                ; X
  42.       0                ; Y
  43.       (size.width desired-size)    ; Width
  44.       (size.height desired-size)    ; Height
  45.       (context.BorderWidth context)
  46.       (context.Border context)
  47.       (context.Background context))))
  48.     (XStoreName display window title)
  49.     window))
  50.  
  51.  
  52. (define (destroy-window w)
  53.   (let ((Xwindow (UITKWindow.XWindow w)))
  54.     (XDestroyWindow (UITKWindow.XDisplay w) Xwindow)))
  55.  
  56.  
  57.  
  58.  
  59.  
  60. |#
  61.  
  62.  
  63. ;;;;UITK main loop
  64.  
  65. #| In general, the system will have two threads running -- the
  66. ordinary REP and the UITK thread, which processes events for the
  67. widgets.
  68.  
  69. When an event is signalled, it is placed (at interrupt level) on a
  70. queue, which is processed at user level by the UITK thread main loop
  71. |#
  72.  
  73. ;;;UITK thread will wake up at at least this interval, since it needs
  74. ;;;to clean up objects labelld for destruction by the GC, even if
  75. ;;;there are no events to process.
  76.  
  77. (define *UITK-INTERVAL* (* 30 1000))    ; 30 seconds, in milliseconds
  78.  
  79. (define uitk-queue 'later)        ;code that processes events
  80. (define idle-queue 'later)        ;not used in MIT version
  81. (define the-agenda 'later)        ;processing scheduled by AFTER-DELAY
  82. (define uitk-thread 'later)
  83. (define more-work-to-do #F)
  84. (define uitk-timer #F)
  85.  
  86. #| #############################################################
  87. This is some debugging stuff for probing the space usage.
  88. |# 
  89.  
  90.  
  91. (DEFINE LOOP-COUNTER 0)
  92. (DEFINE EVENT-COUNTER 0)
  93. (DEFINE MORE-COUNTER 0)
  94. (DEFINE SUSPEND-COUNTER 0)
  95. (DEFINE LOOP-TRACE)
  96. (DEFINE READ-QUEUE-TRACE)
  97. (DEFINE RUN-QUEUE-TRACE)
  98. (define ALLOW-FREE-TRACE? #T)
  99.  
  100. (define (clear-counters!)
  101.   (SET! LOOP-COUNTER 0)
  102.   (SET! EVENT-COUNTER 0)
  103.   (SET! MORE-COUNTER 0)
  104.   (SET! SUSPEND-COUNTER 0)
  105.   0)
  106.  
  107. (define ignore-repl #F)
  108.  
  109. (define (show-counters)
  110.   (pp
  111.    `(events: , event-counter loop: ,loop-counter more: ,more-counter suspend: ,suspend-counter)))
  112.  
  113. (define (make-free-trace n)
  114.   (cons 0 (make-vector n #f)))
  115.  
  116. (define (copy-free-traces)
  117.   (fluid-let ((allow-free-trace? #f))
  118.     (vector (cons (car loop-trace) (vector-copy (cdr loop-trace)))
  119.         (cons (car read-queue-trace) (vector-copy (cdr read-queue-trace)))
  120.         (cons (car run-queue-trace) (vector-copy (cdr run-queue-trace))))))
  121.  
  122. (define (record-free-pointer trace)
  123.   (if allow-free-trace?
  124.       (let-syntax ((ucode-primitive
  125.             (macro arguments
  126.               (apply make-primitive-procedure arguments))))
  127.     (vector-set! (cdr trace)
  128.              (car trace)
  129.              ((ucode-primitive primitive-get-free 1) 26))
  130.     (set-car! trace
  131.           (if (fix:= (fix:+ (car trace) 1) (vector-length (cdr trace)))
  132.               0
  133.               (fix:+ (car trace) 1))))))
  134.  
  135. #| #############################################
  136. end of debugging stuff
  137.  
  138. |#
  139.  
  140.  
  141. (define (make-uitk-thread)
  142.   (set! uitk-thread
  143.     (create-thread (create-thread-continuation) thread-start))
  144.   (kick-uitk-thread))
  145.  
  146. (define initial-thread-state 'later)
  147.  
  148. (define (thread-start)
  149.   (call-with-current-continuation
  150.    (lambda (start-up)
  151.      (set! initial-thread-state start-up)
  152.      (uitk-thread-main-loop))))
  153.  
  154. (define (restart-uitk)
  155.   (restart-thread uitk-thread #T (lambda () (initial-thread-state 'go))))
  156.  
  157. (let-syntax ((last-reference
  158.           (macro (variable)
  159.         `(let ((foo ,variable))
  160.            (set! ,variable #F)
  161.            foo))))
  162.  
  163.   (define (uitk-thread-main-loop)
  164.     (define (flush-all-displays)
  165.       (for-each flush-queued-output
  166.         (protection-list-referenced-elements
  167.          display-protection-list)))
  168.     (define (run thunk) (thunk))
  169.     (SET! LOOP-COUNTER 0)
  170.     (SET! EVENT-COUNTER 0)
  171.     (SET! MORE-COUNTER 0)
  172.     (SET! SUSPEND-COUNTER 0)
  173.     (let process-loop ()
  174.       (SET! LOOP-COUNTER (+ 1 LOOP-COUNTER))
  175.       (block-thread-events)
  176.       (set! more-work-to-do #F)
  177.       ;; Read out the event/idle/delayed thunks
  178.       (let ((events (read-and-empty-queue! uitk-queue))
  179.         (idle (read-and-empty-queue! idle-queue))
  180.         (delayed (read-and-empty-agenda! the-agenda))
  181.         )
  182.     (unblock-thread-events)
  183.     ;;process the thinks that were read, and clear the variables so
  184.     ;; the thunks can GC away after they are run.
  185.     (for-each run (last-reference events))
  186.     (for-each run (last-reference idle))
  187.     (for-each run (last-reference delayed))
  188.     ;; Allow tk to do its pending events (includes handling callbacks)
  189.     (tk-doevents)
  190.     ;;check if a GC has occurred (the GC daemon sets the flag) and
  191.     ;;finalize the GC'd objects.
  192.     (if (with-absolutely-no-interrupts
  193.          (lambda ()
  194.            (let ((result *UITK:GC-HAS-OCCURRED?*))
  195.          (set! *UITK:GC-HAS-OCCURRED?* #F)
  196.          result)))
  197.         (begin            ; Clean up after GC
  198.           (finalize-uitk-objects)
  199.           (close-lost-displays-daemon)))
  200.     (let ((more? (begin (block-thread-events) more-work-to-do)))
  201.       ;; MORE? is #T if work arrived while we were handling the
  202.       ;; previously grabbed event/idle thunks
  203.       (flush-all-displays)
  204.       (IF (OR MORE? IGNORE-REPL)
  205.           (begin
  206.         (unblock-thread-events)
  207.         (SET! MORE-COUNTER (+ 1 MORE-COUNTER))
  208.         (process-loop))        ; Don't give up CPU yet
  209.           (begin
  210.         (let ((tk-wake-up (get-interval-to-tk-wakeup))
  211.               (delayed-wake-up (get-interval-to-next-delayed-event)))
  212.           ;;get time to wake up to for next TK event or
  213.           ;;delayed event
  214.           (let ((wake-up (if tk-wake-up
  215.                      (if delayed-wake-up
  216.                      (min tk-wake-up delayed-wake-up)
  217.                      tk-wake-up)
  218.                      delayed-wake-up)))
  219.             ;;flush the current timer event if there is one
  220.             ;;and register the next actual time to wake up
  221.             (if uitk-timer (deregister-timer-event uitk-timer))
  222.             (set! uitk-timer
  223.               (register-timer-event (if wake-up
  224.                             (min wake-up *UITK-INTERVAL*)
  225.                             *UITK-INTERVAL*)
  226.                         (lambda () (set! uitk-timer #F))))))
  227.         ;;now go to sleep. The timer event, or an X event,
  228.         ;;will wake us up.  We suspend with events still
  229.         ;;blocked to avoid an interrupt hole, whereby an
  230.         ;;event is delivered but doesn't wake us up.
  231.         ;;Suspending atomically unblocks events in the right
  232.         ;;way to prevent this.
  233.         (suspend-current-thread)
  234.         (SET! SUSPEND-COUNTER (+ SUSPEND-COUNTER 1))
  235.         ;;(allow-thread-event-delivery)
  236.         (unblock-thread-events)
  237.         (process-loop))))))
  238.     ))
  239.  
  240. (define (with-uitk-thread-errors-captured thunk)
  241.   (define newline-string "
  242. ")
  243.   (call-with-current-continuation
  244.    (lambda (exit-continuation)
  245.      (fluid-let
  246.      ((standard-error-handler
  247.        (lambda (error-condition)
  248.          (fluid-let ((standard-error-handler standard-error-handler))
  249.            (newline)
  250.            (newline)
  251.            (display
  252.         (string-append
  253.          ";Error in UITK thread:" newline-string
  254.          ";" (condition/report-string error-condition)
  255.          newline-string
  256.          ";To debug, type (debug (unhash "
  257.          (number->string
  258.           (hash (condition/continuation error-condition)))
  259.          "))"))
  260.            (newline)
  261.            (newline)
  262.            (exit-continuation 'punt-o-rama)))))
  263.        (thunk)))))
  264.  
  265. ;;;This forces the UITK thread to wake up
  266. (define kick-uitk-thread
  267.   (let ((*uitk-thread-kicked?* #F))
  268.     (lambda ()
  269.       (if (not *uitk-thread-kicked?*)
  270.       (begin
  271.         (set! *uitk-thread-kicked?* #T)
  272.         (when-idle!
  273.          ;; When-Idle! will make the thread awaken
  274.          (lambda ()
  275.            (set! *uitk-thread-kicked?* #F))))))))
  276.  
  277. ;;; Redefine hook found in mit-xlib.  Running the UITK loop will flush
  278. ;;; all displays.
  279. (define flush-display-hook kick-uitk-thread)
  280.  
  281. (define (when-idle! thunk)
  282.   (signal-thread-event
  283.    uitk-thread
  284.    (lambda ()
  285.      ;; Interrupt level
  286.      (set! more-work-to-do #T)
  287.      (enqueue! idle-queue thunk))))
  288.  
  289.  
  290. ;;; Registering events for processing
  291.  
  292. #| For each display connection, we have a permanently
  293.    registered request to process input from a particular file.
  294.    FORK-TO-WAIT-ON creates such a registration.  When events come in
  295.    on the display connection, the CHILD-WORK-CODE is enqueued for
  296.    user-level execution.  If the CHILD-WORK-CODE has been GCed away,
  297.    then code to deregister the handler is executed.
  298. |#
  299.  
  300. (define fork-to-wait-on
  301.   (let ()
  302.     ;; This group of procedures can NOT be lexically nested inside of
  303.     ;; fork-to-wait-on because we want the link from the enqueued
  304.     ;; thunk to child-work-code to be a weak pointer.  
  305.     ;; Thus child-work-code should not be lexically visible to
  306.     ;; these procedures.  If we had a strong pointer, then the
  307.     ;; registry would point to the child work code and hence to the
  308.     ;; application, so applications could never be GCd.
  309.     (define (try-to-run weak)
  310.       (lambda ()
  311.     (let ((code (weak-car weak))
  312.           (wcdr (weak-cdr weak)))
  313.       (if (and code (not (scxl-destroyed? (weak-car wcdr))))
  314.           (begin
  315.         ;; Reinstall interrupt handler, then run user code
  316.         (register-input-thread-event
  317.          (XConnectionNumber (weak-car wcdr))
  318.          uitk-thread (weak-cdr wcdr))
  319.         (code))))))
  320.     (define (call-if-still-there weak)
  321.       ;; WEAK is a weak-list:
  322.       ;;   (desired-code-thunk display #F)
  323.       ;; In normal use, desired-code-thunk is #F iff the application
  324.       ;; has vanished.  This code creates a procedure to run at
  325.       ;; interrupt level, replaces the #F with the handler, and
  326.       ;; returns the handler to the caller.
  327.       (let ((result
  328.          (lambda ()
  329.            ;; Interrupt level
  330.            (let ((code (weak-car weak)))
  331.          (if code
  332.              (begin
  333.                (set! more-work-to-do #T)
  334.                (enqueue! uitk-queue (try-to-run weak))
  335.                'done
  336.                ))))))
  337.     (weak-set-cdr! (weak-cdr weak) result)
  338.     result))
  339.     (lambda (display child-work-code child-idle-code)
  340.       child-idle-code            ; Not used by MIT Scheme
  341.       (let ((file (XConnectionNumber display))
  342.         (weak (weak-cons child-work-code (weak-cons display #F))))
  343.     (without-interrupts
  344.      (lambda ()
  345.        (register-input-thread-event
  346.         file uitk-thread (call-if-still-there weak))))))))
  347.  
  348. (define (destroy-registration registration)
  349.   (deregister-input-thread-event registration)
  350.   'OK)
  351.  
  352. (define remove-from-registry
  353.   ;; This is called with a file descriptor when the file is closed to
  354.   ;; remove any registered requests for activity on the file.
  355.   (in-package (->environment '(runtime thread))
  356.     (lambda (descriptor)
  357.       (let loop ((dentry input-registrations))
  358.     (cond ((null? dentry) 'NOT-FOUND)
  359.           ((eq? descriptor (dentry/descriptor dentry))
  360.            (without-interrupts
  361.         (lambda ()
  362.           (remove-from-select-registry! input-registry descriptor)
  363.           (let ((prev (dentry/prev dentry))
  364.             (next (dentry/next dentry)))
  365.             (if prev
  366.             (set-dentry/next! prev next)
  367.             (set! input-registrations next))
  368.             (if next
  369.             (set-dentry/prev! next prev)))))
  370.            'REMOVED)
  371.           (else (loop (dentry/next dentry))))))))
  372.  
  373. (define (shut-down-event-server display-number)
  374.   (remove-from-registry (%XConnectionNumber display-number)))
  375.  
  376.  
  377. ;;;Delayed events
  378.  
  379. ;;; Schedule an action to be done later in the UITK thread
  380. ;;; Implementation uses agendas from the 6.001 book
  381.  
  382.  
  383. (define (after-delay delay action-thunk)    ; delay in secs
  384.   (let ((now (real-time-clock)))
  385.     (signal-thread-event
  386.      uitk-thread
  387.      (lambda ()
  388.        ;; Interrupt level
  389.        (set! more-work-to-do #T)
  390.        (add-to-agenda! (+ (* delay 1000) now)    ; in msecs
  391.                action-thunk
  392.                the-agenda)))))
  393.  
  394. (define (make-agenda)
  395.   (list '*agenda*))
  396.  
  397. (define (segments agenda) (cdr agenda))
  398. (define (first-segment agenda) (car (segments agenda)))
  399. (define (rest-segments agenda) (cdr (segments agenda)))
  400. (define (set-segments! agenda segments) (set-cdr! agenda segments))
  401. (define (empty-segments? agenda)
  402.   (null? (segments agenda)))
  403.  
  404. (define (add-to-agenda! time action agenda)
  405.   (define (add-to-segments! segments)
  406.     (if (= (segment-time (car segments)) time)
  407.     (enqueue! (segment-queue (car segments))
  408.           action)
  409.     (let ((rest (cdr segments)))
  410.       (if (or (null? rest)
  411.           (> (segment-time (car rest)) time))
  412.           (insert-new-time! time action agenda)
  413.           (add-to-segments! rest)))))
  414.   (without-interrupts
  415.    (lambda ()
  416.      (let ((segs (segments agenda)))
  417.        (if (null? segs)
  418.        (insert-new-time! time action agenda)
  419.        (add-to-segments! segs))))))
  420.  
  421.  
  422. (define (insert-new-time! time action agenda)
  423.   (let ((segs (segments agenda))
  424.     (q (make-queue)))
  425.     (enqueue! q action)
  426.     (let ((new-segment (make-time-segment time q)))
  427.       (if (null? segs)
  428.       (set-segments! agenda (list new-segment))
  429.       (set-cdr! segs
  430.             (cons new-segment (cdr segs)))))))
  431.  
  432. (define (read-and-empty-agenda! agenda)
  433.   (let ((now (real-time-clock)))
  434.     (define (find-all-events-up-to-now events)
  435.       (if (empty-segments? agenda)
  436.       events
  437.       (let ((current-segment (first-segment agenda)))
  438.         (if (> (segment-time current-segment) now)
  439.         events
  440.         (let ((q (segment-queue current-segment)))
  441.           (if (empty-queue? q)
  442.               (begin (set-segments! agenda (rest-segments agenda))
  443.                  (find-all-events-up-to-now events))
  444.               (find-all-events-up-to-now
  445.                (append events (list (dequeue! q))))))))))
  446.     (without-interrupts
  447.      (lambda ()
  448.        (find-all-events-up-to-now '())))))
  449.  
  450. (define (empty-agenda? agenda)
  451.   (without-interrupts
  452.    (lambda ()
  453.      (or (empty-segments? agenda)
  454.      (and (empty-queue? (segment-queue (first-segment agenda)))
  455.           (null? (rest-segments agenda)))))))
  456.  
  457. (define (make-time-segment time queue)
  458.   (cons time queue))
  459.  
  460. (define (segment-time s) (car s))
  461. (define (segment-queue s) (cdr s))
  462.  
  463. (define (current-time agenda)
  464.   (without-interrupts
  465.    (lambda ()
  466.      (and (not (null? (segments agenda)))
  467.       (segment-time (first-segment agenda))))))
  468.  
  469. (define (get-interval-to-next-delayed-event)
  470.   (let ((agenda-time (current-time the-agenda)))
  471.     (and agenda-time
  472.      (- agenda-time (real-time-clock)))))
  473.  
  474. ;;; make-enqueueable-thunk is unused.  Part of an alternate
  475. ;;; implementation, where the thunk doesn't hold on to the
  476. ;;; application, so that the application can GC away even if there are
  477. ;;; events scheduled. 
  478.  
  479. (define make-enqueueable-thunk
  480.   (let ()
  481.     (define (try-to-run weak)    
  482.       (lambda ()
  483.     (let ((code (weak-car weak)))
  484.       (if code
  485.       (debug-print code)
  486.       (debug-print 'vanished))
  487.       (if code (code)))))
  488.     (lambda (thunk)
  489.       (try-to-run (weak-cons thunk 'IGNORED)))))
  490.  
  491.  
  492. ;;;; UITK objects.  We almost never work with bare X objects.
  493.  
  494.  
  495.  
  496. ;;;convert an Xevent (string) to a UITK event structure.  This defines
  497. ;;;the dispatch only.  The actual make-event procedures for the
  498. ;;;various event types are defined in UITK.scm 
  499.  
  500. (define XEvent-><Event>
  501.   (let ((X-Event-Converters
  502.      (make-vector LASTEVENT
  503.               (lambda (event)
  504.             (decode-unknown-event event
  505.               (lambda (type serial sent? display window)
  506.                 type serial sent? display
  507.                 (make-unknown-event 'UNUSUAL event window)))))))
  508.  
  509.     (define (key name)
  510.       (lambda (e)
  511.     (decode-key-event e
  512.           (lambda (type serial sent? display window root subwindow
  513.             time x y RootX RootY state keycode SameScreen?)
  514.         type serial sent? display root subwindow
  515.         time RootX RootY state keycode SameScreen?
  516.         (make-point-event name e window (Make-Point X Y))))))
  517.     (vector-set! X-Event-Converters KeyPress (key 'KEY-PRESS))
  518.     (vector-set! X-Event-Converters KeyRelease (key 'KEY-RELEASE))
  519.  
  520.     (define (button name)
  521.       (lambda (e)
  522.     (decode-button-event e
  523.           (lambda (type serial sent? display window root subwindow
  524.             time x y RootX RootY state button SameScreen?)
  525.         type serial sent? display root subwindow
  526.         time RootX RootY state button SameScreen?
  527.         (make-point-event name e window (Make-Point X Y))))))
  528.     (vector-set! X-Event-Converters ButtonPress (button 'BUTTON-PRESS))
  529.     (vector-set! X-Event-Converters ButtonRelease (button 'BUTTON-RELEASE))
  530.  
  531.     (define (motion name)
  532.       (lambda (e)
  533.     (decode-motion-event e
  534.      (lambda (type serial sent? display window root subwindow
  535.           time x y RootX RootY state IsHint SameScreen?)
  536.        type serial sent? display window root
  537.        subwindow time RootX RootY state IsHint SameScreen?
  538.        (make-point-event name e window (Make-Point X Y))))))
  539.     (vector-set! X-Event-Converters MotionNotify (motion 'POINTER-MOTION))
  540.  
  541.     (define (crossing name)
  542.       (lambda (e)
  543.     (decode-crossing-event
  544.      e
  545.      (lambda (type serial sent? display window root subwindow
  546.                time x y RootX RootY mode detail SameScreen?
  547.                Focus? state)
  548.        type serial sent? display root subwindow
  549.        time RootX RootY mode detail SameScreen? Focus? state
  550.        (make-point-event name e window (Make-Point X Y))))))
  551.     (vector-set! X-Event-Converters EnterNotify (crossing 'ENTER))
  552.     (vector-set! X-Event-Converters LeaveNotify (crossing 'LEAVE))
  553.  
  554.     ; (vector-set! X-Event-Converters ConfigureNotify ...)
  555.     ; (vector-set! X-Event-Converters FocusIn ...)
  556.     ; (vector-set! X-Event-Converters FocusOut ...)
  557.     ; (vector-set! X-Event-Converters KeymapNotify ...)
  558.  
  559.     (define (expose-fn type-name)
  560.       (lambda (e)
  561.     (decode-expose-event
  562.      e
  563.      (lambda (type serial sent? display
  564.                window x y width height count)
  565.        type serial sent? display count width height
  566.        (make-rectangle-event
  567.                       type-name e window (Make-Point x y)
  568.               width height)))))
  569.     (vector-set! X-Event-Converters Expose (expose-fn 'EXPOSURE))
  570.  
  571.     ; (vector-set! X-Event-Converters GraphicsExpose ...)
  572.     ; (vector-set! X-Event-Converters NoExpose ...)
  573.     ; (vector-set! X-Event-Converters VisibilityNotify ...)
  574.     ; (vector-set! X-Event-Converters CreateNotify ...)
  575.     ; (vector-set! X-Event-Converters DestroyNotify ...)
  576.     ; (vector-set! X-Event-Converters UnmapNotify ...)
  577.     ; (vector-set! X-Event-Converters MapNotify ...)
  578.     ; (vector-set! X-Event-Converters MapRequest ...)
  579.     ; (vector-set! X-Event-Converters ReparentNotify ...)
  580.     ; (vector-set! X-Event-Converters ConfigureNotify ...)
  581.     ; (vector-set! X-Event-Converters ConfigureRequest ...)
  582.     ; (vector-set! X-Event-Converters GravityNotify ...)
  583.     ; (vector-set! X-Event-Converters ResizeRequest ...)
  584.     ; (vector-set! X-Event-Converters CirculateNotify ...)
  585.     ; (vector-set! X-Event-Converters CirculateRequest ...)
  586.     ; (vector-set! X-Event-Converters PropertyNotify ...)
  587.     ; (vector-set! X-Event-Converters SelectionClear ...)
  588.     ; (vector-set! X-Event-Converters SelectionRequest ...)
  589.     ; (vector-set! X-Event-Converters SelectionNotify ...)
  590.     ; (vector-set! X-Event-Converters ColormapNotify ...)
  591.     ; (vector-set! X-Event-Converters ClientMessage ...)
  592.     ; (vector-set! X-Event-Converters MappingNotify ...)
  593.     (lambda (XEvent)
  594.       ((vector-ref X-Event-Converters (xevent-type XEvent))
  595.        XEvent))))
  596.  
  597. ;;This places the XEvent in the given string.  It uses the side effect
  598. ;;to avoid allocating a new string and generating garbage in the inner
  599. ;;event processing loop
  600.  
  601. (define (get-x-event display event-string)
  602.   (if (zero? (XPending display))
  603.       #F
  604.       (XNextEvent! display event-string)))
  605.  
  606.  
  607.  
  608. ;;; open a display and return the  numeric hook
  609.  
  610. (define (open-display)
  611.   (let ((xdisplay (XOpenDisplay "")))
  612.     (if (or (and (number? xdisplay) (zero? xdisplay))
  613.         (and (pair? xdisplay) (number? (cdr xdisplay))
  614.          (zero? (cdr xdisplay))))
  615.     (error 'OPEN-DISPLAY "Could not open display")
  616.     xdisplay)))
  617.  
  618. (define (string->color display)
  619.   (lambda (string)
  620.     (let ((result
  621.        (XAllocNamedColor display
  622.                  (XDefaultColormap display
  623.                            (XDefaultScreen display))
  624.                  string)))
  625.       ;; Result is (Status ScreenColor ExactColor)
  626.       (if (zero? (car result))
  627.       #F                ; Error status
  628.       (list-ref result 1)))))
  629.  
  630.  
  631. #| Fonts don't work yet
  632. (define (string->font display)
  633.   (lambda (string)
  634.     (XLoadFont display string)))
  635. |#
  636.  
  637.  
  638. ;;;; Event-sensitive windows.  
  639.  
  640. (define (Generate-Events! UITKWindow mask)
  641.   (let ((attributes (XMake-SetWindowAttributes))
  642.     (window (UITKWindow.XWindow UITKWindow))
  643.     (display (UITKWindow.XDisplay UITKWindow)))
  644.     (XSetWindowAttributes-Event_Mask! attributes mask)
  645.     (XChangeWindowAttributes display window CWEventMask attributes))
  646.     (let ((result (XGetWindowAttributes display window)))
  647.       (if (= (list-ref result 0) 0)
  648.       (error 'GENERATE-EVENTS!
  649.          "XGetWindowAttributes failed ~A" result)
  650.       (list-ref result 1))))
  651.  
  652.  
  653. (define (handler->sensitivity handler)
  654.   (case (car handler)
  655.     ((#T) NoEventMask)
  656.     ((KEY-PRESS) KeyPressMask)
  657.     ((KEY-RELEASE) KeyReleaseMask)
  658.     ((BUTTON-PRESS) ButtonPressMask)
  659.     ((BUTTON-RELEASE) ButtonReleaseMask)
  660.     ((ENTER) EnterWindowMask)
  661.     ((CONFIGURE-NOTIFY) StructureNotifyMask)
  662.     ((LEAVE) LeaveWindowMask)
  663.     ((POINTER-MOTION) PointerMotionMask)
  664.      ; (bit-or PointerMotionMask PointerMotionHintMask)
  665.     ((BUTTON-1-MOTION) Button1MotionMask)
  666.     ((BUTTON-2-MOTION) Button2MotionMask)
  667.     ((BUTTON-3-MOTION) Button3MotionMask)
  668.     ((BUTTON-4-MOTION) Button4MotionMask)
  669.     ((BUTTON-5-MOTION) Button5MotionMask)
  670.     ((BUTTON-MOTION) ButtonMotionMask)
  671.      ; (bit-or ButtonMotionMask PointerMotionHintMask)
  672.     ((KEYMAP-STATE) KeyMapStateMask)
  673.     ((EXPOSURE) ExposureMask)
  674.     ((VISIBITY-CHANGE) VisibilityChangeMask)
  675.     ((STRUCTURE-NOTIFY) StructureNotifyMask)
  676.     ;; I don't understand ResizeRedirect or substructure stuff
  677.     ((FOCUS-CHANGE) FocusChangeMask)
  678.     ((PROPERTY) PropertyChangeMask)
  679.     ;; Ignoring colormap and owner grab
  680.     (else (error 'HANDLER->SENSITIVITY "Unknown event type ~A" (car handler)))
  681.     ))
  682.  
  683. (define (bit-or . integers)
  684.   (bit-string->unsigned-integer
  685.    (reduce bit-string-or (unsigned-integer->bit-string 32 0)
  686.        (map (lambda (n) (unsigned-integer->bit-string 32 n))
  687.         integers))))
  688.  
  689. ;;;; UITK level "X" calls.  
  690.  
  691. #| In UITK, we almost never work with bare X objects.  Rather there
  692. are two levels of embedding.  The first is the "wrapper" which is used
  693. for garbage collection (see MIT-Xlib).  This wrapped object is then
  694. embedded in a UITK structure that bundles together associated
  695. information.  (For example, a UITKWindow holds both an X window and
  696. its associated X display.)  Thus, a user-level procedure such as
  697. Drawline, operates on UITK windows.  It is defined in terms of a lower
  698. level XDrawline (which operates on wrapped windows) which in tern is
  699. defined in terms of the X primitive %XDrawline. |#
  700.  
  701.  
  702. ;;;; Graphics contexts
  703.  
  704. (define (make-simple-graphics-context uitkwindow)
  705.   (let ((dpy (UITKWindow.XDisplay uitkwindow))
  706.     (win (UITKWindow.XWindow uitkwindow)))
  707.     (XCreateGC dpy win 0 (xmake-gcvalues))))
  708.  
  709. (define (make-colored-graphics-context uitkwindow color-string)
  710.   (let ((gc (make-simple-graphics-context uitkwindow))
  711.     (dpy (UITKWindow.XDisplay uitkwindow)))
  712.     (let ((color ((string->color dpy) color-string)))
  713.       (if (color? color)
  714.       (begin
  715.         (XSetForeground dpy gc color)
  716.         gc)
  717.       (error 'make-colored-graphics-context
  718.          "Can't convert color name to value ~A"
  719.          color-string)))))
  720.  
  721. (define (DrawArc uitkwindow gc X Y Width Height angle1 angle2)
  722.   (XDrawArc (UITKWindow.XDisplay uitkwindow)
  723.         (UITKWindow.XWindow uitkwindow)
  724.         gc x y width height angle1 angle2))
  725.  
  726. (define (DrawLine uitkwindow gc X1 Y1 X2 Y2)
  727.   (XDrawLine (UITKWindow.XDisplay uitkwindow)
  728.           (UITKWindow.XWindow uitkwindow)
  729.           gc x1 y1 x2 y2))
  730.  
  731. (define (DrawRectangle uitkwindow gc X Y Width Height)
  732.   (XDrawRectangle (UITKWindow.XDisplay uitkwindow)
  733.           (UITKWindow.XWindow uitkwindow)
  734.           gc x y width height))
  735.  
  736.  
  737. (define (FillRectangle uitkwindow gc X Y Width Height)
  738.   (XFillRectangle (UITKWindow.XDisplay uitkwindow)
  739.           (UITKWindow.XWindow uitkwindow)
  740.           gc x y width height))
  741.  
  742. (define (FillArc uitkwindow gc X Y Width Height angle1 angle2)
  743.   (XFillArc (UITKWindow.XDisplay uitkwindow)
  744.         (UITKWindow.XWindow uitkwindow)
  745.         gc x y width height angle1 angle2))
  746.  
  747. (define (ClearArea uitkwindow X Y width height exposures?)
  748.   (XClearArea (UITKWindow.XDisplay uitkwindow)
  749.           (UITKWindow.XWindow uitkwindow)
  750.           x y width height exposures?))
  751.  
  752. (define (flush-queued-output display)
  753.   (xflush display))
  754.  
  755. (define (GetDefaultValue display application-name variable)
  756.   (XGetDefault display application-name variable))
  757.  
  758. (define (Decode-Button-Event event receiver)
  759.   (let ((vect (make-vector 15)))
  760.     (XDecodeButtonEvent event vect)
  761.     (apply receiver (vector->list vect))))
  762.  
  763. (define (Decode-Configure-Event event receiver)
  764.   (let ((vect (make-vector 13)))
  765.     (XDecodeConfigureEvent event vect)
  766.     (apply receiver (vector->list vect))))
  767.  
  768. (define (Decode-Crossing-Event event receiver)
  769.   (let ((vect (make-vector 17)))
  770.     (XDecodeCrossingEvent event vect)
  771.     (apply receiver (vector->list vect))))
  772.  
  773. (define (Decode-Expose-Event event receiver)
  774.   (let ((vect (make-vector 10)))
  775.     (XDecodeExposeEvent event vect)
  776.     (apply receiver (vector->list vect))))
  777.  
  778. (define (Decode-Key-Event event receiver)
  779.   (let ((vect (make-vector 15)))
  780.     (XDecodeKeyEvent event vect)
  781.     (apply receiver (vector->list vect))))
  782.  
  783. (define (Decode-Motion-Event event receiver)
  784.   (let ((vect (make-vector 15)))
  785.     (XDecodeMotionEvent event vect)
  786.     (apply receiver (vector->list vect))))
  787.  
  788. (define (Decode-Unknown-Event event receiver)
  789.   (let ((vect (make-vector 5)))
  790.     (XDecodeUnknownEvent event vect)
  791.     (apply receiver (vector->list vect))))
  792.  
  793. (define (XEvent-Type xevent)
  794.   (Decode-Unknown-Event xevent
  795.     (lambda (type . others)
  796.       others                ; Ignored
  797.       type)))
  798.  
  799. (define (Decode-Window-Attributes attributes receiver)
  800.   (let ((vect (make-vector 23)))
  801.     (XDecodeWindowAttributes attributes vect)
  802.     (apply receiver (vector->list vect))))
  803.  
  804. (define (Get-Window-Attributes display window receiver)
  805.   (let ((attributes (list-ref (XGetWindowAttributes display window) 1)))
  806.     (Decode-Window-Attributes attributes receiver)))
  807.  
  808. (define (Rectangle->XRegion rectangle)
  809.   (MakeXRegion (Point.X (UITKRectangle.Offset rectangle))
  810.            (Point.Y (UITKRectangle.Offset rectangle))
  811.            (UITKRectangle.Width rectangle)
  812.            (UITKRectangle.Height rectangle)))
  813.  
  814. (define (MakeXRegion x y width height)
  815.   (let ((region (XCreateRegion)))
  816.     (XUnionRectSpecsWithRegion! x y width height region region)
  817.     region))
  818.  
  819. (define (IntersectXRegions x-region-1 x-region-2)
  820.   (let ((region (XCreateRegion)))
  821.     (XIntersectRegion! x-region-1 x-region-2 region)
  822.     region))
  823.  
  824. (define (UnionXRegions x-region-1 x-region-2)
  825.   (let ((region (XCreateRegion)))
  826.     (XUnionRegion! x-region-1 x-region-2 region)
  827.     region))
  828.  
  829. (define (CopyXRegion region)
  830.   (UnionXRegions (XCreateRegion) region))
  831.  
  832. (define (SubtractXRegions x-region-1 x-region-2)
  833.   (let ((region (XCreateRegion)))
  834.     (XSubtractRegion! x-region-1 x-region-2 region)
  835.     region))
  836.  
  837. (define (SetClipXRegion window graphics-context XRegion)
  838.   (XSetRegion (UITKWindow.XDisplay window)
  839.           graphics-context
  840.           XRegion))
  841.  
  842. ;;;process a mouse drag.
  843. ;;;keep reading motion events and process them 
  844. ;;;stop when there is a button release
  845.  
  846. ;;;This procedure is included here because of the X calls.  
  847.  
  848. (define (mouse-drag surface on-motion)
  849.   ;; *** Maybe this should take an "other events handler" ***
  850.   (let* ((UITKWindow (DrawingSurface.UITKWindow surface))
  851.      (xdisplay (uitkwindow.xdisplay UITKWindow)))
  852.     (without-interrupts
  853.      (lambda ()
  854.        (let loop ()
  855.      (let* ((x-event (XNextEvent xdisplay))) ;**blocks?
  856.        (Decode-Unknown-Event
  857.         x-event
  858.         (lambda (type serial sent? display window)
  859.           serial sent? display window
  860.           (cond ((eq? type MotionNotify)
  861.              (decode-motion-event x-event
  862.               (lambda (type serial sent? display window root subwindow
  863.                    time x y RootX RootY state IsHint SameScreen?)
  864.             type serial sent? display window root subwindow
  865.             time RootX RootY state IsHint SameScreen?
  866.             (on-motion (make-point x y))))
  867.              (loop))
  868.             ((eq? type ButtonRelease) 'endloop)
  869.             (else (loop)))))))))))
  870.  
  871. ;;; GC of UITK objects
  872. ;;; this uses the protrction list mechanism implemented in MIT-Xlib
  873.  
  874. (define uitk-protection-list 'later)
  875.  
  876. (define (when-unreferenced obj thunk)
  877.   (add-to-protection-list! uitk-protection-list obj thunk))
  878.  
  879. (define (finalize-uitk-objects)
  880.   (clean-lost-protected-objects uitk-protection-list
  881.                 (lambda (thunk) (thunk))))
  882.  
  883. (define (finalize-uitk-objects-later)
  884.   (set! *UITK:GC-HAS-OCCURRED?* #T)
  885.   ;; (when-idle! finalize-uitk-objects)
  886.   ;; Handled in the main UITK thread loop.  Also calls the scxl daemon
  887.   ;; there.
  888.   )
  889.  
  890. ;;; In generating hash numbers for callbacks, etc., we use a private
  891. ;;; hash table, separate from the system one.
  892.  
  893. (define *our-hash-table* 'later)
  894. (define *UITK:GC-HAS-OCCURRED?* #F)
  895.  
  896. #|
  897.  
  898. Shutting down the event server may be necessary in UITK even though
  899. the event server is shut down as soon as the UITK application is
  900. destroyed, because the applcation and display may vanish on the same
  901. GC.
  902.  
  903. We must explicitly destroy the tk-widgets for this display (since Xlib
  904. doesn't know about them). The TK widgets must be destroyed BEFORE the
  905. display is closed.
  906.  
  907. |#
  908.  
  909. (define (initialize-uitk!)
  910.   (set! uitk-protection-list (make-protection-list))
  911.   ;; THIS SHOULD BE PUT BACK WHEN remove-gc-daemon! GETS WRITTEN
  912.   ;; (remove-gc-daemon! close-lost-displays-daemon)
  913.   (add-gc-daemon! finalize-uitk-objects-later)
  914.   (set! uitk-queue (make-queue))
  915.   (set! idle-queue (make-queue))
  916.   (set! the-agenda (make-agenda))
  917.   (make-uitk-thread)
  918.   (SCXL-Install-XCloseDisplay-Callback shut-down-event-server)
  919.   (set! *our-hash-table* (hash-table/make 4001))
  920.   )
  921.  
  922. (initialize-uitk!)
  923.