/* 
Copyright (c) 1991-2000 UserLand Software, Inc. 

Permission is hereby granted, free of charge, to any person obtaining a 
copy of this software and associated documentation files (the 
"Software"), to deal in the Software without restriction, including 
without limitation the rights to use, copy, modify, merge, publish, 
distribute, sublicense, and/or sell copies of the Software, and to 
permit persons to whom the Software is furnished to do so, subject to the 
following conditions: 

The above copyright notice and this permission notice shall be 
included in all copies or substantial portions of the Software. 

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
*/ 


#include <appletdefs.h>
#include <iac.h>
#include <appletquickdraw.h>
#include <appletmouse.h>
#include <appletfrontier.h>
#include <appletcursor.h>
#include <appletops.h>
#include <appletfiles.h>
#include <appletcardops.h>
#include <appletzoom.h>
#include <appletcard.h>
#include <appletkb.h>

#include "iowaparser.h"
#include "iowafrontier.h"
#include "iowaattributes.h"
#include "iowascript.h"

#if !TARGET_CPU_PPC
#include <SetupA5.h> // obsolete for PPC
#endif

#ifndef cutCmd
#define	cutCmd		3
#define	copyCmd		4
#define	pasteCmd	5
#define clearCmd	6
#endif


#ifndef iowaRuntime /*in Card Editor, cmd-period kills a running card*/ 

	#define cmdPeriodKillsCard
	
#endif

hdlruntimerecord runtimedata = nil;

boolean flexitcardloop = false;

typedef struct cardwindow {

	WindowPtr w;
	
	hdlruntimerecord hw;
	
	} tycardwindow;

static tycardwindow **hwindowarray = nil; /*dynamic array of WindowPtrs managed by iowa*/
	
#define textticksrecalc 30 /*while typing text, wait this number of ticks before recalcing*/

boolean flquickrecalc = true; /*set false in cardrunner.c, under special circumstances*/






static void defaultActivate (boolean flactivate) {
	} /*defaultActivate*/
	
	
static short sizewindowarray (void) {
	
	if (hwindowarray == nil)
		return (0);
		
	return ((short) (GetHandleSize ((Handle) hwindowarray) / longsizeof (tycardwindow)));
	} /*sizewindowarray*/
	
	
static hdlruntimerecord getwindowdata (WindowPtr w) {
	
	/*return ((hdlruntimerecord) GetWRefCon (w));*/
	
	if (w != nil)
	{
		short ct, i;
		
		ct = sizewindowarray ();
		
		for (i = 0; i < ct; i++) { /*look for the window in the window array*/
			
			if ((*hwindowarray) [i].w == w)
				return ((*hwindowarray) [i].hw);
			}
	}
	
	return (nil); /*it's not in the window array*/
	} /*getwindowdata*/
	
	
static hdlcard getwindowcardrecord (WindowPtr w) {
		
	return ((**getwindowdata (w)).hc);
	} /*getwindowcardrecord*/
	

static hdlcard cardtofind;

static WindowPtr windowtofind = nil;


static boolean getcardrecordwindowvisit (WindowPtr w) {
	
	hdlcard hc = getwindowcardrecord (w);

	if (hc == cardtofind)	
		windowtofind = w;
		
	return (true);
	} /*getcardrecordwindowvisit*/
	
	
WindowPtr getcardrecordwindow (hdlcard card) {
	
	/*
	4.1b4 dmb: I added this routine a couple of builds back for modalcardeventfilter
	in langcard.c. I now see that we must preserve our globals, which visitCardWindows
	automatically sets.
	*/
	
	hdlruntimerecord saveruntimedata = runtimedata;
	hdlcard saveiowadata = iowadata;
	
	cardtofind = card;
	
	visitCardWindows (&getcardrecordwindowvisit);
	
	runtimedata = saveruntimedata;
	
	iowadata = saveiowadata;
	
	return (windowtofind);
	} /*getcardrecordwindow*/

	
short countCardWindows (void) {
	
	short ctcells = sizewindowarray ();
	short ct = 0;
	short i;
	
	for (i = 0; i < ctcells; i++)
		if ((*hwindowarray) [i].w != nil)
			ct++;
			
	return (ct);
	} /*countCardWindows*/
	
	
static boolean addtowindowarray (WindowPtr w, hdlruntimerecord hw) {
	
	short ct, i;
	tycardwindow cw;
	
	cw.w = w;
	
	cw.hw = hw;
	
	ct = sizewindowarray ();
	
	for (i = 0; i < ct; i++) { /*look for an empty slot in the window array*/
		
		if ((*hwindowarray) [i].w == nil) {
			
			(*hwindowarray) [i] = cw;
			
			return (true);
			}
		} /*for*/
	
	/*no empty slots, allocate a new array or make the array bigger*/
	
	if (hwindowarray == nil)
		return (newfilledhandle (&w, longsizeof (tycardwindow), (Handle *) &hwindowarray));
	
	SetHandleSize ((Handle) hwindowarray, (ct + 1) * longsizeof (tycardwindow));

	if (MemError () != noErr)
		return (false);
	
	(*hwindowarray) [ct] = cw;
	
	return (true);
	} /*addtowindowarray*/

	
static boolean inwindowarray (WindowPtr w) {

	return (getwindowdata (w) != nil);
	} /*inwindowarray*/
	
	
static void removefromwindowarray (WindowPtr w) {

	short ct, i;
	
	ct = sizewindowarray ();
	
	for (i = 0; i < ct; i++) { /*look for an empty slot in the window array*/
		
		if ((*hwindowarray) [i].w == w) {
		
			(*hwindowarray) [i].w = nil;
			
			return;
			}
		} /*for*/
	} /*removefromwindowarray*/
	
	
boolean isCardWindow (WindowPtr w) {
	
	return (inwindowarray (w));
	} /*isCardWindow*/


boolean cardToFront (bigstring windowtitle) {

	short ct, i;
	
	ct = sizewindowarray ();
	
	for (i = 0; i < ct; i++) { 
		
		WindowPtr w = (*hwindowarray) [i].w;
		
		if (w != nil) {
			
			bigstring bs;
			
			GetWTitle (w, bs);
			
			if (equalstrings (bs, windowtitle)) {
				
				SelectWindow (w);
				
				return (true);
				}
			}
		} /*for*/
	
	return (false); /*we don't have a window with that name*/
	} /*cardToFront*/


static void runmodeactivate (boolean flactivating) {
	
	/*
	8/9/96 4.1b4 dmb: broke out of handleCardEvent's main switch statement
	
	1.0b19 dmb: call frontSetRuntimeCard when we switch out too.
	*/
	
	frontSetRuntimeCard (flactivating, true);
	
	/*DW 4/6/95: hack -- activate/deactivate the active text object directly*/ {
		
		hdlobject hobj = (**iowadata).activetextobject;
		
		if (hobj != nil) {
		
			hdleditrecord heditrecord = (hdleditrecord) (**hobj).objecteditrecord;
		
			editactivate (heditrecord, flactivating);
			}
		}
	} /*runmodeactivate*/


