home *** CD-ROM | disk | FTP | other *** search
/ QuickTime 2.0 Beta / Quicktime 2.0 Beta.iso / Programming Stuff / Sample Code / DTS Sample Code / MyMultipleMoviesApp ƒ / MyApplication Shell (2.0).c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-14  |  24.1 KB  |  877 lines  |  [TEXT/KAHL]

  1. /*
  2.     File:        MyApplication Shell (2.0).c
  3.     
  4.     Contains:    My Application Shell.
  5.  
  6.     Written by:    John Wang
  7.  
  8.     Copyright:    © 1994 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <1>        03/14/94    JW        Re-Created for Universal Headers.
  13.  
  14.     To Do:
  15.     
  16. */
  17.  
  18. #ifdef THINK_C
  19. #define        applec
  20. #endif
  21.  
  22. #include    <Types.h>
  23. #include    <Memory.h>
  24. #include    <QuickDraw.h>
  25. #include    <Palettes.h>
  26. #include    <QDOffscreen.h>
  27. #include    <Errors.h>
  28. #include    <Fonts.h>
  29. #include    <Dialogs.h>
  30. #include    <Windows.h>
  31. #include    <Menus.h>
  32. #include    <Events.h>
  33. #include    <Desk.h>
  34. #include    <DiskInit.h>
  35. #include    <OSUtils.h>
  36. #include    <Resources.h>
  37. #include    <ToolUtils.h>
  38. #include    <AppleEvents.h>
  39. #include    <EPPC.h>
  40. #include    <GestaltEqu.h>
  41. #include    <Processes.h>
  42. #include    <Balloons.h>
  43. #include    <Aliases.h>
  44. #include    <MixedMode.h>
  45. #include    <Scrap.h>
  46. #include    <LowMem.h>
  47.  
  48. #include    "MyApplication Shell (2.0).h"
  49. #include    "MyApplication.h"
  50.  
  51. #ifdef powerc
  52. QDGlobals        qd;
  53. #endif
  54.  
  55. Boolean            gDoneFlag;            //    Set to true if you want to Application to kindly quit.
  56. Boolean            gHasAppleEvents;    //    true if Gestalt returns saying AppleEvents is available.
  57. short            gScrapCount;        //    Keep track of scrap count.
  58. OSType            gScrapType;            //    Needed to know what type scrap it is.
  59. Handle            gScrap;                //    Must keep a handle to the scrap for update events that
  60.                                     //    happen in the background.  The reason is that when the app
  61.                                     //    is in the background, it does not have access to GetScrap().
  62.  
  63. /* ------------------------------------------------------------------------- */
  64.  
  65. void main()
  66. {
  67.     EventRecord     myEvent;
  68.     long            yieldTime;
  69.     WindowPtr        foundWindow;
  70.     short            windowPart;
  71.     Boolean            isEvent;
  72.     GrafPtr            savePort;
  73.     GDHandle        saveGD;
  74.     PScrapStuff        myScrapStuff;
  75.  
  76.     //    Initialize here.  Set the yield time too.
  77.     Initialize();
  78.     yieldTime = MyYieldTime(suspendResumeMessage);
  79.  
  80.     //    Event loop.
  81.     for ( ; ; ) {
  82.  
  83.         //    Get the event.
  84.         isEvent = WaitNextEvent(everyEvent, &myEvent, yieldTime, nil);
  85.  
  86.         //    Allow application specific event handling.  We have three cases:
  87.         //        MYEVENTDEF == 2: MyEvent gets called for each window.
  88.         //        MYEVENTDEF == 1: MyEvent gets once with window parameter = nil.
  89.         //        MYEVENTDEF == 0: MyEvent never gets called.
  90.         //    MyEvent returns true to indicate that the event is handled and can be ignored.
  91.         //    As the safe thing to do, we always set the port if we know what window is being used.
  92.         #if kMYEVENTDEF == 2
  93.             if ( isEvent ) {
  94.                 foundWindow = (WindowPtr) LMGetWindowList();
  95.                 while ( foundWindow != nil ) {
  96.                     if ( IsMyWindow(foundWindow) ) {
  97.                         GetPort(&savePort);
  98.                         saveGD = GetGDevice();
  99.                         SetPort(foundWindow);
  100.                         SetGDevice(GetMainDevice());
  101.                         if ( MyEvent(foundWindow, &myEvent) )
  102.                             isEvent = false;
  103.                         SetPort(savePort);
  104.                         SetGDevice(saveGD);
  105.                     }
  106.                     foundWindow = (WindowPtr) ((CWindowPeek) foundWindow)->nextWindow;
  107.                 }
  108.             }
  109.         #elif kMYEVENTDEF == 1
  110.             if ( isEvent ) {
  111.                 if ( MyEvent(nil, &myEvent) ) {
  112.                     isEvent = false;
  113.                 }
  114.             }
  115.         #elif kMYEVENTDEF == 0
  116.         #endif
  117.         
  118.         //    If the event is unhandled by app specific event handling, then we proceed.
  119.         if ( isEvent ) {
  120.             switch ( myEvent.what ) {
  121.  
  122.                 case mouseDown:
  123.                     //    Get current port and device.
  124.                     GetPort(&savePort);
  125.                     saveGD = GetGDevice();
  126.                     
  127.                     //    Set the port and gdevice to the window if we own the window.
  128.                     //    We can then assume anytime the event occured in one of our windows,
  129.                     //       that the port and gdevice are set correctly.
  130.                     windowPart = FindWindow(myEvent.where, &foundWindow);
  131.                     if ( IsMyWindow(foundWindow) || IsMyClipWindow(foundWindow) ) {
  132.                         SetPort(foundWindow);
  133.                         SetGDevice(GetMainDevice());
  134.                     }
  135.                     
  136.                     //    Handle the different mouse down events.
  137.                     switch ( windowPart ) {
  138.                         case inSysWindow:
  139.                             SystemClick(&myEvent, foundWindow);
  140.                             break;
  141.                         case inMenuBar:
  142.                             AdjustMenus();
  143.                             DoCommand(MenuSelect(myEvent.where));
  144.                             break;
  145.                         case inContent:
  146.                             //    If in the content area of application's window, then select
  147.                             //    the window and call app specific routine.
  148.                             if ( IsMyWindow(foundWindow) ) {
  149.                                 SelectWindow(foundWindow);
  150.                                 MyInContent(foundWindow, myEvent.where);
  151.                             } else if ( IsMyClipWindow(foundWindow) ) {
  152.                                 SelectWindow(foundWindow);
  153.                             }
  154.                             break;
  155.                         case inDrag:
  156.                             //    If dragging one of the application's windows, then handle it.
  157.                             //    However, if we are dragging a zoomed window, we
  158.                             //    must remember to save the new window location into the
  159.                             //    zoomed rect in the data handle.  Otherwise, the event
  160.                             //    manager will think that we are no longer zoomed.
  161.                             if ( IsMyWindow(foundWindow) || IsMyClipWindow(foundWindow) ) {
  162.                                 WStateData    *zoomData;
  163.                                 Rect        windowRect;
  164.                                 
  165.                                 //    Get window location before drag.
  166.                                 GetGlobalWindow(foundWindow, &windowRect);
  167.                                 
  168.                                 //    Drag window.
  169.                                 DragWindow (foundWindow, myEvent.where, &qd.screenBits.bounds);
  170.  
  171.                                 //    If the windowRect in global coordinates matches the zoom rect,
  172.                                 //    then assume that we are dragging the zoomed window.  update
  173.                                 //    zoom rect.
  174.                                 zoomData = (WStateData *) *(((CWindowPeek) foundWindow)->dataHandle);
  175.                                 if ( EqualRect(&(zoomData->stdState), &windowRect) ) {
  176.                                     GetGlobalWindow(foundWindow, &windowRect);
  177.                                     zoomData = (WStateData *) *(((CWindowPeek) foundWindow)->dataHandle);
  178.                                     zoomData->stdState = windowRect;
  179.                                 }
  180.                             }
  181.                             break;
  182.                         case inGrow:
  183.                             //    If growing one of the application's windows, then handle it.
  184.                             //    This also includes the clip window.
  185.                             //    See inDrag for details.
  186.                             if ( IsMyWindow(foundWindow) || IsMyClipWindow(foundWindow) ) {
  187.                                 WStateData    *zoomData;
  188.                                 Rect        windowRect;
  189.                                 Rect        tempRect;
  190.                                 long        tempLong;
  191.                                 Str255        tempStr;
  192.                                 
  193.                                 //    Get window location before drag.
  194.                                 GetGlobalWindow(foundWindow, &windowRect);
  195.                                 
  196.                                 //    Grow the window.
  197.                                 tempRect = qd.screenBits.bounds;
  198.                                 tempRect.left = tempRect.top = 50;
  199.                                 GetWTitle(foundWindow, tempStr);
  200.                                 tempRect.left = StringWidth(tempStr) + 50;
  201.                                 tempLong = GrowWindow(foundWindow, myEvent.where, &tempRect);
  202.                                 if ( tempLong ) {
  203.                                     tempRect = foundWindow->portRect;
  204.                                     InvalRect(&tempRect);
  205.                                     EraseRect(&tempRect);
  206.                                     InvalRect(&tempRect);
  207.                                     SizeWindow(foundWindow, tempLong, tempLong >> 16, true);
  208.                                 }
  209.  
  210.                                 //    If the windowRect in global coordinates matches the zoom rect,
  211.                                 //    then assume that we are dragging the zoomed window.  update
  212.                                 //    zoom rect.
  213.                                 zoomData = (WStateData *) *(((CWindowPeek) foundWindow)->dataHandle);
  214.                                 if ( EqualRect(&(zoomData->stdState), &windowRect) ) {
  215.                                     GetGlobalWindow(foundWindow, &windowRect);
  216.                                     zoomData = (WStateData *) *(((CWindowPeek) foundWindow)->dataHandle);
  217.                                     zoomData->stdState = windowRect;
  218.                                 }
  219.                             }
  220.                             break;
  221.                         case inGoAway:
  222.                             //    Handle clicking on the go away.  If it is the clip window,
  223.                             //    then hide it.
  224.                             if ( TrackGoAway (foundWindow, myEvent.where) ) {
  225.                                 if ( IsMyWindow(foundWindow) ) {
  226.                                     BringToFront(foundWindow);
  227.                                     MyClose();
  228.                                 } else if ( IsMyClipWindow(foundWindow) ) {
  229.                                     SetItem(GetMHandle(kMENU_EDITID), kMENU_EDITSHOWCLIP, "\pShow Clipboard");
  230.                                     HideClip(foundWindow);
  231.                                 }
  232.                             }
  233.                             break;
  234.                         case inZoomIn:
  235.                         case inZoomOut:
  236.                             //    Zoom application window and the clip window.
  237.                             if ( TrackBox(foundWindow, myEvent.where, windowPart) ) {
  238.                                 if ( IsMyWindow(foundWindow) )
  239.                                     MyZoomWindow(foundWindow, windowPart);
  240.                                 else if ( IsMyClipWindow(foundWindow) )
  241.                                     ZoomClip(foundWindow, windowPart);
  242.                             }
  243.                             break;
  244.                             break;
  245.                         default:
  246.                             break;
  247.                     }
  248.                     
  249.                     //    Restore port and device.
  250.                     SetPort(savePort);
  251.                     SetGDevice(saveGD);
  252.                     
  253.                     break;
  254.                 case keyDown:
  255.                 case autoKey:
  256.                     if ( myEvent.modifiers & cmdKey ) {
  257.                         if ( myEvent.what == keyDown ) {
  258.                             AdjustMenus();
  259.                             DoCommand(MenuKey(myEvent.message & charCodeMask));
  260.                         }
  261.                     } else
  262.                         MyDoKeyDown(&myEvent);
  263.                     break;
  264.                 case updateEvt:
  265.                     //    Handle update events for window and clip window.
  266.                     foundWindow = (WindowPtr) myEvent.message;
  267.                     GetPort(&savePort);
  268.                     saveGD = GetGDevice();
  269.                     SetPort(foundWindow);
  270.                     SetGDevice(GetMainDevice());
  271.                     BeginUpdate(foundWindow);
  272.                     if ( IsMyWindow(foundWindow) )
  273.                         MyDraw(foundWindow);
  274.                     else if ( IsMyClipWindow(foundWindow) )
  275.                         DrawClip(foundWindow);
  276.                     EndUpdate(foundWindow);
  277.                     SetPort(savePort);
  278.                     SetGDevice(saveGD);
  279.                     break;
  280.                 case diskEvt:
  281.                     //    This handles a bad disk.  Otherwise the disk will not eject.
  282.                     if ( myEvent.message >> 16 ) {
  283.                         Point    tempPoint;
  284.                         tempPoint.v = 50; tempPoint.h = 50;
  285.                         DIBadMount(tempPoint, myEvent.message);
  286.                     }
  287.                     break;
  288.                 case activateEvt:
  289.                     break;
  290.                 case app4Evt:
  291.                     switch ( myEvent.message >> 24 ) {
  292.                         case suspendResumeMessage:
  293.                             yieldTime = MyYieldTime(myEvent.message & 0x01);
  294.                             break;
  295.                         default:
  296.                             DebugStr("\pUnexpected suspend/resume message.");
  297.                     }
  298.                     break;
  299.                 case kHighLevelEvent:
  300.                     if ( gHasAppleEvents )
  301.                         AEProcessAppleEvent(&myEvent);
  302.                 default:
  303.                     break;
  304.             }
  305.         }
  306.     
  307.         //    If DoneFlag set, then quit.
  308.         if ( gDoneFlag )
  309.             Finishup();
  310.  
  311.         //    Do Idle routine.
  312.         //        MYIDLEDEF == 2: MyEvent gets called for each window.
  313.         //        MYIDLEDEF == 1: MyEvent gets once with window parameter = nil.
  314.         //        MYIDLEDEF == 0: MyEvent never gets called.
  315.         //    As the safe thing to do, we always set the port if we know what window is being used.
  316.         #if kMYIDLEDEF == 2
  317.             foundWindow = (WindowPtr) LMGetWindowList();
  318.             while ( foundWindow != nil ) {
  319.                 if ( IsMyWindow(foundWindow) ) {
  320.                     GetPort(&savePort);
  321.                     saveGD = GetGDevice();
  322.                     SetPort(foundWindow);
  323.                     SetGDevice(GetMainDevice());
  324.                     MyIdle(foundWindow);
  325.                     SetPort(savePort);
  326.                     SetGDevice(saveGD);
  327.                 }
  328.                 foundWindow = (WindowPtr) ((CWindowPeek) foundWindow)->nextWindow;
  329.             }
  330.         #elif kMYIDLEDEF == 1
  331.             MyIdle(nil);
  332.         #elif kMYIDLEDEF == 0
  333.         #endif
  334.  
  335.         //    See if scrap changed.  If so, redraw if the clip window is found.
  336.         myScrapStuff = InfoScrap();
  337.         if ( gScrapCount != myScrapStuff->scrapCount ) {
  338.             foundWindow = (WindowPtr) LMGetWindowList();
  339.             while ( foundWindow != nil ) {
  340.                 if ( IsMyClipWindow(foundWindow) ) {
  341.                     GetPort(&savePort);
  342.                     saveGD = GetGDevice();
  343.                     SetPort(foundWindow);
  344.                     SetGDevice(GetMainDevice());
  345.                     DrawClip(foundWindow);
  346.                     SetPort(savePort);
  347.                     SetGDevice(saveGD);
  348.                 }
  349.                 foundWindow = (WindowPtr) ((CWindowPeek) foundWindow)->nextWindow;
  350.             }
  351.         }
  352.     }
  353. }
  354.  
  355. /* ------------------------------------------------------------------------- */
  356.  
  357. //    MyApplication Shell support routines (Initialize, DoCommand, and Finishup):
  358.  
  359. void Initialize()
  360. {
  361.     OSErr                err;
  362.     long                vers;
  363.     Handle                myMenu;
  364.     
  365.     //    Initialize Managaer.
  366.     MaxApplZone();
  367.     MoreMasters(); MoreMasters(); MoreMasters(); MoreMasters();
  368.     MoreMasters(); MoreMasters(); MoreMasters(); MoreMasters();
  369.     MoreMasters(); MoreMasters(); MoreMasters(); MoreMasters();
  370.     MoreMasters(); MoreMasters(); MoreMasters(); MoreMasters();
  371.     InitGraf(&qd.thePort);
  372.     FlushEvents(everyEvent, 0);
  373.     InitWindows();
  374.     InitDialogs(nil);
  375.     InitCursor();
  376.  
  377.     //    Set up menus.
  378.     myMenu = GetNewMBar(kMENUBAR);
  379.     SetMenuBar(myMenu);
  380.     DisposHandle(myMenu);
  381.     AddResMenu(GetMHandle(kMENU_APPLEID), 'DRVR');
  382.     DrawMenuBar();
  383.     
  384.     //    Require at least System 7.0 and Color QuickDraw.  We don't really need to be strict
  385.     //    about this.  So, this can be removed if necessary.  But, test thoroughly with
  386.     //    System 6 and non-color if you do.
  387.     Gestalt(gestaltSystemVersion, &vers);
  388.     vers = (vers >> 8) & 0x0f;
  389.     if ( vers < 7 ) {
  390.         ReportError("\pThis Application does not run under System 6!", -1);
  391.         ExitToShell();
  392.     }
  393.     Gestalt(gestaltQuickdrawVersion, &vers);
  394.     if ( vers < 0x100 ) {
  395.         ReportError("\pThis Application requires Color QuickDraw!", -1);
  396.         ExitToShell();
  397.     }
  398.     
  399.     //    Initialize AppleEvents if available.
  400.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &vers) == noErr);
  401.     if ( gHasAppleEvents ) {
  402.         err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, NewAEEventHandlerProc(AEOpenHandler), 0, false);
  403.         if ( err ) {
  404.             ReportError("\pError installing AppleEvent handlers.", err);
  405.             ExitToShell();
  406.         }
  407.         err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerProc(AEOpenDocHandler), 0, false);
  408.         if ( err ) {
  409.             ReportError("\pError installing AppleEvent handlers.", err);
  410.             ExitToShell();
  411.         }
  412.         err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc(AEQuitHandler), 0, false);
  413.         if ( err ) {
  414.             ReportError("\pError installing AppleEvent handlers.", err);
  415.             ExitToShell();
  416.         }
  417.         err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, NewAEEventHandlerProc(AEPrintHandler), 0, false);
  418.         if ( err ) {
  419.             ReportError("\pError installing AppleEvent handlers.", err);
  420.             ExitToShell();
  421.         }
  422.     }
  423.     
  424.     //    Setup other globals.
  425.     gDoneFlag = false;
  426.  
  427.     //    Call app specific Intialization.
  428.     if ( ReportError("\pError returned from MyInitialize:", MyInitialize()) )
  429.         ExitToShell();
  430. }
  431.  
  432. void DoCommand(long mResult)
  433. {
  434.     short             theMenu, theItem;
  435.     Str255            myStr;
  436.     GrafPtr            savePort;
  437.     GDHandle        saveGD;
  438.     WindowPtr        foundWindow;
  439.     
  440.     theItem = LoWord(mResult);
  441.     theMenu = HiWord(mResult);
  442.     
  443.     if ( theItem != 0 || theMenu != 0 ) {
  444.         switch ( theMenu ) {
  445.             case kMENU_APPLEID:
  446.                 if ( theItem == 1 ) {
  447.                     ParamText(gMyAboutTitle, gMyAboutDesc, nil, nil);
  448.                     Alert(kALERT_ABOUT, nil);
  449.                 } else {
  450.                     GetItem(GetMHandle(kMENU_APPLEID), theItem, myStr);
  451.                     GetPort(&savePort);
  452.                     saveGD = GetGDevice();
  453.                     (void) OpenDeskAcc(myStr);
  454.                     SetPort(savePort);
  455.                     SetGDevice(saveGD);
  456.                 }
  457.                 break;
  458.     
  459.             case kMENU_FILEID:
  460.                 switch ( theItem ) {
  461.                     case kMENU_FILENEW:
  462.                         MyNew();
  463.                         break;
  464.                     case kMENU_FILEOPEN:
  465.                         MyOpen(nil);
  466.                         break;
  467.                     case kMENU_FILECLOSE:
  468.                         if ( IsMyClipWindow(FrontWindow()) ) {
  469.                             SetItem(GetMHandle(kMENU_EDITID), kMENU_EDITSHOWCLIP, "\pShow Clipboard");
  470.                             HideClip(FrontWindow());
  471.                         } else if ( IsMyWindow(FrontWindow()) )
  472.                             MyClose();
  473.                         else
  474.                             SysBeep(50);
  475.                         break;
  476.                     case kMENU_FILESAVE:
  477.                         if ( IsMyWindow(FrontWindow()) )
  478.                             MySave();
  479.                         else
  480.                             SysBeep(50);
  481.                         break;
  482.                     case kMENU_FILESAVEAS:
  483.                         if ( IsMyWindow(FrontWindow()) )
  484.                             MySaveAs();
  485.                         else
  486.                             SysBeep(50);
  487.                         break;
  488.                     case kMENU_FILEPAGESETUP:
  489.                         if ( IsMyWindow(FrontWindow()) )
  490.                             MyPageSetup();
  491.                         else
  492.                             SysBeep(50);
  493.                         break;
  494.                     case kMENU_FILEPRINT:
  495.                         if ( IsMyWindow(FrontWindow()) )
  496.                             MyPrint();
  497.                         else
  498.                             SysBeep(50);
  499.                         break;
  500.                     case kMENU_FILEQUIT:
  501.                         gDoneFlag = true;
  502.                         break;
  503.                     default:
  504.                         if ( ReportError("\pError in handling file menu:", theItem) )
  505.                             ExitToShell();
  506.                 }
  507.                 break;
  508.     
  509.             case kMENU_EDITID:
  510.                 switch ( theItem ) {
  511.                     case kMENU_EDITUNDO:
  512.                         MyUndo();
  513.                         break;
  514.                     case kMENU_EDITCUT:
  515.                         MyCut();
  516.                         break;
  517.                     case kMENU_EDITCOPY:
  518.                         MyCopy();
  519.                         break;
  520.                     case kMENU_EDITPASTE:
  521.                         MyPaste();
  522.                         break;
  523.                     case kMENU_EDITCLEAR:
  524.                         MyClear();
  525.                         break;
  526.                     case kMENU_EDITSELECTALL:
  527.                         MySelectAll();
  528.                         break;
  529.                     case kMENU_EDITSHOWCLIP:
  530.                         GetItem(GetMHandle(kMENU_EDITID), kMENU_EDITSHOWCLIP, myStr);
  531.                         if ( myStr[1] == 'S' ) {        //    Obviously not very internationalizeable.
  532.                             ShowClip();
  533.                             SetItem(GetMHandle(kMENU_EDITID), kMENU_EDITSHOWCLIP, "\pHide Clipboard");
  534.                         } else {
  535.                             foundWindow = (WindowPtr) LMGetWindowList();
  536.                             while ( foundWindow != nil ) {
  537.                                 if ( IsMyClipWindow(foundWindow) ) {
  538.                                     SetItem(GetMHandle(kMENU_EDITID), kMENU_EDITSHOWCLIP, "\pShow Clipboard");
  539.                                     HideClip(foundWindow);
  540.                                 }
  541.                                 foundWindow = (WindowPtr) ((CWindowPeek) foundWindow)->nextWindow;
  542.                             }
  543.                         }
  544.                         break;
  545.                     default:
  546.                         if ( ReportError("\pError in handling edit menu:", theItem) )
  547.                             ExitToShell();
  548.                 }
  549.                 break;
  550.  
  551.             default:
  552.                 //    If not handled above, then allow app specific handling to occur.
  553.                 if ( ReportError("\pError returned from MyDoCommand:", MyDoCommand(theMenu, theItem)) )
  554.                     ExitToShell();
  555.         }
  556.     }
  557.     HiliteMenu(0);
  558.     return;
  559. }
  560.  
  561. void AdjustMenus()
  562. {
  563.     MenuHandle        mHandle;
  564.     
  565.     if ( IsMyClipWindow(FrontWindow()) ) {
  566.         mHandle = GetMHandle(kMENU_FILEID);
  567.         DisableItem(mHandle, kMENU_FILESAVE);
  568.         DisableItem(mHandle, kMENU_FILESAVEAS);
  569.         DisableItem(mHandle, kMENU_FILEPAGESETUP);
  570.         DisableItem(mHandle, kMENU_FILEPRINT);
  571.         mHandle = GetMHandle(kMENU_EDITID);
  572.         DisableItem(mHandle, kMENU_EDITUNDO);
  573.         DisableItem(mHandle, kMENU_EDITCUT);
  574.         DisableItem(mHandle, kMENU_EDITCOPY);
  575.         DisableItem(mHandle, kMENU_EDITPASTE);
  576.         DisableItem(mHandle, kMENU_EDITCLEAR);
  577.         DisableItem(mHandle, kMENU_EDITSELECTALL);
  578.     } else {
  579.         mHandle = GetMHandle(kMENU_FILEID);
  580.         if (IsMyWindow(FrontWindow())) {
  581.             EnableItem(mHandle, kMENU_FILESAVE);
  582.             EnableItem(mHandle, kMENU_FILESAVEAS);
  583.             EnableItem(mHandle, kMENU_FILEPAGESETUP);
  584.             EnableItem(mHandle, kMENU_FILEPRINT);
  585.         } else {
  586.             DisableItem(mHandle, kMENU_FILESAVE);
  587.             DisableItem(mHandle, kMENU_FILESAVEAS);
  588.             DisableItem(mHandle, kMENU_FILEPAGESETUP);
  589.             DisableItem(mHandle, kMENU_FILEPRINT);
  590.         }
  591.         mHandle = GetMHandle(kMENU_EDITID);
  592.         EnableItem(mHandle, kMENU_EDITUNDO);
  593.         EnableItem(mHandle, kMENU_EDITCUT);
  594.         EnableItem(mHandle, kMENU_EDITCOPY);
  595.         EnableItem(mHandle, kMENU_EDITPASTE);
  596.         EnableItem(mHandle, kMENU_EDITCLEAR);
  597.         EnableItem(mHandle, kMENU_EDITSELECTALL);
  598.     }
  599.     
  600.     MyAdjustMenus();
  601. }
  602.  
  603. void Finishup()
  604. {
  605.     WindowPtr        frontWindow, nxtWindow;
  606.     
  607.     frontWindow = FrontWindow();
  608.     while ( frontWindow != nil ) {
  609.         nxtWindow = (WindowPtr) ((WindowPeek)frontWindow)->nextWindow;
  610.         if ( IsMyClipWindow(frontWindow) ) {
  611.             HideClip(frontWindow);
  612.         }
  613.         frontWindow = nxtWindow;
  614.     }
  615.     
  616.     //    Cleanup app specific stuff since all of the shell handles will be disposed of
  617.     //    when the heap disappears...
  618.     MyFinishup();
  619.  
  620.     //    Finally, quit app.
  621.     ExitToShell();
  622. }
  623.  
  624. /* ------------------------------------------------------------------------- */
  625.  
  626. //    Clip Window support (ShowClip, DrawClip, HideClip, and ZoomClip):
  627.  
  628. void ShowClip()
  629. {
  630.     WindowPtr    myWindow;
  631.     Rect        clipBounds;
  632.     
  633.     myWindow = (WindowPtr) LMGetWindowList();
  634.     while ( myWindow != nil ) {
  635.         if ( IsMyClipWindow(myWindow) ) {
  636.             return;
  637.         }
  638.         myWindow = (WindowPtr) ((CWindowPeek) myWindow)->nextWindow;
  639.     }
  640.     
  641.     SetRect(&clipBounds, 10, 400, 510, 480);    
  642.     myWindow = NewCWindow(0L, &clipBounds, "\pClipboard", true, zoomDocProc, (WindowPtr) -1, true, 0L);
  643.     SetMyClipWindow(myWindow);
  644.     SetPort(myWindow);
  645.  
  646.     gScrapCount = 0;
  647.     gScrapType = 'NONE';    
  648.     if ( (gScrap = NewHandle(0)) == nil ) {
  649.         ReportError("\pCould not create handle for scrap storage:", -1);
  650.         ExitToShell();
  651.     }
  652. }
  653.  
  654. void DrawClip(WindowPtr clipWindow)
  655. {
  656.     PScrapStuff    myScrapStuff;
  657.     long        scrapOffset, scrapLength;
  658.     Rect        myFrame;
  659.     Str255        myStr;
  660.     short        moveSize;
  661.     
  662.     //    See if scrap changed.
  663.     myScrapStuff = InfoScrap();
  664.     if ( gScrapCount != myScrapStuff->scrapCount ) {
  665.         gScrapCount = myScrapStuff->scrapCount;
  666.         if ( (scrapLength = GetScrap(gScrap, 'PICT', &scrapOffset)) > 0 ) {
  667.             gScrapType = 'PICT';    
  668.         } else if ( (scrapLength = GetScrap(gScrap, 'TEXT', &scrapOffset)) > 0 ) {
  669.             gScrapType = 'TEXT';    
  670.         } else
  671.             gScrapType = 'NONE';    
  672.     }
  673.  
  674.     //    Erase the window.
  675.     EraseRect(&(clipWindow->portRect));
  676.  
  677.     //    Draw something
  678.     if ( gScrapType == 'PICT' ) {
  679.         myFrame = (**(PicHandle) gScrap).picFrame;
  680.         SetWTitle(clipWindow, "\pClipboard contents: picture");
  681.         DrawPicture((PicHandle) gScrap, &myFrame);
  682.  
  683.     } else if ( gScrapType == 'TEXT' ) {
  684.         SetWTitle(clipWindow, "\pClipboard contents: text");
  685.         moveSize = GetHandleSize(gScrap);
  686.         if ( moveSize > 255 )
  687.             moveSize = 255;
  688.         BlockMove(*gScrap, myStr+1, moveSize);
  689.         myStr[0] = moveSize;
  690.         MoveTo(10, 40);
  691.         DrawString(myStr);
  692.     } else
  693.         SetWTitle(clipWindow, "\pNo PICT or TEXT to display.");
  694. }
  695.  
  696. void HideClip(WindowPtr clipWindow)
  697. {
  698.     DisposeWindow(clipWindow);
  699.     gScrapCount = 0;
  700.     gScrapType = 'NONE';
  701.     DisposeHandle(gScrap);
  702. }
  703.  
  704. void ZoomClip(WindowPtr clipWindow, short windowPart)
  705. {
  706.     WStateData    *zoomData;
  707.     
  708.     //    IMPORTANT: Must not change stdState if not zooming out.  Otherwise, it will fool
  709.     //    the WDEF into thinking that it is not zoomed out when it really is.
  710.     
  711.     //    Don't call anything else since zoomData handle is not locked.
  712.     zoomData = (WStateData *) *(((CWindowPeek) clipWindow)->dataHandle);
  713.     
  714.     if ( gScrapType == 'PICT' ) {
  715.         if ( windowPart == 8 ) {
  716.             (zoomData->stdState).right = (zoomData->stdState).left +
  717.                                             ((**(PicHandle) gScrap).picFrame).right;
  718.             (zoomData->stdState).bottom = (zoomData->stdState).top +
  719.                                             ((**(PicHandle) gScrap).picFrame).bottom;
  720.         }
  721.     } else if ( gScrapType == 'TEXT' ) {
  722.         if ( windowPart == 8 ) {
  723.             (zoomData->stdState).right = (zoomData->stdState).left + 620;
  724.         }    
  725.     }
  726.     ZoomWindow(clipWindow, windowPart, true);
  727. }
  728.  
  729. /* ------------------------------------------------------------------------- */
  730.  
  731. //    Shell utilities (ReportError, and GetGlobalWindow):
  732.  
  733. //    Show Alert.  Then, return true is err != noErr.
  734. Boolean ReportError(Str255 procStr, OSErr err)
  735. {
  736.     long    longerr = err;
  737.     Str255    myStr;
  738.     
  739.     if ( longerr ) {
  740.         NumToString(longerr, myStr);
  741.         ParamText("\pFATAL ERROR", procStr, myStr, nil);
  742.         Alert(kALERT_ERROR, nil);
  743.         return ( true );
  744.     } else
  745.         return ( false );
  746. }
  747.  
  748. void GetGlobalWindow(WindowPtr theWindow, Rect *windowRect)
  749. {
  750.     //    Get the windowRect in global coordinates.
  751.     *windowRect = theWindow->portRect;
  752.     LocalToGlobal(&topLeft(*windowRect));
  753.     LocalToGlobal(&botRight(*windowRect));
  754. }
  755.  
  756. /* ------------------------------------------------------------------------- */
  757.  
  758. //    AppleEvents handling (AEOpenHandler, AEOpenDocHandler, AEPrintHandler,
  759. //       and AECloseHandler) :
  760.  
  761. pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  762. {
  763.     //    We don't do anything more than simply call MyNew().
  764.     //    Thus, when app is opened from finder, MyNew will be called because the Finder
  765.     //    will send an open app AppleEvent message.
  766.     if ( kNEWDOCATSTARTUP )
  767.         MyNew();
  768.     
  769.     return ( noErr );
  770. }
  771.  
  772. pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  773. {
  774.     OSErr            err;
  775.     AEDescList        docList;
  776.     long            numItems;
  777.     FSSpec            myFSS;
  778.     Size            actualSize;
  779.     long            i;
  780.     DescType        typeCode;
  781.     AEKeyword        theKeyword;
  782.     
  783.     err = AEGetParamDesc(messagein, keyDirectObject, typeAEList, &docList);
  784.     if ( err )
  785.         return ( err );
  786.     
  787.     err = AECountItems(&docList, &numItems);
  788.     if ( err )
  789.         return ( err );
  790.         
  791.     for ( i=1; i<=numItems; i++ ) {
  792.         err = AEGetNthPtr(&docList, i, typeFSS, &theKeyword, &typeCode, (Ptr) &myFSS,
  793.                             sizeof(FSSpec), &actualSize);
  794.         if ( err )
  795.             return ( err );
  796.         
  797.         MyOpen(&myFSS);
  798.     }
  799.     
  800.     return ( noErr );
  801. }
  802.  
  803. pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  804. {
  805.     OSErr            err;
  806.     AEDescList        docList;
  807.     long            numItems;
  808.     FSSpec            myFSS;
  809.     Size            actualSize;
  810.     long            i;
  811.     DescType        typeCode;
  812.     AEKeyword        theKeyword;
  813.     
  814.     err = AEGetParamDesc(messagein, keyDirectObject, typeAEList, &docList);
  815.     if ( err )
  816.         return ( err );
  817.     
  818.     err = AECountItems(&docList, &numItems);
  819.     if ( err )
  820.         return ( err );
  821.     
  822.     for ( i=1; i<=numItems; i++ ) {
  823.         err = AEGetNthPtr(&docList, i, typeFSS, &theKeyword, &typeCode, (Ptr) &myFSS,
  824.                             sizeof(FSSpec), &actualSize);
  825.         if ( err )
  826.             return ( err );
  827.         
  828.         //    Open each file.  Print it.  Then close it.  MyOpen must make window frontmost.
  829.         MyOpen(&myFSS);
  830.         MyPrint();
  831.         MyClose();
  832.     }
  833.     
  834.     return ( noErr );
  835. }
  836.  
  837. pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  838. {
  839.     gDoneFlag = true;
  840.     
  841.     return ( noErr );
  842. }
  843.  
  844. /* ------------------------------------------------------------------------- */
  845.  
  846. //    Called to determine if the window is owned by app.
  847. Boolean IsMyWindow(WindowPtr theWindow)
  848. {
  849.     if ( theWindow )
  850.         return ( ((CWindowPeek) theWindow)->windowKind == kWINDOWDOC );
  851.     else
  852.         return ( false );
  853. }
  854.  
  855. //    Called to set the window's creator.
  856. void SetMyWindow(WindowPtr theWindow)
  857. {
  858.     if ( theWindow )
  859.         ((CWindowPeek) theWindow)->windowKind = kWINDOWDOC;
  860. }
  861.  
  862. //    Called to determine if window is a show clipboard window.
  863. Boolean IsMyClipWindow(WindowPtr theWindow)
  864. {
  865.     if ( theWindow )
  866.         return ( ((CWindowPeek) theWindow)->windowKind == kWINDOWCLIP );
  867.     else
  868.         return ( false );
  869. }
  870.  
  871. //    Called to set the creator as the window clip.
  872. void SetMyClipWindow(WindowPtr theWindow)
  873. {
  874.     if ( theWindow )
  875.         ((CWindowPeek) theWindow)->windowKind = kWINDOWCLIP;
  876. }
  877.