/****************************************************************
/*								*
/*	HackBench - Part 3 of 4 - hbobj.c - Object Routines 	*
/*								*
/*	Copyright (C) 1987 by Bill Kinnersley			*
/*	CS Dept, Washington State Univ, Pullman, WA 99164	*
/*								*
/*	Permission granted to redistribute this program		*
/*	provided the copyright notice remains intact.		*
/*	May not be used as part of any commercial product.	*
/*								*
/****************************************************************/

#include "hb.h"

extern struct DosLibrary *DosBase;
extern struct DosInfo *rnInfo;
extern struct MsgPort *IDCMPPort, *WBPort;
extern struct Window *wbWin, *curWin;
extern struct DiskObject defDskObj;
extern struct Menu *menuStrip;
extern struct Gadget
	vs_gad, hs_gad, ren_gad, up_gad, dm_gad, lm_gad, rm_gad;
extern struct PropInfo hs_knob, vs_knob;
extern USHORT zz_ptr[];
extern char *title, *rindex();
extern BPTR initialDir, getlock();
extern short debug;

struct Rectangle rect = {4, 11};

struct List wbObjs, selObjs, utilObjs;
short lastHeight=14, toolsRunning = 0, wbFlags = 0;

void *allocList();
int drawobj(), compobj();

char *type[8] = {"", "DISK", "DRAWER", "TOOL", "PROJECT",
	"GARBAGE", "DEVICE", "KICK"};
char *empty = "";

struct IntuiText icon_txt = {1, 0, JAM2, 5, 0, NULL, NULL, NULL};

/* Manufacture a new WBObject with a given name, window, and parent */
struct MyWBObject *makeObj(diskObj, name, w, parent)
struct DiskObject *diskObj; char *name;
struct Window *w; struct MyWBObject *parent; {
	struct MyWBObject *obj;
	char *buf, *p;
	SHORT size, i, s;
	struct Gadget *g;
	struct Image *image;
	USHORT *data;
	struct MyDrawerData *dd;
	struct NewWindow *nwd;

	if (!(obj= ALLOC(MyWBObject)))
		{error("Can't allocate WB Object"); return;}
	NewList(&obj->wo_FreeList.fl_MemList);
	buf = allocList(obj, 31);
	/* Space for 31 chars in case it's later renamed */
	strcpy(buf, name);
	obj->wo_Name = obj->wo_MasterNode.ln_Name = 
	obj->wo_Siblings.ln_Name = obj->wo_SelectNode.ln_Name = buf;
	AddTail(&wbObjs, obj);
	obj->wo_IconWin = w;
	obj->wo_Type = diskObj->do_Type;
	if (diskObj->do_ToolTypes) {
		for (i = 0; p = diskObj->do_ToolTypes[i]; i++) ;
		obj->wo_ToolTypes = allocList(obj, 4*i);
		for (i = 0; p = diskObj->do_ToolTypes[i]; i++) {
			buf = allocList(obj, strlen(p)+1);
			strcpy(buf, p);
			obj->wo_ToolTypes[i] = buf;
		}
	}
	if (diskObj->do_ToolWindow) {
		buf = allocList(obj, strlen(diskObj->do_ToolWindow)+1);
		strcpy(buf, diskObj->do_ToolWindow);
		obj->wo_ToolWindow = buf;
	}
	if (diskObj->do_DefaultTool) {
		buf = allocList(obj, strlen(diskObj->do_DefaultTool)+1);
		strcpy(buf, diskObj->do_DefaultTool);
		obj->wo_DefaultTool = buf;
	}
	obj->wo_StackSize = diskObj->do_StackSize;
	obj->wo_CurrentX = diskObj->do_CurrentX;
	obj->wo_CurrentY = diskObj->do_CurrentY;
	if (diskObj->do_CurrentX==NO_ICON_POSITION) {
		if (debug) printf("<%s>:No Icon Position\n", name);
		obj->wo_CurrentX = 20; obj->wo_CurrentY = 10;
		/* Should do better placement than this */
	}
	g = &diskObj->do_Gadget;
	/* stc means structure copy */
/*stc*/	obj->wo_Gadget = diskObj->do_Gadget;
	image = allocList(obj, sizeof(struct Image));
/*stc*/ *image = *(struct Image *)(diskObj->do_Gadget.GadgetRender);
	obj->wo_Gadget.GadgetRender = (APTR)image;