static void runmodeupdate (void) {
	
	hdlruntimerecord hw = runtimedata;
	WindowPtr w = (**hw).macwindow;
	hdlcard hc = (**hw).hc;
	boolean beginendupdate = (**hw).ownwindow;	/* || (**hc).macevent.what != updateEvt;*/
	
	assert ((**hc).drawwindow == w);
	
	pushmacport (w);
	
	if ((**hc).fullupdate) {
		
		InvalRect (&(*w).portRect);
		
		(**hc).fullupdate = false;
		}
	
	if (beginendupdate) 
		BeginUpdate (w);
	
	(**hc).updaterect = (**(*w).visRgn).rgnBBox;
	
	/*preserve iowadata across an update*/ {
	
		hdlcard oldiowadata = iowadata;
	
		iowadata = hc;
	
		iowaupdate ();
	
		iowadata = oldiowadata;
		}
			
	if (beginendupdate)
		EndUpdate (w);
	
	popmacport ();
	} /*runmodeupdate*/
	
	
static boolean runtimeeditableobject (hdlobject h) {
	
	derefclone (&h);
	
	if (!(**h).objectenabled)
		return (false);
		
	return (calleditableinrunmode (h));
	} /*runtimeeditableobject*/
	
	
static boolean getfirsttextobject (hdlobject *hfirst) {
	
	/*
	return the first editable text object
	*/
	
	hdlcard hc = iowadata;
	hdlobject nomad = (**hc).objectlist;
	short lowesttag = infinity;
	
	*hfirst = nil;
	
	while (nomad != nil) {
		
		if (runtimeeditableobject (nomad)) {
			
			if ((**nomad).sorttag < lowesttag) {
				
				lowesttag = (**nomad).sorttag;
				
				*hfirst = nomad;
				}
			}

		nomad = (**nomad).nextinthread;
		} /*while*/
	
	return (*hfirst != nil);
	} /*getfirsttextobject*/
	

static void getnexttextobject (hdlobject h, hdlobject *hnext) {
	
	hdlcard hc = iowadata;
	hdlobject nomad = (**hc).objectlist;
	short n = (**h).sorttag + 1;
	short nearesttag = infinity;
	hdlobject nearestnomad = nil;
	short lowesttag = infinity;
	hdlobject lowestnomad = nil;

	while (nomad != nil) {
		
		if (runtimeeditableobject (nomad)) {
			
			short nomadtag = (**nomad).sorttag;
			
			if (nomadtag == n) { /*found it the easy way*/
				
				*hnext = nomad;
				
				return;
				}
			
			if (nomadtag < lowesttag) { /*in case we wrap around*/
				
				lowesttag = nomadtag;
				
				lowestnomad = nomad;
				}
				
			if ((nomadtag > n) && (nomadtag < nearesttag)) {
				
				nearestnomad = nomad;
				
				nearesttag = nomadtag;
				}
			}

		nomad = (**nomad).nextinthread;
		} /*while*/
	
	if (nearestnomad == nil) /*wrap around to the first guy*/
		*hnext = lowestnomad;
	else
		*hnext = nearestnomad;
	} /*getnexttextobject*/
	

static void getprevtextobject (hdlobject h, hdlobject *hnext) {
	
	hdlcard hc = iowadata;
	hdlobject nomad = (**hc).objectlist;
	short n = (**h).sorttag - 1;
	short nearesttag = 0;
	hdlobject nearestnomad = nil;
	short highesttag = 0;
	hdlobject highestnomad = nil;

	while (nomad != nil) {
		
		if (runtimeeditableobject (nomad)) {
			
			short nomadtag = (**nomad).sorttag;
			
			if (nomadtag == n) { /*found it the easy way*/
				
				*hnext = nomad;
				
				return;
				}
			
			if (nomadtag > highesttag) { /*in case we wrap around*/
				
				highesttag = nomadtag;
				
				highestnomad = nomad;
				}
				
			if ((nomadtag < n) && (nomadtag > nearesttag)) {
				
				nearestnomad = nomad;
				
				nearesttag = nomadtag;
				}
			}

		nomad = (**nomad).nextinthread;
		} /*while*/
	
	if (nearestnomad == nil) /*wrap around to the first guy*/
		*hnext = highestnomad;
	else
		*hnext = nearestnomad;
	} /*getprevtextobject*/
	
	
static boolean movetextboxcursor (boolean flbackward) {

	hdlcard hc = iowadata;
	hdlobject h;
	
	h = (**hc).activetextobject;
	
	if (h == nil) /*no text objects*/
		return (false);
	
	if (flbackward)
		getprevtextobject (h, &h);
	else
		getnexttextobject (h, &h);
		
	if (h == (**hc).activetextobject) /*only one text object*/
		return (false);
	
	derefclone (&h);
	
	calleditobject (h, true);
			
	validobject (h); /*1.0b15 DW -- part of the flicker avoidance scheme*/
	
	return (true);
	} /*movetextboxcursor*/
	
	
static void hotobject (boolean flpressed) {
	
	/*
	callback routine for the mouse tracker.
	*/
	
	hdlcard hc = iowadata;
	
	(**hc).trackerpressed = flpressed;
	
	invalobject ((**hc).trackerobject);
	
	iowaupdatenow ();
	} /*hotobject*/
	

boolean recalcCardWindow (WindowPtr w, boolean flmajorrecalc) {
	
	if (w == nil) 
		return (false);
		
	pushmacport (w);
		
	runtimedata = getwindowdata (w); /*set up global for runmode routines*/
	
	iowadata = getwindowcardrecord (w); /*set up global for card routines*/
	
	frontSetRuntimeCard (true, false); /*a minor switch, just make embedded objects global*/
	
	(**iowadata).recalcobject = nil;
	
	if (flmajorrecalc)
		visitobjects ((**iowadata).objectlist, &majorrecalcvisit);
	else
		visitobjects ((**iowadata).objectlist, &minorrecalcvisit);
	
	runmodeupdate ();
		
	popmacport ();
	
	return (true); /*keep visiting*/
	} /*recalcCardWindow*/
	
	
static boolean sameasbuttontype (tyobjecttype type) { 
	
	return (type == buttontype);
	} /*sameasbuttontype*/
	
	
static void filterevent (EventRecord *ev) {
	
	tycardeventcallback callback = (**runtimedata).callback;
	
	if (callback == nil) 
		return;
		
	if ((*ev).what == nullEvent) /*DW 8/22/93*/
		(*ev).message = (long) iowadata;
	
	else { /*DW /8/26/93: no klooging to set the global over in the filter, send 2 events*/ 
	
		EventRecord x;
		
		clearbytes (&x, longsizeof (x));
		
		x.what = iowaSetHandleEvent;
		
		x.message = (long) iowadata;
		
		(*callback) (&x);
		}
	
	pushmacport ((**iowadata).drawwindow);
	
	(*callback) (ev);
	
	popmacport ();
	} /*filterevent*/
	
	
static void sendinitmessage (void) {

	tycardeventcallback callback = (**runtimedata).callback;
	EventRecord ev;
	
	if (callback == nil) 
		return;
		
	ev.what = iowaInitEvent;
	
	ev.message = (long) iowadata;
	
	(*callback) (&ev);
	} /*sendinitmessage*/
	
	
