[comp.sys.mac.programmer] MultiFinder switch bug with custom WDEFs

thomas@uvabick.UUCP (Thomas Fruin) (04/19/88)

MultiFinder won't let you switch when there is a modal dialog box open
on the screen, since the user is expecting a modal situation.  To determine
this, MultiFinder looks to see (among other things) if the window definition
procedure of that window is dBoxProc.  (I'm quoting Technical Note 180 here)

Unfortunately MultiFinder doesn't look good enough.  It _only_ examines the
window's variation code, assuming that you are using the standard WDEF with
resource ID 0.  I have written my own WDEF that mimics Apple's standard WDEF
for document windows, but let's you have funky patterns in the title bar
(among other things).  I have my own variation codes that behave similar to,
but not completely the same as Apple's variation codes.  And you guessed it:
I also use a variation code of 1 (dBoxProc == 1).  I assumed MultiFinder
would at least check the resource ID of the WDEF it is examining - my WDEF
has a resource ID of 128, which would give the particular window that is       
giving me problems a window definition ID of 2049 (16 * 128 + 1).
  
Sadly, MultiFinder ignores the resource ID completely.  So if anybody out
there is using custom WDEFs, make sure to avoid variation code 1.  It was
a weird experience not being able to switch at all, even though I had
document windows on top.

I hope Apple fixes this oversight.

-- Thomas Fruin

   fruin@hlerul5.BITNET                       University of Leiden
   thomas@uvabick.UUCP                        University of Amsterdam
   dibs@well.UUCP
   hol0066.AppleLink
   2:508/15.FidoNet                           The Netherlands

goldman@Apple.COM (Phil Goldman) (04/21/88)

In article <242@uvabick.UUCP> thomas@uvabick.UUCP (Thomas Fruin) writes:
>MultiFinder won't let you switch when there is a modal dialog box open
>on the screen, since the user is expecting a modal situation.  To determine
>this, MultiFinder looks to see (among other things) if the window definition
>procedure of that window is dBoxProc.  (I'm quoting Technical Note 180 here)
>...
>Sadly, MultiFinder ignores the resource ID completely.  So if anybody out
>there is using custom WDEFs, make sure to avoid variation code 1.  It was
>a weird experience not being able to switch at all, even though I had
>document windows on top.


This is not a bug, but merely an oversight in not documenting the conditions
completely.  dBoxProc is reserved for modal dialogs, no matter what the
WDEF is.  This is necessary because we have to allow for the system (or even
an app) to easily patch the standard WDEF by adding some code to the front
and then falling thru to the standard one.  This would cause problems if we
checked the resource ID too.

The reason that all of this checking is necessary in the first place is
because some applications will put up a modal dialog without actually calling
the trap _ModalDialog to handle it.  If it always was called we probably
would not have looked at the var code at all.

-Phil Goldman
Apple Computer

darin@Apple.COM (Darin Adler) (04/21/88)

In article <242@uvabick.UUCP> thomas@uvabick.UUCP (Thomas Fruin) writes:
> Unfortunately MultiFinder doesn't look good enough.  It _only_ examines the
> window's variation code, assuming that you are using the standard WDEF with
> resource ID 0.
>
> Sadly, MultiFinder ignores the resource ID completely.  So if anybody out
> there is using custom WDEFs, make sure to avoid variation code 1.  It was
> a weird experience not being able to switch at all, even though I had
> document windows on top.

Although this is a bug, I have heard that some here want to retain it as a
feature. You see, if someone wants to create a non-standard WDEF that is a
modal-type window, there is nothing he can do *without* this bug. With it,
he only needs to define his modal-looking window as variation 1 (and avoid
that variation the rest of the time), and MultiFinder will respect the modal
window.

What do you think?
-- 
Darin Adler						AppleLink:Adler4
UUCP: {sun,voder,nsc,mtxinu,dual}!apple!darin	  CSNET: darin@Apple.com

alibaba@ucscb.UCSC.EDU (Alexander M. Rosenberg) (04/22/88)

God forbid anybody wants to do more than one modal variation...

In other news:
   What's the deal with scroll bars? When they CDEF got updated to work with
the new control manager color support, why didn't it also get the variable
elevator sizing as found on the //gs and GEM? (sorry to say that, but it
has it and we don't...)

   If nobody at Apple wants to waste the under five minutes it takes to
add the under five lines, then send me a current copy of the scroll bar
source (I only have the original 1984 suppliment code, which is vastly outdated)
and _I'll_ do it. If not, I'll do it anyway, and I'll just rewrite the old
1984 code that I have.

-------------------------------------------------------------------------------
-  Alexander M. Rosenberg  - INTERNET: alibaba@ucscb.ucsc.edu   - Yoyodyne    -
-  Crown College, UCSC     - UUCP:...!ucbvax!ucscc!ucscb!alibaba- Propulsion  -
-  Santa Cruz, CA 95064    - BITNET:alibaba%ucscb@ucscc.BITNET  - Systems     -
-  (408) 426-8869          - Disclaimer: Nobody is my employer  - :-)         -
-                          - so nobody cares what I say.        -             -

thomas@uvabick.UUCP (Thomas Fruin) (04/24/88)

 Darin Adler writes:

 > Although this is a bug, I have heard that some here want to retain it as a
 > feature. You see, if someone wants to create a non-standard WDEF that is a
 > modal-type window, there is nothing he can do *without* this bug. With it,
 > he only needs to define his modal-looking window as variation 1 (and avoid
 > that variation the rest of the time), and MultiFinder will respect the modal
 > window.
 >
 > What do you think?

Hmm, hadn't thought of it that way.  It's not a bad idea.  One could still
argue that people who write custom WDEFs that should behave modal will take
the trouble to treat them as modal in their source, but I still like the
idea.  But make sure to document this new "feature" :)

 Phil Goldman writes:

 > dBoxProc is reserved for modal dialogs, no matter what the WDEF is.
 > This is necessary because we have to allow for the system (or even
 > an app) to easily patch the standard WDEF by adding some code to the front
 > and then falling thru to the standard one.  This would cause problems if we
 > checked the resource ID too.

