dubois@uwmacc.UUCP (Paul DuBois) (12/01/86)
#!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # TransSkel.c # # MODERATOR'S NOTE: Tab-width is 4 # sed 's/^X//' << 'SHAR_EOF' > TransSkel.c X/* X TransSkel version 1.02 - Transportable application skeleton X X TransSkel is public domain and is written by: X X Paul DuBois X Wisconsin Regional Primate Research Center X 1220 Capital Court X Madison WI 53706 USA X X UUCP: allegra,ihnp4,seismo}!uwvax!uwmacc!dubois X ARPA: dubois@unix.macc.wisc.edu X dubois@rhesus.primate.wisc.edu X X This version of TransSkel written for LightspeedC. LightspeedC is a X trademark of: X THINK Technologies, Inc X 420 Bedford Street Suite 350 X Lexington, MA 02173 USA X X History X 06/13/86 Beta version. X 08/27/86 Version number changed to 1.01. X v1.0 DoGrow bug fixed - the port at the point of the X InvalRect could have been anything; the fix is to set X the port to the grown window first. This also explains X why the kludge to DoActivate in v1.0 worked. X 10/02/86 Version number changed to 1.02, as a result of adding X modifications by David W. Berry (well!dwb@lll-lcc.arpa) X for supporting window zooming. Also used his modifications X for supporting modeless dialogs (though not in the same X form). Dialogs can be #define'd on or off. X*/ X X X/* X The following symbol controls support for dialogs. X Changing #define to #undef disables the support. X*/ X X# define supportDialogs X X X# ifdef supportDialogs X# include <DialogMgr.h> X# else X# include <WindowMgr.h> X# endif X X# include <EventMgr.h> X# include <MenuMgr.h> X X X# define nil 0L X# define mBarHeight 20 /* menu bar height. All window sizing X code takes this into account */ X X X/* X This window zooming stuff may need to be removed if/when Think X supports it in the compiler. X*/ X Xpascal short TrackBox() = 0xa83b; /* declare traps */ Xpascal void ZoomWindow() = 0xa83a; X Xenum /* declare part codes */ X{ X inZoomIn = 7, X inZoomOut X}; X X X X/* X New(TypeName) returns handle to new object, for any TypeName. X If there is insufficient memory, the result is nil. X*/ X X# define New(x) (x **) NewHandle ((Size) sizeof (x)) X X X/* X Window and Menu handler types, constants, variables. X X whList and mhList are the lists of window and menu handlers. X whClobOnRmve and mhClobOnRmve are true if the handler disposal proc X is to be called when a handler is removed. They are temporarily set X false when handlers are installed for windows or menus that already X have handlers - the old handler is removed WITHOUT calling the X disposal proc. X X Default lower limits on window sizing of 80 pixels both directions is X sufficient to allow text windows room to draw a grow box and scroll X bars without having the thumb and arrows overlap. These values may X be changed if such a constraint is undesirable with SkelGrowBounds. X Default upper limits are for the Macintosh, not the Lisa, but are set X per machine in SkelInit. X*/ X Xtypedef struct WHandler X{ X WindowPtr whWind; /* window/dialog to be handled */ X ProcPtr whClobber; /* data structure disposal proc */ X ProcPtr whMouse; /* mouse-click handler proc */ X ProcPtr whKey; /* key-click handler proc */ X ProcPtr whUpdate; /* update handler proc */ X ProcPtr whActivate; /* activate event handler proc */ X ProcPtr whClose; /* close "event" handler proc */ X ProcPtr whIdle; /* main loop proc */ X# ifdef supportDialogs X ProcPtr whEvent; /* event proc */ X# endif X Rect whGrow; /* limits on window sizing */ X Boolean whSized; /* true = window was resized */ X Boolean whFrontOnly; /* true = idle only when active */ X struct WHandler **whNext; /* next window handler */ X} WHandler; X Xstatic WHandler **whList = nil; Xstatic Boolean whClobOnRmve = true; Xstatic Rect growRect = { 80, 80, 512, 342 - mBarHeight }; X X Xtypedef struct MHandler X{ X int mhID; /* menu id */ X ProcPtr mhSelect; /* item selection handler proc */ X ProcPtr mhClobber; /* menu disposal handler proc */ X struct MHandler **mhNext; /* next menu handler */ X} MHandler; X X Xstatic MHandler **mhList = nil; /* list of menu handlers */ Xstatic Boolean mhClobOnRmve = true; X X X/* X Variables for default Apple menu handler. appleID is set to 1 if X SkelApple is called and is the id of the Apple menu, appleAboutProc X is the procedure to execute if there is an About... item and it's X chosen from the Apple menu. If doAbout is true, then the menu X contains the About... item, otherwise it's just desk accessories. X*/ X Xstatic MenuHandle appleMenu; Xstatic int appleID = 0; Xstatic ProcPtr appleAboutProc = nil; Xstatic Boolean doAbout = false; X X X/* X Miscellaneous X X screenPort points to the window manager port. X X doneFlag determines when SkelMain returns. It is set by calling X SkelWhoa(), which the host does to request a halt. X X pBkgnd points to a background procedure, to be run during event X processing. Set it with SkelBackground. If nil, there's no X procedure. X X pEvent points to an event-inspecting hook, to be run whenever an X event occurs. Set it with SkelEventHook. If nil, there's no X procedure. X X eventMask controls the event types requested in the GetNextEvent X call in SkelMain. X X diskInitPt is the location at which the disk initialization dialog X appears, if an uninitialized disk is inserted. X*/ X Xstatic GrafPtr screenPort; Xstatic int doneFlag = false; Xstatic ProcPtr pBkgnd = nil; Xstatic Boolean (*pEvent)() = nil; Xstatic int eventMask = everyEvent; Xstatic Point diskInitPt = { /* v = */ 120, /* h = */ 100 }; X X# ifdef supportDialogs X X/* X Events that are passed to dialogs. Others are ignored. X Standard mask passes , mousedown, keydown, autokey, update, X activate and null events. Null events are controlled by bit 0. X*/ X Xstatic int dlogEventMask = 0x16b; X X# endif X X X/* -------------------------------------------------------------------- */ X/* Internal (private) Routines */ X/* -------------------------------------------------------------------- */ X X X/* X Get handler associated with user or dialog window. X Return nil if window doesn't belong to any known handler. X This routine is absolutely fundamental to TransSkel. X*/ X X Xstatic WHandler **GetWDHandler (theWind) XWindowPtr theWind; X{ Xregister WHandler **h; X X for (h = whList; h != nil; h = (**h).whNext) X { X if ((**h).whWind == theWind) X return (h); X } X return (nil); X} X X X/* X Get handler associated with user window. X Return nil if window doesn't belong to any known handler. X The order of the two tests is critical: theWind might be nil. X*/ X Xstatic WHandler **GetWHandler (theWind) XWindowPtr theWind; X{ Xregister WHandler **h; X X if ((h = GetWDHandler (theWind)) != nil X && ((WindowPeek) theWind)->windowKind != dialogKind) X { X return (h); X } X return (nil); X} X X X# ifdef supportDialogs X X/* X Get handler associated with dialog window. X Return nil if window doesn't belong to any known handler. X The order of the two tests is critical: theDialog might be nil. X*/ X Xstatic WHandler **GetDHandler (theDialog) XDialogPtr theDialog; X{ Xregister WHandler **h; X X if ((h = GetWDHandler (theDialog)) != nil X && ((WindowPeek) theDialog)->windowKind == dialogKind) X { X return (h); X } X return (nil); X} X X# endif X X X/* X General menu-handler. Just passes selection to the handler's X select routine. If the select routine is nil, selecting items from X the menu is a nop. X*/ X Xstatic DoMenuCommand (command) Xlong command; X{ Xregister int menu; Xregister int item; Xregister MHandler **mh; Xregister ProcPtr p; X X menu = HiWord (command); X item = LoWord (command); X for (mh = mhList; mh != nil; mh = (**mh).mhNext) X { X if ((menu == (**mh).mhID) && ((p = (**mh).mhSelect) != nil)) X { X (*p) (item); X break; X } X } X HiliteMenu (0); /* command done, turn off menu hiliting */ X} X X X/* X Apple menu handler X X DoAppleItem: If the first item was chosen, and there's an "About..." X item, call the procedure associated with it (if not nil). If there X is no "About..." item or the item was not the first one, then open X the associated desk accessory. The port is saved and restored X because OpenDeskAcc does not always preserve it correctly. X X DoAppleClobber disposes of the Apple menu. X*/ X X Xstatic DoAppleItem (item) Xint item; X{ XGrafPtr curPort; XStr255 str; X X if (doAbout && item == 1) X { X if (appleAboutProc != nil) X (*appleAboutProc) (); X } X else X { X GetPort (&curPort); X GetItem (appleMenu, item, str); /* get DA name */ X (void) OpenDeskAcc (str); /* open it */ X SetPort (curPort); X } X} X Xstatic DoAppleClobber () { DisposeMenu (appleMenu); } X X X/* -------------------------------------------------------------------- */ X/* Window-handler routing routines */ X/* */ X/* Each routine sets the port to the handler's window before executing */ X/* the handler procedure. */ X/* -------------------------------------------------------------------- */ X X X/* X Pass local mouse coordinates, click time, and the modifiers flag X word to the handler. X*/ X Xstatic DoMouse (h, theEvent) XWHandler **h; XEventRecord *theEvent; X X{ Xregister ProcPtr p; XPoint thePt; X X if (h != nil) X { X SetPort ((**h).whWind); X if ((p = (**h).whMouse) != nil) X { X thePt = theEvent->where; /* make local copy */ X GlobalToLocal (&thePt); X (*p) (thePt, theEvent->when, theEvent->modifiers); X } X } X} X X X/* X Pass the character and the modifiers flag word to the handler. X*/ X Xstatic DoKey (h, ch, mods) XWHandler **h; Xchar ch; Xint mods; X{ Xregister ProcPtr p; X X if (h != nil) X { X SetPort ((**h).whWind); X if ((p = (**h).whKey) != nil) X (*p) (ch, mods); X } X} X X X/* X Call the window updating procedure, passing to it an indicator whether X the window has been resized or not. Then clear the flag, assuming X the update proc took whatever action was necessary to respond to X resizing. X X If the handler doesn't have any update proc, the Begin/EndUpdate X stuff is still done, to clear the update region. Otherwise the X Window Manager will keep generating update events for the window, X stalling updates of other windows. X X Make sure to save and restore the port, as it's not always the X active window that is updated. X*/ X Xstatic DoUpdate (h) XWHandler **h; X X{ Xregister WHandler **rh; Xregister ProcPtr p; Xregister GrafPtr updPort; XGrafPtr tmpPort; X X if ((rh = h) != nil) X { X GetPort (&tmpPort); X SetPort (updPort = (**rh).whWind); X BeginUpdate (updPort); X if ((p = (**rh).whUpdate) != nil) X { X (*p) ((**rh).whSized); X (**rh).whSized = false; X } X EndUpdate (updPort); X SetPort (tmpPort); X } X} X X X/* X Pass activate/deactivate notification to handler. X*/ X Xstatic DoActivate (h, active) XWHandler **h; XBoolean active; X X{ Xregister ProcPtr p; X X if ((h != nil) && ((p = (**h).whActivate) != nil)) X { X SetPort ((**h).whWind); X (*p) (active); X } X} X X X/* X Execute a window handler's close proc. This may be used by handlers X for temp windows that want to remove themselves when the window X is closed: they can call SkelRmveWind to dispose of the window X and remove the handler from the window handler list. Thus, windows X may be dynamically created and destroyed without filling up the X handler list with a bunch of invalid handlers. X X If the handler doesn't have a close proc, just hide the window. X The host should provide some way of reopening the window (perhaps X a menu selection). Otherwise the window will be lost from user X control if it is hidden, since it won't receive user events. X X The port is set to the window manager port after calling the X handler proc, to avoid a dangling port. X X This is called both for regular and dialog windows. X*/ X Xstatic DoClose (h) XWHandler **h; X{ Xregister WHandler **rh; Xregister ProcPtr p; X X if ((rh = h) != nil) X { X SetPort ((**rh).whWind); X if ((p = (**rh).whClose) != nil) X (*p) (); X else X HideWindow ((**rh).whWind); X SetPort (screenPort); X } X} X X X/* X Execute a window handler's clobber proc. X X The port is set to the window manager port after calling the X handler proc, to avoid a dangling port. X X This is called both for regular and dialog windows. X*/ X Xstatic DoClobber (h) XWHandler **h; X{ Xregister ProcPtr p; X X if (h != nil) X { X SetPort ((**h).whWind); X if ((p = (**h).whClobber) != nil) X (*p) (); X SetPort (screenPort); X } X} X X X/* X Execute handler's idle proc. X X Make sure to save and restore the port, since idle procs may be X called for any window, not just the active one. X*/ X Xstatic DoIdle (h) XWHandler **h; X{ Xregister ProcPtr p; XGrafPtr tmpPort; X X if (h != nil) X { X GetPort (&tmpPort); X SetPort ((**h).whWind); X if ((p = (**h).whIdle) != nil) X (*p) (); X SetPort (tmpPort); X } X} X X X# ifdef supportDialogs X X/* -------------------------------------------------------------------- */ X/* Dialog-handling routines */ X/* -------------------------------------------------------------------- */ X X X/* X Handle event if it's for a dialog. The event must be one of X those that is passed to dialogs according to dlogEventMask. X This mask can be set so that disk-inserts, for instance, don't X get eaten up. X*/ X Xstatic DoDialog (theEvent) XEventRecord *theEvent; X{ Xregister WHandler **dh; XDialogPtr theDialog; Xregister int what; Xint item; XGrafPtr tmpPort; X X/* X handle command keys before they get to IsDialogEvent X*/ X X what = theEvent->what; X if((what == keyDown || what == autoKey) && (theEvent->modifiers & cmdKey)) X { X DoMenuCommand (MenuKey (theEvent->message & charCodeMask)); X return (true); X } X X if(((1 << what) & dlogEventMask) && IsDialogEvent (theEvent)) X { X X if (DialogSelect (theEvent, &theDialog, &item) X && (dh = GetDHandler (theDialog)) != nil X && (**dh).whEvent != nil) X { X GetPort (&tmpPort); X SetPort (theDialog); X (*(**dh).whEvent) (item, theEvent); X SetPort (tmpPort); X } X return (true); X } X return (false); X} X X# endif X X X/* -------------------------------------------------------------------- */ X/* Event-handling routines */ X/* -------------------------------------------------------------------- */ X X X/* X Have either sized or zoomed the window. Invalidate it to force X an update and set the 'resized' flag in the window handler true. X*/ X Xstatic TriggerUpdate (h, thePort) XWHandler **h; XGrafPtr thePort; X{ X SetPort (thePort); X InvalRect (&thePort->portRect); X if (h != nil) X (**h).whSized = true; X} X X X/* X Size a window. If the window has a handler, use the grow limits X in the handler record, otherwise use the defaults. X X The portRect is invalidated to force an update event. (The port X must be set first, as it could be pointing anywhere.) The handler's X update procedure should check the parameter passed to it to check X whether the window has changed size, if it needs to adjust itself to X the new size. THIS IS A CONVENTION. Update procs must notice grow X "events", there is no procedure specifically for such events. X X The clipping rectangle is not reset. If the host application X keeps the clipping set equal to the portRect or something similar, X then it will have to arrange to treat window growing with more X care. X*/ X Xstatic DoGrow (h, thePort, startPt) XWHandler **h; XGrafPtr thePort; XPoint startPt; X{ XRect r; Xregister long growRes; X X if (h != nil) X r = (**h).whGrow; X else X r = growRect; /* use default */ X X /* grow result non-zero if size change */ X X if (growRes = GrowWindow (thePort, startPt, &r)) X { X SizeWindow (thePort, LoWord (growRes), HiWord (growRes), false); X TriggerUpdate (h, thePort); X } X} X X X/* X Zoom the current window. Very similar to DoGrow X*/ X XDoZoom (h, thePort, partCode) Xregister WHandler **h; XGrafPtr thePort; Xshort partCode; X{ X ZoomWindow (thePort, partCode, 0); X TriggerUpdate (h, thePort); X} X X X/* X General event handler X*/ X Xstatic DoEvent (theEvt) XEventRecord *theEvt; X X{ Xregister EventRecord *theEvent; XPoint evtPt; XGrafPtr evtPort; Xregister int evtPart; Xregister char evtChar; Xregister int evtMods; Xregister WHandler **h; XRect r; X X theEvent = theEvt; X X# ifdef supportDialogs X X if(DoDialog (theEvent)) X return; X X# endif X X evtPt = theEvent->where; X switch (theEvent->what) X { X X case nullEvent: X break; X/* X Mouse click. Get the window that the click occurred in, and the X part of the window. X*/ X case mouseDown: X { X evtPart = FindWindow (evtPt, &evtPort); X h = GetWHandler (evtPort); X X switch (evtPart) X { X/* X Click in a desk accessory window. Pass back to the system. X*/ X case inSysWindow: X { X SystemClick (theEvent, evtPort); X break; X } X/* X Click in menu bar. Track the mouse and execute selected command, X if any. X*/ X case inMenuBar: X { X DoMenuCommand (MenuSelect (evtPt)); X break; X } X/* X Click in grow box. Resize window. X*/ X case inGrow: X { X DoGrow (h, evtPort, evtPt); X break; X } X/* X Click in title bar. Drag the window around. Leave at least X 4 pixels visible in both directions. X*/ X case inDrag: X { X r = screenPort->portRect; X r.top += mBarHeight; /* skip down past menu bar */ X InsetRect (&r, 4, 4); X DragWindow (evtPort, evtPt, &r); X break; X } X/* X Click in close box. Call the close proc if the window has one. X*/ X case inGoAway: X { X if (TrackGoAway (evtPort, evtPt)) X DoClose (GetWDHandler (evtPort)); X break; X } X/* X Click in content region. If the window wasn't frontmost (active), X just select it, otherwise pass the click to the window's mouse X click handler. X*/ X case inContent: X { X if (evtPort != FrontWindow ()) X SelectWindow (evtPort); X else X DoMouse (h, theEvent); X break; X } X X/* X Click in zoom box. Track the click and then zoom the window if X necessary X*/ X case inZoomIn: X case inZoomOut: X { X if(TrackBox(evtPort, evtPt, evtPart)) X DoZoom (h, evtPort, evtPart); X break; X } X X } X break; /* mouseDown */ X } X/* X Key event. If the command key was down, process as menu item X selection, otherwise pass the character and the modifiers flags X to the active window's key handler. X X If dialogs are supported, there's no check for command-key X equivalents, since that would have been checked in DoDialog. X*/ X case keyDown: X case autoKey: X { X evtChar = theEvent->message & charCodeMask; X evtMods = theEvent->modifiers; X X# ifndef supportDialogs X X if (evtMods & cmdKey) /* try menu equivalent */ X { X DoMenuCommand (MenuKey (evtChar)); X break; X } X X# endif X X DoKey (GetWHandler (FrontWindow ()), evtChar, evtMods); X break; X } X/* X Update a window. X*/ X case updateEvt: X { X DoUpdate (GetWHandler ((WindowPtr) theEvent->message)); X break; X } X/* X Activate or deactivate a window. X*/ X case activateEvt: X { X DoActivate (GetWHandler ((WindowPtr) theEvent->message), X ((theEvent->modifiers & activeFlag) != 0)); X break; X } X/* X handle inserts of uninitialized disks X*/ X case diskEvt: X { X if (HiWord (theEvent->message) != noErr) X { X DILoad (); X (void) DIBadMount (diskInitPt, theEvent->message); X DIUnload (); X } X break; X } X } X} X X X/* -------------------------------------------------------------------- */ X/* Interface (public) Routines */ X/* -------------------------------------------------------------------- */ X X X/* X Initialize the various Macintosh Managers. X Set default upper limits on window sizing. X FlushEvents does NOT toss disk insert events, so that disks X inserted while the application is starting up don't result X in dead drives. X*/ X XSkelInit () X{ X MaxApplZone (); X FlushEvents (everyEvent - diskMask, 0 ); X InitGraf (&thePort); X InitFonts (); X InitWindows (); X InitMenus (); X TEInit (); X InitDialogs (nil); /* no restart proc */ X InitCursor (); X/* X Set upper limits of window sizing to machine screen size. Allow X for the menu bar. X*/ X GetWMgrPort (&screenPort); X growRect.right = screenPort->portRect.right; X growRect.bottom = screenPort->portRect.bottom - mBarHeight; X} X X X/* X Main loop. X X Task care of DA's with SystemTask. X Run background task if there is one. X If there is an event, check for an event hook. If there isn't X one defined, or if there is but it returns false, call the X general event handler. (Hook returns true if TransSkel should X ignore the event.) X If no event, call the "no-event" handler for the front window and for X any other windows with idle procedures that are always supposed X to run. This is done in such a way that it is safe for idle procs X to remove the handler for their own window if they want (unlikely, X but...) This loop doesn't check whether the window is really X a dialog window or not, but it doesn't have to, because such X things always have a nil idle proc. X X doneFlag is reset upon exit. This allows it to be called X repeatedly, or recursively. X X If dialogs are supported, null events are looked at (in SkelMain) X and passed to the event handler. This is necessary to make sure X DialogSelect gets called repeatedly, or the caret won't blink if X a dialog has any editText items. X X If an event-inspecting hook is installed, null events are not passed X to it. X*/ X XSkelMain () X{ XEventRecord theEvent; Xregister WHandler **wh, **wh2; Xregister WindowPtr w; XBoolean haveEvent; X X while (!doneFlag) X { X SystemTask (); X if (pBkgnd != nil) X (*pBkgnd) (); X X haveEvent = GetNextEvent (eventMask, &theEvent); X X if (pEvent == nil || (haveEvent && (*pEvent) (&theEvent) == false)) X DoEvent(&theEvent); X X if (!haveEvent) X { X for (wh = whList; wh != nil; wh = wh2) X { X wh2 = (**wh).whNext; X w = (**wh).whWind; X if ( (w == FrontWindow () || !(**wh).whFrontOnly ) ) X { X SystemTask (); X DoIdle (wh); X } X } X } X } X doneFlag = false; X} X X X/* X Tell SkelMain to stop X*/ X XSkelWhoa () { doneFlag = true; } X X X/* X Clobber all the menu, window and dialog handlers X*/ X XSkelClobber () X{ X while (whList != nil) X SkelRmveWind ((**whList).whWind); X X while (mhList != nil) X SkelRmveMenu (GetMHandle((**mhList).mhID)); X} X X X/* -------------------------------------------------------------------- */ X/* Menu-handler interface routines */ X/* -------------------------------------------------------------------- */ X X X/* X Install handler for a menu. Remove any previous handler for it. X Pass the following parameters: X X theMenu Handle to the menu to be handled. Must be created by host. X pSelect Proc that handles selection of items from menu. If this is X nil, the menu is installed, but nothing happens when items X are selected from it. X pClobber Proc for disposal of handler's data structures. Usually X nil for menus that remain in menu bar until program X termination. X X The menu is installed and drawn in the menu bar. X*/ X XSkelMenu (theMenu, pSelect, pClobber) XMenuHandle theMenu; XProcPtr pSelect; XProcPtr pClobber; X{ Xregister MHandler **mh; X X mhClobOnRmve = false; X SkelRmveMenu (theMenu); X mhClobOnRmve = true; X X mh = New (MHandler); X (**mh).mhNext = mhList; X mhList = mh; X (**mh).mhID = (**theMenu).menuID; /* get menu id number */ X (**mh).mhSelect = pSelect; /* install selection handler */ X (**mh).mhClobber = pClobber; /* install disposal handler */ X InsertMenu (theMenu, 0); /* put menu at end of menu bar */ X DrawMenuBar (); X} X X X/* X Remove a menu handler. This calls the handler's disposal routine X and then takes the handler out of the handler list and disposes X of it. X X Note that the menu MUST be deleted from the menu bar before calling X the clobber proc, because the menu bar will end up filled with X garbage if the menu was allocated with NewMenu (see discussion of X DisposeMenu in Menu Manager section of Inside Macintosh). X*/ X XSkelRmveMenu (theMenu) XMenuHandle theMenu; X{ Xregister int mID; Xregister MHandler **h, **h2; Xregister ProcPtr p; X X mID = (**theMenu).menuID; X if (mhList != nil) /* if list empty, ignore */ X { X if ((**mhList).mhID == mID) /* is it the first element? */ X { X h2 = mhList; X mhList = (**mhList).mhNext; X } X else X { X for (h = mhList; h != nil; h = h2) X { X h2 = (**h).mhNext; X if (h2 == nil) X return; /* menu not in list! */ X if ((**h2).mhID == mID) /* found it */ X { X (**h).mhNext = (**h2).mhNext; X break; X } X } X } X DeleteMenu (mID); X DrawMenuBar (); X if (mhClobOnRmve && (p = (**h2).mhClobber) != nil) X (*p) (theMenu); /* call disposal routine */ X DisposHandle (h2); /* get rid of handler record */ X } X} X X X/* X Install a handler for the Apple menu. X X SkelApple is called if TransSkel is supposed to handle the apple X menu itself. The title is the title of the first item. If nil, X then only desk accessories are put into the menu. If not nil, then X the title is entered as the first item, followed by a gray line, X then the desk accessories. X*/ X XSkelApple (aboutTitle, aboutProc) XStringPtr aboutTitle; XProcPtr aboutProc; X{ XStr255 appleTitle; X X appleTitle[0] = 1; /* build apple menu title */ X appleTitle[1] = 0x14; /* "apple" character */ X appleID = 1; X appleMenu = NewMenu (appleID, appleTitle); X if (aboutTitle != nil) X { X doAbout = true; X AppendMenu (appleMenu, aboutTitle); /* add About... item title */ X AppendMenu (appleMenu, "\p(-"); /* add gray line */ X appleAboutProc = aboutProc; X } X AddResMenu (appleMenu, 'DRVR'); /* add desk accessories */ X SkelMenu (appleMenu, DoAppleItem, DoAppleClobber); X} X X X/* -------------------------------------------------------------------- */ X/* Window-handler interface routines */ X/* -------------------------------------------------------------------- */ X X X/* X Install handler for a window. Remove any previous handler for it. X Pass the following parameters: X X theWind Pointer to the window to be handled. Must be created by host. X pMouse Proc to handle mouse clicks in window. The proc will be X passed the point (in local coordinates), the time of the X click, and the modifier flags word. X pKey Proc to handle key clicks in window. The proc will be passed X the character and the modifier flags word. X pUpdate Proc for updating window. TransSkel brackets calls to update X procs with calls to BeginUpdate and EndUpdate, so the visRgn X is set up correctly. A flag is passed indicating whether the X window was resized or not. BY CONVENTION, the entire portRect X is invalidated when the window is resized. That way, the X handler's update proc can redraw the entire content region X without interference from BeginUpdate/EndUpdate. The flag X is set to false after the update proc is called; the X assumption is made that it will notice the resizing and X respond appropriately. X pActivate Proc to execute when window is activated or deactivated. X A boolean is passed to it which is true if the window is X coming active, false if it's going inactive. X pClose Proc to execute when mouse clicked in close box. Useful X mainly to temp window handlers that want to know when to X self-destruct (with SkelRmveWind). X pClobber Proc for disposal of handler's data structures X pIdle Proc to execute when no events are pending. X frontOnly True if pIdle should execute on no events only when X theWind is frontmost, false if executes all the time. Note X that if it always goes, everything else may be slowed down! X X If a particular procedure is not needed (e.g., key events are X not processed by a handler), pass nil in place of the appropriate X procedure address. X X All handler procedures may assume that the port is set correctly X at the time they are called. X*/ X XSkelWindow (theWind, pMouse, pKey, pUpdate, pActivate, pClose, X pClobber, pIdle, frontOnly) X XWindowPtr theWind; XProcPtr pMouse, pKey, pUpdate, pActivate, pClose, pClobber, pIdle; XBoolean frontOnly; X{ Xregister WHandler **hHand, *hPtr; X X whClobOnRmve = false; X SkelRmveWind (theWind); X whClobOnRmve = true; X/* X Get new handler, attach to list of handlers. It is attached to the X beginning of the list, which is simpler; the order is presumably X irrelevant to the host, anyway. X*/ X hHand = New (WHandler); X (**hHand).whNext = whList; X whList = hHand; X/* X Fill in handler fields X*/ X hPtr = *hHand; X hPtr->whWind = theWind; X hPtr->whMouse = pMouse; X hPtr->whKey = pKey; X hPtr->whUpdate = pUpdate; X hPtr->whActivate = pActivate; X hPtr->whClose = pClose; X hPtr->whClobber = pClobber; X hPtr->whIdle = pIdle; X hPtr->whFrontOnly = frontOnly; X hPtr->whSized = false; X hPtr->whGrow = growRect; X SetPort (theWind); X} X X X/* X Remove a window handler. This calls the handler's disposal routine X and then takes the handler out of the handler list and disposes X of it. X X SkelRmveWind is also called by SkelRmveDlog. X*/ X XSkelRmveWind (theWind) XWindowPtr theWind; X{ Xregister WHandler **h, **h2; X X if (whList != nil) /* if list empty, ignore */ X { X if ((**whList).whWind == theWind) /* is it the first element? */ X { X h2 = whList; X whList = (**whList).whNext; X } X else X { X for (h = whList; h != nil; h = h2) X { X h2 = (**h).whNext; X if (h2 == nil) X return; /* theWind not in list! */ X if ((**h2).whWind == theWind) /* found it */ X { X (**h).whNext = (**h2).whNext; X break; X } X } X } X if (whClobOnRmve) X DoClobber (h2); /* call disposal routine */ X DisposHandle (h2); /* get rid of handler record */ X } X} X X X# ifdef supportDialogs X X/* -------------------------------------------------------------------- */ X/* Dialog-handler interface routines */ X/* -------------------------------------------------------------------- */ X X X/* X Install a dialog handler. Remove any previous handler for it. X SkelDialog calls SkelWindow as a subsidiary to install a window X handler, then sets the event procedure on return. X X Pass the following parameters: X X theDialog Pointer to the dialog to be handled. Must be created X by host. X pEvent Event-handling proc for dialog events. X pClose Proc to execute when mouse clicked in close box. Useful X mainly to dialog handlers that want to know when to X self-destruct (with SkelRmveDlog). X pClobber Proc for disposal of handler's data structures X X If a particular procedure is not needed, pass nil in place of X the appropriate procedure address. X X All handler procedures may assume that the port is set correctly X at the time they are called. X*/ X XSkelDialog (theDialog, pEvent, pClose, pClobber) XDialogPtr theDialog; XProcPtr pEvent; XProcPtr pClose; XProcPtr pClobber; X{ X SkelWindow (theDialog, nil, nil, nil, nil, pClose, pClobber, nil, false); X (**GetWDHandler (theDialog)).whEvent = pEvent; X} X X X/* X Remove a dialog and its handler X*/ X XSkelRmveDlog (theDialog) XDialogPtr theDialog; X{ X SkelRmveWind (theDialog); X} X X# endif X X X/* -------------------------------------------------------------------- */ X/* Miscellaneous interface routines */ X/* -------------------------------------------------------------------- */ X X X/* X Override the default sizing limits for a window, or, if theWind X is nil, reset the default limits used by SkelWindow. X*/ X XSkelGrowBounds (theWind, hLo, vLo, hHi, vHi) XWindowPtr theWind; Xint hLo, vLo, hHi, vHi; X{ Xregister WHandler **h; XRect r; X X if (theWind == nil) X SetRect (&growRect, hLo, vLo, hHi, vHi); X else if ((h = GetWHandler (theWind)) != nil) X { X SetRect (&r, hLo, vLo, hHi, vHi); X (**h).whGrow = r; X } X} X X X/* X Set the event mask. X*/ X XSkelEventMask (mask) Xint mask; X{ X eventMask = mask; X} X X X/* X Return the event mask. X*/ X XSkelGetEventMask (mask) Xint *mask; X{ X *mask = eventMask; X} X X X/* X Install a background task. If p is nil, the current task is X disabled. X*/ X XSkelBackground (p) XProcPtr p; X{ X pBkgnd = p; X} X X X/* X Return the current background task. Return nil if none. X*/ X XSkelGetBackground (p) XProcPtr *p; X{ X *p = pBkgnd; X} X X X/* X Install an event-inspecting hook. If p is nil, the hook is X disabled. X*/ X XSkelEventHook (p) XBoolean (*p)(); X{ X pEvent = p; X} X X X/* X Return the current event-inspecting hook. Return nil if none. X*/ X XSkelGetEventHook (p) XBoolean (**p)(); X{ X *p = pEvent; X} X X X# ifdef supportDialogs X X/* X Set the mask for event types that will be passed to dialogs. X Bit 1 is always set, so that null events will be passed. X*/ X XSkelDlogMask (mask) Xint mask; X{ X dlogEventMask = mask | 1; X} X X X/* X Return the current dialog event mask. X*/ X XSkelGetDlogMask (mask) Xint *mask; X{ X *mask = dlogEventMask; X} X X# endif SHAR_EOF exit