	size = (image->Width/16) + ((image->Width%16)>0);
	size *= image->Height * image->Depth;
	data = allocList(obj, 2*size);
	for (i=0; i<size; i++) data[i] = (image->ImageData)[i];
	image->ImageData = data;

	image = allocList(obj, sizeof(struct Image));
	if (diskObj->do_Gadget.SelectRender)
/*stc*/		*image = *(struct Image *)(diskObj->do_Gadget.SelectRender);
	else *image = *(struct Image *)(diskObj->do_Gadget.GadgetRender);
	obj->wo_Gadget.SelectRender = (APTR)image;

	size = (image->Width/16) + ((image->Width%16)>0);
	size *= image->Height * image->Depth;
	data = allocList(obj, 2*size);

	if (diskObj->do_Gadget.SelectRender)
		for (i=0; i<size; i++) data[i] = (image->ImageData)[i];
	else
		for (i=0; i<size; i++) data[i] = ~(image->ImageData)[i];
	image->ImageData = data;

	if (diskObj->do_DrawerData) {
		dd = allocList(obj, sizeof(struct MyDrawerData));
		obj->wo_DrawerData = dd;
/* stc */	dd->dd_NewWindow = diskObj->do_DrawerData->dd_NewWindow;
		dd->dd_NewWindow.Title = obj->wo_Name;
		NewList(&dd->dd_Children);
		dd->dd_CurrentX = diskObj->do_DrawerData->dd_CurrentX;
		dd->dd_CurrentY = diskObj->do_DrawerData->dd_CurrentY;
		nwd = &dd->dd_NewWindow;
		nwd->MinWidth = 90;
		nwd->MinHeight = 40;
		nwd->MaxWidth = nwd->MaxHeight = -1;
		dd->dd_MinX = dd->dd_MinY = 0;
		dd->dd_MaxX = nwd->Width - 14;
		dd->dd_MaxY = nwd->Height - 9;
/*stc*/ 	dd->dd_HorizScroll = hs_gad;
/*stc*/		dd->dd_VertScroll = vs_gad;
/*stc*/ 	dd->dd_UpMove = up_gad;
/*stc*/ 	dd->dd_DownMove = dm_gad;
/*stc*/ 	dd->dd_LeftMove = lm_gad;
/*stc*/ 	dd->dd_RightMove = rm_gad;
/*stc*/ 	dd->dd_HorizProp = hs_knob;
/*stc*/ 	dd->dd_VertProp = vs_knob;
		dd->dd_HorizScroll.GadgetRender = (APTR)&dd->dd_HorizImage;
		dd->dd_HorizScroll.SpecialInfo = (APTR)&dd->dd_HorizProp;
		dd->dd_VertScroll.GadgetRender = (APTR)&dd->dd_VertImage;
		dd->dd_VertScroll.SpecialInfo = (APTR)&dd->dd_VertProp;
		dd->dd_HorizScroll.NextGadget = &dd->dd_VertScroll;
		dd->dd_VertScroll.NextGadget = &dd->dd_UpMove;
		dd->dd_UpMove.NextGadget = &dd->dd_DownMove;
		dd->dd_DownMove.NextGadget = &dd->dd_LeftMove;
		dd->dd_LeftMove.NextGadget = &dd->dd_RightMove;
		dd->dd_NewWindow.FirstGadget = &dd->dd_HorizScroll;
	}
	obj->wo_NameXOffset = (g->Width/2)-4*strlen(name);
	obj->wo_NameYOffset = g->Height;
	obj->wo_Parent = parent;
	if (parent && parent->wo_DrawerData) {
		AddHead(&parent->wo_DrawerData->dd_Children,
			&obj->wo_Siblings);
		if (debug) printf("Added %lx <%s> to %lx <%s>\n",
			obj, obj->wo_Name, parent, parent->wo_Name);
	}
	return obj;
}

/* Given a List, use off to find the objects,
then perform fn on each object with parameter p1 */
doList(list, off, fn, p1)
struct List *list; long off; int (*fn)(); {
	struct MyWBObject *obj;
	struct Node *node;

