home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / mpackPPC.lha / mpackPPC / src / macnapp.c < prev    next >
C/C++ Source or Header  |  1998-04-08  |  39KB  |  1,372 lines

  1. /* macnapp.c -- macintosh nifty application library
  2.  */
  3. /* (C) Copyright 1995 by Carnegie Mellon University
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software
  7.  * and its documentation for any purpose is hereby granted without
  8.  * fee, provided that the above copyright notice appear in all copies
  9.  * and that both that copyright notice and this permission notice
  10.  * appear in supporting documentation, and that the name of Carnegie
  11.  * Mellon University not be used in advertising or publicity
  12.  * pertaining to distribution of the software without specific,
  13.  * written prior permission.  Carnegie Mellon University makes no
  14.  * representations about the suitability of this software for any
  15.  * purpose.  It is provided "as is" without express or implied
  16.  * warranty.
  17.  *
  18.  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
  19.  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  20.  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
  21.  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  22.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  23.  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  24.  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  25.  * SOFTWARE.
  26.  */
  27. /* (C) Copyright 1990-1995 by Christopher J. Newman
  28.  * All Rights Reserved.
  29.  *
  30.  * Permission to use, copy, modify, distribute, and sell this software and its
  31.  * documentation for any purpose is hereby granted without fee, provided that
  32.  * the above copyright notice appear in all copies and that both that
  33.  * copyright notice and this permission notice appear in supporting
  34.  * documentation, and that the name of Christopher J. Newman not be used in
  35.  * advertising or publicity pertaining to distribution of the software without
  36.  * specific, written prior permission.  Christopher J. Newman makes no
  37.  * representations about the suitability of this software for any purpose.  It
  38.  * is provided "as is" without express or implied warranty.
  39.  *
  40.  * CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  41.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
  42.  * SHALL CHRISTOPHER J. NEWMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  43.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  44.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  45.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  46.  * OF THIS SOFTWARE.
  47.  *
  48.  * Author:    Christopher J. Newman
  49.  * Message:    This is a nifty program.
  50.  */
  51.  
  52. #ifndef THINK_C
  53. #include <Resources.h>
  54. #include <Dialogs.h>
  55. #include <Desk.h>
  56. #include <SegLoad.h>
  57. #include <OSEvents.h>
  58. #include <DiskInit.h>
  59. #include <Traps.h>
  60. #include <ToolUtils.h>
  61. #endif
  62. #include <AppleEvents.h>
  63. #include "macnapp.h"
  64.  
  65. /* export globals */
  66. na_win **NAhead = (na_win**) NULL;        /* head of the window tree */
  67. na_win **NAtask = (na_win**) NULL;        /* head of the task list */
  68. na_win **NActask = (na_win**) NULL;        /* next task to be called */
  69. na_win *NAwin = (na_win*) NULL;            /* the current window */
  70. na_menup NAmenup = (na_menup) NULL;        /* application menu procedure */
  71. MenuHandle **NAmenus;                    /* list of menu handles */
  72. short NAnewitem = 0;                    /* the new item number */
  73. short NAcloseitem = 0;                    /* the close item number */
  74. short NAappleitems = 0;                    /* number of user apple menu items */
  75. short NAhelpitems = 0;                    /* number of user help menu items */
  76. short NAhelpcount = 0;                    /* number of system help menu items */
  77. Boolean NAhasedit = false;                /* true if application supports edit menu */
  78. long NAdelay = 30;                        /* delay (1/60th of a second) between null events */
  79. SysEnvRec NAsysenv;                        /* set up by Initialize */
  80. Boolean NAinBack = false;                /* true when app is in the background */
  81. short NAlastmouse = NA_RELEASE;            /* the last mouse event type */
  82. long NAmousetime = 0;                    /* the time of the last mouse up */
  83. Point NAmousept;                        /* the point (local) of last mouse down */
  84.  
  85. THz NAappzone;                            /* the application heap zone */
  86. RgnHandle NAfullRgn;                    /* a region containing everything */
  87. RgnHandle NAnullRgn;                    /* a region containing nothing */
  88. Cursor NAibeam;                            /* the Ibeam cursor */
  89. long NAgestaltBits;                        /* flags for gestalt options */
  90.  
  91. /* private globals */
  92. static Point    mselpoint;                /* the menu selection point */
  93. static short    aestatus;                /* if set, close everything */
  94.  
  95. /* constants for DoDraw procedure */
  96. #define    DO_UPDATE        0x0
  97. #define DO_RESIZE        0x1
  98. #define DO_ACTIVATE        0x2
  99. #define DO_DEACTIVATE    0x4
  100.  
  101. /* private routines */
  102.  
  103. static na_win **GetWinH(WindowPtr);
  104. static void DoDraw(na_win*, short);
  105. static short DoActivate(WindowPtr, na_win*, Boolean, Point p);
  106. static short DoMenu(na_win*, BYTE);
  107. static void AdjustCursor(na_win*, Point, Boolean);
  108. static short aboutmouse(na_win*, Point, short, short);
  109.  
  110. /* get the handle to a window
  111.  */
  112. static na_win **GetWinH(WindowPtr window)
  113. {
  114.     na_win        **winh;
  115.     
  116.     /* make positively sure that we have a valid handle */
  117.     if (window != (WindowPtr) NULL && !NAisDAWindow(window)) {
  118. #ifdef DEBUG
  119.         if (PtrZone((Ptr) window) == NAappzone && MemError() == noErr) {
  120. #endif
  121.             if ((winh = (na_win **) GetWRefCon(window)) != (na_win**) NULL) {
  122. #ifdef DEBUG
  123.                 if (HandleZone((Handle) winh) == NAappzone && MemError() == noErr) {
  124.                     if ((*winh)->pwin == window) {
  125. #endif
  126.                         return (winh);
  127. #ifdef DEBUG
  128.                     } else {
  129.                         NAdebug("Corrupted window structure found.\015");
  130.                         NAdebug("handle: %lx, pwin: %lx, window: %lx\015",
  131.                             (long) winh, (long) (*winh)->pwin, (long) window);
  132.                         Debugger();
  133.                     }
  134.                 } else {
  135.                     NAdebug("Corrupted Handle Zone Found.\015");
  136.                     NAdebug("handle: %lx, error: %ld\015", (long) winh,
  137.                         (long) MemError());
  138.                     Debugger();
  139.                 }        
  140. #endif
  141.             }
  142. #ifdef DEBUG
  143.         } else {
  144.             NAdebug("Corrupted Window Pointer Found.\n");
  145.             NAdebug("Pointer: %lx, error: %ld\n", (long) window, (long) MemError());
  146.             Debugger();
  147.         }
  148. #endif
  149.     }
  150.     return ((na_win**) NULL);
  151. }
  152.  
  153. /* handle drawing controls & growbox for update/activate events
  154.  */
  155. static void DoDraw(na_win *winp, short how)
  156. {
  157.     WindowPtr window = winp->pwin;
  158.     long flags = winp->flags;
  159.     ControlHandle ctrl;
  160.     Rect tmpRect;
  161.     RgnHandle tmpRgn;
  162.  
  163.     /* hilite or draw controls as appropriate */
  164.     if (flags & NA_HASCONTROLS) {
  165.         if (how & (DO_ACTIVATE | DO_DEACTIVATE)) {
  166.             if (flags & NA_HILITECTRLS) {
  167.                 for (ctrl = ((WindowPeek) window)->controlList; ctrl;
  168.                         ctrl = (*ctrl)->nextControl) {
  169.                     HiliteControl(ctrl, (how & DO_ACTIVATE) ? 0 : 255);
  170.                 }
  171.             }
  172.         } else {
  173.             DrawControls(window);
  174.         }
  175.     }
  176.     
  177.     /* draw the grow box properly -- mask out scroll bar outlines */
  178.     if (flags & NA_GROWBOX) {
  179.         tmpRgn = window->clipRgn;
  180.         tmpRect.left = (tmpRect.right = window->portRect.right) - 15;
  181.         tmpRect.top = (tmpRect.bottom = window->portRect.bottom) - 15;
  182.         RectRgn(window->clipRgn = NewRgn(), &tmpRect);
  183.         DrawGrowIcon(window);
  184.         DisposeRgn(window->clipRgn);
  185.         window->clipRgn = tmpRgn;
  186.     }
  187.     
  188.     /* draw the default button on a dialog */
  189.     if (flags & NA_DEFBUTTON) NAdefaultButton(window);
  190.     
  191.     /* calculate the un-cursor region if the window size changed */
  192.     if (how & DO_RESIZE) NAcalcCursor(winp);
  193. }
  194.  
  195. /* handle activate event (either activate or MultiFinder suspend/resume)
  196.  */
  197. static short DoActivate(WindowPtr window, na_win *winp, Boolean activate, Point p)
  198. {
  199.     na_win **winh;
  200.     short    status = NA_NOTPROCESSED;
  201.     GrafPtr tmpPort;
  202.  
  203.     /* unlock current front window */
  204.     if (winp != (na_win*) NULL) {
  205.         NAunlockWindow(winp);
  206.         NAwin = (na_win*) NULL;
  207.     }
  208.     
  209.     /* check if there is a new window, and lock it */
  210.     if (window == (WindowPtr) NULL)  return (NA_PROCESSED);
  211.     
  212.     /* for app windows, update the cursor, call the activate proc, and DoDraw */
  213.     if ((NAwin = winp = NAlockWindow(winh = GetWinH(window))) != (na_win*) NULL) {
  214.         GetPort(&tmpPort);
  215.         SetPort(window);
  216.         if (winp->cursorRgn != (RgnHandle) NULL && ((activate && !NAinBack)
  217.                 || winp->flags & NA_CURSORON)) {
  218.             LocalToGlobal(&p);
  219.             AdjustCursor(winp, p, activate);
  220.         }
  221.         if (winp->activep == (na_activep) NULL
  222.                 || (status = (*winp->activep)(winp, activate)) == NA_NOTPROCESSED) {
  223.             DoDraw(winp, activate ? DO_ACTIVATE : DO_DEACTIVATE);
  224.         }
  225.         if (!activate || winp->pwin != FrontWindow()) {
  226.             SetPort(tmpPort);
  227.             NAunlockWindowh(winh, winp);
  228.             NAwin = (na_win*) NULL;
  229.         }
  230.     }
  231.     
  232.     return (status);
  233. }
  234.  
  235. /* handle menu selection -- either menu click or menu shortcut
  236.  */
  237. static short DoMenu(na_win *winp, BYTE key)
  238. {
  239.     WindowPtr    window = FrontWindow();
  240.     short         status = NA_NOTPROCESSED;
  241.     WORD        menuid, itemno;
  242.     MenuHandle    mnu;
  243.     long        menusel;
  244.     PCstr        mItem[256];
  245.     
  246.     /* enable/disable edit menu as appropriate */
  247.     if (NAhasedit) {
  248.         mnu = NAmenuh(mEdit);
  249.         
  250.         if (NAisDAWindow(window)) {
  251.             EnableItem(mnu, iUndo);
  252.             for (itemno = iCut; itemno <= iClear; itemno++) {
  253.                 EnableItem(mnu, itemno);
  254.             }
  255.         } else {
  256.             DisableItem(mnu, iUndo);
  257.             for (itemno = iCut; itemno <= iClear; itemno++) {
  258.                 DisableItem(mnu, itemno);
  259.             }
  260.         }
  261.     }
  262.     
  263.     /* enable/disable the close menu as appropriate */
  264.     if (NAcloseitem) {
  265.         mnu = NAmenuh(mFile);
  266.         
  267.         if (window != (WindowPtr) NULL && (winp == (na_win*) NULL
  268.                 || winp->pwin != window || winp->flags & NA_CLOSEBOX)) {
  269.             EnableItem(mnu, NAcloseitem);
  270.         } else {
  271.             DisableItem(mnu, NAcloseitem);
  272.         }
  273.     }
  274.     
  275.     /* call menu proc to enable/disable items as appropriate */
  276.     if (winp != (na_win*) NULL && winp->menup != (na_menup) NULL) {
  277.         status = (*winp->menup)(winp, (WORD) 0, (WORD) key);
  278.     }
  279.     if (status == NA_NOTPROCESSED && NAmenup != (na_menup) NULL
  280.         && (winp == (na_win *) NULL || !(winp->flags & NA_MODAL))) {
  281.         status = (*NAmenup)(winp, (WORD) 0, (WORD) key);
  282.     }
  283.     if (status != NA_NOTPROCESSED) return (status);
  284.     
  285.     /* get menu selection */
  286.     menusel = (key == 0) ? MenuSelect(mselpoint) : MenuKey(key);
  287.     itemno = LOWORD(menusel);
  288.     if ((menuid = HIWORD(menusel)) == 0) menuid = 1;
  289.     
  290.     /* check for DA menu items */
  291.     switch (menuid) {
  292.         case mApple:    /* check for a desk accessary selection */
  293.             if (itemno > NAappleitems) {
  294.                 if (itemno - NAappleitems <= NAhelpitems) {
  295.                     itemno -= NAappleitems;
  296.                     menuid = mHelp;
  297.                 } else {
  298.                     GetItem(NAmenuh(mApple), itemno, mItem);
  299.                     OpenDeskAcc(mItem);
  300.                     menuid = 1;
  301.                 }
  302.             }
  303.             break;
  304.         
  305.         case mFile:        /* check for the close menu item for DAs */
  306.             if (itemno == NAcloseitem && NAisDAWindow(window)) {
  307.                 CloseDeskAcc(((WindowPeek) window)->windowKind);
  308.                 menuid = 1;
  309.             }
  310.             break;
  311.     
  312.         case mEdit:     /* check for the edit menu for DAs */
  313.             if (NAhasedit && itemno <= iClear && SystemEdit(itemno - iUndo)) {
  314.                 menuid = 1;
  315.             }
  316.             break;
  317.         
  318.         case mHelp:
  319.             itemno -= NAhelpcount;
  320.             break;
  321.     }
  322.     
  323.     /* call menu proc to handle/disable items */
  324.     if (winp != (na_win*) NULL && winp->menup != (na_menup) NULL) {
  325.         status = (*winp->menup)(winp, menuid, itemno);
  326.     }
  327.     if (status != NA_PROCESSED && NAmenup != (na_menup) NULL) {
  328.         status = (*NAmenup)(winp, menuid, itemno);
  329.     }
  330.     
  331.     /* if close/about item wasn't processed, process it */
  332.     if (status == NA_NOTPROCESSED) {
  333.         if (menuid == mFile && itemno == NAcloseitem) {
  334.             status = NA_REQCLOSE;
  335.         } else if (menuid == mApple && itemno == iAbout) {
  336.             NAwindow(0, NA_DIALOGWINDOW | NA_USERESOURCE | NA_MODAL,
  337.             NULL, NA_ABOUTDLOG, (long *) NULL, 0, NAabout);
  338.         }
  339.     }
  340.     
  341.     /* turn off the menu */
  342.     HiliteMenu(0);
  343.     
  344.     return (status);
  345. }
  346.  
  347. /* set the cursor icon appropriately
  348.  */
  349. static void AdjustCursor(na_win *winp, Point gmouse, Boolean active)
  350. {
  351.     short    status = NA_NOTPROCESSED;
  352.     
  353.     /* don't change the cursor when in wrong window */
  354.     if (active && FrontWindow() != winp->pwin) return;
  355.     
  356.     /* if the cursor is on */
  357.     if (winp->flags & NA_CURSORON) {
  358.         /* and the point moves outside the cursor region or window is deactivated
  359.          * turn cursor off */
  360.         if (!active || PtInRgn(gmouse, winp->uncrsrRgn)) {
  361.             winp->flags &= ~NA_CURSORON;
  362.             if (winp->cursorp == (na_cursorp*) NULL) {
  363.                 SetCursor(&QD(arrow));
  364.             } else {
  365.                 goto DOCURSORP;
  366.             }
  367.         }
  368.     
  369.     /* if the cursor is off and the point moves into the window, turn cursor on */
  370.     } else if (PtInRgn(gmouse, winp->cursorRgn)) {
  371.         winp->flags |= NA_CURSORON;
  372.         if (winp->cursorp == (na_cursorp) NULL) {
  373.             SetCursor(&NAibeam);
  374.         } else {
  375.         DOCURSORP:
  376.             GlobalToLocal(&gmouse);
  377.             status = (*winp->cursorp)(winp, gmouse);
  378.         }
  379.     }
  380.     
  381.     /* if cursor event was processed, reset the un-cursor region */
  382.     if (status == NA_PROCESSED) NAcalcCursor(winp);
  383. }
  384.  
  385.  
  386. /* export routines */
  387.  
  388. /* save the current window position in a resource file
  389.  */
  390. void NAsaveWin(na_win *winp)
  391. {
  392.     Rect        *rptr;
  393.     WindowPtr    window = winp->pwin;
  394.     Handle        wind = GetResource('WIND', winp->resid);
  395.     
  396.     HLock(wind);
  397.     rptr = (Rect *) *wind;
  398.     rptr->right = (rptr->left = -window->portBits.bounds.left)
  399.         + window->portRect.right;
  400.     rptr->bottom = (rptr->top = -window->portBits.bounds.top)
  401.         + window->portRect.bottom;
  402.     ChangedResource(wind);
  403.     HUnlock(wind);
  404. }
  405.  
  406. /* calculate the cursor regions for Multi-Finder
  407.  */
  408. void NAcalcCursor(na_win *winp)
  409. {
  410.     if (winp->cursorRgn != (RgnHandle) NULL) {
  411.         if (winp->uncrsrRgn == (RgnHandle) NULL)  winp->uncrsrRgn = NewRgn();
  412.         DiffRgn(NAfullRgn, winp->cursorRgn, winp->uncrsrRgn);
  413.     }
  414. }
  415.  
  416. /* lock a window context
  417.  */
  418. na_win *NAlockWindow(na_win **winh)
  419. {
  420.     if (winh == (na_win**) NULL) return ((na_win*) NULL);
  421.     if (!(*winh)->locks++) {
  422.         MoveHHi((Handle) winh);
  423.         HLock((Handle) winh);
  424.     }
  425.     
  426.     return (*winh);
  427. }
  428.  
  429. /* request or force a window to close
  430.  */
  431. short NAcloseWindow(na_win *winp, short status)
  432. {
  433.     na_win    **winh, ***whp;
  434.     short childstatus;
  435.     
  436.     if (winp == (na_win*) NULL) return (NA_NOTPROCESSED);
  437.     switch (status) {
  438.         case NA_REQCLOSE:
  439.             /* check if window ready to close */
  440.             status = NA_CLOSED;
  441.             if (winp->closep != (na_closep) NULL) status = (*winp->closep)(winp);
  442.             if (status > NA_CLOSED)        break;
  443.         case NA_CLOSED:
  444.             /* close children */
  445.             childstatus = NAcloseWindows(winp->child, NA_REQCLOSEALL);
  446.             /* clear current window */
  447.             if (winp == NAwin) NAwin = (na_win*) NULL;
  448.             /* reset the cursor */
  449.             if (winp->flags & NA_CURSORON) SetCursor(&QD(arrow));
  450.             /* dispose of any cursor regions */
  451.             if (winp->cursorRgn != (RgnHandle) NULL) DisposeRgn(winp->cursorRgn);
  452.             if (winp->uncrsrRgn != (RgnHandle) NULL) DisposeRgn(winp->uncrsrRgn);
  453.             /* close the window */
  454.             if (winp->pwin != (WindowPtr) NULL) {
  455.                 if (winp->flags & NA_DIALOGWINDOW) {
  456.                     DisposDialog((DialogPtr) winp->pwin);
  457.                 } else {
  458.                     DisposeWindow(winp->pwin);
  459.                 }
  460.             }
  461.             /* remove from window list */
  462.             winh = (na_win**) RecoverHandle((Ptr) winp);
  463.             whp = &NAhead;
  464.             if (winp->parent != (na_win**) NULL) whp = &(*winp->parent)->child;
  465.             while (*whp != (na_win**) NULL) {
  466.                 if (*whp == winh) {
  467.                     *whp = winp->next;
  468.                 } else {
  469.                     whp = &(**whp)->next;
  470.                 }
  471.             }
  472.             /* relink children in list */
  473.             if (childstatus > NA_ALLCLOSED) {
  474.                 *whp = winp->child;
  475.                 do {
  476.                     (**whp)->parent = winp->parent;
  477.                     whp = &(**whp)->next;
  478.                 } while (*whp != (na_win**) NULL);
  479.                 *whp = winp->next;
  480.             }
  481.             /* remove from task list */
  482.             whp = &NAtask;
  483.             while (*whp != (na_win**) NULL && *whp != winh) {
  484.                 whp = &(**whp)->task;
  485.             }
  486.             *whp = winp->task;
  487.             NActask = (na_win**) NULL;
  488.             /* after-close function */
  489.             if (winp->afterp != (na_afterp) NULL) (*winp->afterp)(winp);
  490.             /* destroy window structure */
  491.             DisposHandle((Handle) winh);
  492.             if (status < NA_CLOSED) {
  493.                 if ((status = NAcloseWindows(NAhead, status)) > NA_CLOSED) {
  494.                     status = NA_CLOSED;
  495.                 }
  496.             }
  497.             break;
  498.     }
  499.     
  500.     return (status);            
  501. }
  502.  
  503. short NAcloseWindows(na_win **winh, short status)
  504. {
  505.     na_win    *winp, **lasth;
  506.     short    substatus;
  507.     
  508.     while ((winp = NAlockWindow(winh)) != (na_win*) NULL) {
  509.         lasth = winh;
  510.         winh = winp->next;
  511.         substatus = NAcloseWindow(winp, status + 2);
  512.         if (substatus > NA_CLOSED) {
  513.             NAunlockWindowh(lasth, winp);
  514.             return (NA_NOTPROCESSED);
  515.         }
  516.         if (substatus < NA_CLOSED) return (substatus);
  517.     }
  518.     
  519.     return (NA_ALLCLOSED);
  520. }
  521.  
  522. /* remove the window on a mouse-up event
  523.  */
  524. static short aboutmouse(na_win *winp, Point mousep, short type, short mods)
  525. #ifdef applec
  526. #pragma unused (winp, mousep, mods)
  527. #endif
  528. {
  529.     return (type & 1 ? NA_REQCLOSE : NA_PROCESSED);
  530. }
  531.  
  532. /* a standard about box init procedure
  533.  */
  534. short NAabout(na_win *winp, long *dptr)
  535. #ifdef applec
  536. #pragma unused (dptr)
  537. #endif
  538. {
  539.     winp->mousep = aboutmouse;
  540.     
  541.     return (NA_PROCESSED);
  542. }
  543.  
  544. /* flash a button in a dialog box for equivalent keypresses
  545.  */
  546. void NAflashButton(DialogPtr dialog, short item)
  547. {
  548.     long    scratch;
  549.     short    type;
  550.     Handle    ctrl;
  551.     Rect    box;
  552.     
  553.     GetDItem(dialog, item, &type, &ctrl, &box);
  554.     if (type == ctrlItem + btnCtrl) {
  555.         HiliteControl((ControlHandle) ctrl, 1);
  556.         Delay(5, &scratch);
  557.         HiliteControl((ControlHandle) ctrl, 0);
  558.     }
  559. }
  560.  
  561. /* draw the default button
  562.  */
  563. void NAdefaultButton(DialogPtr dialog)
  564. {
  565.     Rect tmpRect;
  566.     PenState pnState;
  567.     
  568.     NAgetDRect(dialog, iOk, &tmpRect);
  569.     GetPenState(&pnState);
  570.     PenNormal();
  571.     PenSize(3, 3);
  572.     InsetRect(&tmpRect, -4, -4);
  573.     FrameRoundRect(&tmpRect, 16, 16);
  574.     SetPenState(&pnState);
  575. }
  576.  
  577. /* a filter proc which handles Return, Enter, Esc, command-period properly
  578.  */
  579. pascal Boolean NAfilterProc(DialogPtr dialog, EventRecord *pevent, short *item)
  580. {
  581.     if (pevent->what == autoKey || pevent->what == keyDown) {
  582.         switch (pevent->message & charCodeMask) {
  583.             case '\r':
  584.             case '\n':
  585.             case 0x03:
  586.                 *item = 1;
  587.                 goto HILITE;
  588.             
  589.             case '.':
  590.                 if (!(pevent->modifiers & cmdKey)) break;
  591.             case '\033':
  592.                 *item = 2;
  593.             HILITE:
  594.                 NAflashButton(dialog, *item);
  595.                 return (true);
  596.         }
  597.     }
  598.     
  599.     return (false);
  600. }
  601.  
  602. /* send an event message to all windows
  603.  */
  604. short NAallWindows(na_win **winh, EventRecord *pevent)
  605. {
  606.     na_win *winp, **oldwinh;
  607.     short    status = NA_NOTPROCESSED;
  608.     
  609.     while ((winp = NAlockWindow(winh)) != (na_win*) NULL) {
  610.         oldwinh = winh;
  611.         winh = winp->next;
  612.         if (winp->miscp != (na_miscp) NULL) {
  613.             GrafPtr    tempPort;
  614.             
  615.             GetPort(&tempPort);
  616.             SetPort(winp->pwin);
  617.             status = (*winp->miscp)(winp, pevent);
  618.             SetPort(tempPort);
  619.         }
  620.         if ((status == NA_CLOSED || status == NA_REQCLOSE)
  621.                 && NAcloseWindow(winp, status) == NA_CLOSED) {
  622.             continue;
  623.         }
  624.         NAunlockWindowh(oldwinh, winp);
  625.         if (status == NA_ALLCLOSED || status == NA_REQCLOSEALL) {
  626.             if (NAcloseWindows(NAhead, status) == NA_ALLCLOSED) {
  627.                 return (NA_ALLCLOSED);
  628.             }
  629.             /* make sure our handle is still valid */
  630.             if (GetHandleSize((Handle) oldwinh) == 0) continue;
  631.         }
  632.         if ((*oldwinh)->child != (na_win**) NULL &&
  633.                 NAallWindows((*oldwinh)->child, pevent) == NA_ALLCLOSED) {
  634.             return (NA_ALLCLOSED);
  635.         }
  636.     }
  637.     
  638.     return (NA_PROCESSED);
  639. }
  640.  
  641. /* apple event handler
  642.  */
  643. pascal OSErr NArequiredAE(AppleEvent *, AppleEvent *, long);
  644. pascal OSErr NArequiredAE(AppleEvent *event, AppleEvent *reply, long ref)
  645. {
  646.     na_openp openp = (na_openp) ref;
  647.     OSErr err;
  648.     DescType actualType, eventID;
  649.     Size actualSize;
  650.     AEDescList doclist;
  651.     long count, i;
  652.     short gotdoc;
  653.     FSSpec fspec;
  654.     AEKeyword keywd;
  655.     FInfo finfo;
  656.     
  657.     err = AEGetAttributePtr(event, keyEventIDAttr, typeType, &actualType,
  658.         (Ptr) &eventID, sizeof (eventID), &actualSize);
  659.     if (err == noErr) {
  660.         gotdoc = 0;
  661.         if (eventID == kAEOpenDocuments || eventID == kAEPrintDocuments) {
  662.             err = AEGetParamDesc(event, keyDirectObject, typeAEList, &doclist);
  663.             if (err == noErr) gotdoc = 1;
  664.         }
  665.         if (err == noErr) {
  666.             err = AEGetAttributePtr(event, keyMissedKeywordAttr, typeWildCard,
  667.                 &actualType, NULL, 0, &actualSize);
  668.             if (err == errAEDescNotFound) {
  669.                 err = noErr;
  670.             } else if (err == noErr) {
  671.                 err = errAEEventNotHandled;
  672.             }
  673.         }
  674.         if (err == noErr) switch (eventID) {
  675.             case kAEOpenApplication:
  676.                 if (NAmenup && NAnewitem) {
  677.                     aestatus = (*NAmenup)(NULL, mFile, NAnewitem);
  678.                 }
  679.                 break;
  680.             case kAEOpenDocuments:
  681.             case kAEPrintDocuments:
  682.                 err = AECountItems(&doclist, &count);
  683.                 if (err != noErr) break;
  684.                 for (i = 1; i <= count; ++i) {
  685.                     err = AEGetNthPtr(&doclist, i, typeFSS, &keywd, &actualType,
  686.                         (Ptr) &fspec, sizeof (fspec), &actualSize);
  687.                     if (err != noErr) break;
  688.                     FSpGetFInfo(&fspec, &finfo);
  689.                     if (!openp || (*openp)(eventID == kAEOpenDocuments
  690.                                 ? appOpen : appPrint, &fspec, &finfo) <= 0) {
  691.                         err = errAEEventNotHandled;
  692.                         break;
  693.                     }
  694.                 }
  695.                 break;
  696.             case kAEQuitApplication:
  697.                 aestatus = NA_ALLCLOSED;
  698.                 if (NAhead != NULL) {
  699.                     aestatus = NAcloseWindows(NAhead, NA_REQCLOSEALL);
  700.                     if (aestatus != NA_ALLCLOSED) err = userCanceledErr;
  701.                 }
  702.                 break;
  703.         }
  704.         if (gotdoc) {
  705.             AEDisposeDesc(&doclist);
  706.         }
  707.     }
  708.     
  709.     return (err);
  710. }
  711.  
  712. /* handle Dialog window events
  713.  */
  714. static Boolean DoDialog(na_win *winp, EventRecord *event, Point mouse,
  715.     short item, short *status)
  716. {
  717.     DialogPtr dialog = NULL;
  718.     ControlHandle ctrlh;
  719.     Boolean result = false;
  720.     
  721.     if (*status == NA_NOTPROCESSED && (item || ((result = IsDialogEvent(event))
  722.         && DialogSelect(event, &dialog, &item))) && winp && winp->ctrlp) {
  723.         if (!dialog) dialog = winp->pwin;
  724.         NAgetDHandle(dialog, item, &ctrlh);
  725.         *status = (*winp->ctrlp)(winp, mouse, item, event->modifiers, ctrlh);
  726.     }
  727.     
  728.     return (result);
  729. }
  730.  
  731. /* call the main loop procedure
  732.  */
  733. void NAmainloop()
  734. {
  735.     na_win *winp, *wp, **wh;
  736.     Boolean gotEvent;
  737.     EventRecord event;
  738.     Point mouse;
  739.     Point ptemp;
  740.     short status;
  741.     short citem, item;
  742.     short part;
  743.     short delay;
  744.     short mousepix;
  745.     short fastdelay = 0;
  746.     long growInfo;
  747.     long key;
  748.     WindowPtr window;
  749.     GrafPtr tempPort;
  750.     ControlHandle ctrl;
  751.     RgnHandle rgn;
  752.     Rect tmpRect, bRect;
  753.     short prioritycnt;
  754.     
  755.     UnloadSeg((Ptr) NAinit);        /* unload the initialize routine */
  756.     
  757.     do {
  758.         /* check for a window in front */
  759.         if ((winp = NAwin) == (na_win*) NULL
  760.                 && (window = FrontWindow()) != (WindowPtr) NULL
  761.                 && (NAwin = winp = NAlockWindow(GetWinH(window))) != (na_win *) NULL) {
  762.             SetPort(window);
  763.         }
  764.     
  765.         /* get an event */
  766.         rgn = NAfullRgn;
  767.         delay = NAdelay;
  768.         /* if there is an app window in front, use app delay & cursor region */
  769.         if (winp != (na_win*) NULL) {
  770.             delay = winp->delay;
  771.             if (winp->cursorRgn != (RgnHandle) NULL && !NAinBack) {
  772.                 rgn = winp->cursorRgn;
  773.                 if (!(winp->flags & NA_CURSORON)) rgn = winp->uncrsrRgn;
  774.             }
  775.             if (winp->mousepix && !(NAlastmouse & 1)) {
  776.                 rgn = NAnullRgn;
  777.                 delay = 0;
  778.             }
  779.         }
  780.         gotEvent = WaitNextEvent(everyEvent, &event, fastdelay ? 0 : delay, rgn);
  781.         fastdelay = 0;
  782.         status = NA_NOTPROCESSED;
  783.         
  784.         /* get mouse position */
  785.         mouse = event.where;
  786.         GlobalToLocal(&mouse);
  787.         item = 0;
  788.  
  789.         /* handle the event */
  790.         if (gotEvent) switch (event.what) {
  791.             case mouseUp:
  792.                 /* deal with mouse up events to keep track of double/triple clicks */
  793.                 if (NAlastmouse & 1) break;
  794.                 ++NAlastmouse;
  795.                 NAmousetime = TickCount();
  796.                 if (winp == (na_win*) NULL) break;
  797.             DOMOUSEP:
  798.                 if (winp->mousep != (na_mousep) NULL) {
  799.                     status = (*winp->mousep)(winp, mouse, NAlastmouse, event.modifiers);
  800.                 }
  801.                 break;
  802.     
  803.             case mouseDown:
  804.                 part = FindWindow(event.where, &window);
  805.                 /* Rules for clicks when a modal dialog is in front:
  806.                  *  1) let the user command-move other windows
  807.                  *  2) don't let user do anything else with other app windows
  808.                  *  3) if not movable, require click to be in window
  809.                  */
  810.                 if (winp != (na_win*) NULL && winp->flags & NA_MODAL
  811.                     && !(part == inDrag && event.modifiers & cmdKey)
  812.                     && ((!(winp->flags & NA_TITLEBAR)
  813.                             && !PtInRect(mouse, &winp->pwin->portRect))
  814.                         || (window != NULL && window != winp->pwin))) {
  815.                     SysBeep(10);
  816.                     status = NA_PROCESSED;
  817.                     break;
  818.                 }
  819.                 switch (part) {
  820.                     case inMenuBar:
  821.                         /* call an appropriate menu bar handler */
  822.                         mselpoint = event.where;
  823.                         status = DoMenu(winp, 0);
  824.                         break;
  825.                         
  826.                     case inSysWindow:
  827.                         /* System Click in DA */
  828.                         SystemClick(&event, window);
  829.                         break;
  830.     
  831.                     case inContent:
  832.                         /* click a window to front if not in front */
  833.                         if (window != FrontWindow()) {
  834.                             SelectWindow(window);
  835.                             if (winp != (na_win*) NULL) NAunlockWindow(winp);
  836.                             NAwin = (na_win*) NULL;
  837.                             NAlastmouse = NA_RELEASE;
  838.                             break;
  839.                         }
  840.                         
  841.                         /* don't bother processing further if no mouse proc */
  842.                         if (winp == (na_win*) NULL) break;
  843.     
  844.                         /* check for control events */
  845.                         if (winp->ctrlp != (na_ctrlp) NULL && winp->flags & NA_HASCONTROLS) {
  846.                             if ((citem = FindControl(mouse, window, &ctrl)) != 0
  847.                                     && (status = (*winp->ctrlp)(winp, mouse, citem,
  848.                                     event.modifiers, ctrl)) != NA_NOTPROCESSED) {
  849.                                 break;
  850.                             }
  851.                         }
  852.                         
  853.                         /* deal with double clicks */
  854.                         if ((NAlastmouse & 1) && NAlastmouse < NA_RELEASE
  855.                                 && event.when - NAmousetime <= GetDblTime()) {
  856.                             if (++NAlastmouse > NA_DOWNN) NAlastmouse = NA_DOWNN;
  857.                         } else {
  858.                             NAlastmouse = NA_DOWN1;
  859.                         }
  860.                         NAmousept = mouse;
  861.                         
  862.                         /* call the mouse handler */
  863.                         goto DOMOUSEP;
  864.     
  865.                     case inDrag:
  866.                         /* drag the window */
  867.                         tmpRect = QD(screenBits.bounds);
  868.                         InsetRect(&tmpRect, 4, 4);
  869.                         bRect = window->portBits.bounds;
  870.                         DragWindow(window, event.where, &tmpRect);
  871.                         if ((bRect.left != window->portBits.bounds.left
  872.                                 || bRect.top != window->portBits.bounds.top) &&
  873.                                 (wp = NAlockWindow(wh = GetWinH(window))) != NULL) {
  874.                             if (wp->flags & NA_SMARTSIZE) NAsaveWin(wp);
  875.                             if (wp->cursorRgn != (RgnHandle) NULL) {
  876.                                 OffsetRgn(wp->cursorRgn,
  877.                                     bRect.left - window->portBits.bounds.left,
  878.                                     bRect.top - window->portBits.bounds.top);
  879.                                 NAcalcCursor(wp);
  880.                             }
  881.                             NAunlockWindowh(wh, wp);
  882.                         }
  883.                         break;
  884.                     
  885.                     case inGoAway:
  886.                         /* deal with the close window box */
  887.                         if (TrackGoAway(window, event.where)) status = NA_REQCLOSE;
  888.                         break;
  889.     
  890.                     case inGrow:
  891.                         /* grow the window */
  892.                         /* assume there is a valid app window in front */
  893.                         /* calculate min & max grow dimensions */
  894.                         tmpRect = QD(screenBits.bounds);
  895.                         tmpRect.bottom -= tmpRect.top;
  896.                         tmpRect.right -= tmpRect.left;
  897.                         tmpRect.top = winp->minh;
  898.                         tmpRect.left = winp->minw;
  899.                         if (winp->maxh) tmpRect.bottom = winp->maxh;
  900.                         if (winp->maxw) tmpRect.right = winp->maxw;
  901.                         
  902.                         /* check for resize proc */
  903.                         if (winp->resizep != (na_resizep) NULL) {
  904.                             status = (*winp->resizep)(winp, event.where, &tmpRect);
  905.                             if (status == NA_PROCESSED) break;
  906.                             goto RESIZEWINDOW;
  907.                         }
  908.                         
  909.                         /* grow, resize, and update the window */
  910.                         if ((growInfo = GrowWindow(window, event.where, &tmpRect))) {
  911.                             SizeWindow(window, LOWORD(growInfo), HIWORD(growInfo),
  912.                                 false);
  913.                             goto RESIZEWINDOW;
  914.                         }
  915.                         break;
  916.                     
  917.                     case inZoomIn:
  918.                     case inZoomOut:
  919.                         /* assume there is a valid app window in front */
  920.                         /* track, zoom, and update the window */
  921.                         if (TrackBox(window, event.where, part)) {
  922.                             SetPort(window);
  923.                             EraseRect(&window->portRect);
  924.                             ZoomWindow(window, part, true);
  925.                     RESIZEWINDOW:
  926.                             if (winp != (na_win*) NULL) {
  927.                                 if (winp->flags & NA_SMARTSIZE) NAsaveWin(winp);
  928.                                 if (winp->updatep == (na_updatep) NULL ||
  929.                                         (status = (*winp->updatep)(winp, (Boolean) true))
  930.                                         == NA_NOTPROCESSED) {
  931.                                     DoDraw(winp, DO_RESIZE);
  932.                                 }
  933.                             }
  934.                             ValidRect(&window->portRect);
  935.                         }
  936.                         break;
  937.                 }
  938.                 break;
  939.             
  940.             case keyDown:
  941.             case autoKey:
  942.                 /* deal with keyboard events */
  943.                 key = event.message & charCodeMask;
  944.  
  945.                 /* call the window's key handling procedure */
  946.                 if (winp != (na_win *) NULL && winp->keyp != (na_keyp) NULL) {
  947.                     status = (*winp->keyp)(winp, winp->flags & NA_RAWKEY ? event.message : key,
  948.                         event.modifiers);
  949.                 }
  950.  
  951.                 /* translate command-foo to an appropriate menu operation */
  952.                 if (status == NA_NOTPROCESSED &&
  953.                     (event.modifiers & cmdKey) && event.what == keyDown &&
  954.                         (status = DoMenu(winp, key)) != NA_NOTPROCESSED) {
  955.                     break;
  956.                 }
  957.                 
  958.                 /* require an app window for further processing */
  959.                 if (winp == (na_win*) NULL) break;
  960.                 
  961.                 /* if it's an unprocessed event in a dialog window */
  962.                 if (status == NA_NOTPROCESSED && (winp->flags & NA_DIALOGWINDOW)) {
  963.                     if (!NAfilterProc(winp->pwin, &event, &item)
  964.                         && (event.modifiers & cmdKey)) {
  965.                         status = NA_PROCESSED;
  966.                     }
  967.                 }
  968.                 break;
  969.             
  970.             case activateEvt:
  971.                 /* deal with activate windows based on activeFlag */
  972.                 status = DoActivate((WindowPtr) event.message, winp,
  973.                     event.modifiers & activeFlag, mouse);
  974.                 break;
  975.                 
  976.             case updateEvt:
  977.                 /* deal with update events with proper port setting, etc. */
  978.                 window = (WindowPtr) event.message;
  979.                 BeginUpdate(window);
  980.                 if ((wp = NAlockWindow(wh = GetWinH(window))) != (na_win*) NULL) {
  981.                     GetPort(&tempPort);
  982.                     SetPort(window);
  983.                     if (wp->flags & NA_DIALOGWINDOW) {
  984.                         UpdtDialog(window, window->visRgn);
  985.                     }
  986.                     if (wp->updatep == (na_updatep) NULL
  987.                         || (status = (*wp->updatep)(wp, (Boolean) false))
  988.                             == NA_NOTPROCESSED) {
  989.                         DoDraw(wp, DO_UPDATE);
  990.                     }
  991.                     DoDialog(winp, &event, mouse, 0, &status);
  992.                     SetPort(tempPort);
  993.                     NAunlockWindowh(wh, wp);
  994.                 }
  995.                 EndUpdate(window);
  996.                 if (status == NA_NOTPROCESSED) status = NA_PROCESSED;
  997.                 break;
  998.             
  999.             case diskEvt:
  1000.                 /* let the user format bad disks */
  1001.                 if (HIWORD(event.message) != noErr) {
  1002.                     SetPt(&ptemp, 0x0070, 0x0050);
  1003.                     (void) DIBadMount(ptemp, event.message);
  1004.                 } else {
  1005.                     status = NAallWindows(NAhead, &event);
  1006.                 }
  1007.                 break;
  1008.             
  1009.             case networkEvt:
  1010.             case driverEvt:
  1011.             case app1Evt:
  1012.             case app2Evt:
  1013.             case app3Evt:
  1014.                 /* send event to all windows */
  1015.                 status = NAallWindows(NAhead, &event);
  1016.                 break;
  1017.             
  1018.             case osEvt:
  1019.                 switch ((event.message >> 24) & 0xff) {
  1020.                     case suspendResumeMessage:
  1021.                         status = DoActivate(FrontWindow(), winp,
  1022.                             !(NAinBack = !(event.message & resumeFlag)), mouse);
  1023.                         break;
  1024.                     
  1025.                     case mouseMovedMessage:
  1026.                         /* only interesting if a window is in front */
  1027.                         if (NAinBack || winp == (na_win*) NULL) break;
  1028.                         
  1029.                         mousepix = winp->mousepix;
  1030.                         
  1031.                         /* deal with mouse dragging */
  1032.                         if (mousepix && !(NAlastmouse & 1)) {
  1033.                             if (NAlastmouse != NA_DRAG) {
  1034.                                 InsetRect(&tmpRect, -mousepix, -mousepix);
  1035.                                 if (PtInRect(mouse, &tmpRect)) break;
  1036.                                 NAlastmouse = NA_DRAG;
  1037.                             }
  1038.                             goto DOMOUSEP;
  1039.                         
  1040.                         /* deal with cursor moving in/out of window */
  1041.                         } else if (winp->cursorRgn != (RgnHandle) NULL) {
  1042.                             AdjustCursor(winp, event.where, true);
  1043.                         }
  1044.                         break;
  1045.                     }
  1046.                 break;
  1047.             
  1048.             case kHighLevelEvent:
  1049.                 if (NAgestaltBits & NA_HASAEVENTS) {
  1050.                     aestatus = status;
  1051.                     (void) AEProcessAppleEvent(&event);
  1052.                     status = aestatus;
  1053.                 }
  1054.                 break;
  1055.         }
  1056.  
  1057.         /* handle dialog events */        
  1058.         DoDialog(winp, &event, mouse, item, &status);
  1059.  
  1060.         /* call the idle procedure of the front window */
  1061.         if (winp != (na_win*) NULL && !NAinBack
  1062.                 && status >= NA_NOTPROCESSED && winp->idlep != (na_idlep) NULL) {
  1063.             status = (*winp->idlep)(winp);
  1064.         }
  1065.         
  1066.         /* deal with window/app close requests and events */
  1067.         switch (status) {
  1068.             case NA_ALLCLOSED:
  1069.             case NA_REQCLOSEALL:
  1070.                 status = NAcloseWindows(NAhead, status);
  1071.                 break;
  1072.                 
  1073.             case NA_CLOSED:
  1074.             case NA_REQCLOSE:
  1075.                 status = NAcloseWindow(winp, status);
  1076.                 break;
  1077.             
  1078.             default:
  1079.                 /* call the next task procedure */
  1080.                 if (NAtask != (na_win**) NULL) {
  1081.                     if (NActask == (na_win**) NULL) {
  1082.                         NActask = NAtask;
  1083.                         prioritycnt = (*NAtask)->priority;
  1084.                     }
  1085.                     for (wh = NAtask; wh; wh = (*wh)->task) {
  1086.                         if ((wh == NActask || (*wh)->priority == -1)
  1087.                             && (wp = NAlockWindow(wh)) != (na_win*) NULL
  1088.                             && wp->taskp != (na_taskp) NULL) {
  1089.                             GetPort(&tempPort);
  1090.                             if (wp->pwin != (WindowPtr) NULL) SetPort(wp->pwin);
  1091.                             status = (*wp->taskp)(wp);
  1092.                             SetPort(tempPort);
  1093.                             if (status == NA_REQCLOSE || status == NA_CLOSED) {
  1094.                                 status = NAcloseWindow(wp, status);
  1095.                                 break;
  1096.                             }
  1097.                             if (status == NA_REQCLOSEALL || status == NA_ALLCLOSED) {
  1098.                                 status = NAcloseWindows(NAhead, status);
  1099.                                 break;
  1100.                             }
  1101.                             if (status == NA_NOTPROCESSED) fastdelay = 1;
  1102.                             NAunlockWindowh(wh, wp);
  1103.                         }
  1104.                     }
  1105.                     if (NActask && prioritycnt-- <= 0
  1106.                         && (NActask = (*NActask)->task) != (na_win **) NULL) {
  1107.                         prioritycnt = (*NActask)->priority;
  1108.                     }
  1109.                 }
  1110.             case NA_USERINTERACT:
  1111.                 break;
  1112.         }
  1113.     } while (status != NA_ALLCLOSED);
  1114.     
  1115.     while (NAtask != NULL) NAcloseWindow(NAlockWindow(NAtask), NA_REQCLOSE);
  1116.     
  1117.     DisposeRgn(NAfullRgn);
  1118.     DisposeRgn(NAnullRgn);
  1119.     DisposHandle((Handle) NAmenus);
  1120. }
  1121.  
  1122. /* position a rectangle based on screen size
  1123.  */ 
  1124. Rect *NAscreenrect(short position)
  1125. {
  1126.     static short stacktimes = 0;
  1127.     static Rect sb;
  1128.     short topoffset, leftoffset;
  1129.     short width, height;
  1130.     short bw;
  1131.             
  1132.     /* calculate the position to open the window */
  1133.     sb = QD(screenBits.bounds);
  1134.     InsetRect(&sb, 4, 4);
  1135.     sb.top += MBarHeight;
  1136.     if (position & NA_TITLEOFFSET) {
  1137.         sb.top += 18;
  1138.     }
  1139.     width = sb.right - sb.left;
  1140.     height = sb.bottom - sb.top;
  1141.     if (position & 0x03) {
  1142.         width = (width * (position & 0x03)) >> 2;
  1143.     }
  1144.     if (position & 0x0c) {
  1145.         height = (height * ((position & 0x0c) >> 2)) >> 2;
  1146.     }
  1147.     if (position & NA_TOPSCN) {
  1148.         sb.bottom = sb.top + height;
  1149.     } else if (position & NA_BOTTOMSCN) {
  1150.         sb.top = sb.bottom - height;
  1151.     } else {
  1152.         short bw = (sb.bottom - sb.top - height) >> 1;
  1153.         sb.top += bw;
  1154.         sb.bottom -= bw;
  1155.     }
  1156.     if (position & NA_LEFTSCN) {
  1157.         sb.right = sb.left + width;
  1158.     } else if (position & NA_RIGHTSCN) {
  1159.         sb.left = sb.right - width;
  1160.     } else {
  1161.         bw = (sb.right - sb.left - width) >> 1;
  1162.         sb.left += bw;
  1163.         sb.right -= bw;
  1164.     }
  1165.     
  1166.     return (&sb);
  1167. }
  1168.  
  1169. /* create a new window/dialog/task structure
  1170.  */
  1171. short NAwindow(Rect *rpos, long flags, char *title, short res, long *initdata,
  1172.     long datasize, na_initp initp)
  1173. {
  1174.     GrafPtr tmpPort;
  1175.     short procID;
  1176.     short status;
  1177.     Boolean goAwayFlag, visible;
  1178.     na_win **winh, *winp;
  1179.     char *newdata, *dcopy;
  1180.     WindowPtr behind, prev, window;
  1181.     Rect wsize, sb;
  1182.     PCstr wtitle[257];
  1183.     Handle items;    
  1184.     
  1185.     /* save previous window */
  1186.     prev = FrontWindow();
  1187.     
  1188.     /* set up flags for the NewWindow call */
  1189.     goAwayFlag = (flags & NA_CLOSEBOX);
  1190.     visible = (flags & NA_NOTVISIBLE) ? false : true;
  1191.     behind = (flags & NA_BEHIND && NAwin != (na_win*) NULL) ? NAwin->pwin : (WindowPtr) -1;
  1192.     
  1193.     /* decide on the correct procID */
  1194.     procID = rDocProc;
  1195.     if ((flags & NA_ROUNDBORDER) != NA_ROUNDBORDER) {
  1196.         procID = plainDBox;
  1197.         if (flags & NA_SHADOWBORDER)    procID = altDBoxProc;
  1198.         if (flags & NA_DOUBLEBORDER)    procID = dBoxProc;
  1199.         if (flags & NA_TITLEBAR) {
  1200.             procID = flags & NA_DOUBLEBORDER ? movableDBoxProc : documentProc;
  1201.         }
  1202.         if (!(flags & NA_GROWBOX)
  1203.             && procID == documentProc)    procID |= noGrowDocProc;
  1204.         if (flags & NA_ZOOMBOX)            procID |= zoomDocProc;
  1205.     }
  1206.     
  1207.     /* get the window title to a pacsal string */
  1208.     if (title) CtoPCstrcpy(wtitle, title);
  1209.         
  1210.     /* allocate memory and copy the user data */
  1211.     if (!datasize) datasize = sizeof (na_win);
  1212.     winh = (na_win**) NewHandleClear((Size) datasize);
  1213.     if (winh == (na_win**) NULL) return (NA_NOTPROCESSED);
  1214.     MoveHHi((Handle) winh);
  1215.     HLock((Handle) winh);
  1216.     winp = *winh;
  1217.     if (initdata != NULL && flags & NA_COPYDATA) {
  1218.         dcopy = (char *) initdata;
  1219.         datasize -= sizeof (na_win);
  1220.         for (newdata = (char*) winp + sizeof (na_win); datasize > 0; datasize--) {
  1221.             *newdata = *dcopy++;
  1222.             newdata++;
  1223.         }
  1224.     }
  1225.     
  1226.     /* initialize winp parameters */
  1227.     winp->locks = 1;
  1228.     winp->delay = NAdelay;
  1229.     winp->flags = flags;
  1230.     winp->minw = 128;
  1231.     winp->minh = 64;
  1232.     winp->resid = res;
  1233.         
  1234.     /* install in window tree */
  1235.     if (flags & NA_CHILDWINDOW && NAwin != (na_win*) NULL) {
  1236.         winp->parent = (na_win**) RecoverHandle((Ptr)NAwin);
  1237.         winp->next = NAwin->child;
  1238.         NAwin->child = winh;
  1239.     } else {
  1240.         winp->next = NAhead;
  1241.         NAhead = winh;
  1242.     }
  1243.     
  1244.     /* install in task list */
  1245.     if (flags & NA_HASTASK) {
  1246.         winp->task = NAtask;
  1247.         NAtask = winh;
  1248.     }
  1249.     
  1250.     /* open the window appropriately */
  1251.     switch (flags & (NA_COLORWINDOW | NA_DIALOGWINDOW)) {
  1252.         case NA_DIALOGWINDOW:
  1253.         case (NA_DIALOGWINDOW | NA_COLORWINDOW):
  1254.             if (flags & NA_USERESOURCE) {
  1255.                 window = (WindowPtr) GetNewDialog(res, (Ptr) NULL, behind);
  1256.             } else {
  1257.                 items = GetResource('DITL', res);
  1258.                 DetachResource(items);
  1259.                 if (flags & NA_COLORWINDOW) {
  1260.                     window = (WindowPtr) NewCDialog((Ptr) NULL, rpos, wtitle,
  1261.                         visible, procID, behind, goAwayFlag, (long) winh, items);
  1262.                 } else {
  1263.                     window = (WindowPtr) NewDialog((Ptr) NULL, rpos, wtitle,
  1264.                         visible, procID, behind, goAwayFlag, (long) winh, items);
  1265.                 }
  1266.             }
  1267.             break;
  1268.             
  1269.         case NA_COLORWINDOW:
  1270.             if (flags & NA_USERESOURCE) {
  1271.                 window = (WindowPtr) GetNewCWindow(res, (Ptr) NULL, behind);
  1272.             } else {
  1273.                 window = (WindowPtr) NewCWindow((Ptr) NULL, rpos, wtitle,
  1274.                     visible, procID, behind, goAwayFlag, (long) winh);
  1275.             }
  1276.             break;
  1277.         
  1278.         default:
  1279.             if (flags & NA_USERESOURCE) {
  1280.                 window = GetNewWindow(res, (Ptr) NULL, behind);
  1281.             } else {
  1282.                 window = NewWindow((Ptr) NULL, rpos, wtitle, visible, procID,
  1283.                     behind, goAwayFlag, (long) winh);
  1284.             }
  1285.             break;
  1286.     }
  1287.     if (title && (flags & NA_USERESOURCE)) SetWTitle(window, wtitle);
  1288.     winp->pwin = window;
  1289.  
  1290.     /* activate the window */
  1291.     GetPort(&tmpPort);
  1292.     SetPort(window);
  1293.  
  1294.     /* additional options for windows from resources */
  1295.     if (flags & NA_USERESOURCE) {
  1296.         SetWRefCon(window, (long) winh);
  1297.         
  1298.         /* force the size */
  1299.         if (flags & NA_FORCESIZE) {
  1300.             MoveWindow(window, rpos->left, rpos->top, false);
  1301.             SizeWindow(window, rpos->right - rpos->left, rpos->bottom - rpos->top, false);
  1302.         }
  1303.     }
  1304.     
  1305.     /* get the screen bounds */
  1306.     sb = QD(screenBits.bounds);
  1307.     InsetRect(&sb, 4, 4);
  1308.     
  1309.     /* get window position */    
  1310.     wsize = window->portRect;
  1311.     LocalToGlobal((Point *)&wsize.top);
  1312.     
  1313.     /* make sure the window is on the screen */
  1314.     if (wsize.top > sb.bottom || wsize.left > sb.right) {
  1315.         MoveWindow(window, 60, 60, false);
  1316.     }
  1317.     
  1318.     /* call the init procedure */
  1319.     if ((status = (*initp)(winp, initdata)) >= NA_NOTPROCESSED) {
  1320.     
  1321.         /* draw the window immediately for better look & update has first newsize */
  1322.         if (winp->updatep == (na_updatep) NULL
  1323.                 || (status = (*winp->updatep)(winp, (Boolean) true))
  1324.                 == NA_NOTPROCESSED) {
  1325.             DoDraw(winp, FrontWindow() != window ? DO_RESIZE | DO_DEACTIVATE :
  1326.                 DO_RESIZE);
  1327.         }
  1328.         if (flags & NA_DIALOGWINDOW) DrawDialog(window);
  1329.         ValidRect(&window->portRect);
  1330.     }
  1331.  
  1332.     /* deal with close requests/events result codes */
  1333.     switch (status) {
  1334.         case NA_ALLCLOSED:
  1335.         case NA_REQCLOSEALL:
  1336.             status = NAcloseWindows(NAhead, status);
  1337.             break;
  1338.  
  1339.         case NA_CLOSED:
  1340.         case NA_REQCLOSE:
  1341.             status = NAcloseWindow(winp, status);
  1342.             break;
  1343.         
  1344.         default:
  1345.             NAunlockWindowh(winh, winp);
  1346.             break;
  1347.     }
  1348.     
  1349.     /* give a nice return value & clean up the port */
  1350.     if (status == NA_NOTPROCESSED)                            status = NA_PROCESSED;
  1351.     if (FrontWindow() != window || status != NA_PROCESSED)    SetPort(tmpPort);
  1352.     
  1353.     return (status);
  1354. }
  1355.  
  1356. /* create & add a new task to the task list
  1357.  */
  1358. na_win **NAaddtask(na_taskp taskp, long size)
  1359. {
  1360.     na_win **task, *winp;
  1361.     
  1362.     if (!size) size = sizeof (na_win);
  1363.     task = (na_win **) NewHandleClear(size);
  1364.     if (task) {
  1365.         (*task)->taskp = taskp;
  1366.         (*task)->task = NAtask;
  1367.         NAtask = task;
  1368.     }
  1369.     
  1370.     return (task);
  1371. }
  1372.