[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

modal dialogs

To:     Guillaume Cartier    cartier@math.uqam.ca
cc:     info-mcl
From:   Steve Mitchell
Date:   5/4/92
Sub:    modal dialogs
> Does anyone know how to do some computations while
> a modal dialog is showing the progress of the computations?
> (like the Finder when it copies files...)
Although it is called in System 7 a "movable modal dialog
box", that is a modeless dialog box the Finder puts up!
> Lots of programs do it, but in MCL it seems like a
> very arduous task. Is there something I'm missing?
Programs that put up a modal dialog as a status window
eg while printing call modal-dialog with a filter proc that
prints a page each time they receive an idle event - that's
why they take so long to cancel! This is what you did and
then complained about in your second message. So if you
want to use a modal dialog, you'll have to fine tune your
code; more on this later.
On-screen clocks that keep ticking, etc while a modal dialog
is up are implemented as a VBL task or somesuch, and can not
be written in MCL.
> One thing I wanted my progress indication modal
> dialog to do, is to respect system 7.0's standards
> (i.e. I want the user to be able to select the applications
> menu to switch application during the computation, etc).
Multifinder uses a hack; if the front window is a double-edged
box it will not allow application switching. modal-dialog has
nothing to do with it. That means the Macintosh standard is to
use double-edged boxes for modal dialogs - you're not supposed
to be able to switch applications while a modal dialog is up.
That's what "modal" means.
So you clearly don't want your dialog to be modal at all. You
also need a good reason for preventing the user from bringing
another MCL window to the front while your task is running.
> I was able to do it using the following new feature of
> modal-dialog:
> (modal-dialog (make-instance 'window)
>               t
>               #'(lambda () (do-some-processing) nil))
> The problem in this case is that the "do-some-processing"
> function has to be very fast not to bog down modal dialog
> processing.
If you're going to do this you can't afford to care about
the modal dialog appearing sluggish; again, see how long it
takes you to get the attention of a Page Layout program while
it's printing a collage.
> "do-some-processing" gets called at a *VERY* slow rate
> (about only 10 times per second, even if does nothing!).
10 times a second is a lot! The main purpose of these null
events when idling is to allow maintaining cursor blink.
By default, *foreground-sleep-ticks* is zero during event
processing so your fn is being called as often as possible.
The eventhook parameter to modal-dialogs was originally
inspired by the desire to be able to have modal dialogs
that timeout; this is tremendous and I don't know of any
other language/system on the Mac that supports timeouts.
Here is an example that monitors the timestamp of null
events for ten seconds and then aborts. This is probably
the kind of thing you're doing in do-some-processing, but
I show it to illustrate the purpose of the event hook for
monitoring rather than heavy work. I hope it works in 2.0b1:
(defparameter *time-in-ticks* nil
  "Has a value when a modal dialog is put up.")
(defun timeout-eventhook ()
  "Timeout after 10 seconds if dialog is still up."
  (let ((num-secs-to-timeout 10)
        (event-type (rref *current-event* eventRecord.what))
        (event-when (rref *current-event* eventRecord.when)))
    (if (equalp event-type 0)  ;$nullEvent
      (if *time-in-ticks*
        (when (> event-when (+ *time-in-ticks* (* 60 num-secs-to-timeout)))
          (setf *time-in-ticks* nil)
          (return-from-modal-dialog "Well, I gave you 10 seconds!"))
        (setf *time-in-ticks* event-when)))
(modal-dialog (make-instance 'window :window-type :double-edge-box)
              t #'timeout-eventhook)
A couple of comments on Bill St. Clair's example:
 - this is a modeless dialog; modal-dialog is not called
 - (let* ((*modal-dialog-on-top* t)...
      has no visible effect that I can see, and the doc string
      says users should not alter its value
 - the "t" after (ed-beep) tells MCL that the eventhook fn
      handled the event. That is why you can't bring up other
      windows by clicking. If you change this to "nil" you
      will be able to bring other windows to the top.
 - (defparameter *d*
       (make-instance 'window :window-type :double-edge-box
                              :window-show nil))
      will not allow you to switch applications because
      Multifinder see the double-edge-box and incorrectly
      assumes it is modal
 - (defparameter *d*
       (make-instance 'window :procid 5
                              :window-show nil))
      under System 7 will give you a "moveable modal dialog"
      (this is a modeless dialog!) and you will be able to
      move the dialog, and switch applications
 - you can combine this with Mark Tapia's lead on where to
      find progress bar source.