	for (node=list->lh_Head; node->ln_Succ; node=node->ln_Succ) {
		obj = OBJ(node,off);
		(*fn)(obj, p1);
	}
}

/* Remove an object from the system */
deleteobj(obj) struct MyWBObject *obj; {
    struct MyDrawerData *dd;
    struct MyWBObject *child;
    struct Node *node;
    long off;

    if (dd = obj->wo_DrawerData) {
	if (dd->dd_DrawerWin) /* Shouldn't happen */
	    {printf("Can't delete me--I'm open\n"); return;}
	if (dd->dd_Lock) {
	    if (debug) printf("deleteobj: Unlocking dd_Lock: <%s> %lx\n",
		obj->wo_Name, dd->dd_Lock);
	    UnLock(dd->dd_Lock);
	    dd->dd_Lock = NULL;
	}
	while (node = RemHead(&dd->dd_Children)) {
	    child = OBJ(node, CHILD);
	    if (debug) printf("Found an orphan %lx\n", child);
	    child->wo_Parent = NULL;
	}
    }
    if (debug) printf("Deleting %lx <%s> %lx\n", obj,
	obj->wo_MasterNode.ln_Name, obj->wo_Lock);
    if (obj->wo_Lock) {
	if (debug) printf("deleteobj: Unlocking wo_Lock: <%s> %lx\n",
	    obj->wo_Name, obj->wo_Lock);
	UnLock(obj->wo_Lock);
	obj->wo_Lock = NULL;
    }
    FreeFreeList(&obj->wo_FreeList);
    for (off=0; off<4; off++) {
	node = (struct Node *)((long)obj + off*sizeof(struct Node));
	if (node->ln_Succ) Remove(node);
    }
    FreeMem(obj, (long)sizeof(struct MyWBObject));
}

struct DiskObject *getDisk(name) char *name; {
	char buf[36];

	strcpy(buf, name);
	strcat(buf,":Disk");
	return GetDiskObject(buf);
}

/* Initial installation of all Volumes on the Device List */
findDisks() {
	struct DeviceList *diDev, *ptr;
	char diskName[31];

	diDev = (struct DeviceList *) BADDR(rnInfo->di_DevInfo);
	for (ptr=diDev; ptr; ptr=(struct DeviceList *)BADDR(ptr->dl_Next)){
	    if (ptr->dl_Type==DLT_VOLUME) {
		bs2cs(diskName, ptr->dl_Name);
		if (debug) printf("<%s>\n", diskName);
		instDisk(diskName);
	    }
	}
}

/* Install an object and icon for a disk */
instDisk(diskName) char *diskName; {
	struct DiskObject *dObj;
	struct MyWBObject *obj;

	if (dObj = getDisk(diskName)) {
		if (dObj->do_CurrentX==NO_ICON_POSITION)
			dObj->do_CurrentX = 576;
		if (dObj->do_CurrentY==NO_ICON_POSITION)
			dObj->do_CurrentY = lastHeight;
		obj = makeObj(dObj, diskName, wbWin, NULL);
		FreeDiskObject(dObj);
	}
	else {
		if (debug) printf("Default icon\n");
		dObj = &defDskObj;
		dObj->do_CurrentY = lastHeight;
		obj = makeObj(dObj, diskName, wbWin, NULL);
	}
	drawobj(obj, NORM);
	lastHeight += 22L;
	/* Should try harder to find an empty spot */
}

/* For debugging, print everybody on a List */
dumplist(list, off) struct List *list; long off; {
	struct Node *node;
	struct MyWBObject *child;

	printf("---\n");
	for (node=list->lh_Head; node->ln_Succ; node=node->ln_Succ) {
		child = OBJ(node,off);
		printf("%lx <%s>\n", node, node->ln_Name);
	}
}