static boolean sendbuttonhitmessage (hdlobject h) {
	
	/*
	return true if the buttonhit has been fully processed
	*/
	
	tycardeventcallback callback = (**runtimedata).callback;
	EventRecord ev;
		
	if (callback == nil)
		return (true);
	
	ev.what = iowaButtonHitEvent;
	
	ev.message = (long) h;
	
	(*callback) (&ev);
	
	if (ev.what == iowaRunScriptEvent) /*pass the buttonhit thru, run the script*/
		return (false);
	
	if (ev.what == iowaCloseEvent) /*the client is telling us to close the window*/
		closeCardWindow ((**runtimedata).macwindow);
		
	return (true); /*we consumed the buttonhit*/
	} /*sendbuttonhitmessage*/
	
	
static boolean sendclosemessage (void) {
	
	/*
	the user just clicked in the close box of a card window, or for some
	other reason the card is about to close. we call back to the client,
	giving him a chance to save data from the card.
	*/
	
	tycardeventcallback callback = (**runtimedata).callback;
	EventRecord ev;
	
	if (callback == nil)
		return (true);
	
	ev.what = iowaCloseEvent;
	
	ev.message = (long) iowadata;
	
	(*callback) (&ev);
	
	return (ev.what != iowaCancelEvent);
	} /*sendclosemessage*/
	
	
static void objectclick (hdlobject listhead, hdlobject h) {
	
	/*
	the user just clicked on this object in run mode. 
	*/
	
	derefclone (&h); /*click on a clone is the same as clicking on the object*/
	
	if (sameasbuttontype ((**h).objecttype)) {
		
		if (sendbuttonhitmessage (h)) {
		
			if (iowadata != nil) /*protect against a closed window*/
				schedulerecalc (h, 0);
			
			return;
			}
		}
		
	if (callclick (listhead, h, mousestatus.localpt, keyboardstatus.flshiftkey, mousestatus.fldoubleclick)) {
	
		if (iowadata == nil) /*protect against closed window*/
			return;
		
		if (!flquickrecalc) { /*1/25/93 DW: very rarely you need to disable the quick recalc*/
			
			flquickrecalc = true; /*must be reset for every call*/
			
			return;
			}
		
		/*1/24/93 DW: streamlined for quick response to click and in recalc*/
			
		runmodeupdate (); /*avoid lag in display during massive recalcs*/
	
		frontSetRuntimeCard (true, false); /*make this card's table global*/
		
		(**iowadata).recalcobject = h;
		
		visitobjects ((**iowadata).objectlist, &minorrecalcvisit); /*recalc now, avoid lag*/
	
		runmodeupdate (); /*avoid lag in display, agents might need to run now*/
		
		(**iowadata).runmodechanges = true;
		}
	} /*objectclick*/
	
	
static boolean returnkeyvisit (hdlobject h) {

	hdlcard hc = iowadata;
	
	if (!(**h).objectenabled) /*keep searching*/
		return (true);
		
	if (!callcatchreturn (h)) /*object doesn't want the Return key*/
		return (true);
		
	(**hc).tracking = true; /*this is what bold buttons do, for example*/

	(**hc).trackerobject = h;

	hotobject (true); /*display button in its hot state*/
	
	waitfornexttick (); waitfornexttick (); waitfornexttick ();
	
	while (returnkeydown ()) {};
	
	hotobject (false); /*display button in its un-hot state*/

	(**hc).tracking = false;
	
	objectclick ((**iowadata).objectlist, h);
	
	return (false); /*stop searching*/
	} /*returnkeyvisit*/
	

static char upperchar (char ch) {

	if ((ch >= 'a') && (ch <= 'z'))
		return (ch - 32);
	else
		return (ch);
	} /*upperchar*/


static boolean mapkeyvisit (hdlobject h) {
	
	/*
	dmb 1.0b20: map chescape to the cancel button
	*/
	
	hdlcard hc = iowadata;
	bigstring bs;
	
	if (!(**h).objectenabled) /*keep searching*/
		return (true);
		
	if ((**h).objecttype != buttontype) /*keep searching*/
		return (true);
		
	texthandletostring ((**h).objectvalue, bs);
	
	if (stringlength (bs) == 0)
		return (true);
	
	if (keyboardstatus.chkb == chescape) {
		
		if (!equalstrings (bs, "\pCancel"))
			return (true);
		}
	else {
	
		if (upperchar (bs [1]) != upperchar (keyboardstatus.chkb))
			return (true);
		}
	
	(**hc).tracking = true; 

	(**hc).trackerobject = h;

	hotobject (true); /*display button in its hot state*/
	
	waitfornexttick (); waitfornexttick (); waitfornexttick ();
	
	hotobject (false); /*display button in its un-hot state*/

	(**hc).tracking = false;
	
	objectclick ((**iowadata).objectlist, h);
	
	return (false); /*stop searching*/
	} /*mapkeyvisit*/


static boolean runmodekeystroke (void) {
	
	/*
	return true if the keystroke was consumed by runtime, otherwise it is 
	passed back to the eventhandler.
	
	dmb 1.0b20: map cmd-. and escape to the cancel button, if present
	and enabled. otherwise, close card as before.
	
	dmb 1.0b20: allow option-Return to type into text field
	
	dmb 1.0b21: on chescape, don't set flexitcardloop true if closeCardWindow
	returns false
	*/
	
	hdlcard hc = iowadata;
	char ch = keyboardstatus.chkb;
	hdlobject activetextobject = (**hc).activetextobject;
	
	if (keyboardstatus.flcmdkey) {
		
		#ifdef cmdPeriodKillsCard /*disabled for LSE on 1/27/95 by DW*/
	
			/*
			if (ch == '.') {
				
				flexitcardloop = true;
				
				closeCardWindow ((**runtimedata).macwindow);
				
				return (true);
				}
			*/
			if (ch == '.')
				keyboardstatus.chkb = ch = chescape;
			else

		#endif
			
		return (false); /*we pass on all other cmd-keystrokes*/
		}
		
	if (ch == chescape) { /*escape always kills the card*/
	
		visitobjects ((**hc).objectlist, &mapkeyvisit); /*dmb 1.0b20*/
		
		if (!flexitcardloop) { /*didn't map to enabled Cancel button. close anyway*/
			
			closeCardWindow ((**runtimedata).macwindow);
			}
		
		return (true);
		}
		
	if (ch == chtab) {
		
		movetextboxcursor (keyboardstatus.flshiftkey);
		
		return (true);
		}
		
	if ((ch == chreturn) || (ch == chenter)) {
	
		if (!keyboardstatus.floptionkey || activetextobject == nil) /*dmb 1.0b20*/
			if (!visitobjects ((**hc).objectlist, &returnkeyvisit))
				return (true);
		}
		
	if (activetextobject == nil) { /*3/18/93 DW -- map keystroke to button*/

		visitobjects ((**hc).objectlist, &mapkeyvisit);
		
		return (true);
		}
		
	callkeyobject (activetextobject, ch);
	
	schedulerecalc (activetextobject, textticksrecalc);
		
	return (true);
	} /*runmodekeystroke*/


