/**************************************************************** /* * /* HackBench - Part 2 of 4 - hbicon.c - Icon 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 DosInfo *rnInfo; extern struct MsgPort *IDCMPPort, WBPort; extern long IDCMPBit, WBBit; extern USHORT x_ptr[]; 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 struct Rectangle rect; extern char *type[], *title; extern short wbFlags, toolsRunning; extern struct List selObjs, wbObjs, utilObjs; extern int drawobj(), clearobj(), compobj(), openobj(), closeobj(); extern char *rindex(); struct MyWBObject *lastObj, *hitObj, *hitWinObj, *findObj(), *makeWbObj(); struct Window *wbWin, *oldWin, *curWin, *hitWin, *errWin; struct IntuiMessage saveMsg; struct Layer_Info *li; ULONG downSecs, downMicros, upSecs, upMicros; short oldX, oldY, dblclik, debug=FALSE; char buf1[61], buf2[61]; struct DeviceList *vol(); BPTR getlock(); long tooSoon(); main() { struct Message *msg; struct WBStartup *wbmsg; long mask; BPTR seg; openAll(); curWin = wbWin; /* Current window is the backdrop */ li = &wbWin->WScreen->LayerInfo; findDisks(); makeMenu(); OnMenu(wbWin, REDRAW); OnMenu(wbWin, VERS); avail(); while (1) { /* We have two ports to monitor at once */ mask = Wait(IDCMPBit | WBBit); if (mask & WBBit) while (msg = GetMsg(WBPort)) { /* Unload the tool that just exited */ wbmsg = (struct WBStartup *)msg; if (debug) printf("Unloading\n"); if (seg = wbmsg->sm_Segment) UnLoadSeg(seg); FreeMem(wbmsg->sm_ArgList, wbmsg->sm_NumArgs*(long)sizeof(struct WBArg)); FreeMem(msg, (long)sizeof(struct WBStartup)); toolsRunning--; } if (mask & IDCMPBit) while (msg = GetMsg(IDCMPPort)) doIDCMP(msg); } } doIDCMP(msg) struct IntuiMessage *msg; { struct MyWBObject *obj; struct DeviceList *diDev, *ptr; char diskName[31]; struct Node *node; /*stc*/ saveMsg = *msg; ReplyMsg(msg); curWin = oldWin = saveMsg.IDCMPWindow; switch (saveMsg.Class) { case CLOSEWINDOW : obj = (struct MyWBObject *)oldWin->UserData; closeobj(obj); clearSel(); avail(); break; case MENUPICK: doMenu(saveMsg.Code); break; case MOUSEBUTTONS: switch(saveMsg.Code) { case SELECTDOWN: doSelDown(); break; case SELECTUP: doSelUp(); break; } break; case GADGETUP: doGadUp(); break; case GADGETDOWN: doGadDown(); break; case DISKINSERTED: /*Delay(10L);*/ /* May be necessary */ /* Scan the Device List for a Volume that does not appear on the Master List of WBObjects */ 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 (!FindName(&wbObjs, diskName)) break; } if (!ptr) break; instDisk(diskName); /* Make a new disk object */ refresh(wbWin); break; case DISKREMOVED: Delay(10L); /* This does seem to be necessary */ /* For each disk object, check to see if it's still on the Device List */ diDev = (struct DeviceList *) BADDR(rnInfo->di_DevInfo); for (node=wbObjs.lh_Head; node->ln_Succ; node=node->ln_Succ) { obj = (struct MyWBObject *)node; if (obj->wo_Type!=WBDISK) continue; for (ptr=diDev; ptr; ptr=(struct DeviceList *) BADDR(ptr->dl_Next)) if (ptr->dl_Type==DLT_VOLUME) { bs2cs(diskName, ptr->dl_Name); if (strcmp(diskName, obj->wo_Name)==0) break; } if (ptr) continue; clearobj(obj); /* Not found--get rid of it */ deleteobj(obj); break; } refresh(wbWin); break; case REFRESHWINDOW: if (debug) printf("Window %lx is SIMPLY REFRESHING!\n", curWin); BeginRefresh(curWin); refresh(curWin); EndRefresh(curWin, TRUE); break; case NEWSIZE: reclip(curWin); resize(curWin); break; } } clearSel() { /* Purge the Select List */ struct Node *node; doList(&selObjs, SEL, drawobj, NORM); while (node = RemHead(&selObjs)) node->ln_Succ = NULL; /* So we can tell later whether a given object is still on the List */ lastObj = NULL; OffMenu(wbWin, OPEN); OffMenu(wbWin, CLOZE); OffMenu(wbWin, DUP); OffMenu(wbWin, RENAME); OffMenu(wbWin, INFO); OffMenu(wbWin, INIT); OffMenu(wbWin, SNAP); OffMenu(wbWin, DISCARD); } doOpen() { struct Node *node; struct MyWBObject *obj; /* If there's a tool or project on the Select List, run it. Otherwise, just open everybody on the List */ for (node=selObjs.lh_Head; node->ln_Succ; node=node->ln_Succ) { obj = OBJ(node,SEL); if (obj->wo_Type==WBTOOL || obj->wo_Type==WBPROJECT) {run(obj); return;} } doList(&selObjs, SEL, openobj); } /* doSelDown does three things: Detects and handles double clicks Accumulates the extended selection list Toggles menu items */ doSelDown() { struct MyWBObject *obj; struct Node *node; if (errWin) {SetWindowTitles(errWin,-1L,title); errWin=NULL;} if (obj = findObj(saveMsg.MouseX, saveMsg.MouseY, curWin)) { /* Hit an icon */ if (dblclik = ((obj==lastObj) && DoubleClick(downSecs, downMicros, saveMsg.Seconds, saveMsg.Micros))) { /* Double click */ if (debug) printf("Double click\n"); saveMsg.Seconds -= 20L; /* To prevent triple clicks */ doOpen(); OffMenu(wbWin, OPEN); OnMenu(wbWin, CLOZE); avail(); } else { /* Single click so far */ if (debug) printf("Single click\n"); SetPointer(oldWin, x_ptr, 12L, 12L, -6L, -6L); if (saveMsg.Qualifier & SHIFT) { /* Extended selection rules out some operations */ OffMenu(wbWin, DUP); OffMenu(wbWin, RENAME); OffMenu(wbWin, INFO); } else { doList(&selObjs, SEL, drawobj, NORM); while (node = RemHead(&selObjs)) node->ln_Succ = node->ln_Pred = NULL; OnMenu(wbWin, DUP); OnMenu(wbWin, RENAME); OnMenu(wbWin, INFO); } OnMenu(wbWin, SNAP); if (!obj->wo_SelectNode.ln_Succ) /* Not yet selected */ AddHead(&selObjs, &obj->wo_SelectNode); /* Exec gets confused if a node is in the same list twice */ drawobj(obj, HIGH); /* Highlight it */ /* Did I hit an open drawer? */ if (obj->wo_DrawerData && obj->wo_DrawerData->dd_DrawerWin) {OnMenu(wbWin, CLOZE); OffMenu(wbWin, OPEN);} /* Either a closed drawer or a tool */ /* Tools can always be opened */ else {OnMenu(wbWin, OPEN); OffMenu(wbWin, CLOZE);} lastObj = obj; oldX = saveMsg.MouseX; oldY = saveMsg.MouseY; downSecs = saveMsg.Seconds; downMicros = saveMsg.Micros; } } else clearSel(); /* Didn't hit an icon */ } doSelUp() { struct Layer *layer; struct Window *w; short dx, dy; BPTR lock, lock2; struct MyDrawerData *dd; if (dblclik) {dblclik = FALSE; return;} ClearPointer(oldWin); if (!lastObj) return; curWin = oldWin; upSecs = saveMsg.Seconds; upMicros = saveMsg.Micros; /* Selectup msg is sent back to the window where selectdown occurred, (oldWin), so we have to search the layers for the real window */ layer = WhichLayer(li, (long)(saveMsg.MouseX + oldWin->LeftEdge), (long)(saveMsg.MouseY + oldWin->TopEdge)); for (hitWin=wbWin->WScreen->FirstWindow; hitWin; hitWin=hitWin->NextWindow) if (hitWin->WLayer==layer) break; if (!hitWin) return; /* Shouldn't happen */ if (!(hitWin->Flags & WBENCHWINDOW)) {error("That's somebody else's window"); return;} if (hitWin!=wbWin) if (lastObj->wo_Type==WBDISK) {error("Disks can't be moved into windows"); return;} if (lastObj->wo_Type==WBGARBAGE) if (hitWin!=lastObj->wo_IconWin) {error("A trashcan must stay in its own window"); return;} if (lastObj->wo_Type==WBDRAWER) if (hitWin==lastObj->wo_DrawerData->dd_DrawerWin) /* You tried to move an icon into its own open window, dodo */ {error("Hey, that's me!"); return;} hitWinObj = (struct MyWBObject *)hitWin->UserData; /* hitWinObj may be NULL if hitWin is the backdrop */ dx = saveMsg.MouseX + oldWin->LeftEdge - hitWin->LeftEdge; dy = saveMsg.MouseY + oldWin->TopEdge - hitWin->TopEdge; hitObj = findObj(dx, dy, hitWin); if (debug) printf("SelUp hitObj=%lx hitWin=%lx\n", hitObj, hitWin); if ((!hitObj) || (hitObj==lastObj)) {moveObj(&selObjs, SEL, dx - oldX, dy - oldY); return;} /* So from here on we must have hit a new icon */ if (debug) printf("Hit <%s>, a %s\n", hitObj->wo_Name, type[hitObj->wo_Type]); switch (hitObj->wo_Type) { case WBDISK: if (lastObj->wo_Type==WBDISK) {error("DiskCopy not implemented"); return;} if (lastObj->wo_Type==WBGARBAGE) {error("A trashcan must stay in its own window"); return;} if (hitObj==lastObj->wo_Parent) break; lock = getlock(lastObj); if (vol(lock)==vol(hitObj->wo_Lock)) { /* On same disk--just rename */ strcpy(buf1, lastObj->wo_Name); strcpy(buf2, lastObj->wo_Name); if (debug) printf("Renaming %lx <%s> to %lx <:%s>\n", lock, lastObj->wo_Name, hitObj->wo_Lock, lastObj->wo_Name); strcat(buf1, ".info"); strcat(buf2, ".info"); renBoth(lock, buf1, hitObj->wo_Lock, buf2); break; } /* Otherwise copy to another disk--not implemented */ if (debug) printf("I should copy %lx <%s> to %lx <%s:>\n", lock, lastObj->wo_Name, hitObj->wo_Lock, hitObj->wo_Name); return; case WBDRAWER: case WBGARBAGE: /* Hit a drawer icon */ if (hitObj==lastObj->wo_Parent) break; if (lastObj->wo_Type==WBDISK) if (hitWin!=wbWin) {error("Can't move a disk into a drawer"); return;} if (lastObj->wo_Type==WBGARBAGE) {error("A trashcan must stay in its own window"); return;} strcpy(buf1, lastObj->wo_Name); strcpy(buf2, hitObj->wo_Name); strcat(buf2, "/"); strcat(buf2, lastObj->wo_Name); lock = getlock(lastObj); lock2 = getlock(hitObj); if (debug) printf("Renaming %lx <%s> to %lx <%s>\n", lock, buf1, lock2, buf2); strcat(buf1, ".info"); strcat(buf2, ".info"); renBoth(lock, buf1, lock2, buf2); break; default: /* Just let the icons overlap */ moveObj(&selObjs, SEL, dx-oldX, dy-oldY); return; } goAway(); doResize(); } goAway() { /* Do move from one window to another */ struct MyDrawerData *dd; struct Window *w; mark(lastObj->wo_IconWin); clearobj(lastObj); Remove(&lastObj->wo_Siblings); lastObj->wo_Siblings.ln_Succ = NULL; dd = hitObj->wo_DrawerData; if (w=dd->dd_DrawerWin) { /* Destination window open */ AddHead(&dd->dd_Children, &lastObj->wo_Siblings); lastObj->wo_Parent = hitObj; lastObj->wo_IconWin = w; mark(w); Remove(lastObj); AddTail(&wbObjs, lastObj); /* Rearrange, so that refresh() draws it last (on top) */ } else deleteobj(lastObj); } moveObj(list, off, x, y) struct List *list; long off; short x, y; { struct Node *node; struct MyWBObject *obj, *iconWinObj; struct Window *w; struct MyDrawerData *dd; char *p; BPTR lock, lock2; mark(hitWin); hitWinObj = (struct MyWBObject *)hitWin->UserData; if (tooSoon()) return; /* If selup too soon, ignore */ doList(list, off, clearobj); for (node=list->lh_Head; node->ln_Succ; node=node->ln_Succ) { obj = OBJ(node,off); if (debug) printf("moveObj: %lx (%d %d) by (%d %d) from %lx to %lx\n", obj, obj->wo_Gadget.LeftEdge, obj->wo_Gadget.TopEdge, x, y, obj->wo_IconWin, hitWin); iconWinObj = (struct MyWBObject *)obj->wo_IconWin->UserData; mark(obj->wo_IconWin); if (obj->wo_IconWin!=hitWin) { /* Changing windows */ /* Adjust the virtual coordinates */ if (obj->wo_IconWin!=wbWin) { dd = iconWinObj->wo_DrawerData; obj->wo_CurrentX -= dd->dd_CurrentX; obj->wo_CurrentY -= dd->dd_CurrentY; } if (hitWin!=wbWin) { dd = hitWinObj->wo_DrawerData; obj->wo_CurrentX += dd->dd_CurrentX; obj->wo_CurrentY += dd->dd_CurrentY; } if (hitWin==wbWin) { /* To the backdrop */ /* A backdrop icon needs its very own lock, in case its parent's drawer is later closed */ obj->wo_Lock = DupLock(obj->wo_Parent-> wo_DrawerData->dd_Lock); if (debug) printf("Duplicate lock: <%s> %lx\n", obj->wo_Name, obj->wo_Lock); } else if (hitWinObj==obj->wo_Parent) { /* Into the open drawer of my parent */ if (debug) printf("Oh Lawdy, I'se home--home at las'!\n"); /* I don't need my lock any more */ if (obj->wo_Lock) { /* Coming from the backdrop */ if (debug) printf("Unlocking <%s>: %lx\n", obj->wo_Name, obj->wo_Lock); UnLock(obj->wo_Lock); obj->wo_Lock = NULL; } } else { /* Into some other open drawer */ lock = getlock(obj); lock2 = hitWinObj->wo_DrawerData->dd_Lock; if (vol(lock)==vol(lock2)) { strcpy(buf1, obj->wo_Name); strcpy(buf2, obj->wo_Name); if (debug) printf("Renaming %lx <%s> to %lx <%s>\n", lock, buf1, lock2, buf2); strcat(buf1, ".info"); strcat(buf2, ".info"); renBoth(lock, buf1, lock2, buf2); } else { bs2cs(buf2, vol(lock2)->dl_Name); if (debug) printf("I should copy %lx <%s> to %lx <%s/%s> on <%s:>\n", lock, obj->wo_Name, lock2, hitWinObj->wo_Name, obj->wo_Name, buf2); } Remove(&obj->wo_Siblings); AddHead(&dd->dd_Children, &obj->wo_Siblings); obj->wo_Parent = hitWinObj; } obj->wo_IconWin = hitWin; } obj->wo_CurrentX += x; obj->wo_CurrentY += y; Remove(obj); AddTail(&wbObjs, obj); /* So that refresh() draws it last (on top) */ } doList(list, off, drawobj, HIGH); doResize(); } mark(w) struct Window *w; { /* Mark window for later resizing */ if (w!=wbWin) ((struct MyWBObject *)w->UserData)->wo_Flags |= RESIZE; else wbFlags |= RESIZE; } doResize() { struct Node *node; struct MyWBObject *obj; struct Window *w; for (node=wbObjs.lh_Head; node->ln_Succ; node=node->ln_Succ) { obj = (struct MyWBObject *)node; if (obj->wo_Flags & RESIZE) { w = obj->wo_DrawerData->dd_DrawerWin; resize(w); refresh(w); obj->wo_Flags &= ~RESIZE; } } if (wbFlags & RESIZE) { /* It might be worth having a fake object whose drawer is the backdrop, but all we really need is the Flags field */ refresh(wbWin); wbFlags &= ~RESIZE; } } doGadDown () { USHORT gid; struct MyDrawerData *dd; short shift; long pos; gid = ((struct Gadget *)saveMsg.IAddress)->GadgetID; dd = ((struct MyWBObject *)oldWin->UserData)->wo_DrawerData; shift = saveMsg.Qualifier & SHIFT; lastObj = NULL; switch (gid) { case GID_VERTSCROLL: case GID_HORIZSCROLL: return; case GID_LEFTSCROLL: pos = (ULONG)dd->dd_HorizProp.HorizPot; dd->dd_CurrentX -= shift ? 1 : 20; break; case GID_RIGHTSCROLL: pos = (ULONG)dd->dd_HorizProp.HorizPot; dd->dd_CurrentX += shift ? 1 : 20; break; case GID_UPSCROLL: pos = (ULONG)dd->dd_VertProp.VertPot; dd->dd_CurrentY -= shift ? 1 : 10; break; case GID_DOWNSCROLL: pos = (ULONG)dd->dd_VertProp.VertPot; dd->dd_CurrentY += shift ? 1 : 10; break; } resize(oldWin); SetRast(oldWin->RPort, 0L); refresh(oldWin); } doGadUp() { USHORT gid; struct MyDrawerData *dd; long pos; gid = ((struct Gadget *)saveMsg.IAddress)->GadgetID; dd = ((struct MyWBObject *)oldWin->UserData)->wo_DrawerData; switch (gid) { case GID_HORIZSCROLL: /* I don't understand this either */ pos = (ULONG)dd->dd_HorizProp.HorizPot; dd->dd_CurrentX = dd->dd_MinX + (pos * (MAX(dd->dd_CurrentX, dd->dd_MaxX - (oldWin->Width-14L)) - MIN(dd->dd_CurrentX, dd->dd_MinX)) ) / MAXBODY; break; case GID_VERTSCROLL: pos = (ULONG)dd->dd_VertProp.VertPot; dd->dd_CurrentY = dd->dd_MinY + (pos * (MAX(dd->dd_CurrentY,dd->dd_MaxY-(oldWin->Height-YOFF-9L)) - MIN(dd->dd_CurrentY, dd->dd_MinY)) ) / MAXBODY; break; } resize(oldWin); SetRast(oldWin->RPort, 0L); refresh(oldWin); } /* Recalculate the size of a window's virtual coord system */ resize(w) struct Window *w; { struct Node *node; struct MyWBObject *obj; struct MyDrawerData *dd; long effH, effW, total, left, right, pot, body; obj = (struct MyWBObject *)w->UserData; dd = obj->wo_DrawerData; dd->dd_MinX = dd->dd_MinY = 10000; dd->dd_MaxX = dd->dd_MaxY = -10000; /* For each icon living in the window.. */ for (node=dd->dd_Children.lh_Head; node->ln_Succ; node=node->ln_Succ) { obj = OBJ(node,CHILD); if (obj->wo_IconWin!=w) continue; /* Each icon contains two pieces..a title and an image */ /* Take the MIN of the left edges.. */ dd->dd_MinX = MIN(dd->dd_MinX, obj->wo_CurrentX + obj->wo_NameXOffset); /* and the MAX of the right edges */ right = MAX(obj->wo_Gadget.Width, obj->wo_NameXOffset + 8*strlen(obj->wo_Name)); dd->dd_MaxX = MAX(dd->dd_MaxX, obj->wo_CurrentX + right); /* Likewise top and bottom edges */ dd->dd_MinY = MIN(dd->dd_MinY, obj->wo_CurrentY); dd->dd_MaxY = MAX(dd->dd_MaxY, obj->wo_CurrentY + obj->wo_Gadget.Height + 10L); } /* Now recalculate the horizontal extent... */ /* total: Total size of virtual coord system */ /* left: Size undisplayed to left */ /* right: Size undisplayed to right */ effW = w->Width-14L; total = MAX(dd->dd_CurrentX + effW, dd->dd_MaxX) - MIN(dd->dd_CurrentX, dd->dd_MinX); left = MAX(dd->dd_CurrentX - dd->dd_MinX, 0L); right = total - left - effW; if ((left + right)==0L) pot = 0L; else pot = (MAXBODY * left) / (left + right); body = (MAXBODY * effW) / total; ModifyProp(&dd->dd_HorizScroll, w, NULL, FREEHORIZ | AUTOKNOB, pot, MAXBODY, body, MAXBODY); /* and the vertical extent */ effH = w->Height-YOFF-9L; total = MAX(dd->dd_CurrentY + effH, dd->dd_MaxY) - MIN(dd->dd_CurrentY, dd->dd_MinY); left = MAX(dd->dd_CurrentY - dd->dd_MinY, 0L); right = total - left - effH; if ((left + right)==0L) pot = 0L; else pot = (MAXBODY * left) / (left + right); body = (MAXBODY * effH) / total; ModifyProp(&dd->dd_VertScroll, w, NULL, FREEVERT | AUTOKNOB, MAXBODY, pot, MAXBODY, body); } /* Must do this each time a window's size is changed */ /* To prevent drawing over the borders */ reclip(w) struct Window *w; { struct Region *reg, *oldreg; reg = NewRegion(); rect.MaxX = w->Width - 19; rect.MaxY = w->Height - 11; OrRectRegion(reg, &rect); oldreg = InstallClipRegion(w->WLayer, reg); if (oldreg) DisposeRegion(oldreg); } BPTR getlock(obj) struct MyWBObject *obj; { BPTR lock; char name[31]; /* Either the obj's own Lock, or the Lock of the drawer it's in, or manufacture a new one */ lock = obj->wo_Lock; if (!lock) if (obj->wo_Parent) lock = obj->wo_Parent->wo_DrawerData->dd_Lock; if (!lock) { /* Presumably a disk */ if (debug) printf("%lx <%s> (a %s) needs a new lock\n", obj, obj->wo_Name, type[obj->wo_Type]); strcpy(name, obj->wo_Name); strcat(name,":"); lock = obj->wo_Lock = Lock(name, ACCESS_READ); /* Maybe user refused to reinsert disk */ if (!lock) printf("Can't lock <%s>\n", name); if (debug) printf("getlock: new lock: %lx\n",lock); } return lock; } struct DeviceList *vol(lock) BPTR lock; { struct FileLock *fl; /* Return the Volume corresponding to a given Lock */ if (!lock) {printf("vol: Null lock\n"); return NULL;} fl = (struct FileLock *)BADDR(lock); return (struct DeviceList *)BADDR(fl->fl_Volume); } /* Convert a BSTR to a C string */ bs2cs(buf, bstr) char *buf; BPTR bstr; { char *p; p = (char *)BADDR(bstr); strncpy(buf, p+1, *p); buf[*p] = 0; } /* C string to BSTR - (buf must be Long Aligned) */ cs2bs(buf, s) char *buf, *s; { strcpy(buf+1, s); *buf = strlen(s); } renpkt(l1, n1, l2, n2) BPTR l1, l2; char *n1, *n2; { long arg[4], res; struct DeviceList *dl1, *dl2; char *buf1, *buf2; struct MsgPort *handid; if (debug) printf("Renpkt: <%s> to <%s>\n", n1, n2); if (!l1 || !l2) {printf("renpkt error: null lock\n"); return;} if ((dl1=vol(l1)) != (dl2=vol(l2))) {printf("renpkt error: different volumes\n"); return;} handid = ((struct FileLock *)BADDR(l1))->fl_Task; /* Must be long aligned: */ buf1 = AllocMem(31L, MEMF_CPC); buf2 = AllocMem(31L, MEMF_CPC); cs2bs(buf1, n1); cs2bs(buf2, n2); arg[0] = l1; arg[2] = l2; arg[1] = ((long)buf1)>>2; arg[3] = ((long)buf2)>>2; if (!sendpkt(handid, ACTION_RENAME_OBJECT, arg, 4L)) printf("Rename failed\n"); FreeMem(buf1, 31L); FreeMem(buf2, 31L); } renBoth(l1, n1, l2, n2) BPTR l1, l2; char *n1, *n2; { /* Rename both the file and its .info file */ renpkt(l1, n1, l2, n2); *rindex(n1,'.') = 0; *rindex(n2,'.') = 0; renpkt(l1, n1, l2, n2); } long tooSoon() { long dt; dt = upSecs - downSecs; if (dt>1) return FALSE; dt = upMicros - downMicros + 1000000L*dt; return (dt<200000L); /* Two-tenths of a sec between selup and seldown is too soon to count as a drag operation */ }