/* Close a drawer object */
closeobj(obj) struct MyWBObject *obj; {
    struct MyDrawerData *dd;
    struct Node *node;
    struct MyWBObject *child;
    struct FileLock mylock;
    struct Region *reg;

    if (!(dd = obj->wo_DrawerData)) return;
    if (!dd->dd_DrawerWin) return;
    NewList(&utilObjs);
    for (node=dd->dd_Children.lh_Head; node->ln_Succ;
    node = node->ln_Succ) {
	child = OBJ(node,CHILD);
	if (debug) printf("child: %lx <%s>\n", child, child->wo_Name);
	if (child->wo_IconWin==dd->dd_DrawerWin) { /* In this window */
	    if (child->wo_DrawerData) /* a drawer */ {
		if (child->wo_DrawerData->dd_DrawerWin) {
		    if (debug) printf("Child open..retained\n");
		    child->wo_IconWin = NULL;
		    if (child->wo_SelectNode.ln_Succ) {
			Remove(&child->wo_SelectNode);
			child->wo_SelectNode.ln_Succ = NULL;
		    }
		    continue;
		}
		if (child->wo_DrawerData->dd_Children.lh_Head->ln_Succ) {
		    if (debug) {
			printf("Child has children..retained\n");
			printf("closeobj: grandchildren:");
			dumplist(&child->wo_DrawerData->dd_Children, CHILD);
		    }
		    child->wo_IconWin = NULL;
		    continue;
		}
	    }/* if drawer */
	    AddHead(&utilObjs, &child->wo_UtilityNode);
	}/* if in window */
    }/* for children */
    doList(&utilObjs, UTIL, deleteobj); /* Kill the kids */
    dd->dd_NewWindow.LeftEdge = dd->dd_DrawerWin->LeftEdge;
    dd->dd_NewWindow.TopEdge = dd->dd_DrawerWin->TopEdge;
    dd->dd_NewWindow.Width = dd->dd_DrawerWin->Width;
    dd->dd_NewWindow.Height = dd->dd_DrawerWin->Height;
    reg = InstallClipRegion(dd->dd_DrawerWin->WLayer, NULL);
    DisposeRegion(reg);
    closeWinSafely(dd->dd_DrawerWin);
    dd->dd_DrawerWin = NULL;
    if (dd->dd_Lock) {
	if (debug) printf("closeobj: cd %lx\n", initialDir);
	CurrentDir(initialDir);
	if (debug) printf("closeobj: Unlocking dd_Lock <%s> %lx\n",
	    obj->wo_Name, dd->dd_Lock);
	UnLock(dd->dd_Lock);
	dd->dd_Lock = NULL;
    }
}

/* Remove an icon from the screen */
clearobj(obj) struct MyWBObject *obj; {
    struct Window *w;
    struct MyDrawerData *dd;
    long cx=0, cy=0;

    if ((w = obj->wo_IconWin)!=wbWin) {
	dd = ((struct MyWBObject *)w->UserData)->wo_DrawerData;
	cx = dd->dd_CurrentX;
	cy = dd->dd_CurrentY;
    }
    if (debug) printf("clearobj: %lx <%s> win=%lx\n", obj, obj->wo_Name, w);
    SetAPen(w->RPort, 0L);
    RectFill(w->RPort,
	obj->wo_CurrentX - cx, obj->wo_CurrentY + YOFF - cy,
	obj->wo_CurrentX + obj->wo_Gadget.Width - cx,
	obj->wo_CurrentY + obj->wo_Gadget.Height + YOFF - cy);
    RectFill(w->RPort,
	obj->wo_CurrentX + obj->wo_NameXOffset - cx,
	obj->wo_CurrentY + obj->wo_NameYOffset + YOFF - cy,
	obj->wo_CurrentX + obj->wo_NameXOffset +
		8L*(long)strlen(obj->wo_Name) - cx,
	obj->wo_CurrentY + obj->wo_NameYOffset + YOFF + 10L - cy);
    SetAPen(w->RPort, 1L);
}

/* Toggle an icon, highlighted <-> normal */
compobj(obj) struct MyWBObject *obj; {
	struct Window *w;
	long cx=0, cy=0;
	struct MyDrawerData *dd;

	if (debug) printf("comp: %lx <%s>\n", obj, obj->wo_Name);
	if ((w = obj->wo_IconWin)!=wbWin) {
		dd = ((struct MyWBObject *)w->UserData)->wo_DrawerData;
		cx = dd->dd_CurrentX;
		cy = dd->dd_CurrentY;
	}
	ClipBlit(w->RPort, obj->wo_CurrentX - cx, obj->wo_CurrentY - cy,
		w->RPort, obj->wo_CurrentX - cx, obj->wo_CurrentY - cy,
		(long)obj->wo_Gadget.Width, (long)obj->wo_Gadget.Height,
		0x50L);
	obj->wo_Flags ^= HIGH;	/* For use by refresh() */
}

