From 494de5839b250aa3030fad70192415c33820d4fe Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Thu, 7 Jan 2010 16:59:37 +0100 Subject: [PATCH] Interface XBoard to Ghostvie file-browser dialog --- Makefile.am | 2 + dir.c | 163 +++++++++++ draw.c | 920 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ path.c | 900 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ selfile.c | 753 ++++++++++++++++++++++++++++++++++++++++++++++++ selfile.h | 149 ++++++++++ xboard.c | 47 +--- xstat.h | 23 ++ 8 files changed, 2918 insertions(+), 39 deletions(-) create mode 100644 dir.c create mode 100644 draw.c create mode 100644 path.c create mode 100644 selfile.c create mode 100644 selfile.h create mode 100644 xstat.h diff --git a/Makefile.am b/Makefile.am index 7345205..697bb3a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,6 +26,8 @@ xboard_SOURCES = backend.c backend.h backendz.h \ xgamelist.c xgamelist.h\ xhistory.c xhistory.h \ xoptions.c \ + selfile.c selfile.h \ + draw.c path.c dir.c xstat.h \ $(ZPY) xboard_LDADD = -lm @XAW_LIBS@ @X_LIBS@ diff --git a/dir.c b/dir.c new file mode 100644 index 0000000..102187e --- /dev/null +++ b/dir.c @@ -0,0 +1,163 @@ +/* + * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Software Research Associates not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Software Research Associates + * makes no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Author: Erik M. van der Poel + * Software Research Associates, Inc., Tokyo, Japan + * erik@sra.co.jp + */ + +#include + +#ifdef SEL_FILE_IGNORE_CASE +#include +#endif /* def SEL_FILE_IGNORE_CASE */ + +#include "selfile.h" + +#if defined(SVR4) || defined(SYSV) || defined(USG) || defined(__osf__) +#include +#else /* defined(SVR4) || defined(SYSV) || defined(USG) */ +#include +#define dirent direct +#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */ + +#include + +#if defined(SVR4) || defined(SYSV) || defined(USG) +extern void qsort(); +#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */ + +#ifdef SEL_FILE_IGNORE_CASE +int +SFcompareEntries(p, q) + SFEntry *p; + SFEntry *q; +{ + register char *r, *s; + register char c1, c2; + + r = p->real; + s = q->real; + + c1 = *r++; + if (islower(c1)) { + c1 = toupper(c1); + } + c2 = *s++; + if (islower(c2)) { + c2 = toupper(c2); + } + + while (c1 == c2) { + if (!c1) { + return strcmp(p->real, q->real); + } + c1 = *r++; + if (islower(c1)) { + c1 = toupper(c1); + } + c2 = *s++; + if (islower(c2)) { + c2 = toupper(c2); + } + } + + return c1 - c2; +} +#else /* def SEL_FILE_IGNORE_CASE */ +int +SFcompareEntries(p, q) + SFEntry *p; + SFEntry *q; +{ + return strcmp(p->real, q->real); +} +#endif /* def SEL_FILE_IGNORE_CASE */ + +int +SFgetDir(dir) + SFDir *dir; +{ + SFEntry *result = NULL; + int alloc = 0; + int i; + DIR *dirp; + struct dirent *dp; + char *str; + int len; + int maxChars; + struct stat statBuf; + + maxChars = strlen(dir->dir) - 1; + + dir->entries = NULL; + dir->nEntries = 0; + dir->nChars = 0; + + result = NULL; + i = 0; + + dirp = opendir("."); + if (!dirp) { + return 1; + } + + (void) stat(".", &statBuf); + dir->mtime = statBuf.st_mtime; + + (void) readdir(dirp); /* throw away "." */ + +#ifndef S_IFLNK + (void) readdir(dirp); /* throw away ".." */ +#endif /* ndef S_IFLNK */ + + while (dp = readdir(dirp)) { + if (i >= alloc) { + alloc = 2 * (alloc + 1); + result = (SFEntry *) XtRealloc((char *) result, + (unsigned) (alloc * sizeof(SFEntry))); + } + result[i].statDone = 0; + str = dp->d_name; + len = strlen(str); + result[i].real = XtMalloc((unsigned) (len + 2)); + (void) strcat(strcpy(result[i].real, str), " "); + if (len > maxChars) { + maxChars = len; + } + result[i].shown = result[i].real; + i++; + } + +#if defined(SVR4) || defined(SYSV) || defined(USG) + qsort((char *) result, (unsigned) i, sizeof(SFEntry), SFcompareEntries); +#else /* defined(SVR4) || defined(SYSV) || defined(USG) */ + qsort((char *) result, i, sizeof(SFEntry), SFcompareEntries); +#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */ + + dir->entries = result; + dir->nEntries = i; + dir->nChars = maxChars + 1; + + closedir(dirp); + + return 0; +} diff --git a/draw.c b/draw.c new file mode 100644 index 0000000..47efa17 --- /dev/null +++ b/draw.c @@ -0,0 +1,920 @@ +/* + * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Software Research Associates not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Software Research Associates + * makes no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Author: Erik M. van der Poel + * Software Research Associates, Inc., Tokyo, Japan + * erik@sra.co.jp + */ + +#include +#include "selfile.h" +#include "xstat.h" +#include +#include +#include + +#define SF_DEFAULT_FONT "9x15" + +#ifdef ABS +#undef ABS +#endif +#define ABS(x) (((x) < 0) ? (-(x)) : (x)) + +typedef struct { + char *fontname; +} TextData, *textPtr; + +int SFcharWidth, SFcharAscent, SFcharHeight; + +int SFcurrentInvert[3] = { -1, -1, -1 }; + +static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC; + +static XtResource textResources[] = { + {XtNfont, XtCFont, XtRString, sizeof (char *), + XtOffset(textPtr, fontname), XtRString, SF_DEFAULT_FONT}, +}; + +static XFontStruct *SFfont; + +static int SFcurrentListY; + +static XtIntervalId SFscrollTimerId; + +SFinitFont() +{ + TextData *data; + + data = XtNew(TextData); + + XtGetApplicationResources(selFileForm, (XtPointer) data, textResources, + XtNumber(textResources), (Arg *) NULL, ZERO); + + SFfont = XLoadQueryFont(SFdisplay, data->fontname); + if (!SFfont) { + SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT); + if (!SFfont) { + char sbuf[256]; + + (void) sprintf(sbuf, "XsraSelFile: can't get font %s", + SF_DEFAULT_FONT); + + XtAppError(SFapp, sbuf); + } + } + + SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2; + SFcharAscent = SFfont->max_bounds.ascent; + SFcharHeight = SFcharAscent + SFfont->max_bounds.descent; +} + +SFcreateGC() +{ + XGCValues gcValues; + XRectangle rectangles[1]; + + gcValues.foreground = SFfore; + + SFlineGC = XtGetGC( + selFileLists[0], + (XtGCMask) + GCForeground | + 0, + &gcValues + ); + + SFscrollGC = XtGetGC( + selFileLists[0], + (XtGCMask) + 0, + &gcValues + ); + + gcValues.function = GXinvert; + gcValues.plane_mask = (SFfore ^ SFback); + + SFinvertGC = XtGetGC( + selFileLists[0], + (XtGCMask) + GCFunction | + GCPlaneMask | + 0, + &gcValues + ); + + gcValues.foreground = SFfore; + gcValues.background = SFback; + gcValues.font = SFfont->fid; + + SFtextGC = XCreateGC( + SFdisplay, + XtWindow(selFileLists[0]), + (unsigned long) + GCForeground | + GCBackground | + GCFont | + 0, + &gcValues + ); + + rectangles[0].x = SFlineToTextH + SFbesideText; + rectangles[0].y = 0; + rectangles[0].width = SFcharsPerEntry * SFcharWidth; + rectangles[0].height = SFupperY + 1; + + XSetClipRectangles( + SFdisplay, + SFtextGC, + 0, + 0, + rectangles, + 1, + Unsorted + ); +} + +SFclearList(n, doScroll) + int n; + int doScroll; +{ + SFDir *dir; + + SFcurrentInvert[n] = -1; + + XClearWindow(SFdisplay, XtWindow(selFileLists[n])); + + XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, + 2); + + if (doScroll) { + dir = &(SFdirs[SFdirPtr + n]); + + if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars) { + XawScrollbarSetThumb( + selFileVScrolls[n], + (float) (((double) dir->vOrigin) / + dir->nEntries), + (float) (((double) ((dir->nEntries < SFlistSize) + ? dir->nEntries : SFlistSize)) / + dir->nEntries) + ); + + XawScrollbarSetThumb( + selFileHScrolls[n], + (float) (((double) dir->hOrigin) / dir->nChars), + (float) (((double) ((dir->nChars < + SFcharsPerEntry) ? dir->nChars : + SFcharsPerEntry)) / dir->nChars) + ); + } else { + XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0, + (float) 1.0); + XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0, + (float) 1.0); + } + } +} + +static +SFdeleteEntry(dir, entry) + SFDir *dir; + SFEntry *entry; +{ + register SFEntry *e; + register SFEntry *end; + int n; + int idx; + + idx = entry - dir->entries; + + if (idx < dir->beginSelection) { + dir->beginSelection--; + } + if (idx <= dir->endSelection) { + dir->endSelection--; + } + if (dir->beginSelection > dir->endSelection) { + dir->beginSelection = dir->endSelection = -1; + } + + if (idx < dir->vOrigin) { + dir->vOrigin--; + } + + XtFree(entry->real); + + end = &(dir->entries[dir->nEntries - 1]); + + for (e = entry; e < end; e++) { + *e = *(e + 1); + } + + if (!(--dir->nEntries)) { + return; + } + + n = dir - &(SFdirs[SFdirPtr]); + if ((n < 0) || (n > 2)) { + return; + } + + XawScrollbarSetThumb( + selFileVScrolls[n], + (float) (((double) dir->vOrigin) / dir->nEntries), + (float) (((double) ((dir->nEntries < SFlistSize) ? + dir->nEntries : SFlistSize)) / dir->nEntries) + ); +} + +static +SFwriteStatChar(name, last, statBuf) + char *name; + int last; + struct stat *statBuf; +{ + name[last] = SFstatChar(statBuf); +} + +static int +SFstatAndCheck(dir, entry) + SFDir *dir; + SFEntry *entry; +{ + struct stat statBuf; + char save; + int last; + + /* + * must be restored before returning + */ + save = *(dir->path); + *(dir->path) = 0; + + if (!SFchdir(SFcurrentPath)) { + last = strlen(entry->real) - 1; + entry->real[last] = 0; + entry->statDone = 1; + if ( + (!stat(entry->real, &statBuf)) + +#ifdef S_IFLNK + + || (!lstat(entry->real, &statBuf)) + +#endif /* ndef S_IFLNK */ + + ) { + if (SFfunc) { + char *shown; + + shown = NULL; + if (SFfunc(entry->real, &shown, &statBuf)) { + if (shown) { + int len; + + len = strlen(shown); + entry->shown = XtMalloc( + (unsigned) (len + 2) + ); + (void) strcpy(entry->shown, + shown); + SFwriteStatChar( + entry->shown, + len, + &statBuf + ); + entry->shown[len + 1] = 0; + } + } else { + SFdeleteEntry(dir, entry); + + *(dir->path) = save; + return 1; + } + } + SFwriteStatChar(entry->real, last, &statBuf); + } else { + entry->real[last] = ' '; + } + } + + *(dir->path) = save; + return 0; +} + +static +SFdrawStrings(w, dir, from, to) + register Window w; + register SFDir *dir; + register int from; + register int to; +{ + register int i; + register SFEntry *entry; + int x; + + x = SFtextX - dir->hOrigin * SFcharWidth; + + if (dir->vOrigin + to >= dir->nEntries) { + to = dir->nEntries - dir->vOrigin - 1; + } + for (i = from; i <= to; i++) { + entry = &(dir->entries[dir->vOrigin + i]); + if (!(entry->statDone)) { + if (SFstatAndCheck(dir, entry)) { + if (dir->vOrigin + to >= dir->nEntries) { + to = dir->nEntries - dir->vOrigin - 1; + } + i--; + continue; + } + } + XDrawImageString( + SFdisplay, + w, + SFtextGC, + x, + SFtextYoffset + i * SFentryHeight, + entry->shown, + strlen(entry->shown) + ); + if (dir->vOrigin + i == dir->beginSelection) { + XDrawLine( + SFdisplay, + w, + SFlineGC, + SFlineToTextH + 1, + SFlowerY + i * SFentryHeight, + SFlineToTextH + SFentryWidth - 2, + SFlowerY + i * SFentryHeight + ); + } + if ( + (dir->vOrigin + i >= dir->beginSelection) && + (dir->vOrigin + i <= dir->endSelection) + ) { + SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 = + SFlowerY + i * SFentryHeight; + SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 = + SFlowerY + (i + 1) * SFentryHeight - 1; + XDrawSegments( + SFdisplay, + w, + SFlineGC, + SFcompletionSegs, + 2 + ); + } + if (dir->vOrigin + i == dir->endSelection) { + XDrawLine( + SFdisplay, + w, + SFlineGC, + SFlineToTextH + 1, + SFlowerY + (i + 1) * SFentryHeight - 1, + SFlineToTextH + SFentryWidth - 2, + SFlowerY + (i + 1) * SFentryHeight - 1 + ); + } + } +} + +SFdrawList(n, doScroll) + int n; + int doScroll; +{ + SFDir *dir; + Window w; + + SFclearList(n, doScroll); + + if (SFdirPtr + (3-NR) + n < SFdirEnd) { + dir = &(SFdirs[SFdirPtr + n + (3-NR)]); + w = XtWindow(selFileLists[n]); + XDrawImageString( + SFdisplay, + w, + SFtextGC, + SFtextX - dir->hOrigin * SFcharWidth, + SFlineToTextV + SFaboveAndBelowText + SFcharAscent, + dir->dir, + strlen(dir->dir) + ); + SFdrawStrings(w, dir, 0, SFlistSize - 1); + } +} + +SFdrawLists(doScroll) + int doScroll; +{ + int i; + + for (i = 0; i < NR; i++) { + SFdrawList(i, doScroll); + } +} + +static +SFinvertEntry(n) + register int n; +{ + XFillRectangle( + SFdisplay, + XtWindow(selFileLists[n]), + SFinvertGC, + SFlineToTextH, + SFcurrentInvert[n] * SFentryHeight + SFlowerY, + SFentryWidth, + SFentryHeight + ); +} + +static unsigned long +SFscrollTimerInterval() +{ + static int maxVal = 200; + static int varyDist = 50; + static int minDist = 50; + int t; + int dist; + + if (SFcurrentListY < SFlowerY) { + dist = SFlowerY - SFcurrentListY; + } else if (SFcurrentListY > SFupperY) { + dist = SFcurrentListY - SFupperY; + } else { + return (unsigned long) 1; + } + + t = maxVal - ((maxVal / varyDist) * (dist - minDist)); + + if (t < 1) { + t = 1; + } + + if (t > maxVal) { + t = maxVal; + } + + return (unsigned long) t; +} + +static void +SFscrollTimer(p, id) + XtPointer p; + XtIntervalId *id; +{ + SFDir *dir; + int save; + int n; + + n = (int) p; + + dir = &(SFdirs[SFdirPtr + n]); + save = dir->vOrigin; + + if (SFcurrentListY < SFlowerY) { + if (dir->vOrigin > 0) { + SFvSliderMovedCallback(selFileVScrolls[n], n, + dir->vOrigin - 1); + } + } else if (SFcurrentListY > SFupperY) { + if (dir->vOrigin < dir->nEntries - SFlistSize) { + SFvSliderMovedCallback(selFileVScrolls[n], n, + dir->vOrigin + 1); + } + } + + if (dir->vOrigin != save) { + if (dir->nEntries) { + XawScrollbarSetThumb( + selFileVScrolls[n], + (float) (((double) dir->vOrigin) / dir->nEntries), + (float) (((double) ((dir->nEntries < SFlistSize) ? + dir->nEntries : SFlistSize)) / dir->nEntries) + ); + } + } + + if (SFbuttonPressed) { + SFscrollTimerId = XtAppAddTimeOut(SFapp, + SFscrollTimerInterval(), SFscrollTimer, (XtPointer) n); + } +} + +static int +SFnewInvertEntry(n, event) + register int n; + register XMotionEvent *event; +{ + register int x, y; + register int new; + static int SFscrollTimerAdded = 0; + + x = event->x; + y = event->y; + + if (SFdirPtr + n >= SFdirEnd) { + return -1; + } else if ( + (x >= 0) && (x <= SFupperX) && + (y >= SFlowerY) && (y <= SFupperY) + ) { + register SFDir *dir = &(SFdirs[SFdirPtr + n]); + + if (SFscrollTimerAdded) { + SFscrollTimerAdded = 0; + XtRemoveTimeOut(SFscrollTimerId); + } + + new = (y - SFlowerY) / SFentryHeight; + if (dir->vOrigin + new >= dir->nEntries) { + return -1; + } + return new; + } else { + if (SFbuttonPressed) { + SFcurrentListY = y; + if (!SFscrollTimerAdded) { + SFscrollTimerAdded = 1; + SFscrollTimerId = XtAppAddTimeOut(SFapp, + SFscrollTimerInterval(), SFscrollTimer, + (XtPointer) n); + } + } + + return -1; + } +} + +/* ARGSUSED */ +void +SFenterList(w, n, event) + Widget w; + register int n; + register XEnterWindowEvent *event; +{ + register int new; + + /* sanity */ + if (SFcurrentInvert[n] != -1) { + SFinvertEntry(n); + SFcurrentInvert[n] = -1; + } + + new = SFnewInvertEntry(n, (XMotionEvent *) event); + if (new != -1) { + SFcurrentInvert[n] = new; + SFinvertEntry(n); + } +} + +/* ARGSUSED */ +void +SFleaveList(w, n, event) + Widget w; + register int n; + XEvent *event; +{ + if (SFcurrentInvert[n] != -1) { + SFinvertEntry(n); + SFcurrentInvert[n] = -1; + } +} + +/* ARGSUSED */ +void +SFmotionList(w, n, event) + Widget w; + register int n; + register XMotionEvent *event; +{ + register int new; + + new = SFnewInvertEntry(n, event); + + if (new != SFcurrentInvert[n]) { + if (SFcurrentInvert[n] != -1) { + SFinvertEntry(n); + } + SFcurrentInvert[n] = new; + if (new != -1) { + SFinvertEntry(n); + } + } +} + +/* ARGSUSED */ +void +SFvFloatSliderMovedCallback(w, n, fnew) + Widget w; + int n; + float *fnew; +{ + int new; + + new = (*fnew) * SFdirs[SFdirPtr + n].nEntries; + + SFvSliderMovedCallback(w, n, new); +} + +/* ARGSUSED */ +void +SFvSliderMovedCallback(w, n, new) + Widget w; + int n; + int new; +{ + int old; + register Window win; + SFDir *dir; + + dir = &(SFdirs[SFdirPtr + n]); + + old = dir->vOrigin; + dir->vOrigin = new; + + if (old == new) { + return; + } + + win = XtWindow(selFileLists[n]); + + if (ABS(new - old) < SFlistSize) { + if (new > old) { + XCopyArea( + SFdisplay, + win, + win, + SFscrollGC, + SFlineToTextH, + SFlowerY + (new - old) * SFentryHeight, + SFentryWidth + SFlineToTextH, + (SFlistSize - (new - old)) * SFentryHeight, + SFlineToTextH, + SFlowerY + ); + XClearArea( + SFdisplay, + win, + SFlineToTextH, + SFlowerY + (SFlistSize - (new - old)) * + SFentryHeight, + SFentryWidth + SFlineToTextH, + (new - old) * SFentryHeight, + False + ); + SFdrawStrings(win, dir, SFlistSize - (new - old), + SFlistSize - 1); + } else { + XCopyArea( + SFdisplay, + win, + win, + SFscrollGC, + SFlineToTextH, + SFlowerY, + SFentryWidth + SFlineToTextH, + (SFlistSize - (old - new)) * SFentryHeight, + SFlineToTextH, + SFlowerY + (old - new) * SFentryHeight + ); + XClearArea( + SFdisplay, + win, + SFlineToTextH, + SFlowerY, + SFentryWidth + SFlineToTextH, + (old - new) * SFentryHeight, + False + ); + SFdrawStrings(win, dir, 0, old - new); + } + } else { + XClearArea( + SFdisplay, + win, + SFlineToTextH, + SFlowerY, + SFentryWidth + SFlineToTextH, + SFlistSize * SFentryHeight, + False + ); + SFdrawStrings(win, dir, 0, SFlistSize - 1); + } +} + +/* ARGSUSED */ +void +SFvAreaSelectedCallback(w, n, pnew) + Widget w; + int n; + int pnew; +{ + SFDir *dir; + int new; + + dir = &(SFdirs[SFdirPtr + n]); + + new = dir->vOrigin + + (((double) pnew) / SFvScrollHeight) * dir->nEntries; + + if (new > dir->nEntries - SFlistSize) { + new = dir->nEntries - SFlistSize; + } + + if (new < 0) { + new = 0; + } + + if (dir->nEntries) { + float f; + + f = ((double) new) / dir->nEntries; + + XawScrollbarSetThumb( + w, + f, + (float) (((double) ((dir->nEntries < SFlistSize) ? + dir->nEntries : SFlistSize)) / dir->nEntries) + ); + } + + SFvSliderMovedCallback(w, n, new); +} + +/* ARGSUSED */ +void +SFhSliderMovedCallback(w, n, new) + Widget w; + int n; + float *new; +{ + SFDir *dir; + int save; + + dir = &(SFdirs[SFdirPtr + n]); + save = dir->hOrigin; + dir->hOrigin = (*new) * dir->nChars; + if (dir->hOrigin == save) { + return; + } + + SFdrawList(n, SF_DO_NOT_SCROLL); +} + +/* ARGSUSED */ +void +SFhAreaSelectedCallback(w, n, pnew) + Widget w; + int n; + int pnew; +{ + SFDir *dir; + int new; + + dir = &(SFdirs[SFdirPtr + n]); + + new = dir->hOrigin + + (((double) pnew) / SFhScrollWidth) * dir->nChars; + + if (new > dir->nChars - SFcharsPerEntry) { + new = dir->nChars - SFcharsPerEntry; + } + + if (new < 0) { + new = 0; + } + + if (dir->nChars) { + float f; + + f = ((double) new) / dir->nChars; + + XawScrollbarSetThumb( + w, + f, + (float) (((double) ((dir->nChars < SFcharsPerEntry) ? + dir->nChars : SFcharsPerEntry)) / dir->nChars) + ); + + SFhSliderMovedCallback(w, n, &f); + } +} + +/* ARGSUSED */ +void +SFpathSliderMovedCallback(w, client_data, new) + Widget w; + XtPointer client_data; + float *new; +{ + SFDir *dir; + int n; + XawTextPosition pos; + int SFdirPtrSave; + + SFdirPtrSave = SFdirPtr; + SFdirPtr = (*new) * SFdirEnd; + if (SFdirPtr == SFdirPtrSave) { + return; + } + + SFdrawLists(SF_DO_SCROLL); + + n = 2; + while (SFdirPtr + n >= SFdirEnd) { + n--; + } + + dir = &(SFdirs[SFdirPtr + n]); + + pos = dir->path - SFcurrentPath; + + if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) { + pos -= strlen(SFstartDir); + if (pos < 0) { + pos = 0; + } + } + + XawTextSetInsertionPoint(selFileField, pos); +} + +/* ARGSUSED */ + +void +SFpathAreaSelectedCallback(w, client_data, pnew) + Widget w; + XtPointer client_data; + int pnew; +{ + int new; + float f; + + new = SFdirPtr + (((double) pnew) / SFpathScrollWidth) * SFdirEnd; + + if (new > SFdirEnd - 3) { + new = SFdirEnd - 3; + } + + if (new < 0) { + new = 0; + } + + f = ((double) new) / SFdirEnd; + + XawScrollbarSetThumb( + w, + f, + (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / + SFdirEnd) + ); + + SFpathSliderMovedCallback(w, (XtPointer) NULL, &f); +} + +Boolean +SFworkProc() +{ + register SFDir *dir; + register SFEntry *entry; + + for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) { + if (!(dir->nEntries)) { + continue; + } + for ( + entry = &(dir->entries[dir->nEntries - 1]); + entry >= dir->entries; + entry-- + ) { + if (!(entry->statDone)) { + (void) SFstatAndCheck(dir, entry); + return False; + } + } + } + + SFworkProcAdded = 0; + + return True; +} diff --git a/path.c b/path.c new file mode 100644 index 0000000..6379e79 --- /dev/null +++ b/path.c @@ -0,0 +1,900 @@ +/* + * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Software Research Associates not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Software Research Associates + * makes no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Author: Erik M. van der Poel + * Software Research Associates, Inc., Tokyo, Japan + * erik@sra.co.jp + */ + +#include + +#ifdef SEL_FILE_IGNORE_CASE +#include +#endif /* def SEL_FILE_IGNORE_CASE */ + +#include +#include +#include "selfile.h" +#include "xstat.h" +#include + +#if defined(SVR4) || defined(SYSV) || defined(USG) +extern uid_t getuid(); +extern void qsort(); +#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */ + +typedef struct { + char *name; + char *dir; +} SFLogin; + +SFDir *SFdirs = NULL; + +int SFdirEnd; + +int SFdirPtr; + +int SFbuttonPressed = 0; + +static int SFdoNotTouchDirPtr = 0; + +static int SFdoNotTouchVorigin = 0; + +static SFDir SFrootDir, SFhomeDir; + +static SFLogin *SFlogins; + +static int SFtwiddle = 0; + +int +SFchdir(path) + char *path; +{ + int result; + + result = 0; + + if (strcmp(path, SFcurrentDir)) { + result = chdir(path); + if (!result) { + (void) strcpy(SFcurrentDir, path); + } + } + + return result; +} + +static +SFfree(i) + int i; +{ + register SFDir *dir; + register int j; + + dir = &(SFdirs[i]); + + for (j = dir->nEntries - 1; j >= 0; j--) { + if (dir->entries[j].shown != dir->entries[j].real) { + XtFree(dir->entries[j].shown); + } + XtFree(dir->entries[j].real); + } + + XtFree((char *) dir->entries); + + XtFree(dir->dir); + + dir->dir = NULL; +} + +static +SFstrdup(s1, s2) + char **s1; + char *s2; +{ + *s1 = strcpy(XtMalloc((unsigned) (strlen(s2) + 1)), s2); +} + +static +SFunreadableDir(dir) + SFDir *dir; +{ + char *cannotOpen = " "; + + dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry)); + dir->entries[0].statDone = 1; + SFstrdup(&dir->entries[0].real, cannotOpen); + dir->entries[0].shown = dir->entries[0].real; + dir->nEntries = 1; + dir->nChars = strlen(cannotOpen); +} + +#ifdef SEL_FILE_IGNORE_CASE +static +SFstrncmp(p, q, n) + register char *p, *q; + register int n; +{ + register char c1, c2; + char *psave, *qsave; + int nsave; + + psave = p; + qsave = q; + nsave = n; + + c1 = *p++; + if (islower(c1)) { + c1 = toupper(c1); + } + c2 = *q++; + if (islower(c2)) { + c2 = toupper(c2); + } + + while ((--n >= 0) && (c1 == c2)) { + if (!c1) { + return strncmp(psave, qsave, nsave); + } + c1 = *p++; + if (islower(c1)) { + c1 = toupper(c1); + } + c2 = *q++; + if (islower(c2)) { + c2 = toupper(c2); + } + } + + if (n < 0) { + return strncmp(psave, qsave, nsave); + } + + return c1 - c2; +} +#endif /* def SEL_FILE_IGNORE_CASE */ + +static +SFreplaceText(dir, str) + SFDir *dir; + char *str; +{ + int len; + + *(dir->path) = 0; + len = strlen(str); + if (str[len - 1] == '/') { + (void) strcat(SFcurrentPath, str); + } else { + (void) strncat(SFcurrentPath, str, len - 1); + } + if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) { + SFsetText(SFcurrentPath); + } else { + SFsetText(&(SFcurrentPath[strlen(SFstartDir)])); + } + + SFtextChanged(); +} + +static void +SFexpand(str) + char *str; +{ + int len; + int cmp; + char *name, *growing; + SFDir *dir; + SFEntry *entry, *max; + + len = strlen(str); + + dir = &(SFdirs[SFdirEnd - 1]); + + if (dir->beginSelection == -1) { + SFstrdup(&str, str); + SFreplaceText(dir, str); + XtFree(str); + return; + } else if (dir->beginSelection == dir->endSelection) { + SFreplaceText(dir, dir->entries[dir->beginSelection].shown); + return; + } + + max = &(dir->entries[dir->endSelection + 1]); + + name = dir->entries[dir->beginSelection].shown; + SFstrdup(&growing, name); + + cmp = 0; + while (!cmp) { + entry = &(dir->entries[dir->beginSelection]); + while (entry < max) { + if (cmp = strncmp(growing, entry->shown, len)) { + break; + } + entry++; + } + len++; + } + + /* + * SFreplaceText() expects filename + */ + growing[len - 2] = ' '; + + growing[len - 1] = 0; + SFreplaceText(dir, growing); + XtFree(growing); +} + +static int +SFfindFile(dir, str) + SFDir *dir; + register char *str; +{ + register int i, last, max; + register char *name, save; + SFEntry *entries; + int len; + int begin, end; + int result; + + len = strlen(str); + + if (str[len - 1] == ' ') { + SFexpand(str); + return 1; + } else if (str[len - 1] == '/') { + len--; + } + + max = dir->nEntries; + + entries = dir->entries; + + i = 0; + while (i < max) { + name = entries[i].shown; + last = strlen(name) - 1; + save = name[last]; + name[last] = 0; + +#ifdef SEL_FILE_IGNORE_CASE + result = SFstrncmp(str, name, len); +#else /* def SEL_FILE_IGNORE_CASE */ + result = strncmp(str, name, len); +#endif /* def SEL_FILE_IGNORE_CASE */ + + name[last] = save; + if (result <= 0) { + break; + } + i++; + } + begin = i; + while (i < max) { + name = entries[i].shown; + last = strlen(name) - 1; + save = name[last]; + name[last] = 0; + +#ifdef SEL_FILE_IGNORE_CASE + result = SFstrncmp(str, name, len); +#else /* def SEL_FILE_IGNORE_CASE */ + result = strncmp(str, name, len); +#endif /* def SEL_FILE_IGNORE_CASE */ + + name[last] = save; + if (result) { + break; + } + i++; + } + end = i; + + if (begin != end) { + if ( + (dir->beginSelection != begin) || + (dir->endSelection != end - 1) + ) { + dir->changed = 1; + dir->beginSelection = begin; + if (str[strlen(str) - 1] == '/') { + dir->endSelection = begin; + } else { + dir->endSelection = end - 1; + } + } + } else { + if (dir->beginSelection != -1) { + dir->changed = 1; + dir->beginSelection = -1; + dir->endSelection = -1; + } + } + + if ( + SFdoNotTouchVorigin || + ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize)) + ) { + SFdoNotTouchVorigin = 0; + return 0; + } + + i = begin - 1; + if (i > max - SFlistSize) { + i = max - SFlistSize; + } + if (i < 0) { + i = 0; + } + + if (dir->vOrigin != i) { + dir->vOrigin = i; + dir->changed = 1; + } + + return 0; +} + +static +SFunselect() +{ + SFDir *dir; + + dir = &(SFdirs[SFdirEnd - 1]); + if (dir->beginSelection != -1) { + dir->changed = 1; + } + dir->beginSelection = -1; + dir->endSelection = -1; +} + +static int +SFcompareLogins(p, q) + SFLogin *p, *q; +{ + return strcmp(p->name, q->name); +} + +static +SFgetHomeDirs() +{ + struct passwd *pw; + int alloc; + int i; + SFEntry *entries = NULL; + int len; + int maxChars; + + { + alloc = 1; + i = 1; + entries = (SFEntry *) XtMalloc(sizeof(SFEntry)); + SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin)); + entries[0].real = XtMalloc(3); + (void) strcpy(entries[0].real, "~"); + entries[0].shown = entries[0].real; + entries[0].statDone = 1; + SFlogins[0].name = ""; + pw = getpwuid((int) getuid()); + SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/"); + maxChars = 0; + } + + (void) setpwent(); + + while ((pw = getpwent()) && (*(pw->pw_name))) { + if (i >= alloc) { + alloc *= 2; + entries = (SFEntry *) XtRealloc( + (char *) entries, + (unsigned) (alloc * sizeof(SFEntry)) + ); + SFlogins = (SFLogin *) XtRealloc( + (char *) SFlogins, + (unsigned) (alloc * sizeof(SFLogin)) + ); + } + len = strlen(pw->pw_name); + entries[i].real = XtMalloc((unsigned) (len + 3)); + (void) strcat(strcpy(entries[i].real, "~"), + pw->pw_name); + entries[i].shown = entries[i].real; + entries[i].statDone = 1; + if (len > maxChars) { + maxChars = len; + } + SFstrdup(&SFlogins[i].name, pw->pw_name); + SFstrdup(&SFlogins[i].dir, pw->pw_dir); + i++; + } + + SFhomeDir.dir = XtMalloc(1) ; + SFhomeDir.dir[0] = 0 ; + SFhomeDir.path = SFcurrentPath ; + SFhomeDir.entries = entries ; + SFhomeDir.nEntries = i ; + SFhomeDir.vOrigin = 0 ; /* :-) */ + SFhomeDir.nChars = maxChars + 2 ; + SFhomeDir.hOrigin = 0 ; + SFhomeDir.changed = 1 ; + SFhomeDir.beginSelection = -1 ; + SFhomeDir.endSelection = -1 ; + +#if defined(SVR4) || defined(SYSV) || defined(USG) + qsort((char *) entries, (unsigned)i, sizeof(SFEntry), SFcompareEntries); + qsort((char *) SFlogins, (unsigned)i, sizeof(SFLogin), SFcompareLogins); +#else /* defined(SVR4) || defined(SYSV) || defined(USG) */ + qsort((char *) entries, i, sizeof(SFEntry), SFcompareEntries); + qsort((char *) SFlogins, i, sizeof(SFLogin), SFcompareLogins); +#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */ + + for (i--; i >= 0; i--) { + (void) strcat(entries[i].real, "/"); + } +} + +static int +SFfindHomeDir(begin, end) + char *begin, *end; +{ + char save; + char *theRest; + int i; + + save = *end; + *end = 0; + + for (i = SFhomeDir.nEntries - 1; i >= 0; i--) { + if (!strcmp(SFhomeDir.entries[i].real, begin)) { + *end = save; + SFstrdup(&theRest, end); + (void) strcat(strcat(strcpy(SFcurrentPath, + SFlogins[i].dir), "/"), theRest); + XtFree(theRest); + SFsetText(SFcurrentPath); + SFtextChanged(); + return 1; + } + } + + *end = save; + + return 0; +} + +SFupdatePath() +{ + static int alloc; + static int wasTwiddle = 0; + char *begin, *end; + int i, j; + int prevChange; + int SFdirPtrSave, SFdirEndSave; + SFDir *dir; + + if (!SFdirs) { + SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir)); + dir = &(SFdirs[0]); + SFstrdup(&dir->dir, "/"); + (void) SFchdir("/"); + (void) SFgetDir(dir); + for (j = 1; j < alloc; j++) { + SFdirs[j].dir = NULL; + } + dir->path = SFcurrentPath + 1; + dir->vOrigin = 0; + dir->hOrigin = 0; + dir->changed = 1; + dir->beginSelection = -1; + dir->endSelection = -1; + SFhomeDir.dir = NULL; + } + + SFdirEndSave = SFdirEnd; + SFdirEnd = 1; + + SFdirPtrSave = SFdirPtr; + SFdirPtr = 0; + + begin = NULL; + + if (SFcurrentPath[0] == '~') { + if (!SFtwiddle) { + SFtwiddle = 1; + dir = &(SFdirs[0]); + SFrootDir = *dir; + if (!SFhomeDir.dir) { + SFgetHomeDirs(); + } + *dir = SFhomeDir; + dir->changed = 1; + } + end = SFcurrentPath; + SFdoNotTouchDirPtr = 1; + wasTwiddle = 1; + } else { + if (SFtwiddle) { + SFtwiddle = 0; + dir = &(SFdirs[0]); + *dir = SFrootDir; + dir->changed = 1; + } + end = SFcurrentPath + 1; + } + + i = 0; + + prevChange = 0; + + while (*end) { + while (*end++ == '/') { + ; + } + end--; + begin = end; + while ((*end) && (*end++ != '/')) { + ; + } + if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) { + SFdirPtr = i - 1; + if (SFdirPtr < 0) { + SFdirPtr = 0; + } + } + if (*begin) { + if (*(end - 1) == '/') { + char save = *end; + + if (SFtwiddle) { + if (SFfindHomeDir(begin, end)) { + return; + } + } + *end = 0; + i++; + SFdirEnd++; + if (i >= alloc) { + SFdirs = (SFDir *) XtRealloc( + (char *) SFdirs, + (unsigned) ((alloc *= 2) * + sizeof(SFDir)) + ); + for (j = alloc / 2; j < alloc; j++) { + SFdirs[j].dir = NULL; + } + } + dir = &(SFdirs[i]); + if ( + (!(dir->dir)) || + prevChange || + strcmp(dir->dir, begin) + ) { + if (dir->dir) { + SFfree(i); + } + prevChange = 1; + SFstrdup(&dir->dir, begin); + dir->path = end; + dir->vOrigin = 0; + dir->hOrigin = 0; + dir->changed = 1; + dir->beginSelection = -1; + dir->endSelection = -1; + (void) SFfindFile(dir - 1, begin); + if ( + SFchdir(SFcurrentPath) || + SFgetDir(dir) + ) { + SFunreadableDir(dir); + break; + } + } + *end = save; + if (!save) { + SFunselect(); + } + } else { + if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) { + return; + } + } + } else { + SFunselect(); + } + } + + if ((end == SFcurrentPath + 1) && (!SFtwiddle)) { + SFunselect(); + } + + for (i = SFdirEnd; i < alloc; i++) { + if (SFdirs[i].dir) { + SFfree(i); + } + } + + if (SFdoNotTouchDirPtr) { + if (wasTwiddle) { + wasTwiddle = 0; + SFdirPtr = SFdirEnd - 1; + if (SFdirPtr < 0) { + SFdirPtr = 0; + } + } else { + SFdirPtr = SFdirPtrSave; + } + SFdoNotTouchDirPtr = 0; + } + + if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) { + XawScrollbarSetThumb( + selFileHScroll, + (float) (((double) SFdirPtr) / SFdirEnd), + (float) (((double) ((SFdirEnd < NR) ? SFdirEnd : NR)) / + SFdirEnd) + ); + } + + if (SFdirPtr != SFdirPtrSave) { + SFdrawLists(SF_DO_SCROLL); + } else { + for (i = 0; i < NR; i++) { + if (SFdirPtr + i < SFdirEnd) { + if (SFdirs[SFdirPtr + i].changed) { + SFdirs[SFdirPtr + i].changed = 0; + SFdrawList(i, SF_DO_SCROLL); + } + } else { + SFclearList(i, SF_DO_SCROLL); + } + } + } +} + +SFsetText(path) + char *path; +{ + XawTextBlock text; + + text.firstPos = 0; + text.length = strlen(path); + text.ptr = path; + text.format = FMT8BIT; + + XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text); + XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer)); +} + +/* ARGSUSED */ +void +SFbuttonPressList(w, n, event) + Widget w; + int n; + XButtonPressedEvent *event; +{ + SFbuttonPressed = 1; +} + +/* ARGSUSED */ +void +SFbuttonReleaseList(w, n, event) + Widget w; + int n; + XButtonReleasedEvent *event; +{ + SFDir *dir; + + SFbuttonPressed = 0; + + if (SFcurrentInvert[n] != -1) { + if (n < 2) { + SFdoNotTouchDirPtr = 1; + } + SFdoNotTouchVorigin = 1; + dir = &(SFdirs[SFdirPtr + n]); + SFreplaceText( + dir, + dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown + ); + SFmotionList(w, n, event); + } +} + +static int +SFcheckDir(n, dir) + int n; + SFDir *dir; +{ + struct stat statBuf; + int i; + + if ( + (!stat(".", &statBuf)) && + (statBuf.st_mtime != dir->mtime) + ) { + + /* + * If the pointer is currently in the window that we are about + * to update, we must warp it to prevent the user from + * accidentally selecting the wrong file. + */ + if (SFcurrentInvert[n] != -1) { + XWarpPointer( + SFdisplay, + None, + XtWindow(selFileLists[n]), + 0, + 0, + 0, + 0, + 0, + 0 + ); + } + + for (i = dir->nEntries - 1; i >= 0; i--) { + if (dir->entries[i].shown != dir->entries[i].real) { + XtFree(dir->entries[i].shown); + } + XtFree(dir->entries[i].real); + } + XtFree((char *) dir->entries); + if (SFgetDir(dir)) { + SFunreadableDir(dir); + } + if (dir->vOrigin > dir->nEntries - SFlistSize) { + dir->vOrigin = dir->nEntries - SFlistSize; + } + if (dir->vOrigin < 0) { + dir->vOrigin = 0; + } + if (dir->hOrigin > dir->nChars - SFcharsPerEntry) { + dir->hOrigin = dir->nChars - SFcharsPerEntry; + } + if (dir->hOrigin < 0) { + dir->hOrigin = 0; + } + dir->beginSelection = -1; + dir->endSelection = -1; + SFdoNotTouchVorigin = 1; + if ((dir + 1)->dir) { + (void) SFfindFile(dir, (dir + 1)->dir); + } else { + (void) SFfindFile(dir, dir->path); + } + + if (!SFworkProcAdded) { + (void) XtAppAddWorkProc(SFapp, SFworkProc, NULL); + SFworkProcAdded = 1; + } + + return 1; + } + + return 0; +} + +static int +SFcheckFiles(dir) + SFDir *dir; +{ + int from, to; + int result; + char old, new; + int i; + char *str; + int last; + struct stat statBuf; + + result = 0; + + from = dir->vOrigin; + to = dir->vOrigin + SFlistSize; + if (to > dir->nEntries) { + to = dir->nEntries; + } + + for (i = from; i < to; i++) { + str = dir->entries[i].real; + last = strlen(str) - 1; + old = str[last]; + str[last] = 0; + if (stat(str, &statBuf)) { + new = ' '; + } else { + new = SFstatChar(&statBuf); + } + str[last] = new; + if (new != old) { + result = 1; + } + } + + return result; +} + +void +SFdirModTimer(cl, id) + XtPointer cl; + XtIntervalId *id; +{ + static int n = -1; + static int f = 0; + char save; + SFDir *dir; + + if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) { + n++; + if ((n > NR-1) || (SFdirPtr + n >= SFdirEnd)) { + n = 0; + f++; + if ((f > NR-1) || (SFdirPtr + f >= SFdirEnd)) { + f = 0; + } + } + dir = &(SFdirs[SFdirPtr + n]); + save = *(dir->path); + *(dir->path) = 0; + if (SFchdir(SFcurrentPath)) { + *(dir->path) = save; + + /* + * force a re-read + */ + *(dir->dir) = 0; + + SFupdatePath(); + } else { + *(dir->path) = save; + if ( + SFcheckDir(n, dir) || + ((f == n) && SFcheckFiles(dir)) + ) { + SFdrawList(n, SF_DO_SCROLL); + } + } + } + + SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000, + SFdirModTimer, (XtPointer) NULL); +} + +/* Return a single character describing what kind of file STATBUF is. */ + +char +SFstatChar (statBuf) + struct stat *statBuf; +{ + if (S_ISDIR (statBuf->st_mode)) { + return '/'; + } else if (S_ISREG (statBuf->st_mode)) { + return S_ISXXX (statBuf->st_mode) ? '*' : ' '; +#ifdef S_ISSOCK + } else if (S_ISSOCK (statBuf->st_mode)) { + return '='; +#endif /* S_ISSOCK */ + } else { + return ' '; + } +} diff --git a/selfile.c b/selfile.c new file mode 100644 index 0000000..422cf7b --- /dev/null +++ b/selfile.c @@ -0,0 +1,753 @@ +/* + * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Software Research Associates not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Software Research Associates + * makes no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Author: Erik M. van der Poel + * Software Research Associates, Inc., Tokyo, Japan + * erik@sra.co.jp + */ + +/* + * Author's address: + * + * erik@sra.co.jp + * OR + * erik%sra.co.jp@uunet.uu.net + * OR + * erik%sra.co.jp@mcvax.uucp + * OR + * try junet instead of co.jp + * OR + * Erik M. van der Poel + * Software Research Associates, Inc. + * 1-1-1 Hirakawa-cho, Chiyoda-ku + * Tokyo 102 Japan. TEL +81-3-234-2692 + */ + +#include +#include +/* BSD 4.3 errno.h does not declare errno */ +extern int errno; +extern int sys_nerr; +//extern char *sys_errlist[]; // [HGM] this produced a compile error in Ubuntu 8.04 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "selfile.h" + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif /* ndef MAXPATHLEN */ + +#if !defined(SVR4) && !defined(SYSV) && !defined(USG) +extern char *getwd(); +#endif /* !defined(SVR4) && !defined(SYSV) && !defined(USG) */ + +int SFstatus = SEL_FILE_NULL; + +char + SFstartDir[MAXPATHLEN], + SFcurrentPath[MAXPATHLEN], + SFcurrentDir[MAXPATHLEN]; + +Widget + selFile, + selFileCancel, + selFileField, + selFileForm, + selFileHScroll, + selFileHScrolls[3], + selFileLists[3], + selFileOK, + selFilePrompt, + selFileVScrolls[3]; + +Display *SFdisplay; + +Pixel SFfore, SFback; + +Atom SFwmDeleteWindow; + +XSegment SFsegs[2], SFcompletionSegs[2]; + +XawTextPosition SFtextPos; + +int SFupperX, SFlowerY, SFupperY; + +int SFtextX, SFtextYoffset; + +int SFentryWidth, SFentryHeight; + +int SFlineToTextH = 3; + +int SFlineToTextV = 3; + +int SFbesideText = 3; + +int SFaboveAndBelowText = 2; + +int SFcharsPerEntry = 15; + +int SFlistSize = 10; + +int SFworkProcAdded = 0; + +XtAppContext SFapp; + +int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth; + +char SFtextBuffer[MAXPATHLEN]; + +XtIntervalId SFdirModTimerId; + +int (*SFfunc)(); + +static char *oneLineTextEditTranslations = "\ + Return: redraw-display()\n\ + CtrlM: redraw-display()\n\ +"; + +/* ARGSUSED */ +static void +SFexposeList(w, n, event, cont) + Widget w; + XtPointer n; + XEvent *event; + Boolean *cont; +{ + if ((event->type == NoExpose) || event->xexpose.count) { + return; + } + + SFdrawList(n, SF_DO_NOT_SCROLL); +} + +/* ARGSUSED */ +static void +SFmodVerifyCallback(w, client_data, event, cont) + Widget w; + XtPointer client_data; + XEvent *event; + Boolean *cont; +{ + char buf[2]; + + if ( + (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) && + ((*buf) == '\r') + ) { + SFstatus = SEL_FILE_OK; + } else { + SFstatus = SEL_FILE_TEXT; + } +} + +/* ARGSUSED */ +static void +SFokCallback(w, cl, cd) + Widget w; + XtPointer cl, cd; +{ + SFstatus = SEL_FILE_OK; +} + +static XtCallbackRec SFokSelect[] = { + { SFokCallback, (XtPointer) NULL }, + { NULL, (XtPointer) NULL }, +}; + +/* ARGSUSED */ +static void +SFcancelCallback(w, cl, cd) + Widget w; + XtPointer cl, cd; +{ + SFstatus = SEL_FILE_CANCEL; +} + +static XtCallbackRec SFcancelSelect[] = { + { SFcancelCallback, (XtPointer) NULL }, + { NULL, (XtPointer) NULL }, +}; + +/* ARGSUSED */ +static void +SFdismissAction(w, event, params, num_params) + Widget w; + XEvent *event; + String *params; + Cardinal *num_params; +{ + if (event->type == ClientMessage && + event->xclient.data.l[0] != SFwmDeleteWindow) return; + + SFstatus = SEL_FILE_CANCEL; +} + +static char *wmDeleteWindowTranslation = "\ + WM_PROTOCOLS: SelFileDismiss()\n\ +"; + +static XtActionsRec actions[] = { + {"SelFileDismiss", SFdismissAction}, +}; + +static void +SFcreateWidgets(toplevel, prompt, ok, cancel) + Widget toplevel; + char *prompt; + char *ok; + char *cancel; +{ + Cardinal i, n; + int listWidth, listHeight; + int listSpacing = 10; + int scrollThickness = 15; + int hScrollX, hScrollY; + int vScrollX, vScrollY; + Cursor + xtermCursor, + sbRightArrowCursor, + dotCursor; + Arg arglist[20]; + + i = 0; + XtSetArg(arglist[i], XtNtransientFor, toplevel); i++; + + selFile = XtAppCreateShell("Browse", "SelFile", + transientShellWidgetClass, SFdisplay, arglist, i); + + /* Add WM_DELETE_WINDOW protocol */ + XtAppAddActions(XtWidgetToApplicationContext(selFile), + actions, XtNumber(actions)); + XtOverrideTranslations(selFile, + XtParseTranslationTable(wmDeleteWindowTranslation)); + + i = 0; + XtSetArg(arglist[i], XtNdefaultDistance, 30); i++; + selFileForm = XtCreateManagedWidget("selFileForm", + formWidgetClass, selFile, arglist, i); + + i = 0; + XtSetArg(arglist[i], XtNlabel, prompt); i++; + XtSetArg(arglist[i], XtNresizable, True); i++; + XtSetArg(arglist[i], XtNtop, XtChainTop); i++; + XtSetArg(arglist[i], XtNbottom, XtChainTop); i++; + XtSetArg(arglist[i], XtNleft, XtChainLeft); i++; + XtSetArg(arglist[i], XtNright, XtChainLeft); i++; + XtSetArg(arglist[i], XtNborderWidth, 0); i++; + selFilePrompt = XtCreateManagedWidget("selFilePrompt", + labelWidgetClass, selFileForm, arglist, i); + + i = 0; + XtSetArg(arglist[i], XtNforeground, &SFfore); i++; + XtSetArg(arglist[i], XtNbackground, &SFback); i++; + XtGetValues(selFilePrompt, arglist, i); + + SFinitFont(); + + SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth + + SFbesideText; + SFentryHeight = SFaboveAndBelowText + SFcharHeight + + SFaboveAndBelowText; + + listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 + + scrollThickness; + listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + + SFlineToTextV + SFlistSize * SFentryHeight + + SFlineToTextV + 1 + scrollThickness; + + SFpathScrollWidth = NR * listWidth + (NR-1) * listSpacing + 4; + + hScrollX = -1; + hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + + SFlineToTextV + SFlistSize * SFentryHeight + + SFlineToTextV; + SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH; + + vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH; + vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV; + SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight + + SFlineToTextV; + + SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1; + SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + + SFlineToTextV; + SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + + SFlineToTextV + SFlistSize * SFentryHeight - 1; + + SFtextX = SFlineToTextH + SFbesideText; + SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent; + + SFsegs[0].x1 = 0; + SFsegs[0].y1 = vScrollY; + SFsegs[0].x2 = vScrollX - 1; + SFsegs[0].y2 = vScrollY; + SFsegs[1].x1 = vScrollX; + SFsegs[1].y1 = 0; + SFsegs[1].x2 = vScrollX; + SFsegs[1].y2 = vScrollY - 1; + + SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH; + SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 = + SFlineToTextH + SFentryWidth - 1; + + i = 0; + XtSetArg(arglist[i], XtNwidth, NR * listWidth + (NR - 1) * listSpacing + 4); + i++; + XtSetArg(arglist[i], XtNborderColor, SFfore); i++; + + XtSetArg(arglist[i], XtNfromVert, selFilePrompt); i++; + XtSetArg(arglist[i], XtNvertDistance, 10); i++; + XtSetArg(arglist[i], XtNresizable, True); i++; + XtSetArg(arglist[i], XtNtop, XtChainTop); i++; + XtSetArg(arglist[i], XtNbottom, XtChainTop); i++; + XtSetArg(arglist[i], XtNleft, XtChainLeft); i++; + XtSetArg(arglist[i], XtNright, XtChainLeft); i++; + XtSetArg(arglist[i], XtNstring, SFtextBuffer); i++; + XtSetArg(arglist[i], XtNlength, MAXPATHLEN); i++; + XtSetArg(arglist[i], XtNeditType, XawtextEdit); i++; + XtSetArg(arglist[i], XtNwrap, XawtextWrapWord); i++; + XtSetArg(arglist[i], XtNresize, XawtextResizeHeight); i++; + XtSetArg(arglist[i], XtNuseStringInPlace, True); i++; + selFileField = XtCreateManagedWidget("selFileField", + asciiTextWidgetClass, selFileForm, arglist, i); + + XtOverrideTranslations(selFileField, + XtParseTranslationTable(oneLineTextEditTranslations)); + XtSetKeyboardFocus(selFileForm, selFileField); + + i = 0; + XtSetArg(arglist[i], XtNorientation, XtorientHorizontal); i++; + XtSetArg(arglist[i], XtNwidth, SFpathScrollWidth); i++; + XtSetArg(arglist[i], XtNheight, scrollThickness); i++; + XtSetArg(arglist[i], XtNborderColor, SFfore); i++; + XtSetArg(arglist[i], XtNfromVert, selFileField); i++; + XtSetArg(arglist[i], XtNvertDistance, 30); i++; + XtSetArg(arglist[i], XtNtop, XtChainTop); i++; + XtSetArg(arglist[i], XtNbottom, XtChainTop); i++; + XtSetArg(arglist[i], XtNleft, XtChainLeft); i++; + XtSetArg(arglist[i], XtNright, XtChainLeft); i++; + selFileHScroll = XtCreateManagedWidget("selFileHScroll", + scrollbarWidgetClass, selFileForm, arglist, i); + + XtAddCallback(selFileHScroll, XtNjumpProc, + SFpathSliderMovedCallback, (XtPointer) NULL); + XtAddCallback(selFileHScroll, XtNscrollProc, + SFpathAreaSelectedCallback, (XtPointer) NULL); + + i = 0; + XtSetArg(arglist[i], XtNwidth, listWidth); i++; + XtSetArg(arglist[i], XtNheight, listHeight); i++; + XtSetArg(arglist[i], XtNborderColor, SFfore); i++; + XtSetArg(arglist[i], XtNfromVert, selFileHScroll); i++; + XtSetArg(arglist[i], XtNvertDistance, 10); i++; + XtSetArg(arglist[i], XtNtop, XtChainTop); i++; + XtSetArg(arglist[i], XtNbottom, XtChainTop); i++; + XtSetArg(arglist[i], XtNleft, XtChainLeft); i++; + XtSetArg(arglist[i], XtNright, XtChainLeft); i++; + selFileLists[0] = XtCreateManagedWidget("selFileList1", + compositeWidgetClass, selFileForm, arglist, i); +#if (NR == 3) + i = 0; + XtSetArg(arglist[i], XtNwidth, listWidth); i++; + XtSetArg(arglist[i], XtNheight, listHeight); i++; + XtSetArg(arglist[i], XtNborderColor, SFfore); i++; + XtSetArg(arglist[i], XtNfromHoriz, selFileLists[0]); i++; + XtSetArg(arglist[i], XtNfromVert, selFileHScroll); i++; + XtSetArg(arglist[i], XtNhorizDistance, listSpacing); i++; + XtSetArg(arglist[i], XtNvertDistance, 10); i++; + XtSetArg(arglist[i], XtNtop, XtChainTop); i++; + XtSetArg(arglist[i], XtNbottom, XtChainTop); i++; + XtSetArg(arglist[i], XtNleft, XtChainLeft); i++; + XtSetArg(arglist[i], XtNright, XtChainLeft); i++; + selFileLists[1] = XtCreateManagedWidget("selFileList2", + compositeWidgetClass, selFileForm, arglist, i); + + i = 0; + XtSetArg(arglist[i], XtNwidth, listWidth); i++; + XtSetArg(arglist[i], XtNheight, listHeight); i++; + XtSetArg(arglist[i], XtNborderColor, SFfore); i++; + XtSetArg(arglist[i], XtNfromHoriz, selFileLists[1]); i++; + XtSetArg(arglist[i], XtNfromVert, selFileHScroll); i++; + XtSetArg(arglist[i], XtNhorizDistance, listSpacing); i++; + XtSetArg(arglist[i], XtNvertDistance, 10); i++; + XtSetArg(arglist[i], XtNtop, XtChainTop); i++; + XtSetArg(arglist[i], XtNbottom, XtChainTop); i++; + XtSetArg(arglist[i], XtNleft, XtChainLeft); i++; + XtSetArg(arglist[i], XtNright, XtChainLeft); i++; + selFileLists[2] = XtCreateManagedWidget("selFileList3", + compositeWidgetClass, selFileForm, arglist, i); +#endif + for (n = 0; n < NR; n++) { + + i = 0; + XtSetArg(arglist[i], XtNx, vScrollX); i++; + XtSetArg(arglist[i], XtNy, vScrollY); i++; + XtSetArg(arglist[i], XtNwidth, scrollThickness); i++; + XtSetArg(arglist[i], XtNheight, SFvScrollHeight); i++; + XtSetArg(arglist[i], XtNborderColor, SFfore); i++; + selFileVScrolls[n] = XtCreateManagedWidget("selFileVScroll", + scrollbarWidgetClass, selFileLists[n], arglist, i); + + XtAddCallback(selFileVScrolls[n], XtNjumpProc, + SFvFloatSliderMovedCallback, (XtPointer) n); + XtAddCallback(selFileVScrolls[n], XtNscrollProc, + SFvAreaSelectedCallback, (XtPointer) n); + + i = 0; + + XtSetArg(arglist[i], XtNorientation, XtorientHorizontal); + i++; + XtSetArg(arglist[i], XtNx, hScrollX); i++; + XtSetArg(arglist[i], XtNy, hScrollY); i++; + XtSetArg(arglist[i], XtNwidth, SFhScrollWidth); i++; + XtSetArg(arglist[i], XtNheight, scrollThickness); i++; + XtSetArg(arglist[i], XtNborderColor, SFfore); i++; + selFileHScrolls[n] = XtCreateManagedWidget("selFileHScroll", + scrollbarWidgetClass, selFileLists[n], arglist, i); + + XtAddCallback(selFileHScrolls[n], XtNjumpProc, + SFhSliderMovedCallback, (XtPointer) n); + XtAddCallback(selFileHScrolls[n], XtNscrollProc, + SFhAreaSelectedCallback, (XtPointer) n); + } + + i = 0; + XtSetArg(arglist[i], XtNlabel, ok); i++; + XtSetArg(arglist[i], XtNresizable, True); i++; + XtSetArg(arglist[i], XtNcallback, SFokSelect); i++; + XtSetArg(arglist[i], XtNborderColor, SFfore); i++; + XtSetArg(arglist[i], XtNfromVert, selFileLists[0]); i++; + XtSetArg(arglist[i], XtNvertDistance, 30); i++; + XtSetArg(arglist[i], XtNtop, XtChainTop); i++; + XtSetArg(arglist[i], XtNbottom, XtChainTop); i++; + XtSetArg(arglist[i], XtNleft, XtChainLeft); i++; + XtSetArg(arglist[i], XtNright, XtChainLeft); i++; + selFileOK = XtCreateManagedWidget("selFileOK", commandWidgetClass, + selFileForm, arglist, i); + + i = 0; + XtSetArg(arglist[i], XtNlabel, cancel); i++; + XtSetArg(arglist[i], XtNresizable, True); i++; + XtSetArg(arglist[i], XtNcallback, SFcancelSelect); i++; + XtSetArg(arglist[i], XtNborderColor, SFfore); i++; + XtSetArg(arglist[i], XtNfromHoriz, selFileOK); i++; + XtSetArg(arglist[i], XtNfromVert, selFileLists[0]); i++; + XtSetArg(arglist[i], XtNhorizDistance, 30); i++; + XtSetArg(arglist[i], XtNvertDistance, 30); i++; + XtSetArg(arglist[i], XtNtop, XtChainTop); i++; + XtSetArg(arglist[i], XtNbottom, XtChainTop); i++; + XtSetArg(arglist[i], XtNleft, XtChainLeft); i++; + XtSetArg(arglist[i], XtNright, XtChainLeft); i++; + selFileCancel = XtCreateManagedWidget("selFileCancel", + commandWidgetClass, selFileForm, arglist, i); + + XtSetMappedWhenManaged(selFile, False); + XtRealizeWidget(selFile); + + /* Add WM_DELETE_WINDOW protocol */ + SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False); + XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1); + + SFcreateGC(); + + xtermCursor = XCreateFontCursor(SFdisplay, XC_xterm); + + sbRightArrowCursor = XCreateFontCursor(SFdisplay, XC_sb_right_arrow); + dotCursor = XCreateFontCursor(SFdisplay, XC_dot); + + XDefineCursor(SFdisplay, XtWindow(selFileForm), xtermCursor); + XDefineCursor(SFdisplay, XtWindow(selFileField), xtermCursor); + + for (n = 0; n < NR; n++) { + XDefineCursor(SFdisplay, XtWindow(selFileLists[n]), + sbRightArrowCursor); + } + XDefineCursor(SFdisplay, XtWindow(selFileOK), dotCursor); + XDefineCursor(SFdisplay, XtWindow(selFileCancel), dotCursor); + + for (n = 0; n < NR; n++) { + XtAddEventHandler(selFileLists[n], ExposureMask, True, + SFexposeList, (XtPointer) n); + XtAddEventHandler(selFileLists[n], EnterWindowMask, False, + SFenterList, (XtPointer) n); + XtAddEventHandler(selFileLists[n], LeaveWindowMask, False, + SFleaveList, (XtPointer) n); + XtAddEventHandler(selFileLists[n], PointerMotionMask, False, + SFmotionList, (XtPointer) n); + XtAddEventHandler(selFileLists[n], ButtonPressMask, False, + SFbuttonPressList, (XtPointer) n); + XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False, + SFbuttonReleaseList, (XtPointer) n); + } + + XtAddEventHandler(selFileField, KeyPressMask, False, + SFmodVerifyCallback, (XtPointer) NULL); + + SFapp = XtWidgetToApplicationContext(selFile); + +} + +/* position widget under the cursor */ +void +SFpositionWidget(w) + Widget w; +{ + Arg args[3]; + Cardinal num_args; + Dimension width, height, b_width; + int x, y, max_x, max_y; + Window root, child; + int dummyx, dummyy; + unsigned int dummymask; + + XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &x, &y, + &dummyx, &dummyy, &dummymask); + num_args = 0; + XtSetArg(args[num_args], XtNwidth, &width); num_args++; + XtSetArg(args[num_args], XtNheight, &height); num_args++; + XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++; + XtGetValues(w, args, num_args); + + width += 2 * b_width; + height += 2 * b_width; + + x -= ( (Position) width/2 ); + if (x < 0) x = 0; + if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x; + + y -= ( (Position) height/2 ); + if (y < 0) y = 0; + if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y; + + num_args = 0; + XtSetArg(args[num_args], XtNx, x); num_args++; + XtSetArg(args[num_args], XtNy, y); num_args++; + XtSetValues(w, args, num_args); +} + +FILE * +SFopenFile(name, mode, prompt, failed) + char *name; + char *mode; + char *prompt; + char *failed; +{ + Arg args[1]; + FILE *fp; + + SFchdir(SFstartDir); + if ((fp = fopen(name, mode)) == NULL) { + char *buf; + if (errno <= sys_nerr) { + buf = XtMalloc(strlen(failed) + strlen(sys_errlist[errno]) + + strlen(prompt) + 2); + strcpy(buf, failed); + strcat(buf, sys_errlist[errno]); + strcat(buf, "\n"); + strcat(buf, prompt); + } else { + buf = XtMalloc(strlen(failed) + strlen(prompt) + 2); + strcpy(buf, failed); + strcat(buf, "\n"); + strcat(buf, prompt); + } + XtSetArg(args[0], XtNlabel, buf); + XtSetValues(selFilePrompt, args, ONE); + XtFree(buf); + return NULL; + } + return fp; +} + +SFtextChanged() +{ + + if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~')) { + (void) strcpy(SFcurrentPath, SFtextBuffer); + + SFtextPos = XawTextGetInsertionPoint(selFileField); + } else { + (void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer); + + SFtextPos = XawTextGetInsertionPoint(selFileField) + + strlen(SFstartDir); + } + + if (!SFworkProcAdded) { + (void) XtAppAddWorkProc(SFapp, SFworkProc, NULL); + SFworkProcAdded = 1; + } + + SFupdatePath(); +} + +static char * +SFgetText() +{ + return strcpy(XtMalloc((unsigned) (strlen(SFtextBuffer) + 1)), + SFtextBuffer); +} + +static +SFprepareToReturn() +{ + SFstatus = SEL_FILE_NULL; + XtRemoveGrab(selFile); + XtUnmapWidget(selFile); + XtRemoveTimeOut(SFdirModTimerId); + if (SFchdir(SFstartDir)) { + XtAppError( + SFapp, + "XsraSelFile: can't return to current directory" + ); + } +} + +FILE * +XsraSelFile(toplevel, prompt, ok, cancel, failed, + init_path, mode, show_entry, name_return) + Widget toplevel; + char *prompt; + char *ok; + char *cancel; + char *failed; + char *init_path; + char *mode; + int (*show_entry)(); + char **name_return; +{ + static int firstTime = 1; + Cardinal i; + Arg arglist[20]; + XEvent event; + FILE *fp; + + if (!prompt) { + prompt = "Pathname:"; + } + + if (!ok) { + ok = "OK"; + } + + if (!cancel) { + cancel = "Cancel"; + } + + if (firstTime) { + firstTime = 0; + SFdisplay = XtDisplay(toplevel); + SFcreateWidgets(toplevel, prompt, ok, cancel); + } else { + i = 0; + + XtSetArg(arglist[i], XtNlabel, prompt); i++; + XtSetValues(selFilePrompt, arglist, i); + + i = 0; + XtSetArg(arglist[i], XtNlabel, ok); i++; + XtSetValues(selFileOK, arglist, i); + + i = 0; + XtSetArg(arglist[i], XtNlabel, cancel); i++; + XtSetValues(selFileCancel, arglist, i); + } + + SFpositionWidget(selFile); + XtMapWidget(selFile); + +#if defined(SVR4) || defined(SYSV) || defined(USG) + if (!getcwd(SFstartDir, MAXPATHLEN)) { +#else /* defined(SVR4) || defined(SYSV) || defined(USG) */ + if (!getwd(SFstartDir)) { +#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */ + + XtAppError(SFapp, "XsraSelFile: can't get current directory"); + } + (void) strcat(SFstartDir, "/"); + (void) strcpy(SFcurrentDir, SFstartDir); + + if (init_path) { + if (init_path[0] == '/') { + (void) strcpy(SFcurrentPath, init_path); + if (strncmp( + SFcurrentPath, + SFstartDir, + strlen(SFstartDir) + )) { + SFsetText(SFcurrentPath); + } else { + SFsetText(&(SFcurrentPath[strlen(SFstartDir)])); + } + } else { + (void) strcat(strcpy(SFcurrentPath, SFstartDir), + init_path); + SFsetText(&(SFcurrentPath[strlen(SFstartDir)])); + } + } else { + (void) strcpy(SFcurrentPath, SFstartDir); + } + + SFfunc = show_entry; + + SFtextChanged(); + + XtAddGrab(selFile, True, True); + + SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000, + SFdirModTimer, (XtPointer) NULL); + + while (1) { + XtAppNextEvent(SFapp, &event); + XtDispatchEvent(&event); + switch (SFstatus) { + case SEL_FILE_TEXT: + SFstatus = SEL_FILE_NULL; + SFtextChanged(); + break; + case SEL_FILE_OK: + *name_return = SFgetText(); + if (fp = SFopenFile(*name_return, mode, + prompt, failed)) { + SFprepareToReturn(); + return fp; + } + SFstatus = SEL_FILE_NULL; + break; + case SEL_FILE_CANCEL: + SFprepareToReturn(); + return NULL; + case SEL_FILE_NULL: + break; + } + } +} diff --git a/selfile.h b/selfile.h new file mode 100644 index 0000000..558175e --- /dev/null +++ b/selfile.h @@ -0,0 +1,149 @@ +/* + * File-Selector dialog of GhostView 1.5, incorporated in XBoard by H.G.Muller + * + * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Software Research Associates not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Software Research Associates + * makes no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Author: Erik M. van der Poel + * Software Research Associates, Inc., Tokyo, Japan + * erik@sra.co.jp + */ + +#include +#include +#include +#include +#include + +#define SEL_FILE_CANCEL -1 +#define SEL_FILE_OK 0 +#define SEL_FILE_NULL 1 +#define SEL_FILE_TEXT 2 + +#define SF_DO_SCROLL 1 +#define SF_DO_NOT_SCROLL 0 + +#define NR 3 /* [HGM] (so far failed) attempt to suppress some of the director listings */ + +typedef struct { + int statDone; + char *real; + char *shown; +} SFEntry; + +typedef struct { + char *dir; + char *path; + SFEntry *entries; + int nEntries; + int vOrigin; + int nChars; + int hOrigin; + int changed; + int beginSelection; + int endSelection; + time_t mtime; +} SFDir; + +extern int SFstatus; + +extern char SFcurrentPath[], SFstartDir[], SFcurrentDir[]; + +extern Widget + selFile, + selFileCancel, + selFileField, + selFileForm, + selFileHScroll, + selFileHScrolls[], + selFileLists[], + selFileOK, + selFilePrompt, + selFileVScrolls[]; + +extern Display *SFdisplay; + +extern int SFcharWidth, SFcharHeight, SFcharAscent; + +extern SFDir *SFdirs; + +extern int SFdirEnd, SFdirPtr; + +extern Pixel SFfore, SFback; + +extern Atom SFwmDeleteWindow; + +extern XSegment SFsegs[], SFcompletionSegs[]; + +extern XawTextPosition SFtextPos; + +extern void + SFenterList(), + SFleaveList(), + SFmotionList(), + SFbuttonPressList(), + SFbuttonReleaseList(); + +extern void + SFvSliderMovedCallback(), + SFvFloatSliderMovedCallback(), + SFhSliderMovedCallback(), + SFpathSliderMovedCallback(), + SFvAreaSelectedCallback(), + SFhAreaSelectedCallback(), + SFpathAreaSelectedCallback(); + +extern int SFupperX, SFlowerY, SFupperY; + +extern int SFtextX, SFtextYoffset; + +extern int SFentryWidth, SFentryHeight; + +extern int SFlineToTextH, SFlineToTextV; + +extern int SFbesideText, SFaboveAndBelowText; + +extern int SFcharsPerEntry; + +extern int SFlistSize; + +extern int SFcurrentInvert[]; + +extern int SFworkProcAdded; + +extern Boolean SFworkProc(); + +extern XtAppContext SFapp; + +extern int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth; + +extern char SFtextBuffer[]; + +extern int SFbuttonPressed; + +extern int SFcompareEntries(); + +extern void SFdirModTimer(); + +extern char SFstatChar(); + +extern XtIntervalId SFdirModTimerId; + +extern int (*SFfunc)(); diff --git a/xboard.c b/xboard.c index 88bc31d..9ddf884 100644 --- a/xboard.c +++ b/xboard.c @@ -4924,45 +4924,14 @@ void FileNamePopUp(label, def, proc, openMode) fileProc = proc; /* I can't see a way not */ fileOpenMode = openMode; /* to use globals here */ - - i = 0; - XtSetArg(args[i], XtNresizable, True); i++; - XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++; - XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++; - fileNameShell = popup = - XtCreatePopupShell("File name prompt", transientShellWidgetClass, - shellWidget, args, i); - - layout = - XtCreateManagedWidget(layoutName, formWidgetClass, popup, - layoutArgs, XtNumber(layoutArgs)); - - i = 0; - XtSetArg(args[i], XtNlabel, label); i++; - XtSetArg(args[i], XtNvalue, def); i++; - XtSetArg(args[i], XtNborderWidth, 0); i++; - dialog = XtCreateManagedWidget("fileName", dialogWidgetClass, - layout, args, i); - - XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog); - XawDialogAddButton(dialog, _("cancel"), FileNameCallback, - (XtPointer) dialog); - - XtRealizeWidget(popup); - CatchDeleteWindow(popup, "FileNamePopDown"); - - XQueryPointer(xDisplay, xBoardWindow, &root, &child, - &x, &y, &win_x, &win_y, &mask); - - XtSetArg(args[0], XtNx, x - 10); - XtSetArg(args[1], XtNy, y - 30); - XtSetValues(popup, args, 2); - - XtPopup(popup, XtGrabExclusive); - filenameUp = True; - - edit = XtNameToWidget(dialog, "*value"); - XtSetKeyboardFocus(popup, edit); + { // [HGM] use file-selector dialog stolen from Ghostview + char *name; + int index; // this is not supported yet + FILE *f; + if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ", + NULL, openMode, NULL, &name)) + (void) (*fileProc)(f, index=0, name); + } } void FileNamePopDown() diff --git a/xstat.h b/xstat.h new file mode 100644 index 0000000..2b4826e --- /dev/null +++ b/xstat.h @@ -0,0 +1,23 @@ +#include +#if !defined(S_ISDIR) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) && defined(S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif + +#ifndef S_IXUSR +#define S_IXUSR 0100 +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 +#endif + +#define S_ISXXX(m) ((m) & (S_IXUSR | S_IXGRP | S_IXOTH)) + -- 1.7.0.4