bill@utastro.UUCP (William H. Jefferys) (03/14/85)
# This is a shar archive. Extract with sh, not csh. echo x - SKEL.R cat > SKEL.R << '!Funky!Stuff!' * SkelR -- Resource definition file for small skeleton application * Written by Steve Maker * Modified for Macintosh RMaker program * by Bill Jefferys 3/8/85 * Tell RMAKER what to name the resource file * It is most convenient during the development cycle to append * the resources to a.out, which is the standard output file from * the Megamax C compiler (v. 1.2) !a.out APPLSKEL * Version data for the finder * Our signature is "SKEL" * res. ID = 0, by convention * finder version data * Note that the blank in 'STR ' is significant 3/8/85 WHJ TYPE SKEL = STR ,0 Skel 2.2C -- Mar 11, 1985 * Menus * ID (4 => pre-load the resource; MUST NOT be purgeable!) * menu title: an Apple symbol (in hex) for the Apple menu. * menu entries, one per line. ( means it's initially disabled. * An entry of (- means a disabled line of dashes. * A trailing /Q means a command-key equivalent. * blank line at end of menu. Type MENU ,1(4) \14 About Skel (- Type MENU ,2(4) File Rattle Frighten (- Quit/Q * A Window template * ID,(4 => pre-load the resource; 32 => purgeable) * title * BoundsRect (global Top, Left, Bottom, Right): where it appears on the screen * Vis NoGo: it's visible, does not have close box * ProcId: this is a standard type of window * Refcon, for program's use. Skel doesn't use it. Type WIND ,260(36) A Skeleton Application 85 128 256 384 Visible NoGoAway 0 0 * Strings (kept here for ease of change) * ID,(4 => pre-load the resource) * A string for "About Skel" * Rattle string * Frighten String type STR ,1(4) Skel 2.2 by Steve Maker; Version 2.2C by Bill Jefferys 3/11/85 ,2(4) Too tired to Rattle them bones. ,3(4) Boo! * dialog box for Report * ID (4 => pre-load the resource; MUST NOT be purgeable!) * title * BoundsRect(global: TLBR) * Vis NoGo: it's visible, but has no close box * ProcID: Window type is modal dialog * RefCon: Unused user variable * res. ID of item list Type DLOG ,257(4) Report Box 80 20 131 492 Visible NoGoAway 1 0 257 * dialog item list for Report * ID (4 => pre-loaded; 32 => purgeable - it should always be purgeable.) * # Items * the first item: * a Button you can select * display rect (local coords) * title * the second item: * Static text, disabled (i.e. can't select it) * display rect * text to be set by ParamText Type DITL ,257(36) 2 button Enabled 25 186 46 286 OK staticText Disabled 5 25 20 450 ^0 **************************************************************************** **** This section contains information for the Finder; **** **** the program SKEL never accesses this information directly. **** **** The entire section can be omitted from the first versions **** **** of a program (you must then set the application's type to **** **** APPL, the creator to ????, and don't set the bundle bit); **** **** the default application icon will be used. **** **** For more info, read "Putting together a Mac Application" **** **** and "The Structure of a Mac Application". **** * * To make the finder show your application's special icon on the desktop, * make documents of your type show their icons, make an * application start when a document is opened, * and move all files associated with your application * when a copy is done, you must: * For documents of new types: * - set the document's type to the new type (here BONE) * (often the program that creates them will do this) * - if you want the application to start when a document file * is opened, set the file's creator to the signature of * the application, here SKEL; otherwise, to ????. * For the application: * - set the application's type to APPL ("it's an application") * - set the creator to its signature, here SKEL * - set the bundle bit. This tells the finder that it should read * this info from the SKEL resource file and use it when displaying * SKEL's icon. * If you use SendOne, these items will have to be set with SetFile the first * time, and then not again; if you use MacCom, they are set every time * (usually in the exec file). * If you change the icon, the change may not have effect on the desktop, * until you reboot with the command and option keys held down. This tells * the Finder to reconstruct the desktop; the correct icons will be displayed, * but all folders will be lost. * a Bundle: contains references to other finder info, (below) * ID (32 => purgeable) * Bundle owner: SKEL (our signature), Res ID of version data = 0 * "ICN#" (means icon list), # of icon resources in bndl = 2 * local ID 0 maps to global ID 128 (the FREF uses a local ID, to refer to * an icon which has a global ID. See the FREF resource, below); * local ID 1 maps to global ID 129 * "FREF" (means file reference), # of FREF res in bndl = 2 * local ID 0 maps to global ID 128; local ID 1 maps to global ID 129 Type BNDL ,128(32) SKEL 0 ICN# 2 0 128 1 129 FREF 2 0 128 1 129 * a File Reference * ID, (32 => purgeable) * "APPL" : a file of type APPL (SKEL itself) gets the following icon (a skull); * local icon ID; maps to global ID as specified in BNDL * name of file that must accompany application if transferred; omit if none. Type FREF ,128(32) APPL 0 * Another File Reference * ID, (32 => purgeable) * "BONE" : a file of type BONE gets the following icon (crossbones); local icon ID * no filename Type FREF ,129(32) BONE 1 * An icon list for the application icon (a skull) * ID (the application icon), (32 => purgeable) * Data is Hex data (.H) * the icon data: 32 lines of 8 hex chars each * the icon mask: 32 lines of 8 hex chars each Type ICN# = GNRL ,128(32) .H 001F F000 01E0 0F00 0700 01C0 0C00 0060 1878 3C30 10CC 6610 3184 4318 2104 4108 2104 4108 218C 6308 20F8 3E08 3000 0018 1000 0010 0800 0020 0402 8040 0302 8180 0182 8300 0082 8200 0040 0400 0040 0400 0040 0400 004F E400 005B B400 005B B400 007F FC00 0020 0800 0030 1800 0018 3000 0007 E000 0000 0000 0000 0000 0000 0000 001F F000 01FF FF00 07FF FFC0 0FFF FFE0 1FFF FFF0 1FFF FFF0 3FFF FFF8 3FFF FFF8 3FFF FFF8 3FFF FFF8 3FFF FFF8 3FFF FFF8 1FFF FFF0 0FFF FFE0 07FF FFC0 03FF FF80 01FF FF00 00FF FE00 007F FC00 007F FC00 007F FC00 007F FC00 007F FC00 007F FC00 007F FC00 003F F800 003F F800 001F F000 0007 E000 0000 0000 0000 0000 0000 0000 * An icon list for a file of type BONE (crossbones) * ID (the icon for BONE files), (32 => purgeable) * Data is Hex data (.H) * the icon data: 32 lines of 8 hex chars each * the icon mask: 32 lines of 8 hex chars each ,129(32) .H 03C0 00F0 0660 0198 0430 0308 1C30 030E 3020 0103 2030 0301 2018 0601 300C 0C03 1F06 183E 0D83 306C 00C1 E0C0 0060 C180 0030 6300 0018 3600 000C 1C00 000E 0C00 001B 0600 0031 8300 0060 C180 00C1 E0C0 0183 3060 0306 1830 1E0C 0C1E 3018 0603 2030 0301 2060 0181 2040 0081 2040 0081 3040 0083 18C0 00C6 0F80 007C 0000 0000 03C0 00F0 07E0 01F8 07F0 03F8 1FF0 03FE 3FE0 01FF 3FF0 03FF 3FF8 07FF 3FFC 0FFF 1FFE 1FFE 0DFF 3FEC 00FF FFC0 007F FF80 003F FF00 001F FE00 000F FC00 000F FC00 001F FE00 003F FF00 007F FF80 00FF FFC0 01FF 3FE0 03FE 1FF0 1FFC 0FFE 3FF8 07FF 3FF0 03FF 3FE0 01FF 3FC0 00FF 3FC0 00FF 3FC0 00FF 1FC0 00FE 0F80 007C 0000 0000 **** end of information for the finder **** *********************************************************************** !Funky!Stuff! echo x - SKEL.c cat > SKEL.c << '!Funky!Stuff!' /* PROGRAM Skel; Original Lisa Pascal version written by Steve Maker Academic Computing Kiewit Computation Center Dartmouth College July 14, 1984 Translated for Megamax C compiler by Bill Jefferys Astronomy Department University of Texas Austin TX 78712 March 11, 1985 Copyright notice: SKEL may be copied and used by anyone, so long as that use is not for commercial purposes. Please send significant changes back to Steve Maker for incorporation into future versions. Why SKEL? Skel is a skeleton demo program. Its purpose is to illustrate in a clear fashion, isolated from any particular application, the basic code for handling a simple Macintosh user interface. It strives to be correct as far as it goes, without many short-cuts that would lead to trouble in larger applications. I think of SKEL as a program that does nothing, but does it well. What does SKEL do? It handles: Events, carefully handling only those which are its business, and passing the others on to their respective handlers. A Window, which is filled with Dark Gray, and can be activated or inactivated, updated, dragged and grown but NOT scrolled or closed. Menus, including the Apple Menu. An "About Skel" menu entry is provided. A File menu offers Rattle and Frighten, which just invoke dialog boxes, and Quit. Command key equivalents are supported. The Desk Accessories, supported in the Apple menu, and correctly meshed with the other features. NOT supported are Undo, Cut, Copy, Paste and Clear (and keyboard equivalents) for desk accessories. A Modal Dialog Box, used to communicate with the user. Special icons for the application and its related files. The Finder information (in the resource file). In accordance with Macintosh guidelines, everything possible is kept in the resource file: window description, menus, dialog specification, and the "About Skel" and other strings. In addition, the resource file handles the Bundle, File References, and Icons that determine what Skel's icon looks like, and other information for the Finder. How do I use SKEL? Study it. Modify it to test your knowledge. Steal working pieces of code for your own programs. Beat on it. Subject it to cruel and unusual experiments. Pay heed to its warnings. What do I study first in SKEL? Initially you should ignore several sections of SKEL, and the calls made to them. I recommend X-ing them out in your listing. The sections to ignore on the first round of study are: Report: ignore the implementation SetUpMemory: ignore all of it DrawWindow: ignore the scroll bar and grow icon handling ReSize: ignore all of it DoCommand: ignore the Desk Accessory handling in the Apple Menu MainEventLoop: MouseDown handling: ignore inSysWindow, inDrag, inGrow keyDown, autoKey handling: ignore this. In the resource definition file, SKEL.R: Finder information (offset by asterisks): ignore this whole section, icons and all. What should I read in Inside Macintosh? You should read the following sections of Inside Macintosh, in the order given. At first, just lightly skim the sections with parenthesized names. Read the others in some depth. Read the starred (*) ones in great detail. Eventually, you will have to read all sections thoroughly, and many many times, I promise you. To start: * Inside Macintosh: A Road Map (User Interface Guidelines) Structure of a Macintosh Application * Putting Together a Macintosh Application Then, (low-level sections are listed first): * Memory Mgr Intro (Memory Mgr) * Resource Mgr (through "Using the Resource Mgr") * QuickDraw (Desk Mgr) * Event Mgr (through "Event Mgr routines") Window Mgr Menu Mgr (Dialog Mgr) How do I get SKEL to run? With Version 1.2 of the Megamax Compiler, compile and link the application as usual, obtaining an application a.out with the standard application icon. Run RMaker, and click on SKEL.R as the input file. RMaker appends the resource information to the file a.out (a.out is specified by name in SKEL.R!) I have not been able to transfer from the linker directly to RMaker unless RMaker is on the same disk as the linker; furthermore, RMaker will not work unless a.out is on the same disk as RMaker. What is the history of SKEL? v1.0 July 14, 1984 sm: major revision of earlier version Sept 30, 1984 sm: used \14 for apple symbol in res. file, bracketed OpenDeskAcc with Get and SetPort, Oct 11, 1984 sm: changed FREF, BNDL resources from HEXA to readable, nested some routines in SKEL, added constants for FILE menu items, v2.0 Nov 12, 1984 sm: made resources pre-loaded and/or purgeable, turned off range-checking, documented no Resume proc passed to InitDialogs, added SetUpMemory: calls MoreMasters, MaxApplZone, sets the NIL address to -1, lots of general memory doc. added a warning about passing doubly- dereferenced handles, removed en/disabling of Rattle and Frighten items, v2.1 Dec 4, 1984 sm: added menu key handling, put Rattle and Frighten strings in res file, rewrote intro documentation v2.2 Mar 6, 1985 sm: converted to % describes, fixed SKELX for both 2.0 and 3.0 workshop, set the event mask v2.2C Mar 11, 1985 sm: converted to Megamax "C"; future Megamax "C" version numbers will have the same version number as the corresponding Pascal version, but with an appended "C". */ /* .h files needed by skeleton */ #include <mem.h> /* use type defs in MemTypes unit */ #include <qd.h> /* Search "Obj/Quickdraw" for */ #include <win.h> /* the "QuickDraw" unit, etc. */ #include <qdvars.h> #include <os.h> #include <menu.h> #include <event.h> #include <te.h> #include <stdio.h> #include <dialog.h> /* #include <pack.h>; {these are not needed for SKEL,} #include <math.h>; { but may be useful later.} I don't know what Megamax C statements correspond to the following three Pascal statements (WHJ): {$U Obj/Elems } Elems, {Assume normal SANE, not SANELIB} {$U Obj/Graf3D } Graf3D, {$U Obj/MacPrint } MacPrint; */ /* The following two constants are not defined in any .h file. They are described in "Inside Macintosh" - Event Manager, pp. 14-15. */ #define charcodemask 255 #define cmdkey 256 #define lastmenu 2 /* number of menus */ #define applemenu 1 /* menu ID for desk accessory menu */ #define filemenu 2 /* menu ID for File menu */ #define irattle 1 /* items in the File menu */ #define ifrighten 2 /*-------*/ #define iquit 4 #define aboutskelid 1 /* Resource ID of the string */ #define rattleid 2 #define frightenid 3 #define windowid 260 /* Resource ID for my window */ grafptr screenport; /* a port for the whole screen */ windowptr mywindow; /* our one window */ windowrecord wrecord; /* storage for window record */ rect dragrect; /* rect to drag within */ rect growrect; /* bounds for the growth of the windows */ menuhandle mymenus[lastmenu + 1];/* our menus */ eventrecord myevent; windowptr whichwindow; /* points to window of MouseDown */ int windowcode; /* what mouse was in when event posted */ boolean userdone; /* true when user wants to exit program */ /* Print a string in dialog box ############################ Report ################################# We put up a dialog box, show the string, and wait for user to hit OK. */ report (reportstr) char *reportstr; #define rptboxid 257 /* ID of our report dialog in resource file */ #define rpttext 2 /* Item # of dialog's report text */ { int itemhit; /* which Item was clicked on (only OK avail) */ dialogptr reportptr; /* WARNING: paramtext assumes that the strings passed to it are Pascal-type, byte-encoded strings, instead of C-type, NULL-terminated strings. This works here for two reasons: First, getstring() returns a handle to the resource, which is in the proper format; and second, the Pascal and C style empty strings happen to look the same - WHJ 3/11/85 Exercise: Modify Report so that it displays an internally generated string instead of a string obtained from the resource fork. Be careful! This is pretty straightforward, but you can get stung! */ paramtext (reportstr, "", "", "");/* set text to display */ reportptr = getnewdialog (rptboxid, NULL, (long) - 1); /* get from Resource file; NIL => use heap storage; -1 => make dlg frontmost */ modaldialog (NULL, &itemhit); /* carry out dialog; NIL => no FilterProc; return item Hit when done */ disposdialog (reportptr); /* release storage and remove dialog from screen */ } /* Report */ /* SetUps for handling memory ########################## SetUpMemory ############################ This very important set of initializations can be left out of the first versions of a program. We are making sure that memory is laid out as we desire, with adequate protection against running out of memory, bad handles, etc. */ setupmemory () { #define maxStackSize 8192 /* max size of stack; the heap gets the rest */ typedef long *lomemptr; /* a pointer to low memory locations */ lomemptr nilptr; /* will have value NIL */ lomemptr stackbaseptr; /* points to current stack base */ /* If you define a GrowZone function to handle bad memory problems, you should define it at the top level (not nested), and set it here. We don't. */ /* setgrowzone(&mygrowzone); */ /* Place a longint -1 (an odd and therefore illegal address) in the memory location that would be referenced by an accidentally-NULL handle, so the error will be caught at handle-reference time (as an Address error, ID=02) instead of later on. */ nilptr = NULL; *nilptr = -1; /* If you needed to use an Application heap limit other than the default (which allows 8K for the stack), you'd set it here, possible using this technique of explicitly specifying the maximum stack size and allocating the rest to the heap. Should be independent of memory size. */ stackbaseptr = (lomemptr) 0x908; /* CurStackBase from Tlasm/sysequ.text */ setappllimit ((ptr) (*stackbaseptr - maxStackSize)); /* Expand the application heap zone to its maximum size, without purging any purgeable resources. This saves memory compactions and heap expansions later. */ maxapplzone (); /* get plenty of master pointers now; if we let the Memory Manager allocate them as needed, they'd form non-relocatable islands in the heap. */ moremasters (); moremasters (); moremasters (); /* Here you might install bulwarks against running out of memory unexpectedly. One such (cheesy) technique is to here allocate a large handle, call it "CheeseBuf", which you can de-allocate in your GrowZone function, when you must obtain more memory to avoid a crash. While de-allocated, the program could prevent the user from doing anything requiring memory, and tell him he must discard windows or some such memory freeing action. Each time he does so, the program can try to re-allocate CheeseBuf; if it succeeds, the user can go on doing memory-eating operations. */ } /* SetUpMemory */ /* ############################ SetUpMenus ############################# Once-only initialization for menus We read in all menus from the resource file, and install them, and all desk accessories (drivers). */ setupmenus () { int i; for (i = 1; i <= lastmenu; i++)/* get all my menus in */ mymenus[i] = getmenu (i);/* use the fact that our menu ID's start at 1 */ addresmenu (mymenus[applemenu], "DRVR"); /* pull in all desk accessories */ for (i = 1; i <= lastmenu; i++) insertmenu (mymenus[i], 0);/* insert menus; 0 => put at end */ drawmenubar (); } /* body of SetUp Once-only initialization for Skel ############################ SetUp ############################## Initialize our program. It seems best to handle: Memory inits first, ToolBox inits second, then the program variables' inits. Note that the order of inits is important; see "Using the Dialog Manager" in the Dialog Mgr section. */ setup () { /* The following function is not defined in <win.h>, although that is where you would expect it. - WHJ 3/10/85 */ extern windowptr getnewwindow (); rect screenrect; /* size of screen; could be machine-dependent */ setupmemory (); /* init memory layout and protection */ /* init QuickDraw, and everybody else */ initgraf (&theport); initfonts (); initwindows (); initmenus (); teinit (); initdialogs (NULL); /* NULL => no Restart proc; see Dialog Mgr and System Error Handler */ initcursor (); /* Init the system event mask, in case the previous program left it in a bad state. If you set it non-standard here, FIX IT BEFORE EXITING, because the Finder (1.1g) does NOT set it. */ seteventmask (everyevent - keyupmask);/* standard setting */ /* Get the port which is the whole screen, to use when deactivating our window. This prevents the current grafPort pointer from ever dangling. */ getwmgrport (&screenport); /* get whole screen port that window mgr uses */ setport (screenport); /* and start off with it */ /* get window: use wRecord storage. Port is set to that of the new window. GetNewWindow posts an update event for the new window, so it will be redrawn right away. */ mywindow = getnewwindow (windowid, &wrecord, (long) - 1); /* -1 => frontmost window */ /* set up dragRect; we can drag the window within it */ screenrect.a.top = screenbits.bounds.a.top; /* don't assume screen size */ screenrect.a.left = screenbits.bounds.a.left; screenrect.a.bottom = screenbits.bounds.a.bottom; screenrect.a.right = screenbits.bounds.a.right; /* set drag rect to avoid menu bar, and keep at least 4 pixels on screen */ setrect (&dragrect, 4, 24, screenrect.a.right - 4, screenrect.a.bottom - 4); /* set up GrowRect, for limits on window growing */ setrect (&growrect, 48, 14, screenrect.a.right - 7, screenrect.a.bottom - 7); /* pull in and set up our menus */ setupmenus (); } /* Redraw my window ############################ DrawWindow ############################# We draw all the contents of our one window, myWindow. Note that this must include scroll bar areas and the grow icon; the Window Manager will NOT handle those for us. Since there are no scroll bars, we must erase the region they would be in. Echh. */ drawwindow () { rect arect; /* rectangle to erase */ fillrect (&mywindow -> portrect, &dkgray); /* first, fill the window with dark gray; this fills scroll bars, too */ /* second, erase the scroll bars and draw the grow icon */ /* erase the horizontal scroll bar */ setrect (&arect, /* cover the horizontal bar */ mywindow -> portrect.a.left, mywindow -> portrect.a.bottom - 15, mywindow -> portrect.a.right - 15, mywindow -> portrect.a.bottom); fillrect (&arect, &white); /* fill with white */ /* erase the vertical scroll bar */ setrect (&arect, /* cover the vertical bar */ mywindow -> portrect.a.right - 15, mywindow -> portrect.a.top, mywindow -> portrect.a.right, mywindow -> portrect.a.bottom - 15); fillrect (&arect, &white); /* fill with white */ drawgrowicon (mywindow); /* draw the size box in the corner of the window */ } /* DrawWindow */ /* Update the contents of the given window ############################ UpdateWindow ########################## This is our response to receipt of an update event for myWindow. Since the window is likely to be inactive, the current grafPort will be elsewhere. We must change it for drawing, yet leave it as it was. */ updatewindow (awindow) windowptr awindow; { grafptr saveport; /* to save and restore the old port */ beginupdate (awindow); /* reset ClipRgn etc to only redraw what's necessary. */ getport (&saveport); /* don't trash the port; we might be updating an inactive window */ setport (awindow); /* work in the specified window */ drawwindow (); /* redraw contents of window */ setport (saveport); /* all nice and tidy as before */ endupdate (awindow); } /* UpdateWindow */ /* handle a command given through a menu selection ############################ DoCommand ############################## We carry out the command indicated by mResult. If it was Quit, we return true, else false. Since the menu was highlighted by MenuSelect, we must finish by unhighlighting it to indicate we're done. */ int docommand (mresult) long mresult; { int refnum; int themenu, theitem; char name[255]; grafptr saveport; /* for saving current port in when opening a desk accessory */ stringhandle astr; /* a utility string */ int returns; returns = 0; /* assume Quit not selected */ themenu = hiword (mresult); /* get the menu selected */ theitem = loword (mresult); /* ... and the item of that menu */ switch (themenu) { case 0: break; /* user made no selection; do nothing */ case applemenu: if (theitem == 1) { /* get string, and tell about Skel */ /* It's important not to pass Report a de-referenced handle; if Report were in another segment, loading it could cause a memory compaction; the de-referenced handle could become invalid. Watch out for this and similar nasties everywhere in your program. See the Memory Manager and the Segment Loader. */ astr = getstring (aboutskelid); /* WARNING! getstring returns handle to Pascal-style string! - WHJ 3/10/85 */ report (*astr); } else { /* run a desk accessory; make sure port is preserved */ getport (&saveport); getitem (mymenus[applemenu], theitem, name); /* get name */ refnum = opendeskacc (name);/* run the desk accessory */ setport (saveport); } break; case filemenu: switch (theitem) { case irattle: /* Rattle */ astr = getstring (rattleid); /* WARNING! getstring returns handle to Pascal-style string! - WHJ */ report (*astr); break; case ifrighten: /* Frighten */ astr = getstring (frightenid); /* WARNING! getstring returns handle to Pascal-style string! - WHJ */ report (*astr); break; case iquit: returns = 1;/* Quit */ } /* fileMenu case */ } /* menu case */ hilitemenu (0); /* turn off hilighting on the menu just used */ return (returns); } /* DoCommand */ /* Change the size of the given window ############################ ReSize ############################### Called on a mouse-down in the grow box, this allows the user to change the size of the window. We change the size, then claim that the whole of the window contents is no longer validly drawn, because we're too lazy to do so for just the scroll bar regions that are actually subject to change. See the Window Manager. */ resize (a_window, downpt) windowptr a_window; point * downpt; { int w, h; /* new width and height of the sized window */ long newsize; /* the new size */ newsize = growwindow (a_window, downpt, &growrect); /* find new size */ w = loword (newsize); /* find the width */ h = hiword (newsize); /* find the height */ sizewindow (a_window, w, h, 1);/* change to the new window size */ /* place whole window into update region to be sure it all gets updated. This is more than is strictly necessary, but a lot easier than just invalidating the regions that actually may have changed. */ invalrect (&a_window -> portrect); } /* ReSize */ /* the main loop that handles events ############################ MainEventLoop ########################## Brace yourself: here's where the action is. Most Mac programs just wait for events (as do we all), and then process them. There are two sorts of events: those directly initiated by the user, like key presses and mouse-downs, and those consequent events posted by the Event Manager, like update and activate events. The latter MUST be handled correctly and carefully. In particular, it's important for all events to make sure that the event occurred in or for the window you expect -- it's possible to get events which are not for one of our windows, despite GetNextEvent's return value. Similarly, be sure to check that the window it occured in is the active one, if it matters. A common mistake in handling update and activate events is in finding out which window they are for. It is "(windowptr)myevent.message " that gives this information, NOT "whichwindow" (the WindowPtr returned by FindWindow). The latter pointer merely tells you what window the mouse was in at the time the event was posted -- completely irrelevant for Update and Activate events. Think it through carefully. */ maineventloop () { /* body of MainEventLoop */ flushevents (everyevent, 0);/* discard leftover events */ /* get next event, and handle it appropriately, until user QUITs */ userdone = 0; do { systemtask (); /* handle desk accessories */ if (getnextevent (everyevent, &myevent)) { /* get event; if for us... */ switch (myevent.what) {/* handle each kind of event */ case mousedown: /* find out what window the mouse went down in, and where in it */ windowcode = findwindow (&myevent.where, &whichwindow); switch (windowcode) { /* handle mouse-down for each place */ case insyswindow: /* handle the desk accessories */ systemclick (&myevent, whichwindow); break;/* insyswindow */ case inmenubar: /* handle the command */ userdone = docommand (menuselect (&myevent.where)); break;/* inmenubar */ case indrag: /* drag the window */ dragwindow (whichwindow, &myevent.where, &dragrect); break; case incontent: /* includes inGrow if window inactive. Activate window */ if (whichwindow = mywindow) /* make sure it's for mine */ if (whichwindow != frontwindow ()) selectwindow (whichwindow); /* make it active */ break; case ingrow: /* window is already active; change its size */ if (whichwindow = mywindow) /* moke sure it's for mine */ resize (mywindow, &myevent.where); break;/* ingrow */ case ingoaway: /* we don't have a GoAway region */ /* break; I got a compiler error here with the break left in. Good C programming style would have a break even after the last case - WHJ 3/11/85 */ } break; /* switch */ case keydown: case autokey: /* if command key, pass the char to MenuKey */ if ((myevent.modifiers & cmdkey) != 0) userdone = docommand (menukey ((char) (myevent.message & charcodemask))); case updateevt: /* if it's for our window, update it */ if ((windowptr) (myevent.message) == mywindow) updatewindow (mywindow); /* redraw the window contents */ break; case activateevt: /* if for our window, set port as nec. */ if ((windowptr) (myevent.message) == mywindow) { /* my window */ drawgrowicon (mywindow); /* redraw grow icon to reflect new state */ if (myevent.modifiers & 1) /* odd means an activate event */ setport (mywindow); /* activate evt: work in our own port */ else setport (screenport); /* deactivate evt: our port is gone; keep port from dangling */ } break; } } } while (userdone == 0); } /* body of Skel */ main () { setup (); maineventloop (); } !Funky!Stuff! -- "Men never do evil so cheerfully and so completely as when they do so from religious conviction." -- Blaise Pascal Bill Jefferys 8-% Astronomy Dept, University of Texas, Austin TX 78712 (USnail) {allegra,ihnp4}!{ut-sally,noao}!utastro!bill (uucp) bill%utastro.UTEXAS@ut-sally.ARPA (ARPANET)