/* At position (x,y) see if an icon was hit and if so whom */
struct MyWBObject *findObj(x, y, w) short x, y; struct Window *w; {
	struct Node *node;
	struct Gadget *gad;
	struct MyWBObject *obj;
	struct MyDrawerData *dd;
	long cx=0, cy=0;

	if (w!=wbWin) {
		dd = ((struct MyWBObject *)w->UserData)->wo_DrawerData;
		cx = dd->dd_CurrentX;
		cy = dd->dd_CurrentY;
	}
	/* Scan list in reverse order,
	so that last icon drawn is first one found */
	for (node=wbObjs.lh_TailPred; node->ln_Pred; node=node->ln_Pred) {
		obj = (struct MyWBObject *)node;
		if (w != obj->wo_IconWin) continue;
		gad = &obj->wo_Gadget;
		if ((x > (obj->wo_CurrentX-cx)) &&
			(x < (obj->wo_CurrentX + gad->Width - cx)) &&
			(y > (obj->wo_CurrentY + YOFF - cy)) &&
			(y < (obj->wo_CurrentY + gad->Height + YOFF - cy)))
			return obj;
	}
	return NULL;
}

openobj(obj) struct MyWBObject *obj; {
	struct Window *w;
	struct MyDrawerData *dd;
	char name[80];
	struct Region *reg;
	BPTR lock;

	if (debug) printf("openobj:%lx <%s>\n",obj, obj->wo_Name);
	if (!(dd = obj->wo_DrawerData)) {
		printf("What's this %s doing here??\n",type[obj->wo_Type]);
		return;
	}
	if (dd->dd_DrawerWin) return; /* Already open */
	SetPointer(curWin, zz_ptr, 19L, 16L, -7L, -8L);
	dd->dd_NewWindow.Title = obj->wo_Name;
	dd->dd_NewWindow.IDCMPFlags = 0;
	if (!(w = OpenWindow(&dd->dd_NewWindow)))
		{error("Couldn't open the drawer\n"); goto opcln;}
	dd->dd_DrawerWin = w;
	w->UserPort = IDCMPPort;
	ModifyIDCMP(w, CLOSEWINDOW | GADGETUP | GADGETDOWN |
		MENUPICK | NEWSIZE | MOUSEBUTTONS | REFRESHWINDOW);
	SetMenuStrip(w, menuStrip);
	SetWindowTitles(w, -1L, title);
	reclip(w);
	/* UserData holds a pointer back to the object */
	w->UserData = (BYTE *)obj;

	lock = getlock(obj);
	if (debug) printf("openobj: cd %lx\n", lock);
	CurrentDir(lock);
	if (!dd->dd_Lock) {
		strcpy(name, obj->wo_Name);
		if (obj->wo_Type==WBDISK) strcat(name,":");
		dd->dd_Lock = Lock(name, ACCESS_READ);
		if (debug) printf("openobj Locked <%s> %lx\n",
			name, dd->dd_Lock);
		if (!dd->dd_Lock) {
			error("This drawer cannot be opened");
			/* Probably an .info file all by itself */
			reg = InstallClipRegion(w->WLayer, NULL);
			DisposeRegion(reg);
			closeWinSafely(w);
			dd->dd_DrawerWin = NULL;
			goto opcln;
		}
	}
	dir(obj, w);
	resize(w);
opcln:	ClearPointer(curWin);
}