static void runmodetracker (hdlobject listhead, hdlobject x) {

	hdlcard hc = iowadata;
	Rect r;
	boolean flclick;
	hdlobject htarget;
	
	htarget = x;
	
	if (!(**htarget).objectenabled)
		return;
	
	derefclone (&htarget);
	
	if (!(**htarget).objectenabled)
		return;
	
	if (callhandlesmousetrack (htarget)) { /*object handles its own mouse tracking*/
	
		objectclick (listhead, x);
			
		return;
		}
		
	getobjectrect (x, &r);
	
	(**hc).tracking = true;
	
	(**hc).trackerobject = x;
	
	hotobject (true); /*display object in its hot state*/
	
	flclick = false;
	
	if (mousetrack (r, &hotobject)) {
	
		hotobject (false); /*display object in its un-hot state*/
		
		flclick = true;
		}
	
	(**hc).tracking = false;
	
	if (flclick)
		objectclick (listhead, x);
	} /*runmodetracker*/
	
	
static boolean findrunmodeobject (Point pt, hdlobject listhead, hdlobject *hparent, hdlobject *hobject) {
	
	/*
	special object-finder for runmode. it passes right thru clones.
	*/
	
	hdlobject x;
	
	while (true) { 
		
		if (!findobject (pt, listhead, &x))
			return (false);
			
		switch ((**x).objecttype) {
			
			case grouptype:
				getchildobjectlist (x, &listhead);
				
				break;
				
			case clonetype:
				listhead = x;
				
				derefclone (&listhead);
				
				break;
				
			default:
				*hparent = listhead;
			
				*hobject = x;
			
				return (true);
			} /*switch*/
		} /*while*/
	} /*findrunmodeobject*/
	

static void runmodecontentclick (WindowPtr w, Point pt) {
			
	hdlobject listhead, x;
		
	if (w != FrontWindow ()) {
	
		if ((**runtimedata).ownwindow)
			SelectWindow (w);
		
		return;
		}
		
	SetPort (w);
	
	mousestatus.localpt = pt;
	
	globaltolocalpoint (w, &mousestatus.localpt);

	mousestatus.fldoubleclick = mousedoubleclick (pt);	
	
	listhead = (**iowadata).objectlist;
	
	if (findrunmodeobject (mousestatus.localpt, listhead, &listhead, &x)) 
		runmodetracker (listhead, x);
	} /*runmodecontentclick*/
	

static void runmodemouseup (long when, Point where) {
	
	/*
	call this when you receive an mouse up event.  if the last mouse down was
	a double click, we set things up so that the next single click will not
	be interpreted as a double click.
	*/
	
	if (!mousestatus.fldoubleclickdisabled) {
		
		mousestatus.mouseuptime = when;
		
		mousestatus.mouseuppoint = where;
		
		mousestatus.mousedowntime = 0L; /*hasn't happened yet*/
		}
	
	mousestatus.fldoubleclickdisabled = false; /*next mouse up is important*/
	} /*runmodemouseup*/


static boolean runmodemousedown (long when, Point pt, boolean *flcloseallwindows) {
	
	/*
	1.0b20 dmb: made boolean, return false if we don't handle it.
	*/
	
	WindowPtr w;
	short part;
	boolean flhandled = true;
	
	mousestatus.mousedowntime = when; 
	
	mousestatus.mousedownpoint = pt;
	
	part = FindWindow (pt, &w);
	
	switch (part) {
		
		case inDrag: {
			Rect r;
		
			r = quickdrawglobal (screenBits).bounds; 
			
			r.top = r.top + GetMBarHeight (); 
			
			InsetRect (&r, 4, 4);
			
			DragWindow (w, pt, &r);
			
			break;
			}
			
		case inContent:
			runmodecontentclick (w, pt);
			
			break;
			
		case inGoAway:
			if (TrackGoAway (w, pt)) {
			
				if (keyboardstatus.floptionkey) {
				
					closeAllCardWindows ();
					
					*flcloseallwindows = true;
					}
				else
					closeCardWindow (w); 
				}
				
			break;
		
		default:
			flhandled = false;
			
			break;
		} /*switch*/
	
	return (flhandled);
	} /*runmodemousedown*/


static void runmodecheckupdate (void) {

	hdlcard hc = iowadata;
	WindowPtr w = (**runtimedata).macwindow;
	
	if ((**hc).needsupdate && ((**hc).runmode)) {
		
		(**hc).needsupdate = false; /*consume it*/
				
		pushmacport (w);
		
		pushclip ((*w).portRect);
		
		iowapreupdate (); /*actually inval everything that's been logically inval'd*/
	
		runmodeupdate ();
		
		popclip ();
		
		popmacport ();
		}
	} /*runmodecheckupdate*/
	

static boolean alwaysidlevisit (hdlobject h) {
	
	if (callalwaysidle (h))
		callidleobject (h);
		
	return (true);
	} /*alwaysidlevisit*/
	
	
static void runmodeidle (void) {
	
	hdlcard hc = iowadata;
	boolean flcursorset = false;
	hdlobject hparent, h;

	GetMouse (&mousestatus.localpt);
	
	if (findrunmodeobject (mousestatus.localpt, (**hc).objectlist, &hparent, &h)) {
		
		if ((**h).objectenabled) 
			flcursorset = callsetcursor (h, mousestatus.localpt);
		}
	
	if (!flcursorset)
		setcursortype (cursorisarrow);

	callidleobject ((**hc).activetextobject);
	
	visitobjects ((**hc).objectlist, &alwaysidlevisit);

	runmodecheckupdate ();
	
	checkrecalc ();
	} /*runmodeidle*/
	
	
boolean closeCardWindow (WindowPtr w) {
	
	Boolean ownwindow;
	
	if (!isCardWindow (w))
		return (false);
	
	runtimedata = getwindowdata (w); /*set up global for runmode routines*/
	
	iowadata = getwindowcardrecord (w); /*set up global for card routines*/
	
	if (!sendclosemessage ()) /*abort the close*/
		return (false);
	
	ownwindow = (**runtimedata).ownwindow;
	
	#ifdef iowaRuntimeInApp /*12/5/93 DW -- baling wire*/
		iowadata = getwindowcardrecord (w); 
	#endif
	
	pushmacport (w); /*8/27/94 DW -- on quit, if one modeless card is open, the port isn't properly set*/
	
	clearactivetextobject ();
	
	popmacport ();
	
	if (ownwindow)
		HideWindow (w); /*12/16/93 -- immediate feedback*/
	
	iowadisposerecord (); /*disposes iowadata and its contents*/

	iowadata = nil; /*help out EvenBetterBusError*/

	disposehandle ((Handle) runtimedata);
	
	runtimedata = nil; /*help out EvenBetterBusError*/
	
	removefromwindowarray (w);
	
	if (ownwindow)
		DisposeWindow (w);
	
	flexitcardloop = true;
	
	return (true);
	} /*closeCardWindow*/
	
	
void closeAllCardWindows (void) {

	short ct, i;
	
	ct = sizewindowarray ();
	
	for (i = 0; i < ct; i++) 
		closeCardWindow ((*hwindowarray) [i].w);
	} /*closeAllCardWindows*/
	