What a dirty thing to do!  I thought I had seen some pretty bad things one
could do with WDEFs in MacTutor, but this beats everything ...

Seriously, I hadn't thought of this one.  Anyway, I had to put some extra
code in my own application (that uses the custom WDEF), because I had used
up all 4 bits in the variation code.

-- Thomas Fruin

   fruin@hlerul5.BITNET                       University of Leiden
   thomas@uvabick.UUCP                        University of Amsterdam
   dibs@well.UUCP
   hol0066.AppleLink
   2:508/15.FidoNet                           The Netherlands

herbw@midas.TEK.COM (Herb Weiner) (05/05/88)

--------

Perhaps someone could explain the rationale for PROHIBITING a context switch
when a modal dialog box is in front.  I find that it would sometimes be
convenient to switch to the finder (for example) when a sfGetFile dialog
is active, so I could examine (for example) file creation dates, sizes, etc.

It might be reasonable to require the application developer to take an
explicit action to ALLOW the context switch (such as providing an event
filter for the modal dialog).

Perhaps what I'm really suggesting is that modal dialogs are only modal
with respect to that application that displays them, but that they should
be MODELESS with respect to OTHER applications running under MultiFinder.

If the real problem is that Apple depends upon non-reentrant code (such
as Standard File) which uses modal dialogs, perhaps we should all be asking
when Apple will make this code reentrant.

Looking forward to some enlightenment...

                                      Herb Weiner
                                      UUCP: !tektronix!midas!herbw
                                      AppleLink: D0521

goldman@Apple.COM (Phil Goldman) (05/06/88)