/* Search a directory for .info files */
dir(obj, w) struct MyWBObject *obj; struct Window *w; {
	FILE *fd;
	struct InfoData *id;
	LONG success;
	struct FileInfoBlock *m;
	BPTR oldlock, newLock;
	char *name, buf[80], buf2[80], *s;
	struct DiskObject *dObj;
	struct MyWBObject *wbObj;
	struct Node *node;
	struct MyDrawerData *dd;

	dd = obj->wo_DrawerData;
	name = obj->wo_Name;
	strcpy(buf, name);
	strcat(buf,":");

	if (!(newLock = dd->dd_Lock)) {printf("No lock\n"); return;}
	if (debug) printf("dir: cd %lx\n", newLock);
	oldlock = CurrentDir(newLock);
	/* If we were using the .info file itself: */
	/*if (fd=fopen(".info","r")) {
	    if (fseek(fd, 16L, 0)!=-1) {
		while (fgets(buf2, 70, fd)) {
		    buf2[strlen(buf2)-1]=0;
		    if (dObj=GetDiskObject(buf2)) {
			obj = makeObj(dObj, buf2, w, obj);
			doList(&selObjs, SEL, drawobj, NORM);
			FreeDiskObject(dob);
		    }
		    else printf("can't get <%s>\n",buf2);
		}
	    }
	    fclose(fd);
	    return;
	}*/
	if (!(id = ALLOC(InfoData)))
		{error("Can't allocate id"); goto dirCln;}
	if (!(success = Info(newLock, id)))
		{error("Can't get info"); goto dirCln;}
	if (!(m = ALLOC(FileInfoBlock)))
		{error("Can't allocate m"); goto dirCln;}
	if (!(success = Examine(newLock, m)))
		{error("Can't examine directory"); goto dirCln;}
	if (m->fib_DirEntryType<=0)
		{error("Not a directory"); goto dirCln;}
	NewList(&utilObjs);
	while (success = ExNext(newLock, m)) {
	    strcpy(buf, m->fib_FileName);
	    if (s = rindex(buf,'.')) if (strcmp(s,".info")==0) {
		*s = 0;
		if ((*buf) && (strcmp(buf,"Disk"))) {
		    if (debug) printf("Looking for <%s>\n", buf);
		    if (node = FindName(&dd->dd_Children, buf)) {
			wbObj = OBJ(node,CHILD);
			if (debug) printf("Found child <%s> %lx\n",
				node->ln_Name, wbObj);
			if (!wbObj->wo_IconWin)
			    wbObj->wo_IconWin = dd->dd_DrawerWin;
			AddTail(&utilObjs, &wbObj->wo_UtilityNode);
		    }
		    else if (dObj = GetDiskObject(buf)) {
			wbObj = makeObj(dObj, buf, w, obj);
			FreeDiskObject(dObj);
			AddTail(&utilObjs, &wbObj->wo_UtilityNode);
		    }
		    else printf("Can't get <%s>\n", m->fib_FileName);
		} /* if buf */
	    } /* if s */
	} /* while */
	doList(&utilObjs, UTIL, drawobj, NORM);
dirCln:	if (m) FreeMem(m, (long)sizeof(struct FileInfoBlock));
	if (id) FreeMem(id, (long)sizeof(struct InfoData));
}

/* Draw an icon, either normal or hightlighted */
drawobj(obj, mode) struct MyWBObject *obj; {
	struct Window *w;
	long cx=0, cy=0;
	struct MyDrawerData *dd;
	APTR im;

	if ((w = obj->wo_IconWin)!=wbWin) {
		dd = ((struct MyWBObject *)w->UserData)->wo_DrawerData;
		cx = dd->dd_CurrentX;
		cy = dd->dd_CurrentY;
	}
	im = (mode & HIGH) ? obj->wo_Gadget.SelectRender :
		obj->wo_Gadget.GadgetRender;
	DrawImage(w->RPort, im, obj->wo_CurrentX - cx,
		obj->wo_CurrentY + YOFF - cy);
	if (mode & HIGH) obj->wo_Flags |= HIGH;	/* For use by refresh() */
	else obj->wo_Flags &= ~HIGH;
	icon_txt.IText = obj->wo_Name;
	icon_txt.LeftEdge = obj->wo_NameXOffset;
	icon_txt.TopEdge = obj->wo_NameYOffset;
	PrintIText(w->RPort, &icon_txt, obj->wo_CurrentX - cx,
		obj->wo_CurrentY + YOFF - cy);
}