static void initeditabletext (void) {
	
	/*
	activate the first edittext object we find.
	*/
	
	hdlobject h;
	
	if (getfirsttextobject (&h)) {
	
		derefclone (&h);
		
		calleditobject (h, true);
		
		validobject (h); 
		}
	} /*initeditabletext*/
	

static boolean nilvaluesvisit (hdlobject h) {
	
	/*
	if an object is editable, and it recalcs,  we dispose of the initial value, 
	which helped the card designer visualize what the running card would look 
	like, but has no value for the card user.
	
	example: if you have a text object initialized to user.name, without
	this hack, you'd see the designer's name first, then the user's name.
	*/
	
	if (!calleditableinrunmode (h))
		return (true);
		
	if ((**h).objectrecalcstatus == neverrecalc)
		return (true);
	
	disposehandle ((**h).objectvalue);
	
	(**h).objectvalue = nil;
	
	return (true);
	} /*nilvaluesvisit*/
	

static void cardcheckinit (void) {
	
	/*
	1.0b23 dmb: call startCard script directly from here, after doing 
	preliminary auto-initialization. also, detect when startCard sets 
	the active text and don't override it.
	*/
	
	if ((**runtimedata).initfields) {
		
		if (!(**iowadata).notscriptedcard) {
			
			hdlobject objectlist = (**iowadata).objectlist;
			Handle hscript;
			bigstring errorstring;
		
			frontSetRuntimeCard (true, false);
		
			visitobjects (objectlist, &nilvaluesvisit);
			
			visitobjects (objectlist, &initexclusiveobjectsvisit);
			
			turnonfirstexclusiveobject (objectlist);
			
			/*1.0b23 dmb: call startCard now that we've done default setup*/
			newtexthandle ("\pif defined (startCard) {startCard ()}", &hscript);
			
			if (!runcardscript (hscript, idfrontier, false, errorstring, nil)) {
				
				if ((**iowadata).runmode)
					alertdialog (errorstring);
				}
			
			visitobjects (objectlist, &majorrecalcvisit);
			}
		
		iowapreupdate ();
		
		runmodeupdate (); 
		
		if ((**iowadata).activetextobject == nil) /*startup script didn't init text*/
			initeditabletext ();
		
		(**runtimedata).initfields = false;
		}
	} /*cardcheckinit*/
	

WindowPtr newCardWindow (Point pt, boolean notscriptedcard, Handle hpackedcard) {
	
	/*
	create a new window to run the packed card.
	
	dmb 6/27/96: don't disposehandle (iowadata); must iowadisposerecord.
				 (fixes memory leak.)
	*/
	
	WindowPtr w = nil;
	hdlruntimerecord hw;
	hdlcard hc;
	
	iowadata = nil;
	
	if (!newclearhandle (longsizeof (tyruntimerecord), (Handle *) &runtimedata))
		return (false);
	
	if (!newclearhandle (longsizeof (tycard), (Handle *) &iowadata))
		goto error;
		
	hw = runtimedata; 
	
	hc = iowadata; 
		
	(**hw).hc = hc;
	
	(**hc).runmode = true; 
	
	if (!iowaunpack (hpackedcard))
		goto error;

	(**hc).runmode = true;
	
	(**hc).notscriptedcard = notscriptedcard;
	
	(**hc).updatecallback = &runmodeupdate;
	
	/*DW 10/17/93: transition from default window resources, to letting the card specify*/ {
		
		short resnum = (**hc).idwindow; /*first try, use the resnum specified by card editor*/
		
		if (systemhascolor ())
			w = GetNewCWindow (resnum, nil, (WindowPtr) -1);
		else
			w = GetNewWindow (resnum, nil, (WindowPtr) -1);
			
		if (w == nil)
			goto error;
		}
	
	SizeWindow (w, (**hc).rightborder, (**hc).bottomborder, false);
	
	SetPort (w);
	
	if ((pt.h != 0) && (pt.v != 0))
		MoveWindow (w, pt.h, pt.v, false);
	else
		centerwindow ((DialogPtr) w, quickdrawglobal (screenBits).bounds);
	
	(**hw).macwindow = w;
	
	(**hw).ownwindow = true;
	
	(**hw).initfields = true;
	
	/*set the window title*/ {
		
		bigstring bs;
		
		texthandletostring ((**hc).windowtitle, bs);
		
		SetWTitle (w, bs);
		}
		
	(**hc).drawwindow = w; /*all drawing goes into this window*/
	
	IACglobals.waitroutine = nil; /*no callback when in runmode*/
	
	sortobjectlist (); /*sort objects based on window position*/
	
	laythread (); /*make sure flat threads are installed*/
	
	addtowindowarray (w, runtimedata);
	
	/*SetWRefCon (w, (long) runtimedata);*/
	
	return (w);
	
	error:
	
	iowadisposerecord ();
	
	disposehandle ((Handle) runtimedata);
	
	if (w != nil)
		DisposeWindow (w);
	
	return (nil);
	} /*newCardWindow*/
	
	
boolean visitCardWindows (tycardwindowvisitroutine visit) {

	short ct, i;
	
	ct = sizewindowarray ();
	
	for (i = 0; i < ct; i++) { /*look for an empty slot in the window array*/
		
		WindowPtr w = (*hwindowarray) [i].w;
		
		if (w != nil) {
			
			runtimedata = getwindowdata (w); /*set up global for runmode routines*/
	
			iowadata = getwindowcardrecord (w); /*set up global for card routines*/
			
			if (!(*visit) (w))
				return (false);
			}
		} /*for*/
		
	return (true);
	} /*visitCardWindows*/
	
	
void getCardData (WindowPtr w, hdlruntimerecord *hcardwindow) {
	
	/*
	after calling newCardWindow, you can use this entry to get the data handle
	linked into the window, so you can override the default settings.
	*/
	
	*hcardwindow = getwindowdata (w); 
	} /*getCardData*/
	
	
boolean cardEditCommand (short editcommand) {
	
	WindowPtr w = FrontWindow ();
	hdlcard hcard;
	hdlobject hobject;
	hdleditrecord hedit;
	
	if (!inwindowarray (w)) /*it's not one of our windows, app handles the command*/
		return (false);
	
	hcard = getwindowcardrecord (w); /*set up global for card routines*/
	
	hobject = (**hcard).activetextobject;
	
	if (hobject == nil) /*consume the command, but there's nothing to do*/
		return (true);
		
	hedit = (hdleditrecord) (**hobject).objecteditrecord;
		
	switch (editcommand) {
		
		case cutCmd:
			editcut (hedit);
			
			break;
			
		case copyCmd:
			editcopy (hedit);
			
			break;
			
		case pasteCmd:
			editpaste (hedit);
			
			(**hcard).runtimevaluechanged = true; /*DW 10/27/95*/
			
			break;
			
		case clearCmd:
			editreplace ("\p", hedit);
			
			break;
			
		} /*switch*/
		
	return (true);
	} /*cardEditCommand*/


