home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / lang / generic_.hqx / GenericDA.SIT / GenericCDA.c < prev   
Encoding:
C/C++ Source or Header  |  1988-04-12  |  11.7 KB  |  445 lines  |  [TEXT/KAHL]

  1. /*
  2.  *    
  3.  *    A Generic Desk Accessory written in LightSpeedC¬
  4.  *
  5.  *    By David HM Spector
  6.  *    Copyright ⌐1986,1987, 1988 All Rights Reserved
  7.  *
  8.  * Permission is granted for unlimited non-commercial use.
  9.  * Permission is granted for commercial use provided credit is given in the
  10.  * desk accessory and its documentation.
  11.  *
  12.  *  Donations for continuing development graciously accepted!
  13.  *
  14.  *  Please mail suggestions, et al to:
  15.  *
  16.  *    US Snail:    David HM Spector
  17.  *                310 West 18th St. #5A
  18.  *                New York, NY 10011
  19.  *
  20.  *    ARPAnet:    SPECTOR@NYU.EDU (or SPECTOR@GBA.NYU.EDU)        
  21.  *    USEnet:        ...{allegra, harvard, rocky, ihnp4}!cmcl2!spector
  22.  *    CompuServe: 71260,1410
  23.  *    MCIMail:    DSpector
  24.  *
  25.  *
  26.  *  This is a Generic DA written in LightSpeedC¬.  I wrote it because I often
  27.  *  write DA's, and I hate to start them from scratch each and every time.
  28.  *  Gutting other DA's is also, to say the least, a pain. So I decided to write
  29.  *  a complete minimal Desk Accessory that would do everything a real DA
  30.  *  could do and still be simple to modify and understand.  Hence, the GenericDA.
  31.  *
  32.  *    Among other things, GenericDA will do the following:
  33.  *        Ñ put up its own window
  34.  *        Ñ put up its own menu(s) (with an about box)
  35.  *        Ñ respond to update events
  36.  *        Ñ respond to activate events (including inserting/removing its menu)
  37.  *        Ñ respond to keydown/autokey events (you'll have to write your own edit
  38.  *          functions though)
  39.  *
  40.  *
  41.  *    What you need:
  42.  *    1. LightSpeedC¬ version 1.05 or later.
  43.  *    2. RMaker1.01b1 or later (for the GenericDA.r file) -or- ResEdit1.0 or later
  44.  *
  45.  *    Compiling the DA:
  46.  *    1. Make a new project and add this file, and the MacTraps library.
  47.  *    2. Set the project type to "Desk Accessory" (and pick a name).
  48.  *    3. Edit the GenericDA file to use the correct path names for your system
  49.  *    4. Compile and save the DA.
  50.  *    5. Edit the RMaker file to reflect the path name for the name you gave the
  51.  *       DA you just compiled.
  52.  *    6. Run the RMaker on the Rmaker file and install the DA with Font/DA Mover.
  53.  *
  54.  *
  55.  *
  56.  *                        Revision History
  57.  *
  58.  *        Date    Version        Who                        What
  59.  *  11/8/86            0.0        DHMS        Start. Defined routines, added
  60.  *                                        event handler.
  61.  *                    0.5        DHMS        Added Menus and owned resources
  62.  *                    1.0        DHMS        Fixed bug in doEvent.[ Forgot to
  63.  *                                        Cast csParam[0] to be (EventRecord *)
  64.  *                                        -- causes an address error...
  65.  *    2/16/88            1.20    DHMS        Cleaned up stuff for LSC2.xx, mostly. 
  66.  *                                        Removed long path names as LSC2.xx handles
  67.  *                                        includes better.
  68.  *                                        Included the GenericDA.rsrc as well as the old
  69.  *                                        and crufty (blech!) RMaker file. If I can get 
  70.  *                                        ResTools from SUMEX--AIM I'll add a ResTools file too.
  71.  *                                        Set the dCtlFlags.  (I dunno why I didn't do this 
  72.  *                                        before╔musta been late or something.)
  73.  *
  74.  *    2/29/88            1.21    DHMS        Added check for NIL menu handle in activate event
  75.  *                                        if ths da has no menu, or menu is lost we won't put
  76.  *                                        junk on the menu bar.
  77.  */
  78.  
  79.  
  80. /*    This covers almost all of the available include files, some of these may 
  81.  *  not be needed by your Desk Accessory... it would speed compilation to
  82.  *  remove all but the ones you need.
  83.  */
  84. #include <MacTypes.h>
  85. #include <AppleTalk.h>
  86. #include <ControlMgr.h>
  87. #include <DeskMgr.h>
  88. #include <DeviceMgr.h>
  89. #include <DialogMgr.h>
  90. #include <FontMgr.h>
  91. #include <EventMgr.h>
  92. #include <HFS.h>
  93. #include <MemoryMgr.h>
  94. #include <MenuMgr.h>
  95. #include <OSUtil.h>
  96. #include <PackageMgr.h>
  97. #include <Quickdraw.h>
  98. #include <ResourceMgr.h>
  99. #include <StdFilePkg.h>
  100. #include <TextEdit.h>
  101. #include <ToolboxUtil.h>
  102. #include <WindowMgr.h>
  103.  
  104. /* Misc useful define's */
  105. #define    NIL    0        /* for pointers, etc  But note below!*/             
  106. #define    NILL    0L    /* different from NIL, this is a *LONG* zero */
  107.                     /* In fact this is sooo important I'll go further and say that
  108.                      * some things that expect 'nil' values are not always coerced into
  109.                      * longs.  LSC is very good about this, but if Inside Macintosh says
  110.                      * to use a pointer or procPointer, and you want to pass a nil, use 0L, 
  111.                      * its safer and can save you much grief. This used to get me killed
  112.                      * in Consulair's Mac C _all the time_.
  113.                      */             
  114. #define    INFRONT    -1    /* for windows */
  115. #define    False 0
  116. #define    True 0xFF
  117. #define    OFF    0        /* RadioButton control values */
  118. #define    ON    1
  119. #define    ACTIVE    0    /* For fiddling with other control states */
  120. #define    INACTIVE 255
  121. #define    plain    0    /* Plain text */
  122. #define    drvrOpen    0
  123. #define    drvrPrime    1
  124. #define    drvrControl    2
  125. #define    drvrStatus    3
  126. #define    drvrClose    4
  127.  
  128. #define    WINDOWTYPE     rDocProc    /* Lisa style window */
  129. #define    WINDOWTITLE "\pA Generic DA" /* a resource would be a good idea here... */
  130. #define    THEMENUID    1    /*     this is a local ID that must be resolved    */
  131. #define    ABOUTBOX    1    /*    The    About╔ box for this DA                    */
  132.  
  133.  
  134. Rect windowRect = {50, 20, 200, 220};
  135. MenuHandle ourMenu = NIL; /* Important safety tip: ALWAYS initialize handles╔ */
  136. int    refNum = 0;    /* this is the drivers refnum that is in dce->dCtlRefNum */
  137.  
  138. /*                Routines used by the driver's main routines                */  
  139.  
  140. /* This could have been done with a macro, but I often find macros to be 
  141.  * cryptic, and often lead the what I call "clever C".  I hate to have
  142.  * to clever myself _out_ of corners I've clevered myself into..
  143.  */ 
  144.     int    resolveid(refNum,theid)
  145.     int refNum;
  146.     int theid;
  147.     /* See Inside Macintosh, Vol.I, Pp.109-110 for info on calculating owned IDs */
  148.     {
  149.     return ( ( 0xC000 | (refNum<<5) ) + theid);
  150.     }
  151.  
  152. char validWindow(window)
  153.   WindowPtr window;
  154.   {
  155.   WindowPtr nextWindow;
  156.   
  157.   if (window)
  158.     {
  159.         nextWindow = FrontWindow();
  160.     while (nextWindow)
  161.      if (window == nextWindow) return (1);
  162.         else nextWindow = (WindowPtr)(((WindowPeek)nextWindow)->nextWindow);
  163.      }
  164.     return 0;
  165.   }
  166.  
  167. void doAboutBox(window)
  168. WindowPtr window;
  169. {
  170.  DialogPtr theDialog;
  171.  int itemHit;
  172.  
  173.  theDialog = GetNewDialog(resolveid(refNum,ABOUTBOX),NIL,INFRONT);
  174.  SetPort(theDialog);
  175.    while (itemHit != 1)
  176.     ModalDialog(NILL, &itemHit);
  177.  CloseDialog(theDialog);
  178.  SetPort(window);
  179. }
  180.     
  181. void drawOurWindowContents()
  182.  {
  183.      EraseRect(&thePort->portRect);
  184.      MoveTo(10,10);
  185.      TextFace(monaco);
  186.      TextSize(10);
  187.      DrawString("\pA Customizable Desk Accessory");
  188.      MoveTo(10,30);
  189.      DrawString("\pWritten in LightSpeed¬ C");
  190.  }
  191.  
  192.  
  193. /*                    Driver Routines Live Here                            */
  194.     
  195. open(iopb,dce)
  196.     cntrlParam *iopb;    /*     pointer to parameter block    */
  197.     DCtlPtr dce;        /*     the device control entry    */
  198.     {
  199.     WindowPtr window;
  200.     GrafPtr oldPort;
  201.     
  202.      refNum = dce->dCtlRefNum;
  203.      if (refNum < 0)
  204.         refNum = -refNum;
  205.     refNum = refNum - 1;
  206.         
  207.   if ((window = dce->dCtlWindow) == 0) /* already have a window? */
  208.     { 
  209.     GetPort(&oldPort);/* no, make new one╔ */
  210.     window = NewWindow(0, &windowRect, WINDOWTITLE, 0, WINDOWTYPE,INFRONT, 1, 0);
  211.     SetPort(window);
  212.     ((WindowPeek)window)->windowKind = dce->dCtlRefNum;
  213.     dce->dCtlWindow = window;
  214.     
  215.     ourMenu = GetMenu(resolveid(refNum,THEMENUID));
  216.     /* if we got a handle, then install the menu...see also activate/deactivate event code*/    
  217.     if (ourMenu)    {
  218.         dce->dCtlMenu = resolveid(refNum,THEMENUID); /*note this is the menu ID, not its handle*/
  219.         InsertMenu(ourMenu,0);
  220.         }
  221.  
  222.     SetPort(oldPort);
  223.     }
  224.   return(0);
  225.   }
  226.     
  227. prime(iopb,dce)
  228.     cntrlParam *iopb;    /*     pointer to parameter block    */
  229.     DCtlPtr dce;        /*     the device control entry    */
  230.     {
  231.     /*    Generally, only 'real' device drivers respond to prime calls    */
  232.     return(0);
  233.     }
  234.     
  235. control(iopb,dce)
  236.     cntrlParam *iopb;    /*     pointer to parameter block    */
  237.     DCtlPtr dce;        /*     the device control entry    */
  238.     {
  239.     GrafPtr ourPort;
  240.     WindowPtr window;
  241.     
  242.     if (validWindow(window = dce->dCtlWindow))
  243.         {
  244.         GetPort(&ourPort);
  245.         SetPort(window);
  246.         
  247.         switch (iopb->csCode)
  248.             {
  249.             case accEvent:
  250.              doEvent(((EventRecord *) * (long *) &iopb->csParam),window);
  251.                     break;
  252.             case accRun:
  253.                     /*
  254.                      * If you are getting time from the system, here's where to 
  255.                      * do your thing.
  256.                      */
  257.                     break;
  258.             case accCursor:
  259.                     break;
  260.             case accMenu:
  261.                     {
  262.                     int menuItem;
  263.                     menuItem = iopb->csParam[1];
  264.                     switch (menuItem)
  265.                         {
  266.                         /* Handle your menu items here╔     */
  267.                         case 1:
  268.                             doAboutBox(window);
  269.                             break;
  270.                         case 2:
  271.                             SysBeep(3); /* this shouldn't ever get called: #2 is a dimmed line*/ 
  272.                             break;        /* but its here for completeness╔ */
  273.                         case 3:
  274.                             SysBeep(3); 
  275.                             break;
  276.                             /* 
  277.                              * There are other menu items in the rsrc file, but we don't
  278.                              * look at them.
  279.                              */
  280.                         default:
  281.                             SysBeep(3); 
  282.                             break;
  283.                     }
  284.                 HiliteMenu(0);
  285.                 break;
  286.                 }
  287.             case accUndo:
  288.                     SysBeep(2);
  289.                     break; 
  290.             case accCut:
  291.                     SysBeep(2); 
  292.                     break; 
  293.             case accCopy:
  294.                     SysBeep(2); 
  295.                     break; 
  296.             case accPaste:
  297.                     SysBeep(2); 
  298.                     break; 
  299.             case accClear:
  300.                     SysBeep(2);
  301.                     break; 
  302.                 }
  303.         SetPort(ourPort);
  304.         }
  305.  return(0);
  306.  }
  307.  
  308. doEvent(event, window)
  309.     EventRecord *event;
  310.     WindowPtr    window;
  311.     {
  312.     SetPort(window);
  313.     switch (event->what)
  314.         {
  315.             case keyDown:
  316.             case autoKey:
  317.                 if ((event->modifiers & cmdKey))
  318.                     {
  319.                     switch ((char) (event->message)) /* command keys (vs. Edit Menu) */
  320.                         {
  321.                         /* These are the standard editing keys - See the Apple Publication
  322.                          * "Human Interface Guidelines"
  323.                          */
  324.                         case 'z':
  325.                         case 'Z':
  326.                             SysBeep(2);
  327.                             break;
  328.                         case 'x':
  329.                         case 'X':
  330.                             SysBeep(2);
  331.                             break;
  332.                         case 'c':
  333.                         case 'C':
  334.                             SysBeep(2);
  335.                             break;
  336.                         case 'v':
  337.                         case 'V':
  338.                             SysBeep(2);
  339.                             break;
  340.                         case 'b':
  341.                         case 'B':
  342.                             SysBeep(2);
  343.                             break;
  344.                         default: /* since this DA doesn't support other CMD keys, just beep */
  345.                             SysBeep(2);
  346.                         }
  347.                     break;
  348.                     } /* the else clause is where you'd handle real typing by the user╔*/
  349.                     return;
  350.             
  351.             case mouseDown:
  352.                     GlobalToLocal(&event->where); 
  353.                     return;
  354.             
  355.             case updateEvt:
  356.                     SetPort(window);
  357.                     BeginUpdate(window);
  358.                     /*    Do update stuff here, for example: */
  359.                     drawOurWindowContents();
  360.                     EndUpdate(window);
  361.                     return;
  362.                     
  363.             case activateEvt:
  364.                     if ((event->modifiers & activeFlag) && (ourMenu != NIL) ) {
  365.                         InsertMenu(ourMenu,0);    /* activate evt. put menu up */
  366.                         DrawMenuBar();
  367.                         }
  368.                     else {
  369.                           if (ourMenu != NIL)    {
  370.                               DeleteMenu(resolveid(refNum,THEMENUID));
  371.                              DrawMenuBar();    /* deactivate evt. take menu down */
  372.                              }
  373.                          }
  374.                          return;
  375.             }
  376.         }
  377.         
  378.         
  379. status(iopb,dce)
  380.     cntrlParam *iopb;    /*     pointer to parameter block    */
  381.     DCtlPtr dce;        /*     the device control entry    */
  382.     {
  383.     /*    Generally, only 'real' device drivers respond to status calls    */
  384.     return(0);
  385.     }
  386.     
  387. close(iopb,dce)
  388.     cntrlParam *iopb;    /*     pointer to parameter block    */
  389.     DCtlPtr dce;        /*     the device control entry    */
  390.     {
  391.    WindowPtr window;
  392.    
  393.      if (validWindow(window = dce->dCtlWindow))
  394.      {
  395.        DeleteMenu(resolveid(refNum,THEMENUID)); /* remove the menu */
  396.        DrawMenuBar();    /* update the menu to reflect present reality */
  397.        dce->dCtlMenu = NIL; /* not really needed, but we'll be complete */
  398.        DisposeWindow(window); /* take down our window */
  399.        dce->dCtlWindow = NIL; /* ttfn (ta-ta-for-now) */
  400.      }
  401.     return(0);
  402.     }
  403.  
  404.  
  405. main(iopb, dce, n)
  406.     cntrlParam *iopb;    /*     pointer to parameter block    */
  407.     DCtlPtr dce;        /*     the device control entry    */
  408.     int    n;                /*    routine selector            */
  409.     {
  410.     
  411.     /*    Make sure that our 'globals' we actually allocated for us.
  412.      *    give up if they weren't.
  413.      */
  414.     if (dce->dCtlStorage == 0) {
  415.         if (n == 0) {    /*  Open, but no data. */
  416.             SysBeep(3);
  417.             CloseDriver(dce->dCtlRefNum);
  418.         }
  419.         return(0);
  420.     }
  421.     /*            Since we're here, we have our globals, now set the flags╔        */
  422.     dce->dCtlFlags |= dNeedLock | dNeedTime; /* see IM-Vol.2 p.188 */
  423.     dce->dCtlDelay = 60;    /* 1 second - 60 ticks    */
  424.     dce->dCtlEMask |= mouseDown | keyDown | autoKey | updateEvt;
  425.  
  426.     switch (n) {
  427.     case drvrOpen:            
  428.             open(iopb,dce);
  429.             break;
  430.     case drvrPrime:
  431.             prime(iopb,dce);
  432.             break;
  433.     case drvrControl:
  434.             control(iopb,dce);
  435.             break;
  436.     case drvrStatus:
  437.             status(iopb,dce);
  438.             break;
  439.     case drvrClose:
  440.             close(iopb,dce);
  441.             break;
  442.         }
  443.     
  444.     }
  445.