sdo@soliado.East.Sun.COM (Scott Oaks - Sun Consulting NYC) (04/29/91)
Submitted-by: sdo@soliado.East.Sun.COM (Scott Oaks - Sun Consulting NYC) Posting-number: Volume 12, Issue 62 Archive-name: olvwm/part06 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 6 (of 16)." # Contents: client.c slots.c win.h # Wrapped by sdo@piccolo on Fri Apr 26 17:31:05 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'client.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'client.c'\" else echo shar: Extracting \"'client.c'\" \(14648 characters\) sed "s/^X//" >'client.c' <<'END_OF_FILE' X/* X * (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents X * pending in the U.S. and foreign countries. See LEGAL_NOTICE X * file for terms of the license. X * X * Written for Sun Microsystems by Crucible, Santa Cruz, CA. X */ X X/* client.c - functions relating to clients as a whole X */ X static char sccsid[] = "@(#)client.c 1.2 olvwm version 3/30/91"; X X/* X * Based on static char sccsid[] = "@(#) client.c 25.15 90/05/31 Crucible"; X * X */ X X#include <errno.h> X#include <stdio.h> X#include <X11/Xos.h> X#include <X11/Xlib.h> X#include <X11/Xutil.h> X#include <X11/Xatom.h> X#include <olgx/olgx.h> X X#include "events.h" X#include "mem.h" X#include "olwm.h" X#include "win.h" X#include "menu.h" X#include "group.h" X#include "globals.h" X X/*************************************************************************** X* global data X***************************************************************************/ X List *ActiveClientList; X X/* X * FocusIndeterminate indicates that no window has the focus and that the X * focus should be transferred to the NoFocus window. FocusIndeterminate is X * set when the window with the focus becomes Withdrawn. Since the Unmap- X * Notify event has no timestamp, setting the focus to the NoFocus window X * immediately is difficult to do properly. Instead, this flag is set and a X * message is sent to the NoFocus window. If this flag is still set when the X * message is received, the focus is set to the NoFocus window. This flag is X * unset whenever the focus changes, so the transfer of focus to the NoFocus X * window is nullified if there has been an intervening focus transfer. X */ Bool FocusIndeterminate = False; X extern Atom AtomColorMapWindows; extern Atom AtomDeleteWindow; extern Atom AtomLeftFooter; extern Atom AtomProtocols; extern Atom AtomRightFooter; extern Atom AtomShowProperties; extern Atom AtomTakeFocus; extern Atom AtomWindowBusy; extern Atom AtomWMState; X extern Window NoFocusWin; X extern void RecursiveRefresh(); X X/*************************************************************************** X* private data X***************************************************************************/ X X/*************************************************************************** X* private functions X***************************************************************************/ X static void clientSetBusy(); X X/*************************************************************************** X* global functions X***************************************************************************/ X X X/* ClientSendProtocol - send a protocol message to a client X */ void * ClientSendProtocol(cli,proto,evtime) Client *cli; Atom proto; Time evtime; X{ X XEvent clientEvent; X X clientEvent.xclient.type = ClientMessage; X clientEvent.xclient.message_type = AtomProtocols; X clientEvent.xclient.format = 32; X clientEvent.xclient.display = cli->dpy; X clientEvent.xclient.window = ClientPane(cli); X clientEvent.xclient.data.l[0] = proto; X clientEvent.xclient.data.l[1] = evtime; X X XSendEvent(cli->dpy, clientEvent.xclient.window, False, X NoEventMask, &clientEvent); X return NULL; X} X X/* ClientShowProps - send a ClientMessage of type WM_SHOW_PROPERTIES X */ void ClientShowProps(cli) Client *cli; X{ X XEvent clientEvent; X X clientEvent.xclient.type = ClientMessage; X clientEvent.xclient.message_type = AtomShowProperties; X clientEvent.xclient.format = 32; X clientEvent.xclient.display = cli->dpy; X clientEvent.xclient.window = PANEWINOFCLIENT(cli); X X XSendEvent(cli->dpy, clientEvent.xclient.window, False, X NoEventMask, &clientEvent); X} X X/* ClientKill - a client must be killed. If it can handle the DELETE_WINDOW X * protocol, use it; otherwise, if we are forcing the client to go X * away, kill it. X */ void * ClientKill(cli,pforce) Client *cli; Bool pforce; X{ X if (cli->protocols & DELETE_WINDOW) X ClientSendProtocol(cli,AtomDeleteWindow,LastEventTime); X else X if (pforce) X XKillClient(cli->dpy,ClientPane(cli)); X return NULL; X} X X X/* UnparentClient - while exiting OLWM: unmap all icons that are on the X * screen. Reparent all windows back to the root, suitably offset X * according to their window-gravities. Also remap all non-withdrawn X * windows, and remove all Withdrawn windows from the save-set (so X * they don't get remapped. REMIND: We have to do this because X * Withdrawn windows are still left reparented inside the frame; this X * shouldn't be the case. X */ void * UnparentClient(cli,junk) Client *cli; void *junk; X{ X WinPaneFrame *frameInfo; X WinPane *paneInfo; X Window pane; X extern int IgnoreErrors(), ErrorHandler(); X X#ifdef DEBUG X printf("UnparentClient: %x\n",cli); X#endif X X if (cli->wmState == IconicState) X { X IconHide(cli, cli->iconwin); X } X X frameInfo = cli->framewin; X paneInfo = (WinPane*)(frameInfo->fcore.panewin); X pane = paneInfo->core.self; X FrameUnparentPane(cli, frameInfo, paneInfo); X X if (cli->wmState == DontCareState) X { X XChangeSaveSet(cli->dpy, pane, SetModeDelete); X } X else X { X XMapWindow(cli->dpy,pane); X } X X return NULL; X} X X/* X * addClient -- add this client structure to the list of active clients X */ static void addClient(cli) Client *cli; X{ X List *l = ActiveClientList; X Client *tc; X X#ifdef DEBUG X printf("addClient: %x\n",cli); X#endif X /* First look to see if window is already listed. */ X for(tc = ListEnum(&l); tc != NULL; tc = ListEnum(&l)) X { X if (tc == cli) X return; X } X X /* Wasn't present, add to list. */ X ActiveClientList = ListCons(cli, ActiveClientList); X} X X/* X * removeClient -- remove this client structure from the list of active X * clients. X */ static void removeClient(cli) Client *cli; X{ X List **l; X X for (l = &ActiveClientList ; *l != NULL; l = &((*l)->next)) X { X if ((*l)->value == cli) X { X ListDestroyCell(l); X return; X } X } X} X X/* X * DestroyClient -- destroy all resources associated with this client X */ void DestroyClient(cli) Client *cli; X{ X /* remove any possible external references to the client */ X X UnTrackSubwindows(cli, True); X if (IsSelected(cli)) X RemoveSelection(cli); X removeClient(cli); X X /* destroy the window resources associated with the client */ X WinCallDestroy(cli); X X GroupRemove(cli->groupid, cli); X X /* free up the client structure resources */ X /* REMIND there's lots of other stuff to free up here */ X /* REMIND what's to be done with followers here? */ X MemFree(cli); X} X X/* X * ClientConfigure - a configure request event has been received on the X * pane. Configure the windows accordingly. X */ void ClientConfigure(cli,win,pxcre) Client *cli; WinGeneric *win; XXConfigureRequestEvent *pxcre; X{ X XWindowChanges winChange; X X if ((cli == NULL) || (win == NULL)) X { X /* We don't know about this window, or it's withdrawn X * convert the request into an XConfigureWindow X * call. We do not look at the hints to see if X * the resize is in the proper increments, but since X * the app is asking for the reconfigure this seems X * right. X */ X winChange.x = pxcre->x; X winChange.y = pxcre->y; X winChange.width = pxcre->width; X winChange.height = pxcre->height; X winChange.border_width = pxcre->border_width; X winChange.stack_mode = pxcre->detail; X winChange.sibling = pxcre->above; X X XConfigureWindow(pxcre->display, X pxcre->window, X /* lint will warn: this is a long, not int */ X pxcre->value_mask, X &winChange ); X } X else /* cli->wmState == NormalState or IconicState */ X { X WinCallConfig(cli->dpy,win,pxcre); X } X} X X/* X * ClientGetWMState -- get the contents of the WM_STATE property. X */ Bool ClientGetWMState( dpy, win, state, iconwin ) X Window win; X int *state; X Window *iconwin; X{ X int nitems, remain; X int *data; X X data = GetWindowProperty(dpy, win, AtomWMState, 0L, X LONG_LENGTH(int)+LONG_LENGTH(Window), AtomWMState, 32, &nitems, X &remain); X if (data == NULL) X { X return False; X } X else if (nitems != 2) X { X XFree(data); X return False; X } X *state = data[0]; X *iconwin = (Window) data[1]; X XFree(data); X return True; X} X X/* X * ClientSetWMState -- set the contents of the WM_STATE property, X * given the information in the WinInfo struct. X */ void ClientSetWMState( cli ) X Client *cli; X{ X unsigned long data[2]; X WinIconFrame *iconWinInfo = cli->iconwin; X Window pane = PANEWINOFCLIENT(cli); X X data[0] = cli->wmState; X if ( iconWinInfo ) { X if ( iconWinInfo->fcore.panewin ) X data[1] = iconWinInfo->fcore.panewin->core.self; X else X data[1] = iconWinInfo->core.self; X } else { X data[1] = None; X } X XChangeProperty(cli->dpy, pane, AtomWMState, AtomWMState, X 32, PropModeReplace, (unsigned char *)data, 2); X} X X X/* ClientCreate -- allocate and initialise a client structure X */ Client * ClientCreate(dpy,screen) Display *dpy; int screen; X{ X Client *cli = MemNew(Client); X X cli->wmState = DontCareState; X cli->dpy = dpy; X cli->screen = screen; X /* all other fields set to zero by allocation function */ X addClient(cli); X return cli; X} X X/* ClientPane - return the pane window of a client X */ Window ClientPane(cli) Client *cli; X{ X WinPaneFrame *wf; X WinPane *wp; X X if ((wf = cli->framewin) == NULL) X return NULL; X if ((wp = (WinPane *)(wf->fcore.panewin)) == NULL) X return NULL; X return wp->core.self; X} X X/* ClientDistributeProperty -- a property of the client has changed. X * Forward the change notification to the appropriate handler. X */ X /* REMIND this is pretty sketchy at the moment */ void ClientDistributeProperty(cli, event) Client *cli; XXPropertyEvent *event; X{ X X /* REMIND check that we're seeing a change, not a delete X * on some of these */ X X if (event->atom == AtomColorMapWindows) X { X if (event->state == PropertyNewValue) X { X TrackSubwindows(cli); X } X else X { X UnTrackSubwindows(cli, False); X } X } X else if (event->atom == XA_WM_ICON_NAME) X { X IconChangeName(cli->iconwin, PANEWINOFCLIENT(cli)); X } X else if ((event->atom == AtomRightFooter) || (event->atom == AtomLeftFooter)) X { X FrameNewFooter(cli); X } X else if (event->atom == XA_WM_NAME) X { X FrameNewHeader(cli); X } X else if (event->atom == AtomWindowBusy) X { X clientSetBusy(cli,event->time,event->state); X } X} X X/* refresh the window. We do this by creating a window on top X * of the window to refresh and then immediately destroy it X */ void ClientRefresh(cli) Client *cli; X{ X WinPaneFrame *winFrame = cli->framewin; X Window w; X XSetWindowAttributes xswa; X X if (GRV.RefreshRecursively) { X RecursiveRefresh(cli->dpy, winFrame->core.self); X } else { X w = XCreateWindow(cli->dpy, winFrame->core.self, 0, 0, X winFrame->core.width, winFrame->core.height, 0, X CopyFromParent, InputOutput, CopyFromParent, X 0, &xswa); X XMapRaised(cli->dpy,w); X XDestroyWindow(cli->dpy,w); X } X} X X X/* ClientInBox -- given a bounding box, apply a function to all clients X * which fall inside the rectangle X */ void * ClientInBox(cli, close) Client *cli; clientInBoxClosure *close; X{ X int x, y, w, h; X X if (cli->wmState == IconicState) X { X x = cli->iconwin->core.x; X y = cli->iconwin->core.y; X w = cli->iconwin->core.width; X h = cli->iconwin->core.height; X } X else X { X x = cli->framewin->core.x; X y = cli->framewin->core.y; X w = cli->framewin->core.width; X h = cli->framewin->core.height; X } X X if ((x >= close->bx) && X (y >= close->by) && X ((x + w) <= (close->bx + close->bw)) && X ((y + h) <= (close->by + close->bh))) X (close->func)(cli, close->timestamp); X X return NULL; X} X X/* X * ClientSetBusy -- the busy state has (possibly) been changed for a client. X * if the client is going from normal to busy: X * mark the client as busy X * put up a busy window X * if the client is going from busy to normal: X * mark the client as unbusy X * take down a busy window (if it exists) X */ static void clientSetBusy(cli,evtime,state) X Client *cli; X Time evtime; X int state; X{ X int *newBusyPtr; X int newBusy; X unsigned long nItems, remain; X X if (state == PropertyNewValue) { X newBusyPtr = GetWindowProperty(cli->dpy, PANEWINOFCLIENT(cli), X AtomWindowBusy, 0L, LONG_LENGTH(*newBusyPtr), X XA_INTEGER, 32, &nItems, &remain); X X if (newBusyPtr == NULL) { X /* property not found or has the wrong type */ X newBusy = 0; X } else { X if (nItems != LONG_LENGTH(newBusy) || remain != 0) { X /* got a property, but it is invalid */ X newBusy = 0; X } else { X /* valid property */ X newBusy = *newBusyPtr; X } X XFree(newBusyPtr); X } X } else { X /* property was deleted */ X newBusy = 0; X } X X if (cli->isBusy && (newBusy == 0)) { X /* losing busy */ X cli->isBusy = False; X if (cli->isFocus) X ClientSetFocus(cli,True,evtime); X FrameSetBusy(cli->framewin, False); X } X else if (!cli->isBusy && (newBusy == 1)) { X /* gaining busy */ X cli->isBusy = True; X FrameSetBusy(cli->framewin, True); X if (cli->isFocus) X ClientSetFocus(cli,True,evtime); X } X} X X/* X * ClientSetFocus -- possibly set the focus to this client. If the X * client is GloballyActive, we only send TakeFocus messages X * if sendTF is true. If the client has a different focus X * mode sendTF is ignored. X */ void ClientSetFocus(cli,sendTF,evtime) Client *cli; Bool sendTF; Time evtime; X{ X FocusIndeterminate = False; X X if (cli->isBusy) X { X /* REMIND X * setting RevertToNone is problematic. When the window goes X * unbusy, the winBusy will be unmapped, which may leave the focus X * at None until the client gets around to responding to our X * WM_TAKE_FOCUS message. X */ X if (cli->framewin->winBusy != NULL) X XSetInputFocus(cli->dpy, cli->framewin->winBusy->core.self, X RevertToNone, evtime); X else X XSetInputFocus(cli->dpy, NoFocusWin, X RevertToPointerRoot, evtime); X } X else X { X switch (cli->focusMode) X { X case NoInput: X /* do nothing */ X break; X X case Passive: X case LocallyActive: X XSetInputFocus(cli->dpy, PANEWINOFCLIENT(cli), X RevertToParent, evtime); X break; X X case GloballyActive: X if (sendTF) X { X ClientSendProtocol(cli, AtomTakeFocus, evtime); X } X break; X } X } X} END_OF_FILE if test 14648 -ne `wc -c <'client.c'`; then echo shar: \"'client.c'\" unpacked with wrong size! fi # end of 'client.c' fi if test -f 'slots.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'slots.c'\" else echo shar: Extracting \"'slots.c'\" \(14674 characters\) sed "s/^X//" >'slots.c' <<'END_OF_FILE' X/* X * (c) Copyright 1990 Sun Microsystems, Inc. Sun design patents X * pending in the U.S. and foreign countries. See LEGAL_NOTICE X * file for terms of the license. X * X * Written for Sun Microsystems by Crucible, Santa Cruz, CA. X */ X static char sccsid[] = "@(#)slots.c 1.2 olvwm version 3/30/91"; X X/* based on @(#) slots.c 1.5 90/05/15 Crucible */ X X#include <stdio.h> X#include <X11/Xos.h> X#include <X11/Xlib.h> X#include <X11/Xutil.h> X#include "mem.h" X#include "st.h" X#include "olwm.h" X#include "win.h" X#include "globals.h" X#include "list.h" X#include "slots.h" X X/*************************************************************************** X* Local data X***************************************************************************/ X static SlotOrder SOmajor = SOBottomToTop; static SlotOrder SOminor = SOLeftToRight; X typedef struct _slotrgn { X int ma, mi, maw, miw; X } slotRgn; typedef struct _slotabs { X int x, y, w, h; X } slotAbs; X static int *occupancy = NULL; static int minoccupancy = 0; static List *iconList = NULL_LIST; static int maslots, mislots; static int slotshoriz, slotsvert; static int pixhoriz, pixvert; X X#define PLUSINFINITY 0xfffffff /* REMIND fix this for architecture-independence */ X X#ifdef BRAP extern int VirtualDesktopHeight, VirtualDesktopWidth, VirtualDesktopX, VirtualDesktopY; X#endif X X/*************************************************************************** X* Local functions X***************************************************************************/ X X X#define ROUNDUP(n,d) (((n)+(d)-1)/(d)) X/* #define ROUND(n,d) ((0.5+((float)(n)/(float)(d)))*(int)(d)) */ X#define ROUND(n,d) (((((n)%(d))>((d)/2))?(((n)/(d))+1):((n)/(d)))*(d)) X X#define SLOTOFFSET(ma, mi) (((ma))*mislots+(mi)) X#define AOCCUPANCY(ma,mi) ((occupancy+SLOTOFFSET((ma),(mi)))) X#define OCCUPANCY(ma,mi) (*(AOCCUPANCY((ma),(mi)))) X X#define ISVERT(so) (((so)==SOBottomToTop)||((so)==SOTopToBottom)) X#define ISHORZ(so) (((so)==SOLeftToRight)||((so)==SORightToLeft)) X#define ISDECREASING(so) (((so)==SORightToLeft)||((so)==SOBottomToTop)) X X#ifdef NOTDEF static char * sotochar(so) SlotOrder so; X{ X if (so == SOTopToBottom) X return ("SOTopToBottom"); X if (so == SOBottomToTop) X return ("SOBottomToTop"); X if (so == SOLeftToRight) X return ("SOLeftToRight"); X if (so == SORightToLeft) X return ("SORightToLeft"); X return("SOIllegal"); X} X#endif X X#ifdef DEBUG X/* dumpocc -- print the occupancy count table to stderr X */ static void dumpocc() X{ X int ima, imi; X X fprintf(stderr,"dump of occupancy table:\n"); X for (ima = 0; ima<maslots; ima++) X for (imi = 0; imi<mislots; imi++) X if (OCCUPANCY(ima,imi)!=0) X fprintf(stderr,"%x: occ[%d,%d]/[%d] = %d\n",AOCCUPANCY(ima,imi),ima,imi,SLOTOFFSET(ima,imi),OCCUPANCY(ima,imi)); X fprintf(stderr,"end of dump of occupancy table\n"); X} X#endif X X X/* setMajorMinor -- set two output variables from two input variables, X * based on the major/minor settings. X */ static void setMajorMinor(r,c,pma,pmi) int r, c, *pma, *pmi; X{ X if (ISVERT(SOmajor)) X { X *pma = r; X *pmi = c; X } X else X { X *pma = c; X *pmi = r; X } X} X X/* setAbsolute -- set two output variables from two input variables, based X * on major/minor settings; this is the inverse of setMajorMinor. X */ static void setAbsolute(ma,mi,pr,pc) int ma, mi; int *pr, *pc; X{ X if (ISVERT(SOmajor)) X { X *pr = ma; X *pc = mi; X } X else X { X *pc = ma; X *pr = mi; X } X} X X/* incrRegion -- increment the occupancy count of a region X */ static void incrRegion(slot,val) IconSlot *slot; int val; X{ X int ii,jj; X X for (ii = slot->ma; (ii>=0)&&(ii<maslots)&&(ii<slot->ma+slot->maw); ii++) X for (jj = slot->mi; (jj>=0)&&(jj<mislots)&&(jj<slot->mi+slot->miw); jj++) X { X if ((OCCUPANCY(ii,jj) += val) < minoccupancy) X minoccupancy = OCCUPANCY(ii,jj); X } X} X X/* findMinMaxRgn -- find the minimum and maximum occupancies of a region X */ static void findMinMaxRgn(ma, mi, nmajor, nminor, pminrgn, pmaxrgn) int ma, mi, nmajor, nminor, *pminrgn, *pmaxrgn; X{ X int min, max; X int ii, jj; X int occ; X X min = PLUSINFINITY; X max = -1; X X for (ii=ma; ii<ma+nmajor; ii++) X for (jj = mi; jj<mi+nminor; jj++) X { X occ = OCCUPANCY(ii,jj); X if (occ < min) X min = occ; X if (occ > max) X max = occ; X } X *pminrgn = min; X *pmaxrgn = max; X} X static IconSlot * incrDynamicSlots(nmajor, nminor) int nmajor, nminor; X{ X int minoccrgn; /* smallest occupancy found for a region of given size */ X int minfound, minfoundrgn; /* smallest occupancy found for one slot X * and a region respectively; used to reset X * search values */ X int ma, mi; /* indices in major and minor directions */ X int maxrgn, minrgn; /* max and min occupancies in a region */ X IconSlot *slot = MemNew(IconSlot); X X minoccrgn = minoccupancy; X slot->positioned = False; X X for (;;) /* will actually only iterate twice */ X { X minfound = minfoundrgn = PLUSINFINITY; X for (ma = 0; (ma <= maslots-nmajor); ma++) X { X for (mi = 0; (mi <= mislots-nminor); mi++) X { X findMinMaxRgn(ma, mi, nmajor, nminor, &minrgn, &maxrgn); X if (minrgn < minfound) X minfound = minrgn; X if (maxrgn < minfoundrgn) X minfoundrgn = maxrgn; X if (maxrgn <= minoccrgn) X { X slot->ma = ma; X slot->mi = mi; X slot->maw = nmajor; X slot->miw = nminor; X incrRegion(slot,1); X return slot; X } X } X } X /* no regions available with occupancy <= known minimum */ X if (minfound > minoccupancy) /* increase global slot minimum */ X minoccupancy = minfound; X minoccrgn = minfoundrgn; /* increase local region min */ X } X} X X/* setIconPos -- given a slot, position the icon frame window accordingly. X */ static void setIconPos(win, slot) WinIconFrame *win; IconSlot *slot; X{ X int x,y; X X if (SOmajor == SOTopToBottom) X { X y = ICON_GRID_HEIGHT*slot->ma; X if (SOminor == SOLeftToRight) X { X x = ICON_GRID_WIDTH*slot->mi; X } X else X { X x = pixhoriz - slot->mi*ICON_GRID_WIDTH - win->core.width; X } X } X else if (SOmajor == SOBottomToTop) X { X y = pixvert - ICON_GRID_HEIGHT*slot->ma - win->core.height; X if (SOminor == SOLeftToRight) X { X x = ICON_GRID_WIDTH*slot->mi; X } X else X { X x = pixhoriz - slot->mi*ICON_GRID_WIDTH - win->core.width; X } X } X else if (SOmajor == SOLeftToRight) X { X x = ICON_GRID_WIDTH*slot->ma; X if (SOminor == SOTopToBottom) X { X y = ICON_GRID_HEIGHT*slot->mi; X } X else X { X y = pixvert - slot->mi*ICON_GRID_HEIGHT - win->core.height; X } X } X else if (SOmajor == SORightToLeft) X { X x = pixhoriz - ICON_GRID_WIDTH*slot->ma - win->core.width; X if (SOminor == SOTopToBottom) X { X y = ICON_GRID_HEIGHT*slot->mi; X } X else X { X y = pixvert - slot->mi*ICON_GRID_HEIGHT - win->core.height; X } X } X X (WinFunc(win,core.newposfunc))(win,x,y); X} X X/* incrPositionedSlots -- an icon has been explicitly positioned; create an X * iconslot record and increment the occupancy count of the affected slots. X */ static IconSlot * incrPositionedSlots(x,y,w,h,snaptogrid) int x,y,w,h; Bool snaptogrid; X{ X IconSlot *slot = MemNew(IconSlot); X#define ROUNDIF(v,w) (snaptogrid?ROUND((v),(w)):(v))/(w) X#define ROUNDDIM(p,s,w) (ROUNDUP(((p)%(w))+(s),(w))) X X if (SOmajor == SOTopToBottom) X { X slot->ma = ROUNDIF(y,ICON_GRID_HEIGHT); X slot->maw = ROUNDDIM(y,h,ICON_GRID_HEIGHT); X if (SOminor == SOLeftToRight) X { X slot->mi = ROUNDIF(x,ICON_GRID_WIDTH); X slot->miw = ROUNDDIM(x,w,ICON_GRID_WIDTH); X } X else X { X slot->mi = ROUNDIF(pixhoriz-(x+w),ICON_GRID_WIDTH); X slot->miw = ROUNDDIM(pixhoriz-(x+w),w,ICON_GRID_WIDTH); X } X } X else if (SOmajor == SOBottomToTop) X { X slot->ma = ROUNDIF(pixvert-(y+h),ICON_GRID_HEIGHT); X slot->maw = ROUNDDIM(pixvert-(y+h),h,ICON_GRID_HEIGHT); X slot->miw = w; X if (SOminor == SOLeftToRight) X { X slot->mi = ROUNDIF(x,ICON_GRID_WIDTH); X slot->miw = ROUNDDIM(x,w,ICON_GRID_WIDTH); X } X else X { X slot->mi = ROUNDIF(pixhoriz-(x+w),ICON_GRID_WIDTH); X slot->miw = ROUNDDIM(pixhoriz-(x+w),w,ICON_GRID_WIDTH); X } X } X else if (SOmajor == SOLeftToRight) X { X slot->ma = ROUNDIF(x,ICON_GRID_WIDTH); X slot->maw = ROUNDDIM(x,w,ICON_GRID_WIDTH); X if (SOminor == SOTopToBottom) X { X slot->mi = ROUNDIF(y,ICON_GRID_HEIGHT); X slot->miw = ROUNDDIM(y,h,ICON_GRID_HEIGHT); X } X else X { X slot->mi = ROUNDIF(pixvert-(y+h),ICON_GRID_HEIGHT); X slot->miw = ROUNDDIM(pixvert-(y+h),h,ICON_GRID_HEIGHT); X } X } X else if (SOmajor == SORightToLeft) X { X slot->ma = ROUNDIF(pixhoriz-(x+w),ICON_GRID_WIDTH); X slot->maw = ROUNDDIM(pixhoriz-(x+w),w,ICON_GRID_WIDTH); X if (SOminor == SOTopToBottom) X { X slot->mi = ROUNDIF(y,ICON_GRID_HEIGHT); X slot->miw = ROUNDDIM(y,h,ICON_GRID_HEIGHT); X } X else X { X slot->mi = ROUNDIF(pixvert-(y+h),ICON_GRID_HEIGHT); X slot->miw = ROUNDDIM(pixvert-(y+h),h,ICON_GRID_HEIGHT); X } X } X if (slot->ma < 0) slot->ma = 0; X if (slot->ma >= maslots) slot->ma = maslots-1; X if (slot->mi < 0) slot->mi = 0; X if (slot->mi >= mislots) slot->mi = mislots-1; X slot->positioned = True; X incrRegion(slot,1); X return slot; X} X X X/*************************************************************************** X* Global functions X***************************************************************************/ X X/* X * SlotInit -- does nothing right now X */ void SlotInit(dpy) Display *dpy; X{ X if (occupancy != NULL) X { X ErrorGeneral("Tried to multiply initialise Slots module\n"); X } X X iconList = NULL_LIST; X pixhoriz = DisplayWidth(dpy,DefaultScreen(dpy)); X pixvert = DisplayHeight(dpy,DefaultScreen(dpy)); X slotshoriz = pixhoriz/ICON_GRID_WIDTH; X slotsvert = pixvert/ICON_GRID_HEIGHT; X occupancy = MemAlloc(slotshoriz*slotsvert*sizeof(int)); X SlotSetLocations(dpy); X} X X/* SlotAlloc - given a sized and possibly positioned icon window, allocate X * the appropriate slots for it. If the window is positioned, X * True should be passed for the second parameter, and the x,y X * position will be honoured. If the window is not positioned, it X * will be positioned by this function to the appropriate slots(s). X * If snaptogrid is true and positioned is true, the given position is X * modified so that the upper left corner of the icon is at the closest X * icon grid point. Modifies the icon structure to assign it the icon X * slot. X * Returns an IconSlot pointer if successful; NULL otherwise. X */ struct _iconSlot * SlotAlloc(winicon, positioned, snaptogrid) WinIconFrame *winicon; Bool positioned; Bool snaptogrid; X{ X int nhoriz, nvert; /* number of slots occupied, horizontally & vertically */ X int nmajor, nminor; /* number of slots occupied, in major & minor directions */ X IconSlot *slot; X X iconList = ListCons(winicon, iconList); X X if (positioned) X { X slot = incrPositionedSlots(winicon->core.x, winicon->core.y, X winicon->core.width, winicon->core.height, snaptogrid); X winicon->iconslot = slot; X if (snaptogrid) X setIconPos(winicon,slot); X else X (WinFunc(winicon,core.newposfunc))(winicon,winicon->core.x,winicon->core.y); X } X else X { X nhoriz = ROUNDUP(winicon->core.width, ICON_GRID_WIDTH); X nvert = ROUNDUP(winicon->core.height, ICON_GRID_HEIGHT); X setMajorMinor(nvert, nhoriz, &nmajor, &nminor); X slot = incrDynamicSlots(nmajor, nminor); X winicon->iconslot = slot; X setIconPos(winicon,slot); X } X X return slot; X} X X/* SlotFree -- An icon is going away, so its references to slots should also go X * away. Returns True iff the free was successful. X * Note that if this code is changed, the similar code in SlotSetLocations X * may need to be changed also. X */ Bool SlotFree(winicon) WinIconFrame *winicon; X{ X List **l; X X if (winicon->iconslot == NULL) X { X return; X } X X incrRegion(winicon->iconslot,-1); X MemFree(winicon->iconslot); X winicon->iconslot = NULL; X X l = &iconList; X for (l = &iconList ; (*l) != NULL ; l = &((*l)->next)) X { X if ((WinIconFrame *)((*l)->value) == winicon) X { X ListDestroyCell(l); X break; X } X } X} X X/* sets the order in which slots are allocated for icons which are X * not explicitly positioned. The order is gotten from the global X * resource vector. X * For example, the AlongBottom order is expressed as X * major BottomToTop, minor LeftToRight. The major and minor orders X * cannot be both vertical or horizontal. Any icons which were X * automatically positioned are repositioned to equivalent positions X * in the new order. X */ Bool SlotSetLocations(dpy) Display *dpy; X{ X List *lauto, *lpos; X List **l; X WinIconFrame *win; X int ima, imi; X X /* set up the new order of things */ X switch (GRV.IconPlacement) X { X case AlongTop: X SOmajor = SOTopToBottom; X SOminor = SOLeftToRight; X break; X X case AlongTopRL: X SOmajor = SOTopToBottom; X SOminor = SORightToLeft; X break; X X case AlongBottom: X SOmajor = SOBottomToTop; X SOminor = SOLeftToRight; X break; X X case AlongBottomRL: X SOmajor = SOBottomToTop; X SOminor = SORightToLeft; X break; X X case AlongLeft: X SOmajor = SOLeftToRight; X SOminor = SOTopToBottom; X break; X X case AlongLeftBT: X SOmajor = SOLeftToRight; X SOminor = SOBottomToTop; X break; X X case AlongRight: X SOmajor = SORightToLeft; X SOminor = SOTopToBottom; X break; X X case AlongRightBT: X SOmajor = SORightToLeft; X SOminor = SOBottomToTop; X break; X } X X setMajorMinor(slotsvert,slotshoriz,&maslots,&mislots); X X if (iconList == NULL_LIST) X { X for (ima = 0; ima<maslots; ima++) X for (imi = 0; imi<mislots; imi++) X OCCUPANCY(ima,imi)=0; X return; X } X X /* partition existing icons */ X lauto = NULL_LIST; X lpos = NULL_LIST; X l = &iconList; X for (win = ListEnum(l); win != NULL; win = ListEnum(l)) X { X if (!win->iconslot->positioned) X { X lauto = ListCons(win,lauto); X } X else X { X lpos = ListCons(win,lpos); X } X /* this is the basics of a SlotFree */ X MemFree(win->iconslot); X win->iconslot = NULL; X } X ListDestroy(iconList); X iconList = NULL_LIST; X X for (ima = 0; ima<maslots; ima++) X for (imi = 0; imi<mislots; imi++) X OCCUPANCY(ima,imi)=0; X X /* place positioned icons */ X l = &lpos; X for (win = ListEnum(l); win != NULL; win = ListEnum(l)) X { X SlotAlloc(win,True,False); X (WinFunc(win,core.setconfigfunc))(win->core.client->dpy,win); X } X ListDestroy(lpos); X X /* place auto-positioned icons */ X l = &lauto; X for (win = ListEnum(l); win != NULL; win = ListEnum(l)) X { X SlotAlloc(win,False,False); X (WinFunc(win,core.setconfigfunc))(win->core.client->dpy,win); X } X ListDestroy(lauto); X} END_OF_FILE if test 14674 -ne `wc -c <'slots.c'`; then echo shar: \"'slots.c'\" unpacked with wrong size! fi # end of 'slots.c' fi if test -f 'win.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'win.h'\" else echo shar: Extracting \"'win.h'\" \(14880 characters\) sed "s/^X//" >'win.h' <<'END_OF_FILE' X/* X * (c) Copyright 1989 Sun Microsystems, Inc. Sun design patents X * pending in the U.S. and foreign countries. See LEGAL_NOTICE X * file for terms of the license. X * X * Written for Sun Microsystems by Crucible, Santa Cruz, CA. X */ X X/* @(#)win.h 1.2 olvwm version 3/30/91 */ X/* based on @(#) win.h 25.8 90/05/23 Crucible */ X X#include "list.h" X X/*************************************************************************** X* Client state structures X***************************************************************************/ X X/* X * The following structure is defined in Xutil.h, but it differs between X11R3 X * and X11R4 to reflect the acceptance of the ICCCM (version 1.0) as a X * Consortium standard. This replacement is necessary so that olwm can be X * assured of getting the right structure, independent of the include files X * present on the system it's compiled on. Defining this this way allows olwm X * to accomodate clients that use the R4-based structure as well as older X * clients. X */ typedef struct { X long flags; X struct { X int x; X int y; X int width; X int height; X } pad; /* x, y, w, h replaced by pad[4] for X11R4 */ X int min_width; X int min_height; X int max_width; X int max_height; X int width_inc; X int height_inc; X struct { X int x; X int y; X } min_aspect, max_aspect; X int base_width; /* added in X11R4 */ X int base_height; /* added in X11R4 */ X int win_gravity; /* added in X11R4 */ X} NewXSizeHints; X X/* X * The following definitions are new in ICCCM version 1.0. Olwm requires X * them, but they may not be present if olwm is being compiled against an old X * version of Xutil.h (e.g. from X11R3). We define them here if necessary. X */ X X#ifndef PBaseSize X#define PBaseSize (1L << 8) /* program specified base for incrementing */ X#endif X X#ifndef PWinGravity X#define PWinGravity (1L << 9) /* program specified window gravity */ X#endif X X#ifndef WithdrawnState X#define WithdrawnState 0 /* for windows that are not mapped */ X#endif X X/* a type for the four possible focus modes */ typedef enum { Passive, NoInput, LocallyActive, GloballyActive } FocusMode; X typedef struct { X long flags; X enum { X MENU_FULL = 0, /* Close, Zoom, Props, Scale, Back, X * Refresh, Quit X */ X MENU_LIMITED = 1, /* Dismiss, Scale, Refresh */ X MENU_NONE = 2, /* No Menu */ X } menu_type; X int pushpin_initial_state; X /* numbers assigned as per OLXCI 3/20/89 */ X} WMDecorations; X X/* pin states numbers, as per OLXCI 3/20/89 */ X#define PIN_OUT 0 X#define PIN_IN 1 X X/* value for flags */ X#define WMDecorationHeader (1L<<0) X#define WMDecorationFooter (1L<<1) X#define WMDecorationPushPin (1L<<2) X#define WMDecorationCloseButton (1L<<3) X#define WMDecorationHeaderDeco (WMDecorationPushPin | WMDecorationCloseButton) X#define WMDecorationOKButton (1L<<4) X#define WMDecorationResizeable (1L<<5) X X/* window kinds */ typedef enum { OLBASEWINDOW, OLCMDWINDOW, OLPROPWINDOW, OLHELPWINDOW, X OLNOTICEWINDOW, OLOTHERWINDOW, OLTRANSIENTWINDOW, OLSPECIAL, X OLMINIMALDECOR } OLType; X typedef int WMState; /* use state codes in Xutil.h */ X typedef struct { /* pointer warp state data */ X int warpToX, warpToY; /* where to pointer goes on warp */ X int dflButtonX, dflButtonY; /* location of default button */ X int dflButtonW, dflButtonH; /* size of default button */ X Window warpBackWin; /* return warp window */ X int warpBackX, warpBackY; /* where to put it back */ X} WarpInfo; X X/*************************************************************************** X* Client structures X***************************************************************************/ X X/* a top-level client window */ X typedef struct _client X{ X OLType *olType; X WMDecorations *wmDecors; X WMState wmState; X NewXSizeHints *normHints; /* WM_NORMAL_HINTS */ X XWMHints *wmHints; /* WM_HINTS */ X char *wmInstance; /* WM_CLASS instance name */ X char *wmClass; /* WM_CLASS class name */ X Bool hasMessages; /* WM_HINTS has obsolete fields */ X int protocols; X FocusMode focusMode; X Bool isFocus; X Bool isSelected; X Bool isBusy; X Display *dpy; X int screen; X struct _winpaneframe *framewin; X struct _winiconframe *iconwin; X WarpInfo warpInfo; X Window groupid; /* Actually GroupID */ X unsigned int groupmask; /* role that client is playing in group */ X long busyState; X List *colormapWins; X int sticky; X Window virtualWindow; X int root; X Window virtualInactive; X} Client; X X X/*************************************************************************** X* Window class structures X***************************************************************************/ X X/* classes of window which we can deal with */ typedef enum { WIN_FRAME, WIN_ICON, WIN_RESIZE, WIN_PUSHPIN, WIN_WINBUTTON, X WIN_PANE, WIN_ICONPANE, WIN_COLORMAP, WIN_MENU, WIN_NOFOCUS, X WIN_ROOT, WIN_BUSY } WinKind; X typedef int (*EvFunc)(); typedef int (*IntFunc)(); typedef struct _genericclasscore { X WinKind kind; X EvFunc xevents[LASTEvent]; /* function for each X event */ X EvFunc focusfunc; /* focus state has changed */ X EvFunc drawfunc; /* draw window */ X EvFunc destroyfunc; /* destroy window and structures */ X EvFunc selectfunc; /* selecte state has changed */ X EvFunc newconfigfunc; /* compute configuration */ X EvFunc newposfunc; /* set position */ X EvFunc setconfigfunc; /* set configuration */ X EvFunc createcallback; /* used in menu creation */ X IntFunc heightfunc; /* compute correct height */ X IntFunc widthfunc; /* compute correct width */ X} GenericClassCore; X typedef struct _classgeneric { X GenericClassCore core; X} ClassGeneric; X typedef struct _genericframeclasscore { X IntFunc heighttop, heightbottom, widthleft, widthright; X IntFunc menuPress; X IntFunc adjustPress, adjustClick; X IntFunc selectPress, selectClick, selectDoubleClick, selectDrag; X} GenericFrameClassCore; X typedef struct _classgenericframe { X GenericClassCore core; X GenericFrameClassCore fcore; X} ClassGenericFrame; X typedef struct _genericpaneclasscore { X EvFunc setsizefunc; X} GenericPaneClassCore; X typedef struct _classpane { X GenericClassCore core; X GenericPaneClassCore pcore; X} ClassGenericPane; X typedef ClassGenericFrame ClassPaneFrame; typedef ClassGenericFrame ClassIconFrame; typedef ClassGeneric ClassPushPin; typedef ClassGenericPane ClassPane; typedef ClassGenericPane ClassMenu; typedef ClassGeneric ClassResize; typedef ClassGeneric ClassButton; typedef ClassGeneric ClassBusy; typedef ClassGenericPane ClassIconPane; typedef ClassGeneric ClassRoot; typedef ClassGeneric ClassNoFocus; typedef ClassGeneric ClassColormap; X X/* Core functions: X * X * destroyfunc - int (*destroyfunc)(Display *dpy, WinGeneric *win) X * Called when the window is being destroyed; should destroy any private X * resources associated with the window (including possibly destroying X * the X window) and destroy the window information structure. X * X * selectfunc - int (*selectfunc)(Display *dpy, WinGeneric *win, Bool selected) X * Called whenever the window is selected/deselected. The window should X * update its private state -- most particularly, its screen appearance -- X * to match the new state. This function is only called when the selection X * state has changed. X * X * focusfunc - int (*focusfunc)(Display *dpy, WinGeneric *win, Bool focus) X * Called whenever the window gains/loses focus. The window should update X * its private state -- most particularly, its screen appearance -- X * to match the new state. The window does _not_ need to take focus if X * it is active; this has already been taken care of. This function is X * only called when the focus has changed. X * X * newconfigfunc - int (*newconfigfunc)(WinGeneric *win, X * XConfigureRequestEvent *xcre) X * Called when the configuration of a window should be recomputed. It X * can be assumed that all child windows will have already computed their X * sizes. This function should compute the size of this window, and call X * the newposfunc of each child that needs to be moved. If the configuration X * of the window is changed by this function, the dirtyconfig flag should be X * set. The xcre parameter will be be set to a configure request event X * structure only if a configure request was received for this X * particular window; otherwise the parameter will be null. X * Returns True if any dirtyconfig flag has been set. X * X * newposfunc - int (*newposfunc)(WinGeneric *win, int x, y) X * Instructs a child window to move to a position (x,y). If this position X * is different from the old position, then the dirtyconfig flag X * should be set. Returns True if any dirtyconfig flag has been set. X * X * setconfigfunc - int (*setconfigfunc)(Display *dpy, WinGeneric *win) X * The window's configuration may have changed; if so, call XConfigureWindow X * to make the changes. Clear the dirtyconfig bits in the process. X * The pane window will need to send a synthetic configure notify for X * any configuration call. X * X * createcallback - int (*createcallback)(WinGeneric *self, Client *cli, X * WinGeneric *parent) X * For internally-created panes, the client and parent are filled out X * when the StateNew process would normally create a pane. X * X * heightfunc - int (*heightfunc)(WinGeneric *self, XConfigureRequestEvent *pxcre) X * should return the window's correct height, given a configure request X * event and the current environment. Used to see if a window needs to X * be resized. X * X * widthfunc - same as heightfunc, except that it returns correct width X */ X X/*************************************************************************** X* Window instance structures X***************************************************************************/ X X/* X * The wincore structure contains common information about each window. X * X * stack_mode, stack_sib, and dirtyconfig contain information pending window X * configuration changes that have not yet been sent to the server. X * X * exposures is a list of exposed rectangles that have not yet been repainted. X * X * colormapClients is a list of clients that have this window in their X * colormapWins list. tag is used only while processing changes to a client's X * colormapWins list. X */ typedef struct _wincore { X Window self; X WinKind kind; X struct _wingeneric *parent; X List *children; X Client *client; X int x, y; X unsigned int width, height; X int stack_mode; X Window stack_sib; X unsigned int dirtyconfig; X Colormap colormap; X List *exposures; X List *colormapClients; X Bool tag; X} WinCore; X/* REMIND maybe add: cursor */ X X/* macros associated with a window core */ X#define WinIsKind(w,k) ((w)->core.kind == (k)) X#define WinClass(w) ((w)->class) X#define WinFunc(w,f) ((w)->class->f) X X/* FrameCore defines fields common to all types of frame */ typedef struct _winframecore { X struct _wingenericpane *panewin; /* pane inside frame */ X char *name; /* name to be displayed on frame */ X void *menu; /* actually Menu * */ X} WinFrameCore; X X/* PaneCore defines fields common to all types of panes */ typedef struct _winpanecore { X int oldBorderWidth; X int oldSaveUnder; X int pendingUnmaps; X} WinPaneCore; X X/* Specific window types */ X typedef struct _wingeneric { X ClassGeneric *class; X WinCore core; X} WinGeneric; X typedef struct _wingenericframe { X ClassGenericFrame *class; X WinCore core; X WinFrameCore fcore; X} WinGenericFrame; X X/* macros for generic frames */ X#define FrameHeightTop(w) (WinFunc((w),fcore.heighttop))((w)) X#define FrameHeightBottom(w) (WinFunc((w),fcore.heightbottom))((w)) X#define FrameWidthLeft(w) (WinFunc((w),fcore.widthleft))((w)) X#define FrameWidthRight(w) (WinFunc((w),fcore.widthright))((w)) X X typedef struct _wingenericpane { X ClassGenericPane *class; X WinCore core; X WinPaneCore pcore; X} WinGenericPane; X typedef struct _winpaneframe { X ClassPaneFrame *class; X WinCore core; X WinFrameCore fcore; X X /* footer fields */ X char *leftfooter; X int leftfooterLength, leftfooterWidth; X char *rightfooter; X int rightfooterLength, rightfooterWidth; X X /* title fields */ X int titleOff; /* x offset of title area in pix */ X int nameLength; /* length of name in chars */ X int nameWidth; /* width of name in pix */ X int titlex, titley; /* title position */ X X /* pointer warp status */ X Bool pointerIsWarped; X X /* sizing functions */ X void (*normfullsizefunc)(); /* normal/full size function */ X Bool restoreSet; /* True => restore values valid */ X int restoreY, restoreWidth, restoreHeight; X /* context for full/norm size X * note that y is frame; w/h are pane X */ X X /* other decorations */ X WinGeneric *winDeco; /* window button or pushpin */ X struct _winbusy *winBusy; /* special window when busy */ X} WinPaneFrame; X typedef struct _winiconframe { X ClassIconFrame *class; X WinCore core; X WinFrameCore fcore; X struct _iconSlot *iconslot; X Bool fManuallyPositioned; X int nameX, nameY; /* name of icon */ X int nameWidth; X int nameLength; X} WinIconFrame; X typedef struct _winiconpane { X ClassIconPane *class; X WinCore core; X WinPaneCore pcore; X Bool iconClientWindow; /* true iff client owns pane */ X Pixmap iconPixmap; /* None if icon has client window */ X#ifdef OBSOLETE X int iconX, iconY; /* geometry of iconDrawable */ X unsigned int iconWidth, iconHeight; X#endif X} WinIconPane; X typedef struct _winpushpin { X ClassPushPin *class; X WinCore core; X Bool pushpinin; X} WinPushPin; X typedef struct _winpane { X ClassPane *class; X WinCore core; X WinPaneCore pcore; X} WinPane; X typedef struct _winmenu { /* menus are a subclass of panes */ X ClassMenu *class; X WinCore core; X WinPaneCore pcore; X Bool pushpinin; X void *menu; /* actually Menu * */ X} WinMenu; X typedef enum {upleft, upright, lowleft, lowright} WhichResize; X typedef struct _winresize { X ClassResize *class; X WinCore core; X WhichResize which; X Bool depressed; X} WinResize; X typedef struct _winbutton { X ClassButton *class; X WinCore core; X} WinButton; X typedef struct _winbusy { X ClassBusy *class; X WinCore core; X Bool isFocus; X} WinBusy; X typedef WinGeneric WinRoot; typedef WinGeneric WinNoFocus; X X/* colormap windows aren't linked into the ordinary window tree since they X * are presumed under client control. We create info structures for them X * only so appropriate events can be dispatched on them. Colormap windows X * are in a list on the client structure. X */ typedef WinGeneric WinColormap; X X/* functions mapping windows to infos */ X extern void WIInstallInfo(); extern Bool WIUninstallInfo(); extern WinGeneric *WIGetInfo(); extern void WIApply(); X X/* window functions */ extern void WinAddChild(); extern void WinRemoveChild(); X X/* Useful client macros */ X#define PANEOFCLIENT(cli) ((cli)->framewin->fcore.panewin) X#define PANEWINOFCLIENT(cli) (PANEOFCLIENT(cli)->core.self) END_OF_FILE if test 14880 -ne `wc -c <'win.h'`; then echo shar: \"'win.h'\" unpacked with wrong size! fi # end of 'win.h' fi echo shar: End of archive 6 \(of 16\). cp /dev/null ark6isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 16 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Dan Heller O'Reilly && Associates Z-Code Software Comp-sources-x: Senior Writer President comp-sources.x@uunet.uu.net argv@ora.com argv@zipcode.com