| 
    
        |  | This technical note provides answers to some of the more frequently asked
questions about MultiFinder. The development name for MultiFinder was Juggler,
so the term "juggle" is used in this technical note to denote a context switch. [Nov 01 1993] |  
 
 
 
 
 
How can I tell if WaitNextEvent is implemented?
Most applications should not need to tell if MultiFinder is running. Most of
the time, the application really needs to know something like: "How can I tell
if WaitNextEventis implemented?" Here's a Pascal fragment that
demonstrates how to check to see ifWaitNextEventis implemented: 
	|     FUNCTION TrapAvailable(tNumber: INTEGER; tType: TrapType): BOOLEAN;
       CONST
          UnimplementedTrapNumber = $A89F;  {number of "unimplemented trap"}
    BEGIN {TrapAvailable}
    {Check and see if the trap exists.}
    {On 64K ROM machines, tType will be ignored.}
       TrapAvailable := ( NGetTrapAddress(tNumber, tType) <>
                          GetTrapAddress(UnimplementedTrapNumber) );
    END;  {TrapAvailable}
    FUNCTION WNEIsImplemented: BOOLEAN;
       CONST
          WNETrapNumber = $A860; {trap number of WaitNextEvent}
       VAR
          theWorld      : SysEnvRec; {to check if machine has new traps}
          discardError  : OSErr; {to ignore OSErr return from SysEnvirons}
    BEGIN {WNEIsImplemented}
    {  Since WaitNextEvent and HFSDispatch both have the same trap
       number ($60), we can only call TrapAvailable for WaitNextEvent
       if we are on a machine that supports separate OS and Toolbox
       trap tables. We call SysEnvirons and check if machineType < 0.}
       discardError := SysEnvirons(1, theWorld);
    {  Even if we got an error from SysEnvirons, the SysEnvirons glue
       has set up machineType.}
       IF theWorld.machineType < 0 THEN
          WNEIsImplemented := FALSE
          {this ROM doesn't have separate trap tables or WaitNextEvent}
       ELSE
          WNEIsImplemented := TrapAvailable(WNETrapNumber, ToolTrap);
          {check for WaitNextEvent}
    END;  {WNEIsImplemented}
    {Note that we call SystemTask if WaitNextEvent isn't available.}
    ...
       hasWNE := WNEIsImplemented;
    ...
       IF hasWNE THEN BEGIN
          {call WaitNextEvent}
          ...
       END ELSE BEGIN
          {call SystemTask and GetNextEvent}
          ...
       END;
 |  
Here's a C fragment: 
	|     Boolean TrapAvailable(tNumber, tType)
    short    tNumber
    TrapType tType
    {
    /* define trap number for old MPW or non-MPW C */
    #ifndef _Unimplemented
    #define _Unimplemented 0xA89F
    #endif
    /* Check and see if the trap exists. */
    /* On 64K ROM machines, tType will be ignored. */
       return( NGetTrapAddress(tNumber, tType) !=
               GetTrapAddress(_Unimplemented) );
    }
    Boolean WNEIsImplemented()
    {
    /* define trap number for old MPW or non-MPW C */
    #ifndef _WaitNextEvent
    #define _WaitNextEvent 0xA860
    #endif
       SysEnvRec theWorld; /* used to check if machine has new traps */
    /* Since WaitNextEvent and HFSDispatch both have the same trap
       number ($60), we can only call TrapAvailable for WaitNextEvent
       if we are on a machine that supports separate OS and Toolbox
       trap tables. We call SysEnvirons and check if machineType < 0. */
       SysEnvirons(1, &theWorld);
    /* Even if we got an error from SysEnvirons, the SysEnvirons glue
       has set up machineType. */
       if (theWorld.machineType < 0) {
          return(false)
          /* this ROM doesn't have separate trap tables or WaitNextEvent */
       } else {
          return(TrapAvailable(_WaitNextEvent, ToolTrap));
           /* check for WaitNextEvent */
       }
    }
    /* Note that we call SystemTask if WaitNextEvent isn't available. */
    ...
       hasWNE = WNEIsImplemented();
    ...
       if (hasWNE) {
          /* call WaitNextEvent */
          ...
       } else {
          /* call SystemTask and GetNextEvent */
          ...
       }
 |  
 
| Note:Testing to see if
 WaitNextEventis implemented is
not the same as testing to see whether MultiFinder is running. Systems
6.0 and newer includeWaitNextEventwhether or not MultiFinder is
running. |  
 Back to top 
How can I tell if the MultiFinder Temporary Memory Allocation calls are
implemented?Date Written:  9/87 Last reviewed:  3/88 
The technique that's used to determine this is similar to the above technique.
The TrapAvailable routine above is reused. In Pascal: 
	|     FUNCTION TempMemCallsAvailable: BOOLEAN;
       CONST
          OSDispatchTrapNumber = $A88F; {number for temporary memory calls}
    BEGIN {TempMemCallsAvailable}
    {  Since OSDispatch has a trap number that was always defined
       to be a toolbox trap ($8F), we can always call TrapAvailable.
       If we are on a machine that does not have separate OS and
       Toolbox trap tables, we'll still get the right trap address.}
       TempMemCallsAvailable := TrapAvailable(OSDispatchTrapNumber, ToolTrap);
       {check for OSDispatch}
 |  
In C: 
	|     Boolean
    TempMemCallsAvailable()
    {
    /* define trap number for old MPW or non-MPW C */
    #ifndef _OSDispatch
    #define _OSDispatch 0xA88F
    #endif
    /* Since OSDispatch has a trap number that was always defined to
       be a toolbox trap ($8F), we can always call TrapAvailable.
       If we are on a machine that does not have separate OS and
       Toolbox trap tables, we'll still get the right trap address. */
       return(TrapAvailable(_OSDispatch, ToolTrap));
       /* check for OSDispatch */
 |  Back to top 
How can I tell if my application is running in the background?Date Written:  9/87 Last reviewed:  3/88 
To run in the background under MultiFinder, an application must have set the
canBackgroundbit (bit 12 of the first word) in the SIZE resource. In
addition, theacceptSuspendResumeEventsbit (bit 14) should be set. An
application can tell it is running in the background if it has received a
suspend event but not a resume event. Back to top 
When exactly does juggling take place?Date Written:  9/87 Last reviewed:  3/88 
Juggling takes place at WaitNextEvent/GetNextEvent/EventAvailtime. If
you have theacceptSuspendResumeEventsbit set in the SIZE resource,
you will receive suspend/resume events. When you get a suspend event (or, when
you callEventAvailand a suspend event has been posted), you will be
juggled out the next time that you callWNE/GNE/EventAvail. When you
receive a suspend event, you are going to be juggled, so don't do anything to
try to retain control (such as callingModalDialog). 
Speaking of ModalDialog, MultiFinder will not suspend your
application when the frontmost window is a modal dialog, though background
tasks will continue to get time. Back to top 
Can I disable suspend/resume events by passing the appropriate event mask to
WNE/GNE/EventAvail?Date Written:  9/87 Last reviewed:  3/88 
suspend/resu,e events are not queued, so be careful when masking out
app4Evts. You will still get the event, all that will happen if you
mask outapp4Evtsis that your application won't know when it is going
to be juggled out (your application will still be juggled out when you callWNE/GNE/EventAvail). If your application sets a boolean to tell
whether or not it's in the foreground or the background, you definitely don't
want to mask outapp4Evts. Back to top 
Should my application use WaitNextEvent?Date Written:  9/87 Last reviewed:  3/88 
Yes, this will enable background tasks to get as much time as possible. All
user events that your program needs to handle will be passed to your
application as quickly as possible. Applications that run in the background
should try to be as friendly as possible. It's best to do things a small chunk
at a time so as to give maximum time to the foreground application.
"Cooperative multi-tasking" requires cooperation! 
If your application calls WaitNextEvent, it shouldn't callSystemTask. Back to top 
Is there anything else that I can do to be MultiFinder friendly?Date Written:  9/87 Last reviewed:  11/16/93 
It is very important that you save the positions of windows that you open, so
that the next time the user launches your application, the windows will go
where they had them last. This greatly enhances the usability of MultiFinder.
See Technote TB575 - Window Manager Q&As: "How to save and restore window
positions." Back to top 
Can I use a debugger with MultiFinder?Date Written:  9/87 Last reviewed:  3/88 
Yes, MacsBug will load normally, since it is loaded well before MultiFinder.
Since TMON is currently installed as a startup application, you should Set
Startup to it, then launch MultiFinder manually (by holding down Option-Command
while double-clicking the MultiFinder icon) or use a program that will run
multiple startup applications (such as Sequencer), making sure that TMON is run
before MultiFinder. If you try to run TMON after MultiFinder has been
installed, a system crash will result. The latest version of TMON (2.8) has an
INIT that loads it before MultiFinder is present. 
It is necessary to check CurApName($910) when you first
enter a debugger (TMON users can anchor a window to$910) to see which
layer (whose code, which low-memory globals and so on) is currently executing,
especially if you entered the debugger by pressing the interrupt button. Back to top 
What happened to animated icons under MultiFinder?Date Written:  9/87 Last reviewed:  3/88 
Finders 6.0 and newer no longer use the mask that you supply in an ICN# to
"punch a hole" in the desktop. Instead, the Finder uses a default mask that
consists of a solid black copy of the icon with no hole. Back to top 
How can I ensure maximal compatibility with MultiFinder?Date Written:  9/87 Last reviewed:  3/88 
If you follow the guidelines presented in the MultiFinder Developer's Package
you will stand a very good chance of being fully compatible with MultiFinder. Back to top ReferencesM.OV.GestaltSysenvirons M.OV.ChkForFunction MultiFinder Developer's Package Back to top Downloadables
            
               | 
 | Acrobat version of this Note (60K). | Download |  
 |