home *** CD-ROM | disk | FTP | other *** search
- /*
- *
- * A Generic Desk Accessory written in LightSpeedC¬
- *
- * By David HM Spector
- * Copyright ⌐1986,1987, 1988 All Rights Reserved
- *
- * Permission is granted for unlimited non-commercial use.
- * Permission is granted for commercial use provided credit is given in the
- * desk accessory and its documentation.
- *
- * Donations for continuing development graciously accepted!
- *
- * Please mail suggestions, et al to:
- *
- * US Snail: David HM Spector
- * 310 West 18th St. #5A
- * New York, NY 10011
- *
- * ARPAnet: SPECTOR@NYU.EDU (or SPECTOR@GBA.NYU.EDU)
- * USEnet: ...{allegra, harvard, rocky, ihnp4}!cmcl2!spector
- * CompuServe: 71260,1410
- * MCIMail: DSpector
- *
- *
- * This is a Generic DA written in LightSpeedC¬. I wrote it because I often
- * write DA's, and I hate to start them from scratch each and every time.
- * Gutting other DA's is also, to say the least, a pain. So I decided to write
- * a complete minimal Desk Accessory that would do everything a real DA
- * could do and still be simple to modify and understand. Hence, the GenericDA.
- *
- * Among other things, GenericDA will do the following:
- * Ñ put up its own window
- * Ñ put up its own menu(s) (with an about box)
- * Ñ respond to update events
- * Ñ respond to activate events (including inserting/removing its menu)
- * Ñ respond to keydown/autokey events (you'll have to write your own edit
- * functions though)
- *
- *
- * What you need:
- * 1. LightSpeedC¬ version 1.05 or later.
- * 2. RMaker1.01b1 or later (for the GenericDA.r file) -or- ResEdit1.0 or later
- *
- * Compiling the DA:
- * 1. Make a new project and add this file, and the MacTraps library.
- * 2. Set the project type to "Desk Accessory" (and pick a name).
- * 3. Edit the GenericDA file to use the correct path names for your system
- * 4. Compile and save the DA.
- * 5. Edit the RMaker file to reflect the path name for the name you gave the
- * DA you just compiled.
- * 6. Run the RMaker on the Rmaker file and install the DA with Font/DA Mover.
- *
- *
- *
- * Revision History
- *
- * Date Version Who What
- * 11/8/86 0.0 DHMS Start. Defined routines, added
- * event handler.
- * 0.5 DHMS Added Menus and owned resources
- * 1.0 DHMS Fixed bug in doEvent.[ Forgot to
- * Cast csParam[0] to be (EventRecord *)
- * -- causes an address error...
- * 2/16/88 1.20 DHMS Cleaned up stuff for LSC2.xx, mostly.
- * Removed long path names as LSC2.xx handles
- * includes better.
- * Included the GenericDA.rsrc as well as the old
- * and crufty (blech!) RMaker file. If I can get
- * ResTools from SUMEX--AIM I'll add a ResTools file too.
- * Set the dCtlFlags. (I dunno why I didn't do this
- * before╔musta been late or something.)
- *
- * 2/29/88 1.21 DHMS Added check for NIL menu handle in activate event
- * if ths da has no menu, or menu is lost we won't put
- * junk on the menu bar.
- */
-
-
- /* This covers almost all of the available include files, some of these may
- * not be needed by your Desk Accessory... it would speed compilation to
- * remove all but the ones you need.
- */
- #include <MacTypes.h>
- #include <AppleTalk.h>
- #include <ControlMgr.h>
- #include <DeskMgr.h>
- #include <DeviceMgr.h>
- #include <DialogMgr.h>
- #include <FontMgr.h>
- #include <EventMgr.h>
- #include <HFS.h>
- #include <MemoryMgr.h>
- #include <MenuMgr.h>
- #include <OSUtil.h>
- #include <PackageMgr.h>
- #include <Quickdraw.h>
- #include <ResourceMgr.h>
- #include <StdFilePkg.h>
- #include <TextEdit.h>
- #include <ToolboxUtil.h>
- #include <WindowMgr.h>
-
- /* Misc useful define's */
- #define NIL 0 /* for pointers, etc But note below!*/
- #define NILL 0L /* different from NIL, this is a *LONG* zero */
- /* In fact this is sooo important I'll go further and say that
- * some things that expect 'nil' values are not always coerced into
- * longs. LSC is very good about this, but if Inside Macintosh says
- * to use a pointer or procPointer, and you want to pass a nil, use 0L,
- * its safer and can save you much grief. This used to get me killed
- * in Consulair's Mac C _all the time_.
- */
- #define INFRONT -1 /* for windows */
- #define False 0
- #define True 0xFF
- #define OFF 0 /* RadioButton control values */
- #define ON 1
- #define ACTIVE 0 /* For fiddling with other control states */
- #define INACTIVE 255
- #define plain 0 /* Plain text */
- #define drvrOpen 0
- #define drvrPrime 1
- #define drvrControl 2
- #define drvrStatus 3
- #define drvrClose 4
-
- #define WINDOWTYPE rDocProc /* Lisa style window */
- #define WINDOWTITLE "\pA Generic DA" /* a resource would be a good idea here... */
- #define THEMENUID 1 /* this is a local ID that must be resolved */
- #define ABOUTBOX 1 /* The About╔ box for this DA */
-
-
- Rect windowRect = {50, 20, 200, 220};
- MenuHandle ourMenu = NIL; /* Important safety tip: ALWAYS initialize handles╔ */
- int refNum = 0; /* this is the drivers refnum that is in dce->dCtlRefNum */
-
- /* Routines used by the driver's main routines */
-
- /* This could have been done with a macro, but I often find macros to be
- * cryptic, and often lead the what I call "clever C". I hate to have
- * to clever myself _out_ of corners I've clevered myself into..
- */
- int resolveid(refNum,theid)
- int refNum;
- int theid;
- /* See Inside Macintosh, Vol.I, Pp.109-110 for info on calculating owned IDs */
- {
- return ( ( 0xC000 | (refNum<<5) ) + theid);
- }
-
- char validWindow(window)
- WindowPtr window;
- {
- WindowPtr nextWindow;
-
- if (window)
- {
- nextWindow = FrontWindow();
- while (nextWindow)
- if (window == nextWindow) return (1);
- else nextWindow = (WindowPtr)(((WindowPeek)nextWindow)->nextWindow);
- }
- return 0;
- }
-
- void doAboutBox(window)
- WindowPtr window;
- {
- DialogPtr theDialog;
- int itemHit;
-
- theDialog = GetNewDialog(resolveid(refNum,ABOUTBOX),NIL,INFRONT);
- SetPort(theDialog);
- while (itemHit != 1)
- ModalDialog(NILL, &itemHit);
- CloseDialog(theDialog);
- SetPort(window);
- }
-
- void drawOurWindowContents()
- {
- EraseRect(&thePort->portRect);
- MoveTo(10,10);
- TextFace(monaco);
- TextSize(10);
- DrawString("\pA Customizable Desk Accessory");
- MoveTo(10,30);
- DrawString("\pWritten in LightSpeed¬ C");
- }
-
-
- /* Driver Routines Live Here */
-
- open(iopb,dce)
- cntrlParam *iopb; /* pointer to parameter block */
- DCtlPtr dce; /* the device control entry */
- {
- WindowPtr window;
- GrafPtr oldPort;
-
- refNum = dce->dCtlRefNum;
- if (refNum < 0)
- refNum = -refNum;
- refNum = refNum - 1;
-
- if ((window = dce->dCtlWindow) == 0) /* already have a window? */
- {
- GetPort(&oldPort);/* no, make new one╔ */
- window = NewWindow(0, &windowRect, WINDOWTITLE, 0, WINDOWTYPE,INFRONT, 1, 0);
- SetPort(window);
- ((WindowPeek)window)->windowKind = dce->dCtlRefNum;
- dce->dCtlWindow = window;
-
- ourMenu = GetMenu(resolveid(refNum,THEMENUID));
- /* if we got a handle, then install the menu...see also activate/deactivate event code*/
- if (ourMenu) {
- dce->dCtlMenu = resolveid(refNum,THEMENUID); /*note this is the menu ID, not its handle*/
- InsertMenu(ourMenu,0);
- }
-
- SetPort(oldPort);
- }
- return(0);
- }
-
- prime(iopb,dce)
- cntrlParam *iopb; /* pointer to parameter block */
- DCtlPtr dce; /* the device control entry */
- {
- /* Generally, only 'real' device drivers respond to prime calls */
- return(0);
- }
-
- control(iopb,dce)
- cntrlParam *iopb; /* pointer to parameter block */
- DCtlPtr dce; /* the device control entry */
- {
- GrafPtr ourPort;
- WindowPtr window;
-
- if (validWindow(window = dce->dCtlWindow))
- {
- GetPort(&ourPort);
- SetPort(window);
-
- switch (iopb->csCode)
- {
- case accEvent:
- doEvent(((EventRecord *) * (long *) &iopb->csParam),window);
- break;
- case accRun:
- /*
- * If you are getting time from the system, here's where to
- * do your thing.
- */
- break;
- case accCursor:
- break;
- case accMenu:
- {
- int menuItem;
- menuItem = iopb->csParam[1];
- switch (menuItem)
- {
- /* Handle your menu items here╔ */
- case 1:
- doAboutBox(window);
- break;
- case 2:
- SysBeep(3); /* this shouldn't ever get called: #2 is a dimmed line*/
- break; /* but its here for completeness╔ */
- case 3:
- SysBeep(3);
- break;
- /*
- * There are other menu items in the rsrc file, but we don't
- * look at them.
- */
- default:
- SysBeep(3);
- break;
- }
- HiliteMenu(0);
- break;
- }
- case accUndo:
- SysBeep(2);
- break;
- case accCut:
- SysBeep(2);
- break;
- case accCopy:
- SysBeep(2);
- break;
- case accPaste:
- SysBeep(2);
- break;
- case accClear:
- SysBeep(2);
- break;
- }
- SetPort(ourPort);
- }
- return(0);
- }
-
- doEvent(event, window)
- EventRecord *event;
- WindowPtr window;
- {
- SetPort(window);
- switch (event->what)
- {
- case keyDown:
- case autoKey:
- if ((event->modifiers & cmdKey))
- {
- switch ((char) (event->message)) /* command keys (vs. Edit Menu) */
- {
- /* These are the standard editing keys - See the Apple Publication
- * "Human Interface Guidelines"
- */
- case 'z':
- case 'Z':
- SysBeep(2);
- break;
- case 'x':
- case 'X':
- SysBeep(2);
- break;
- case 'c':
- case 'C':
- SysBeep(2);
- break;
- case 'v':
- case 'V':
- SysBeep(2);
- break;
- case 'b':
- case 'B':
- SysBeep(2);
- break;
- default: /* since this DA doesn't support other CMD keys, just beep */
- SysBeep(2);
- }
- break;
- } /* the else clause is where you'd handle real typing by the user╔*/
- return;
-
- case mouseDown:
- GlobalToLocal(&event->where);
- return;
-
- case updateEvt:
- SetPort(window);
- BeginUpdate(window);
- /* Do update stuff here, for example: */
- drawOurWindowContents();
- EndUpdate(window);
- return;
-
- case activateEvt:
- if ((event->modifiers & activeFlag) && (ourMenu != NIL) ) {
- InsertMenu(ourMenu,0); /* activate evt. put menu up */
- DrawMenuBar();
- }
- else {
- if (ourMenu != NIL) {
- DeleteMenu(resolveid(refNum,THEMENUID));
- DrawMenuBar(); /* deactivate evt. take menu down */
- }
- }
- return;
- }
- }
-
-
- status(iopb,dce)
- cntrlParam *iopb; /* pointer to parameter block */
- DCtlPtr dce; /* the device control entry */
- {
- /* Generally, only 'real' device drivers respond to status calls */
- return(0);
- }
-
- close(iopb,dce)
- cntrlParam *iopb; /* pointer to parameter block */
- DCtlPtr dce; /* the device control entry */
- {
- WindowPtr window;
-
- if (validWindow(window = dce->dCtlWindow))
- {
- DeleteMenu(resolveid(refNum,THEMENUID)); /* remove the menu */
- DrawMenuBar(); /* update the menu to reflect present reality */
- dce->dCtlMenu = NIL; /* not really needed, but we'll be complete */
- DisposeWindow(window); /* take down our window */
- dce->dCtlWindow = NIL; /* ttfn (ta-ta-for-now) */
- }
- return(0);
- }
-
-
- main(iopb, dce, n)
- cntrlParam *iopb; /* pointer to parameter block */
- DCtlPtr dce; /* the device control entry */
- int n; /* routine selector */
- {
-
- /* Make sure that our 'globals' we actually allocated for us.
- * give up if they weren't.
- */
- if (dce->dCtlStorage == 0) {
- if (n == 0) { /* Open, but no data. */
- SysBeep(3);
- CloseDriver(dce->dCtlRefNum);
- }
- return(0);
- }
- /* Since we're here, we have our globals, now set the flags╔ */
- dce->dCtlFlags |= dNeedLock | dNeedTime; /* see IM-Vol.2 p.188 */
- dce->dCtlDelay = 60; /* 1 second - 60 ticks */
- dce->dCtlEMask |= mouseDown | keyDown | autoKey | updateEvt;
-
- switch (n) {
- case drvrOpen:
- open(iopb,dce);
- break;
- case drvrPrime:
- prime(iopb,dce);
- break;
- case drvrControl:
- control(iopb,dce);
- break;
- case drvrStatus:
- status(iopb,dce);
- break;
- case drvrClose:
- close(iopb,dce);
- break;
- }
-
- }
-