static boolean showinvisiblesvisit (hdlobject h) {
	
	derefclone (&h);
	
	if (!(**h).objectvisible) {
		
		Rect r;
		
		getobjectrect (h, &r);
		
		pushpen ();
		
		PenPat (&quickdrawglobal (gray)); 
		
		FrameRect (&r);
		
		poppen ();
		
		InvalRect (&r);
		}
		
	return (true);
	} /*showinvisiblesvisit*/
	

static void checkinvisibles (void) {
	
	boolean flfirstloop = true;
	
	if (iowadata == nil) /*defensive, it can happen*/
		return;
	
	while (cmdkeydown () && optionkeydown ()) {
		
		if (flfirstloop) {
		
			visitobjects ((**iowadata).objectlist, &showinvisiblesvisit);
			
			flfirstloop = false;
			}
		} /*while*/
		
	if (!flfirstloop) 
		runmodeupdate ();
	} /*checkinvisibles*/


boolean handleCardEvent (WindowPtr w, EventRecord *ev, boolean *flcloseallwindows) {
	
	/*
	returns true if the event has been handled. 
	
	if false, you should handle it.
	
	dmb 1.0b21: for iowaOkeyDokeyEvent, press default button if there is one,
	else the cancel	button. In any case, we'll end up calling closeCardWindow
	
	dmb 1.0b24: don't filter activate and update event that are ours. The client
	will see those events if they're not for us.
	*/
	
	boolean flhandled;
	
	*flcloseallwindows = false; 
	
	setkeyboardstatus (*ev); /*set fields of keyboardstatus record*/
		
	if (!inwindowarray (w)) /*it's not one of our windows, you handle the event*/
		return (false);

	runtimedata = getwindowdata (w); /*set up global for runmode routines*/
	
	iowadata = getwindowcardrecord (w); /*set up global for card routines*/
	
	if ((*ev).what != activateEvt && (*ev).what != updateEvt) { /*1.0b24 dmb: don't give them our updates & activate*/
	
		filterevent (ev); /*pass the event thru the callback routine if there is one*/
	}
	
	iowadata = getwindowcardrecord (w); /*set up global for card routines*/
	
	(**iowadata).macevent = *ev; /*for anyone with an interest in the event record*/
	
	releasetemphandles (); /*dispose of any temps created by the previous event*/
	
	pushmacport (w);
	
	cardcheckinit ();
	
	iowavalidate (true); 
	
	flhandled = true; /*default, we handled the event*/
	
	switch ((*ev).what) {
	
		case keyDown: case autoKey:
			flhandled = runmodekeystroke ();
			
			break;
			
		case mouseUp:
			runmodemouseup ((*ev).when, (*ev).where);
			
			break;
		   
		case mouseDown:	
			flhandled = runmodemousedown ((*ev).when, (*ev).where, flcloseallwindows);
			
			break;	
			
		case activateEvt:
			runmodeactivate ((*ev).modifiers & activeFlag);
			
			break;
		
		case updateEvt:
			runmodeupdate ();
			
			break;
		
		/*4.1b4 dmb: must handle own activates*/
		case osEvt:
			runmodeactivate ((*ev).modifiers & resumeFlag);
			
			break;
		
		case nullEvent:
			if (w == FrontWindow ())
				runmodeidle ();
			else
				runmodecheckupdate (); /*DW 9/13/93: may need update even if it's not in front*/
			
			flhandled = false; /*let the client get a shot at null events too*/
			
			break;
		
		case iowaOkeyDokeyEvent: /*dmb 1.0b21*/
			flhandled = !visitobjects ((**iowadata).objectlist, &returnkeyvisit);
			
			if (!flhandled) {
				
				keyboardstatus.chkb = chescape;
				
				flhandled = runmodekeystroke ();
				}
			
			break;
		} /*switch*/
	
	checkinvisibles ();
	
	popmacport ();
	
	return (flhandled);
	} /*handleCardEvent*/
	
	
static boolean nullsforallvisit (WindowPtr w) {
	
	hdlruntimerecord hcw = getwindowdata (w);
	EventRecord ev;
	boolean flcloseallwindows;
	
	if ((**hcw).modeless) {
	
		clearbytes (&ev, longsizeof (ev));
	
		ev.what = nullEvent;
	
		handleCardEvent (w, &ev, &flcloseallwindows);
		}
	
	return (true);
	} /*nullsforallvisit*/
	
	
static boolean nullsforall (void) {
	
	/*
	send a null event to every modeless card that's open.
	*/
	
	visitCardWindows (&nullsforallvisit);
	
	return (true);
	} /*nullsforall*/
	
	
boolean setObjectValue (hdlcard hcard, bigstring name, Handle hvalue) {

	hdlcard oldcard = iowadata;
	boolean fl;
	
	iowadata = hcard;
	
	fl = setCardValue (name, hvalue);
	
	iowadata = oldcard;
	
	return (fl);
	} /*setObjectValue*/
	
	
boolean getObjectValue (hdlcard hcard, bigstring name, Handle *hvalue) {
	
	hdlcard oldcard = iowadata;
	boolean fl;
	
	iowadata = hcard;
	
	fl = getCardValue (name, hvalue);
	
	iowadata = oldcard;
	
	return (fl);
	} /*getObjectValue*/


boolean getObjectHandle (hdlcard hcard, bigstring name, hdlobject *h) {
	
	hdlcard oldcard = iowadata;
	boolean fl;
	
	iowadata = hcard;
	
	fl = lookupname (name, h);
	
	iowadata = oldcard;
	
	return (fl);
	} /*getObjectHandle*/
	
	
boolean recalcObject (hdlobject h) {
	
	/*
	Card Editor has all of its recalculation done for it thru Iowa
	Runtime. the object handle has a handle to the card that contains
	it. its objecttmpbit is set true if it's a major recalc, false
	if its a minor one.
	*/
	
	hdlcard oldcard = iowadata;
	boolean fl;
	
	iowadata = (**h).owningcard;
	
	fl = recalcbottleneck (h, (**h).objecttmpbit);
	
	(**h).objecttmpbit = false;
	
	iowadata = oldcard;
	
	return (fl);
	} /*recalcObject*/
	
	
boolean updateCard (hdlcard hcard) {

	hdlcard oldcard = iowadata;
	
	iowadata = hcard;
	
	runtimedata = getwindowdata ((**iowadata).drawwindow); 
	
	runmodecheckupdate ();
	
	runmodeupdate ();
	
	iowadata = oldcard;
	
	if (iowadata == nil)
		runtimedata = nil;
	else
		runtimedata = getwindowdata ((**iowadata).drawwindow); 
	
	return (true);
	} /*updateCard*/


boolean cardIsModal (Handle hpackedcard) {

	tydiskheader header;
	
	moveleft (*hpackedcard, &header, longsizeof (header));
	
	switch (header.idwindow) {
		
		case 1024: case 1025:
			return (true);
			
		case 1026: case 1027:
			return (false);
			
		} /*switch*/
		
	#ifdef fldebug
	
		DebugStr ("\punexpected window resource id");
		
	#endif
	
	return (true);
	} /*cardIsModal*/
	
	