In article <2887@midas.TEK.COM> herbw@midas.UUCP (Herb Weiner) writes:
>--------
>
>Perhaps someone could explain the rationale for PROHIBITING a context switch
>when a modal dialog box is in front...

The rationale is one of user interface.  A modal dialog should be used when the user must interact with it before the (visible) task can continue.  If this is not its purpose, then the dialog should be modeless.

>Perhaps what I'm really suggesting is that modal dialogs are only modal
>with respect to that application that displays them, but that they should
>be MODELESS with respect to OTHER applications running under MultiFinder.
>

There might be some use for dialogs that are modal within their layer.
This can already be accomplished by the applications themselves.  Hopefully
these will not too often be used.

There has been some thought given to allowing the power user to override modal
dialogs, possibly by holding down the command key, or some equivalent, while
switching.

>If the real problem is that Apple depends upon non-reentrant code (such
>as Standard File) which uses modal dialogs, perhaps we should all be asking
>when Apple will make this code reentrant.
>

And modeless too, right?  Why shouldn't other application windows be allowed
to be put in front of the StdFile dialog, as well as other layers?  What's
the distinction (besides a change to the app interface)?

Anyway...
Do you really want multiple instances of StdFile?  I'd think that it would
be nicer to *never* have to use it.  In MultiFinder 6.0 (due real real soon
now) it is possible to double-click on documents in the Finder and have an
running application open them anyway, thus eliminating the need for StdFile
(unless the latter is a preferred form of navigation), especially if it is
desirable to look at the file info beforehand.

-Phil Goldman
Apple Computer

kaufman@polya.STANFORD.EDU (Marc T. Kaufman) (05/06/88)

In article <9332@apple.Apple.Com> goldman@apple.UUCP (Phil Goldman) writes:
>In article <2887@midas.TEK.COM> herbw@midas.UUCP (Herb Weiner) writes:

.>Perhaps someone could explain the rationale for PROHIBITING a context switch
.>when a modal dialog box is in front...

>The rationale is one of user interface.  A modal dialog should be used when the user must interact with it before the (visible) task can continue.  If this is not its purpose, then the dialog should be modeless.

.>Perhaps what I'm really suggesting is that modal dialogs are only modal
.>with respect to that application that displays them, but that they should
.>be MODELESS with respect to OTHER applications running under MultiFinder.

>There might be some use for dialogs that are modal within their layer.
>This can already be accomplished by the applications themselves.  Hopefully
>these will not too often be used.

One of the main reasons for using modal dialogs where modeless dialogs
would do, is the availability of the Dialog Manager for handling most of
the buttons, switches, and events.  If a dialog is modeless, you cannot
use IsDialogEvent, NewDialog, GetNewDialog, or the ModalDialog event filter.

Provide these tools for modeless dialogs, and more people would use them.

Marc Kaufman (kaufman@polya.stanford.edu)

darin@Apple.COM (Darin Adler) (05/07/88)

In article <2770@polya.STANFORD.EDU> kaufman@polya.stanford.edu (Marc T. Kaufman) writes:
> One of the main reasons for using modal dialogs where modeless dialogs
> would do, is the availability of the Dialog Manager for handling most of
> the buttons, switches, and events.  If a dialog is modeless, you cannot
> use IsDialogEvent, NewDialog, GetNewDialog, or the ModalDialog event filter.

Absolutely untrue! IsDialogEvent, NewDialog, and GetNewDialog can all be used
with modeless dialogs. Note that for a modeless dialog, you create the dialog
and then return to the main event loop. Some of the events you receive from
GetNextEvent or WaitNextEvent need to be passed to the dialog manager. After
gettin an event, you call IsDialogEvent. If that returns TRUE, then you call
DialogSelect for the event. This is the equivalent of what ModalDialog does for
modal dialogs. Note that you can do the same filtering that you would do in a
ModalDialog event filter just before calling DialogSelect. I even sometimes use
the same dialog filter for both modal and modeless dialogs like this:

    modal case:

	... NewDialog ...

	ModalDialog(itemHit, @DialogFilter);

    modeless case:

	... NewDialog ... {fall back to main event loop}

	... GetNextEvent(everyEvent, event) ...
	IF IsDialogEvent(event) THEN BEGIN
	    dialog := FrontWindow;
	    hitSomething := FALSE;
	    IF WindowPeek(dialog)^.windowKind = dialogKind THEN
		hitSomething := DialogFilter(dialog, event, itemHit);
	    IF NOT hitSomething THEN
		hitSomething := DialogSelect(event, dialog, itemHit);
	... {handle hits here} ...
	END;
