[mod.mac.sources] TransSkel.c.Hqx Human Readable Version

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