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