-- 
Darin Adler						AppleLink:Adler4
UUCP: {sun,voder,nsc,mtxinu,dual}!apple!darin	  CSNET: darin@Apple.com

kaufman@polya.STANFORD.EDU (Marc T. Kaufman) (05/07/88)

In article <9364@apple.Apple.Com> darin@apple.UUCP (Darin Adler) writes:
>In article <2770@polya.STANFORD.EDU> kaufman@polya.stanford.edu (Marc T. Kaufman) writes:
.> One of the main reasons for using modal dialogs where modeless dialogs
.> would do, is the availability of the Dialog Manager for handling most of
.> the buttons, switches, and events.  If a dialog is modeless, you cannot
.> use IsDialogEvent, NewDialog, GetNewDialog, or the ModalDialog event filter.

>Absolutely untrue! IsDialogEvent, NewDialog, and GetNewDialog can all be used
>with modeless dialogs. Note that for a modeless dialog, you create the dialog
>and then return to the main event loop. Some of the events you receive from
>GetNextEvent or WaitNextEvent need to be passed to the dialog manager. After
>gettin an event, you call IsDialogEvent. If that returns TRUE, then you call
>DialogSelect for the event.

OK, I agree that GetNewDialog and NewDialog can be used for modeless dialogs,
but the important thing is that the DLOG resource has no way of specifying
a window type other than modal-dialog.  I HAVE used these routines to start
a modeless dialog, by setting the initial window to invisible, then changing
the window type in the dialog before showing the window for the first time.
However, and here is the catch, if you make the window a non-dialog type
(so that Multifinder will switch -- remember that multifinder doesn't care
how you USE the window, only its type), then IsDialogEvent will always
return FALSE -- because IsDialogEvent goes through the Window list looking
for MODAL DIALOG windows.

DialogSelect, and the other dialog item handlers that take a DialogPtr
as a parameter, work OK because they know where to find the dialog window
(you gave them the pointer).

Now... how do you do the IsDialogEvent function without writing a whole
event loop -- which is why you use ModalDialog in the first place.?

Marc Kaufman (kaufman@polya.stanford.edu)

dwb@Apple.COM (David W. Berry) (05/10/88)

In article <2770@polya.STANFORD.EDU> kaufman@polya.stanford.edu (Marc T. Kaufman) writes:
>One of the main reasons for using modal dialogs where modeless dialogs
>would do, is the availability of the Dialog Manager for handling most of
>the buttons, switches, and events.  If a dialog is modeless, you cannot
>use IsDialogEvent, NewDialog, GetNewDialog, or the ModalDialog event filter.
	Umm... beg to disagree, but, of the four things you mentioned,
only one of them (ModalDialog) isn't *supposed* to be used with modeless
dialogs, and ModalDialog isn't supposed to be used with modeless dialogs
because it specifically makes a dialog modal (kinda like the name suggests).
IsDialogEvent is primarily useful with modeless dialogs:
	Inside Macintosh I, pg. 416:  "If your application includes
any modeless dialog boxes, you'll pass events to IsDialogEvent to
learn whether need to be handled as part of a dialog, and then usually
call DialogSelect if so."  DialogSelect handles things like tab moving
to the next field, caret blinking, etc.  What is left for the programmer
to handle are things like:
	Buttons, CheckBoxes, RadioButtons - none of which are handled
		automatically by the system for modal dialogs either.
	Return, Cmd-., Enter - which are handled by ModalDialog, but
		which are pretty simple to deal with anyway.
	NewDialog and GetNewDialog are used to create dialogs, possibly