static boolean returnNamedValueVisit (hdlobject h) {
	
	/*
	a special AE that might only be useful in Card Editor's
	double-click dialog. but it makes it much faster.
	
	we return the values of all objects that have four-
	character names. only checkboxes, radio buttons and 
	edittexts.
	*/
	
	Handle hname, hvalue;
	bigstring bs;
	OSType key;
	
	getobjectname (h, &hname);
	
	if (hname == nil)
		return (true);
		
	texthandletostring (hname, bs);
		
	if (stringlength (bs) != 4) /*keep going*/
		return (true);
	
	BlockMove (&bs [1], &key, 4);
	
	switch ((**h).objecttype) {
		
		case checkboxtype: case radiobuttontype:
			IACpushbooleanparam ((**h).objectflag, key);
			
			break;
			
		case edittexttype:
			getobjectvalue (h, &hvalue);
			
			copyhandle (hvalue, &hvalue);
			
			IACpushtextparam (hvalue, key);
			
			break;
		} /*switch*/
		
	return (true); /*keep visiting*/
	} /*returnNamedValueVisit*/


static void getCardAttributesVerb (void) {
	
	Boolean returnedValue;
	
	returnedValue = IACgetcardattributes ();
	
	IACreturnboolean (returnedValue);
	} /*getCardAttributesVerb*/


static void setCardAttributesVerb (void) {
	
	Boolean returnedValue;
	
	returnedValue = IACsetcardattributes ();
	
	IACreturnboolean (returnedValue);
	} /*setCardAttributesVerb*/


static void getObjectAttributesVerb (void) {
	
	Handle param1;
	Boolean returnedValue;
	
	if (!IACgettextparam ('prm1', ¶m1))
		return;
	
	returnedValue = IACgetobjectattributes (param1);
	
	IACreturnboolean (returnedValue);
	} /*getObjectAttributesVerb*/


static void setObjectAttributesVerb (void) {
	
	Handle param1;
	Boolean returnedValue;
	
	if (!IACgettextparam ('prm1', ¶m1))
		return;
	
	returnedValue = IACsetobjectattributes (param1);
	
	IACreturnboolean (returnedValue);
	} /*setObjectAttributesVerb*/
	
	
static pascal OSErr appleEventHandler (const AppleEvent *event, AppleEvent *reply, long refcon) {
	
	/*
	4.1b14 dmb: since we're installing out handler in the client's process,
	we need to set up our A5 globals
	*/
	
#if !TARGET_CPU_PPC
	long curA5 = SetUpAppA5 ();
#endif

	IACglobals.event = (AppleEvent *) event; 
	
	IACglobals.reply = reply;
	
	IACglobals.refcon = refcon;
		
	switch (IACgetverbtoken ()) {
	
		case 'clos':
			if (runtimedata != nil)
				(**runtimedata).closethiswindow = true;
			
			break;
			
		case 'gacd':
			getCardAttributesVerb (); 
			
			break;
		
		case 'sacd':
			setCardAttributesVerb (); 
			
			break;
		
		case 'gaob':
			getObjectAttributesVerb (); 
			
			break;
		
		case 'saob':
			setObjectAttributesVerb (); 
			
			break;
			
		case 'mema': {
			Size x;
	
			MaxMem (&x);
			
			IACreturnlong (FreeMem ());
			
			break;
			}
			
		case 'rnov':
			IACglobals.event = IACglobals.reply; /*push the values onto the reply record*/
			
			visitobjects ((**iowadata).objectlist, &returnNamedValueVisit); 
			
			break;
		} /*switch*/
	
#if !TARGET_CPU_PPC
	RestoreA5 (curA5);
#endif
	
	return (noErr);
	} /*appleEventHandler*/


#if !GENERATINGCFM

	#define appleEventHandlerUPP (&appleEventHandler)
	
#else

	static RoutineDescriptor appleEventHandlerDesc = BUILD_ROUTINE_DESCRIPTOR (uppAEEventHandlerProcInfo, appleEventHandler);

	#define appleEventHandlerUPP (&appleEventHandlerDesc)

#endif



void installRuntimeEventHandlers (void) {
	
	/*
	1.0b19 dmb: reinstall handlers every time we're called. It could be 
	the we're competing with handlers installed by other cards being 
	run from OSA scripts. along with this, we must be sure to create 
	the UPP just once, so we can't use IACinstallhandler.
	*/
	
	static boolean flinstalled = false;
	
	if (!flinstalled) {
	
		AEInstallEventHandler ('card', typeWildCard, appleEventHandlerUPP, 0, false);
		
		/*
		IACinstallhandler ('card', typeWildCard, (ProcPtr) &appleEventHandler);
		
		flinstalled = true; // 1.0b19 dmb: commented out
		*/
		}
	} /*installRuntimeEventHandlers*/
	
	
static boolean passthruevent (short what) {
	
	return ((what == updateEvt) || (what == activateEvt) || (what == osEvt)  || (what == diskEvt));
	} /*passthruevent*/


boolean runModalCard (Handle hpackedcard, boolean flscriptedcard, short top, short left, tycardeventcallback callback) {
	
	/*
	dmb 1.0b24: changed flcallback logic. we no longer call back on activate
	and update events that we just handled
	*/
	
	hdlcard oldiowadata = iowadata; 
	hdlruntimerecord oldruntimedata = runtimedata;
	GrafPtr oldport;
	WindowPtr modalwindow;
	Point winpos;
	boolean flreturn;
	
	GetPort (&oldport);
	
	installRuntimeEventHandlers ();
	
	winpos.v = top;
	
	winpos.h = left;
	
	modalwindow = newCardWindow (winpos, !flscriptedcard, hpackedcard);
	
	flreturn = true;
		
	if (modalwindow == nil) {
		
		flreturn = false;
		
		goto exit;
		}
		
	(**runtimedata).callback = callback;
		
	(**runtimedata).modeless = false;
	
	if (flscriptedcard) {
	
		if (!frontStartCard (nil)) {
			
			flreturn = false;
			
			goto exit;
			}
		}
	
	SetPort (modalwindow);
	
	sendinitmessage ();
		
	cardcheckinit (); /*1.0b23 dmb: init field before showing the card. more responsive*/
	
	flexitcardloop = false;
	
	ShowWindow (modalwindow);
	
	while (true) {
		
		EventRecord ev;
		WindowPtr eventwindow;
		boolean flcloseallwindows;
		boolean flcallback = false;
		
		WaitNextEvent (everyEvent, &ev, 1, nil);
		
		if (ev.what == nullEvent) /*send a null event to every modeless card*/
			nullsforall ();
			
		geteventwindow (&ev, &eventwindow);
		
		if (eventwindow == modalwindow)
			flcallback = !handleCardEvent (eventwindow, &ev, &flcloseallwindows);
		else
			flcallback = passthruevent (ev.what) || (eventwindow == nil);
		
		/*
		if (eventwindow == modalwindow) {
		
			flcallback = !handleCardEvent (eventwindow, &ev, &flcloseallwindows);
			}
		else {
			if ((passthruevent (ev.what)) || (eventwindow == nil)) {
				
				if (!handleCardEvent (eventwindow, &ev, &flcloseallwindows)) {
					
					flcallback = true;
					}
				}
			}
		*/
			
		if ((flcallback) && (callback != nil)) {
			
			hdlcard oldiowadata = iowadata;
			hdlruntimerecord oldruntimedata = runtimedata;
			
			(*callback) (&ev);
			
			iowadata = oldiowadata;
		
			runtimedata = oldruntimedata;
	
			SetPort (modalwindow);
			}
			
		if (flexitcardloop)
			break;
		
		if ((**runtimedata).closethiswindow) /*set true by an Apple Event*/
			closeCardWindow (modalwindow); 
		
		if (flexitcardloop) /*can be set by closeCardWindow*/
			break;
		} /*while*/
		
	exit:
		
	flexitcardloop = false; /*we consume it, modal cards can be nested*/
	
	/*restore saved globals*/ {
	
		iowadata = oldiowadata;
		
		runtimedata = oldruntimedata;
	
		SetPort (oldport);
		}
	
	return (flreturn);
	} /*runModalCard*/
	