/* Run something */
run(obj) struct MyWBObject *obj; {
	struct WBStartup *msg;
	struct Process *proc;
	long seg, stack;
	struct MsgPort *id;
	struct Node *node;
	char *name, i;
	struct MyWBObject *arg;
	BPTR lock;

	if (obj->wo_Type==WBPROJECT) {
		if (!(name = obj->wo_DefaultTool))
		{error("This project has no default tool"); return;}
		if (debug) printf("Default Tool: <%s>\n", name);
	}
	else if (obj->wo_Type==WBTOOL) name = obj->wo_Name;
	if (debug) printf("Running <%s>\n", name);
	if (!obj->wo_Parent) {printf("I've lost my mommy\n"); return;}
	lock = getlock(obj);
	if (debug) printf("run: cd %lx\n", lock);
	CurrentDir(lock);
	if (!(seg = LoadSeg(name)))
		{error("Can't load the tool"); goto runCln;}
	stack = (obj->wo_StackSize) ? obj->wo_StackSize : 5000L;
	if (debug) printf("stack=%ld\n", stack);
	if (!(id = CreateProc(name, 0L, seg, stack)))
		{printf("Can't create a process\n"); goto runCln;}
	proc = (struct Process *)((long)(id) - sizeof(struct Task));
	if (!(msg = ALLOC(WBStartup)))
		{printf("Can't make a msg\n"); goto runCln;}
	msg->sm_Message.mn_ReplyPort = WBPort;
	msg->sm_Process = id;
	msg->sm_Segment = seg;
	msg->sm_NumArgs = 0;
	if (obj->wo_Type==WBPROJECT) msg->sm_NumArgs++;
	for (node=selObjs.lh_Head; node->ln_Succ; node=node->ln_Succ)
		msg->sm_NumArgs++;
	if (debug) printf("%ld args\n",msg->sm_NumArgs);
	if (!(msg->sm_ArgList =
	AllocMem(msg->sm_NumArgs*(long)sizeof(struct WBArg), MEMF_CPC)))
		{printf("Can't allocate arglist\n"); return;}
	i = 0;
	if (obj->wo_Type==WBPROJECT) {
		msg->sm_ArgList[i].wa_Name = name;
		msg->sm_ArgList[i].wa_Lock = Lock(name, ACCESS_READ);
		i++;
	}
	msg->sm_ArgList[i].wa_Name = obj->wo_Name;
	msg->sm_ArgList[i].wa_Lock = lock;
	i++;
	for (node=selObjs.lh_Head; node->ln_Succ; node=node->ln_Succ) {
		arg = OBJ(node,SEL);
		if (arg==obj) continue;
		if (arg->wo_Type==WBTOOL || arg->wo_Type==WBPROJECT)
			msg->sm_ArgList[i].wa_Name = arg->wo_Name;
		else msg->sm_ArgList[i].wa_Name = empty;
		msg->sm_ArgList[i].wa_Lock = getlock(arg);
		if (debug) printf("<%s> %lx\n",
			msg->sm_ArgList[i].wa_Name,
			msg->sm_ArgList[i].wa_Lock);
		/* Wrong for dirs--the lock should be a lock
		on the object itself */
		i++;
	}
	msg->sm_ToolWindow = obj->wo_ToolWindow;
	if (obj->wo_ToolWindow) if (debug)
		printf("ToolWindow:<%s>\n", obj->wo_ToolWindow);
	PutMsg(id, msg);
	toolsRunning++;
	return;
runCln:	if (seg) {
		if (debug) printf("runCln: unloading\n");
		UnLoadSeg(seg);
	}
}

void *allocList(obj, size) struct MyWBObject *obj; {
	void *buf;

	if (!(buf = AllocMem((long)size, MEMF_CPC)))
		closeAll("Can't allocList");
	AddFreeList(&obj->wo_FreeList, buf, (long)size);
	return buf;
}

refresh(w) struct Window *w; {
	struct MyWBObject *obj;
	struct Node *node;

	if (debug) printf("Refresh %lx <%s>\n", w, w->Title);
	for (node=wbObjs.lh_Head; node->ln_Succ; node=node->ln_Succ) {
		obj = (struct MyWBObject *) node;
		if (obj->wo_IconWin==w) drawobj(obj, obj->wo_Flags & HIGH);
	}
}