from resources, no matter what they are to be used for.

	Making a dialog modeless is really a lot easier than people
seem to think.  Basically, you put the following code into your event
loop:

	if(IsDialogEvent(&myEvent))
	{
		if(DialogSelect(&myEvent, &whichDialog, &whichItem))
		{
			if(whichDialog == dialog1)
				DoDialog1(&myEvent, whichItem);
			else if (whichDialog == dialog2)
				DoDialog2(&myEvent, whichItem);
		}
	}
	else
	{
		HandleEvent(&myEvent);
	}

	which corresponds to the part of the modal dialog which looks
like:
	do
	{
		ModalDialog(NULL, &whichItem);
		DoDialog1(whichItem);
	} while(not terminated);

	The only change necessary to DoDialog? is to add at the top
something like:

	if((myEvent->what == keyDown) || (myEvent->what == autoKey))
	{
		key = message & charCodeMask;
		if((key == 0x0d) || (key = 0x03))
			TerminateDialog();
		if((key == '.') && (myEvent->modifiers & cmdKey))
			CancelDialog();
	}

	Pretty easy, huh?
>
>Marc Kaufman (kaufman@polya.stanford.edu)

dwb@Apple.COM (David W. Berry) (05/10/88)

In article <2781@polya.STANFORD.EDU> kaufman@polya.stanford.edu (Marc T. Kaufman) writes:
>OK, I agree that GetNewDialog and NewDialog can be used for modeless dialogs,
>but the important thing is that the DLOG resource has no way of specifying
>a window type other than modal-dialog.  I HAVE used these routines to start
>a modeless dialog, by setting the initial window to invisible, then changing
>the window type in the dialog before showing the window for the first time.
>However, and here is the catch, if you make the window a non-dialog type
>(so that Multifinder will switch -- remember that multifinder doesn't care
>how you USE the window, only its type), then IsDialogEvent will always
>return FALSE -- because IsDialogEvent goes through the Window list looking
>for MODAL DIALOG windows.
	Well, two problems here:
	1.  The correct way of setting the window type when creating
	a dialog is to via procID argument to NewDialog.  The DLOG
	resource has a similar field at offset 8, so it works with
	GetNewDialog too.
	2.  IsDialogEvent does *not* look for modal dialog windows.  It
	look for windows with windowKind == dialogKind.  Works out
	quite well since NewDialog and GetNewDialog both set windowKind
	to dialogKind.
>Now... how do you do the IsDialogEvent function without writing a whole
>event loop -- which is why you use ModalDialog in the first place.?
	Huh?  If you're saying you are using ModalDialog to avoid putting
an event loop in your program at all, go ahead, you're program isn't
very macintosh anyway so why bother.  If you're claiming that using
modeless dialogs requires a separate event loop, you're way off base.
It merely requires the addition of a few lines to your existing
event loop, a few subroutines to deal with button clicks and the like
(the code would be needed for modal dialogs also) and a few globals to
keep track of what dialogs are currently displayed and active.

	Get a hold of the version of TransSkel which has been modified
to work with modeless dialogs.  It works.  It will show you how these
things ought to be done.  It may even save more argument here :-)
>
>Marc Kaufman (kaufman@polya.stanford.edu)


-- 
David W. Berry
dwb@Delphi	dwb@apple.com	973-5168@408.MaBell
Disclaimer: Apple doesn't even know I have an opinion and certainly
	wouldn't want if they did.

darin@Apple.COM (Darin Adler) (05/10/88)