boolean isModelessCardEvent (EventRecord *ev, boolean *flcloseallwindows) {
	
	hdlcard oldiowadata = iowadata; 
	hdlruntimerecord oldruntimedata = runtimedata;
	GrafPtr oldport = quickdrawglobal (thePort);
	boolean flreturn = false;
	WindowPtr w;
	
	if ((*ev).what == nullEvent) {
	
		nullsforall ();
		
		goto exit; /*return false -- let the main event loop process it too*/
		}
		
	geteventwindow (ev, &w);

	if (isCardWindow (w)) 
		flreturn = handleCardEvent (w, ev, flcloseallwindows);
	
	exit:
	
	/*restore saved globals*/ {
	
		iowadata = oldiowadata;
		
		runtimedata = oldruntimedata;
	
		SetPort (oldport);
		}
	
	return (flreturn);
	} /*isModelessCardEvent*/
	
	
boolean runModelessCard (Handle hpackedcard, boolean flscriptedcard, short top, short left, tycardeventcallback callback) {
	
	/*
	dmb 1.024: call cardcheckinit here, before showing window. 
	this accomplishes three things:
	
	1. It ensures that all fields are before the card is shown.
	
	2. Invoking a card is crisper; we don't need to wait for a null
	   event before running startup scripts.
	   
	3. It allows the calling script's context to be in force as our 
	   initial recalc scripts and starupScript run.
	*/
	
	hdlcard oldiowadata = iowadata; 
	hdlruntimerecord oldruntimedata = runtimedata;
	GrafPtr oldport = quickdrawglobal (thePort);
	Point winpos;
	WindowPtr modelesswindow;
	boolean flreturn;
	
	installRuntimeEventHandlers ();
	
	winpos.v = top;
	
	winpos.h = left;
	
	modelesswindow = newCardWindow (winpos, !flscriptedcard, hpackedcard);
	
	flreturn = true;
	
	if (modelesswindow == nil) {
		
		flreturn = false;
		
		goto exit;
		}
		
	(**runtimedata).callback = callback;
		
	(**runtimedata).modeless = true;
	
	if (flscriptedcard) {
	
		if (!frontStartCard (nil)) {
		
			flreturn = false;
		
			goto exit;
			}
		}
	
	SetPort (modelesswindow);
	
	sendinitmessage ();
	
	cardcheckinit (); /*1.0b24 dmb: see comment above*/
	
	ShowWindow (modelesswindow);

	exit:
	
	/*restore saved globals*/ {
	
		iowadata = oldiowadata;
		
		runtimedata = oldruntimedata;
	
		SetPort (oldport);
		}
		
	return (flreturn);
	} /*runModelessCard*/
	 

boolean runCard (Handle hpackedcard, boolean flscriptedcard, short top, short left, tycardeventcallback callback) {
	
	boolean fl;
	
	if (cardIsModal (hpackedcard)) 
		fl = runModalCard (hpackedcard, flscriptedcard, top, left, callback);
	else
		fl = runModelessCard (hpackedcard, flscriptedcard, top, left, callback);
		
	return (fl);
	} /*runCard*/
	
	
static WindowPtr moveIntoCardWindow (WindowPtr hostwindow, boolean notscriptedcard, Handle hpackedcard) {
	
	/*
	use existing window to run the packed card.
	
	dmb 2.1.96: this could share plenty of code with newCardWindow
	*/
	
	WindowPtr w = hostwindow;
	hdlruntimerecord hw;
	hdlcard hc;
	
	iowadata = nil;
	
	if (!newclearhandle (longsizeof (tyruntimerecord), (Handle *) &runtimedata))
		return (false);
	
	if (!newclearhandle (longsizeof (tycard), (Handle *) &iowadata))
		goto error;
		
	hw = runtimedata; 
	
	hc = iowadata; 
	
	(**hw).hc = hc;
	
	(**hc).runmode = true; 
	
	if (!iowaunpack (hpackedcard))
		goto error;

	(**hc).runmode = true;
	
	(**hc).notscriptedcard = notscriptedcard;
	
	(**hc).updatecallback = &runmodeupdate;
	
	(**hw).macwindow = w;
	
	(**hw).ownwindow = false;
	
	(**hw).initfields = true;
	
	(**hc).drawwindow = w; /*all drawing goes into this window*/
	
	IACglobals.waitroutine = nil; /*no callback when in runmode*/
	
	sortobjectlist (); /*sort objects based on window position*/
	
	laythread (); /*make sure flat threads are installed*/
	
	addtowindowarray (w, hw);
	
	return (w);
	
	error:
	
	disposehandle ((Handle) iowadata);
	
	disposehandle ((Handle) runtimedata);
	
	iowadata = nil;
	
	runtimedata = nil;
	
	return (nil);
	} /*moveIntoCardWindow*/
	
	
boolean runHostedCard (WindowPtr hostwindow, Handle hpackedcard, boolean flscriptedcard, tycardeventcallback callback) {
	
	hdlcard oldiowadata = iowadata; 
	hdlruntimerecord oldruntimedata = runtimedata;
	GrafPtr oldport;
	WindowPtr modelesswindow;
	boolean flreturn;
	
	GetPort (&oldport);
	
	installRuntimeEventHandlers ();
	
	modelesswindow = moveIntoCardWindow (hostwindow, !flscriptedcard, hpackedcard);
	
	flreturn = true;
	
	(**runtimedata).callback = callback;
	
	(**runtimedata).modeless = true;
	
	if (flscriptedcard) {
	
		if (!frontStartCard (nil)) {
		
			flreturn = false;
		
			goto exit;
			}
		}
	
	SetPort (modelesswindow);
	
	sendinitmessage ();

	exit:
	
	/*restore saved globals*/ {
	
		iowadata = oldiowadata;
		
		runtimedata = oldruntimedata;
	
		SetPort (oldport);
		}
		
	return (flreturn);
	} /*runHostedCard*/
	
	
boolean initIowaRuntime (void) {
	
	/*
	4.1b14 dmb: remember A5 for AE handler
	*/

#if !TARGET_CPU_PPC	
	RememberA5 ();
#endif

	return (true);
	} /*initIowaRuntime*/