In article <2781@polya.STANFORD.EDU> kaufman@polya.stanford.edu (Marc T. Kaufman) writes:
> In article <9364@apple.Apple.Com> darin@apple.UUCP (Darin Adler) writes:
> >In article <2770@polya.STANFORD.EDU> (Marc T. Kaufman) writes:
> .> One of the main reasons for using modal dialogs where modeless dialogs
> .> would do, is the availability of the Dialog Manager for handling most of
> .> the buttons, switches, and events.
> 
> >Absolutely untrue! IsDialogEvent, NewDialog, and GetNewDialog can all be used
> >with modeless dialogs.
> 
> OK, I agree that GetNewDialog and NewDialog can be used for modeless dialogs,
> but the important thing is that the DLOG resource has no way of specifying
> a window type other than modal-dialog.

You are confusing windowKind with the window definition ID of a window.
Dialogs have a windowKind of 2 (dialogKind), and normal application windows
have a windowKind of 8. MultiFinder looks at the window definition ID to decide
whether or not to switch. This is the value that determines what a window looks
like, but it has *nothing* to do with the Dialog Manager. The reason that the
definition ID is checked is that it determines how the window appears; if it
looks to the user like it should be modal, MultiFinder makes it modal by
ignoring attempts to switch.

This has little to do with managing modeless dialogs with the Dialog Manger.
-- 
Darin Adler						AppleLink:Adler4
UUCP: {sun,voder,nsc,mtxinu,dual}!apple!darin	  CSNET: darin@Apple.com

kaufman@polya.STANFORD.EDU (Marc T. Kaufman) (05/10/88)

In article <9442@apple.Apple.Com> dwb@apple.UUCP (David W. Berry) writes:

>	Making a dialog modeless is really a lot easier than people
>seem to think.  Basically, you put the following code into your event
>loop:

	[14 lines of code]

>	which corresponds to the part of the modal dialog which looks
>like:

	[5 lines of code]

Well, yes but.  More interesting is that you seem to be telling me that
Multifinder looks for dBoxProcs, and doesn't care about windowkind, and
that IsDialogEvent looks at windowkind, and doesn't care about dBoxProcs.

If so, then one can have a layered application-modal dialog (e.g. one
that uses the ModalDialog call) without disabling task switching??  Or
does the ModalDialog event loop preclude switching.

I think the original point (in an article that must have expired by now)
was that LOTS of applications have Alerts, etc., that have been coded
with ModalDialog, that COULD be changed to modeless if everyone took the
time to do it, but that have existed lo these many years just fine until
Multifinder.  If they can be made to layer properly by RezEditing the
WDEF entry in the DLOG resource, fine.

By the way:  it may suprise you to know that there are useful Mac tools
that don't have event loops, but still occasionally need to put up simple
dialogs.  It WAS nice not to have to code an event loop... (sigh!).

Marc Kaufman (kaufman@polya.stanford.edu)

darin@Apple.COM (Darin Adler) (05/11/88)

In article <2792@polya.STANFORD.EDU> kaufman@polya.Stanford.EDU (Marc T. Kaufman) writes:
> ... More interesting is that you seem to be telling me that
> Multifinder looks for dBoxProcs, and doesn't care about windowkind, and
> that IsDialogEvent looks at windowkind, and doesn't care about dBoxProcs.

True.

> If so, then one can have a layered application-modal dialog (e.g. one
> that uses the ModalDialog call) without disabling task switching??  Or
> does the ModalDialog event loop preclude switching.

Yes. No.

You also mentioned that it would be nice to be able to switch out of modal
dialogs by simply changing the procID in the DLOG resource. This will sometimes
work! I've even tried it with the Finder file copy dialog. It's not really
recommended, since the programmer may be assuming that no suspend/resume events
will come in while the modal dialog is frontmost. Also, in the case of the
Finder dialog, GetNextEvent is not called very often while file copies are going
on!
-- 
Darin Adler						AppleLink:Adler4
UUCP: {sun,voder,nsc,mtxinu,dual}!apple!darin	  CSNET: darin@Apple.com