GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
/****************************************************************************1**2*W selfile.c XGAP Source Erik M. van der Poel3*W modified by Frank Celler4**5**6** This file is based on the file selector distributed with ghostview, it7** contained the following notice:8**9*Y Copyright 1989, Software Research Associates Inc., Tokyo, Japan10**11** Permission to use, copy, modify, and distribute this software and its12** documentation for any purpose and without fee is hereby granted, provided13** that the above copyright notice appear in all copies and that both that14** copyright notice and this permission notice appear in supporting15** documentation, and that the name of Software Research Associates not be16** used in advertising or publicity pertaining to distribution of the17** software without specific, written prior permission. Software Research18** Associates makes no representations about the suitability of this19** software for any purpose. It is provided "as is" without express or20** implied warranty.21**22** SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS23** SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND24** FITNESS, IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY25** SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER26** RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF27** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN28** CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.29**30** Author: Erik M. van der Poel31** Software Research Associates, Inc., Tokyo, Japan32** [email protected]33**34** Author's address:35**36** [email protected]37** OR38** erik%[email protected]39** OR40** erik%[email protected]41** OR42** try junet instead of co.jp43** OR44** Erik M. van der Poel45** Software Research Associates, Inc.46** 1-1-1 Hirakawa-cho, Chiyoda-ku47** Tokyo 102 Japan. TEL +81-3-234-269248*/49#ifndef NO_FILE_SELECTOR5051#ifdef hpux52# define USG53#endif5455#include "utils.h"5657#if HAVE_DIRENT_H58# include <dirent.h>59# define NAMLEN(dirent) strlen((dirent)->d_name)60#else61# define dirent direct62# define NAMLEN(dirent) (dirent)->d_namlen63# if HAVE_SYS_NDIR_H64# include <sys/ndir.h>65# endif66# if HAVE_SYS_DIR_H67# include <sys/dir.h>68# endif69# if HAVE_NDIR_H70# include <ndir.h>71# endif72#endif7374#include <unistd.h>7576#include "selfile.h"7778#define SEL_FILE_CANCEL -179#define SEL_FILE_OK 080#define SEL_FILE_NULL 181#define SEL_FILE_TEXT 28283#define SF_DO_SCROLL 184#define SF_DO_NOT_SCROLL 0858687/****************************************************************************88**8990*T Typedefs . . . . . . . . . . . . . . . . . . . various private typedefs91*/92typedef struct {93int statDone;94char *real;95char *shown;96} SFEntry;9798typedef struct {99char *dir;100char *path;101SFEntry *entries;102int nEntries;103int vOrigin;104int nChars;105int hOrigin;106int changed;107int beginSelection;108int endSelection;109time_t mtime;110} SFDir;111112static void113SFenterList(),114SFleaveList(),115SFmotionList(),116SFbuttonPressList(),117SFbuttonReleaseList();118119static void120SFvSliderMovedCallback(),121SFvFloatSliderMovedCallback(),122SFhSliderMovedCallback(),123SFpathSliderMovedCallback(),124SFvAreaSelectedCallback(),125SFhAreaSelectedCallback(),126SFpathAreaSelectedCallback();127128static Boolean SFworkProc();129130static int SFcompareEntries();131132static void SFdirModTimer();133134static char SFstatChar();135136137/* BSD 4.3 errno.h does not declare errno */138extern int errno;139/* extern int sys_nerr; */140141#if !defined(S_ISDIR) && defined(S_IFDIR)142#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)143#endif144#if !defined(S_ISREG) && defined(S_IFREG)145#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)146#endif147#if !defined(S_ISSOCK) && defined(S_IFSOCK)148#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)149#endif150151#ifndef S_IXUSR152#define S_IXUSR 0100153#endif154#ifndef S_IXGRP155#define S_IXGRP 0010156#endif157#ifndef S_IXOTH158#define S_IXOTH 0001159#endif160161#define S_ISXXX(m) ((m) & (S_IXUSR | S_IXGRP | S_IXOTH))162163#ifndef MAXPATHLEN164#define MAXPATHLEN 1024165#endif /* ndef MAXPATHLEN */166167static int SFstatus = SEL_FILE_NULL;168169static char170SFstartDir[MAXPATHLEN],171SFcurrentPath[MAXPATHLEN],172SFcurrentDir[MAXPATHLEN];173174static Widget175selFile,176selFileCancel,177selFileField,178selFileForm,179selFileHScroll,180selFileHScrolls[3],181selFileLists[3],182selFileOK,183selFileHome,184selFilePrompt,185selFileVScrolls[3];186187static Display *SFdisplay = 0;188189static Pixel SFfore, SFback;190191static Atom SFwmDeleteWindow;192193static XSegment SFsegs[2], SFcompletionSegs[2];194195static XawTextPosition SFtextPos;196197static int SFupperX, SFlowerY, SFupperY;198199static int SFtextX, SFtextYoffset;200201static int SFentryWidth, SFentryHeight;202203static int SFlineToTextH = 3;204205static int SFlineToTextV = 3;206207static int SFbesideText = 3;208209static int SFaboveAndBelowText = 2;210211static int SFcharsPerEntry = 15;212213static int SFlistSize = 10;214215static int SFworkProcAdded = 0;216217static XtAppContext SFapp;218219static int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;220221static char SFtextBuffer[MAXPATHLEN];222223static XtIntervalId SFdirModTimerId;224225static int (*SFfunc)( String, String*, struct stat* ) = 0;226227228static SFDir *SFdirs = NULL;229230static int SFdirEnd;231232static int SFdirPtr;233234static int SFbuttonPressed = 0;235236static int SFdoNotTouchDirPtr = 0;237238static int SFdoNotTouchVorigin = 0;239240static SFDir SFrootDir, SFhomeDir;241242typedef struct {243char *name;244char *dir;245} SFLogin;246247static SFLogin *SFlogins;248249static int SFtwiddle = 0;250251252253/****************************************************************************254**255*F SFcompareEntries( <p>, <q> ) . . . . . . . . . . compare two sf entries256*/257static int SFcompareEntries ( const void *p, const void *q )258{259return strcmp(((const SFEntry *)p)->real, ((const SFEntry *)q)->real);260}261262263static int SFgetDir( SFDir *dir )264{265SFEntry *result = NULL;266int alloc = 0;267int i;268DIR *dirp;269struct dirent *dp;270char *str;271int len;272int maxChars;273struct stat statBuf;274275maxChars = strlen(dir->dir) - 1;276277dir->entries = NULL;278dir->nEntries = 0;279dir->nChars = 0;280281result = NULL;282i = 0;283284dirp = opendir(".");285if (!dirp) {286return 1;287}288289(void) stat(".", &statBuf);290dir->mtime = statBuf.st_mtime;291292(void) readdir(dirp); /* throw away "." */293294#ifndef S_IFLNK295(void) readdir(dirp); /* throw away ".." */296#endif /* ndef S_IFLNK */297298while ( (dp=readdir(dirp)) ) {299if (i >= alloc) {300alloc = 2 * (alloc + 1);301result = (SFEntry *) XtRealloc((char *) result,302(unsigned) (alloc * sizeof(SFEntry)));303}304result[i].statDone = 0;305str = dp->d_name;306len = strlen(str);307result[i].real = XtMalloc((unsigned) (len + 2));308(void) strcat(strcpy(result[i].real, str), " ");309if (len > maxChars) {310maxChars = len;311}312result[i].shown = result[i].real;313i++;314}315316qsort(result, i, sizeof(SFEntry), SFcompareEntries);317318dir->entries = result;319dir->nEntries = i;320dir->nChars = maxChars + 1;321322closedir(dirp);323324return 0;325}326327static char *oneLineTextEditTranslations = "\328<Key>Return: redraw-display()\n\329Ctrl<Key>M: redraw-display()\n\330";331332#define SF_DEFAULT_FONT "9x15"333334#ifdef ABS335#undef ABS336#endif337#define ABS(x) (((x) < 0) ? (-(x)) : (x))338339typedef struct {340char *fontname;341} TextData, *textPtr;342343int SFcharWidth, SFcharAscent, SFcharHeight;344345int SFcurrentInvert[3] = { -1, -1, -1 };346347static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;348349static XtResource textResources[] = {350{XtNfont, XtCFont, XtRString, sizeof (char *),351XtOffset(textPtr, fontname), XtRString, SF_DEFAULT_FONT},352};353354static XFontStruct *SFfont;355356static int SFcurrentListY;357358static XtIntervalId SFscrollTimerId;359360void SFinitFont()361{362TextData *data;363364data = XtNew(TextData);365366XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,367XtNumber(textResources), (Arg *) NULL, ZERO);368369SFfont = XLoadQueryFont(SFdisplay, data->fontname);370if (!SFfont) {371SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);372if (!SFfont) {373char sbuf[256];374375(void) sprintf(sbuf, "XsraSelFile: can't get font %s",376SF_DEFAULT_FONT);377378XtAppError(SFapp, sbuf);379}380}381382SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;383SFcharAscent = SFfont->max_bounds.ascent;384SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;385}386387void SFcreateGC()388{389XGCValues gcValues;390XRectangle rectangles[1];391392gcValues.foreground = SFfore;393394SFlineGC = XtGetGC(395selFileLists[0],396(XtGCMask)397GCForeground |3980,399&gcValues400);401402SFscrollGC = XtGetGC(403selFileLists[0],404(XtGCMask)4050,406&gcValues407);408409gcValues.function = GXinvert;410gcValues.plane_mask = (SFfore ^ SFback);411412SFinvertGC = XtGetGC(413selFileLists[0],414(XtGCMask)415GCFunction |416GCPlaneMask |4170,418&gcValues419);420421gcValues.foreground = SFfore;422gcValues.background = SFback;423gcValues.font = SFfont->fid;424425SFtextGC = XCreateGC(426SFdisplay,427XtWindow(selFileLists[0]),428(unsigned long)429GCForeground |430GCBackground |431GCFont |4320,433&gcValues434);435436rectangles[0].x = SFlineToTextH + SFbesideText;437rectangles[0].y = 0;438rectangles[0].width = SFcharsPerEntry * SFcharWidth;439rectangles[0].height = SFupperY + 1;440441XSetClipRectangles(442SFdisplay,443SFtextGC,4440,4450,446rectangles,4471,448Unsorted449);450}451452void SFclearList(int n, int doScroll)453{454SFDir *dir;455456SFcurrentInvert[n] = -1;457458XClearWindow(SFdisplay, XtWindow(selFileLists[n]));459460XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs,4612);462463if (doScroll) {464dir = &(SFdirs[SFdirPtr + n]);465466if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars) {467XawScrollbarSetThumb(468selFileVScrolls[n],469(float) (((double) dir->vOrigin) /470dir->nEntries),471(float) (((double) ((dir->nEntries < SFlistSize)472? dir->nEntries : SFlistSize)) /473dir->nEntries)474);475476XawScrollbarSetThumb(477selFileHScrolls[n],478(float) (((double) dir->hOrigin) / dir->nChars),479(float) (((double) ((dir->nChars <480SFcharsPerEntry) ? dir->nChars :481SFcharsPerEntry)) / dir->nChars)482);483} else {484XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,485(float) 1.0);486XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,487(float) 1.0);488}489}490}491492static void493SFdeleteEntry(SFDir *dir, SFEntry *entry)494{495register SFEntry *e;496register SFEntry *end;497int n;498int idx;499500idx = entry - dir->entries;501502if (idx < dir->beginSelection) {503dir->beginSelection--;504}505if (idx <= dir->endSelection) {506dir->endSelection--;507}508if (dir->beginSelection > dir->endSelection) {509dir->beginSelection = dir->endSelection = -1;510}511512if (idx < dir->vOrigin) {513dir->vOrigin--;514}515516XtFree(entry->real);517518end = &(dir->entries[dir->nEntries - 1]);519520for (e = entry; e < end; e++) {521*e = *(e + 1);522}523524if (!(--dir->nEntries)) {525return;526}527528n = dir - &(SFdirs[SFdirPtr]);529if ((n < 0) || (n > 2)) {530return;531}532533XawScrollbarSetThumb(534selFileVScrolls[n],535(float) (((double) dir->vOrigin) / dir->nEntries),536(float) (((double) ((dir->nEntries < SFlistSize) ?537dir->nEntries : SFlistSize)) / dir->nEntries)538);539}540541static void542SFwriteStatChar(char *name, int last, struct stat *statBuf)543{544name[last] = SFstatChar(statBuf);545}546547static int SFchdir(char *path)548{549int result;550551result = 0;552553if (strcmp(path, SFcurrentDir)) {554result = chdir(path);555if (!result) {556(void) strcpy(SFcurrentDir, path);557}558}559560return result;561}562563static int564SFstatAndCheck(SFDir *dir, SFEntry *entry)565{566struct stat statBuf;567char save;568int last;569570/*571* must be restored before returning572*/573save = *(dir->path);574*(dir->path) = 0;575576if (!SFchdir(SFcurrentPath)) {577last = strlen(entry->real) - 1;578entry->real[last] = 0;579entry->statDone = 1;580if (581(!stat(entry->real, &statBuf))582583#ifdef S_IFLNK584585|| (!lstat(entry->real, &statBuf))586587#endif /* ndef S_IFLNK */588589) {590if (SFfunc) {591char *shown;592593shown = NULL;594if (SFfunc(entry->real, &shown, &statBuf)) {595if (shown) {596int len;597598len = strlen(shown);599entry->shown = XtMalloc(600(unsigned) (len + 2)601);602(void) strcpy(entry->shown,603shown);604SFwriteStatChar(605entry->shown,606len,607&statBuf608);609entry->shown[len + 1] = 0;610}611} else {612SFdeleteEntry(dir, entry);613614*(dir->path) = save;615return 1;616}617}618SFwriteStatChar(entry->real, last, &statBuf);619} else {620entry->real[last] = ' ';621}622}623624*(dir->path) = save;625return 0;626}627628static void629SFdrawStrings(Window w, SFDir *dir, int from, int to)630{631register int i;632register SFEntry *entry;633int x;634635x = SFtextX - dir->hOrigin * SFcharWidth;636637if (dir->vOrigin + to >= dir->nEntries) {638to = dir->nEntries - dir->vOrigin - 1;639}640for (i = from; i <= to; i++) {641entry = &(dir->entries[dir->vOrigin + i]);642if (!(entry->statDone)) {643if (SFstatAndCheck(dir, entry)) {644if (dir->vOrigin + to >= dir->nEntries) {645to = dir->nEntries - dir->vOrigin - 1;646}647i--;648continue;649}650}651XDrawImageString(652SFdisplay,653w,654SFtextGC,655x,656SFtextYoffset + i * SFentryHeight,657entry->shown,658strlen(entry->shown)659);660if (dir->vOrigin + i == dir->beginSelection) {661XDrawLine(662SFdisplay,663w,664SFlineGC,665SFlineToTextH + 1,666SFlowerY + i * SFentryHeight,667SFlineToTextH + SFentryWidth - 2,668SFlowerY + i * SFentryHeight669);670}671if (672(dir->vOrigin + i >= dir->beginSelection) &&673(dir->vOrigin + i <= dir->endSelection)674) {675SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =676SFlowerY + i * SFentryHeight;677SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =678SFlowerY + (i + 1) * SFentryHeight - 1;679XDrawSegments(680SFdisplay,681w,682SFlineGC,683SFcompletionSegs,6842685);686}687if (dir->vOrigin + i == dir->endSelection) {688XDrawLine(689SFdisplay,690w,691SFlineGC,692SFlineToTextH + 1,693SFlowerY + (i + 1) * SFentryHeight - 1,694SFlineToTextH + SFentryWidth - 2,695SFlowerY + (i + 1) * SFentryHeight - 1696);697}698}699}700701void SFdrawList(int n, int doScroll)702{703SFDir *dir;704Window w;705706SFclearList(n, doScroll);707708if (SFdirPtr + n < SFdirEnd) {709dir = &(SFdirs[SFdirPtr + n]);710w = XtWindow(selFileLists[n]);711XDrawImageString(712SFdisplay,713w,714SFtextGC,715SFtextX - dir->hOrigin * SFcharWidth,716SFlineToTextV + SFaboveAndBelowText + SFcharAscent,717dir->dir,718strlen(dir->dir)719);720SFdrawStrings(w, dir, 0, SFlistSize - 1);721}722}723724void SFdrawLists(int doScroll)725{726int i;727728for (i = 0; i < 3; i++) {729SFdrawList(i, doScroll);730}731}732733static void734SFinvertEntry(register int n)735{736XFillRectangle(737SFdisplay,738XtWindow(selFileLists[n]),739SFinvertGC,740SFlineToTextH,741SFcurrentInvert[n] * SFentryHeight + SFlowerY,742SFentryWidth,743SFentryHeight744);745}746747static unsigned long748SFscrollTimerInterval()749{750static int maxVal = 200;751static int varyDist = 50;752static int minDist = 50;753int t;754int dist;755756if (SFcurrentListY < SFlowerY) {757dist = SFlowerY - SFcurrentListY;758} else if (SFcurrentListY > SFupperY) {759dist = SFcurrentListY - SFupperY;760} else {761return (unsigned long) 1;762}763764t = maxVal - ((maxVal / varyDist) * (dist - minDist));765766if (t < 1) {767t = 1;768}769770if (t > maxVal) {771t = maxVal;772}773774return (unsigned long) t;775}776777static void778SFscrollTimer(XtPointer p, XtIntervalId *id)779{780SFDir *dir;781int save;782long n;783784n = (long) p;785786dir = &(SFdirs[SFdirPtr + n]);787save = dir->vOrigin;788789if (SFcurrentListY < SFlowerY) {790if (dir->vOrigin > 0) {791SFvSliderMovedCallback(selFileVScrolls[n], n,792dir->vOrigin - 1);793}794} else if (SFcurrentListY > SFupperY) {795if (dir->vOrigin < dir->nEntries - SFlistSize) {796SFvSliderMovedCallback(selFileVScrolls[n], n,797dir->vOrigin + 1);798}799}800801if (dir->vOrigin != save) {802if (dir->nEntries) {803XawScrollbarSetThumb(804selFileVScrolls[n],805(float) (((double) dir->vOrigin) / dir->nEntries),806(float) (((double) ((dir->nEntries < SFlistSize) ?807dir->nEntries : SFlistSize)) / dir->nEntries)808);809}810}811812if (SFbuttonPressed) {813SFscrollTimerId = XtAppAddTimeOut(SFapp,814SFscrollTimerInterval(), SFscrollTimer, (XtPointer) n);815}816}817818static int819SFnewInvertEntry(long n, XMotionEvent *event)820{821register int x, y;822register int new;823static int SFscrollTimerAdded = 0;824825x = event->x;826y = event->y;827828if (SFdirPtr + n >= SFdirEnd) {829return -1;830} else if (831(x >= 0) && (x <= SFupperX) &&832(y >= SFlowerY) && (y <= SFupperY)833) {834register SFDir *dir = &(SFdirs[SFdirPtr + n]);835836if (SFscrollTimerAdded) {837SFscrollTimerAdded = 0;838XtRemoveTimeOut(SFscrollTimerId);839}840841new = (y - SFlowerY) / SFentryHeight;842if (dir->vOrigin + new >= dir->nEntries) {843return -1;844}845return new;846} else {847if (SFbuttonPressed) {848SFcurrentListY = y;849if (!SFscrollTimerAdded) {850SFscrollTimerAdded = 1;851SFscrollTimerId = XtAppAddTimeOut(SFapp,852SFscrollTimerInterval(), SFscrollTimer,853(XtPointer) n);854}855}856857return -1;858}859}860861/* ARGSUSED */862static void863SFenterList(Widget w, long n, XEnterWindowEvent *event)864{865register int new;866867/* sanity */868if (SFcurrentInvert[n] != -1) {869SFinvertEntry(n);870SFcurrentInvert[n] = -1;871}872873new = SFnewInvertEntry(n, (XMotionEvent *) event);874if (new != -1) {875SFcurrentInvert[n] = new;876SFinvertEntry(n);877}878}879880/* ARGSUSED */881static void882SFleaveList(Widget w, int n, XEvent *event)883{884if (SFcurrentInvert[n] != -1) {885SFinvertEntry(n);886SFcurrentInvert[n] = -1;887}888}889890/* ARGSUSED */891static void892SFmotionList(Widget w, int n, XMotionEvent *event)893{894register int new;895896new = SFnewInvertEntry(n, event);897898if (new != SFcurrentInvert[n]) {899if (SFcurrentInvert[n] != -1) {900SFinvertEntry(n);901}902SFcurrentInvert[n] = new;903if (new != -1) {904SFinvertEntry(n);905}906}907}908909/* ARGSUSED */910static void911SFvFloatSliderMovedCallback(Widget w, int n, float *fnew)912{913int new;914915new = (*fnew) * SFdirs[SFdirPtr + n].nEntries;916917SFvSliderMovedCallback(w, n, new);918}919920/* ARGSUSED */921static void922SFvSliderMovedCallback(Widget w, long n, int new)923{924int old;925register Window win;926SFDir *dir;927928dir = &(SFdirs[SFdirPtr + n]);929930old = dir->vOrigin;931dir->vOrigin = new;932933if (old == new) {934return;935}936937win = XtWindow(selFileLists[n]);938939if (ABS(new - old) < SFlistSize) {940if (new > old) {941XCopyArea(942SFdisplay,943win,944win,945SFscrollGC,946SFlineToTextH,947SFlowerY + (new - old) * SFentryHeight,948SFentryWidth + SFlineToTextH,949(SFlistSize - (new - old)) * SFentryHeight,950SFlineToTextH,951SFlowerY952);953XClearArea(954SFdisplay,955win,956SFlineToTextH,957SFlowerY + (SFlistSize - (new - old)) *958SFentryHeight,959SFentryWidth + SFlineToTextH,960(new - old) * SFentryHeight,961False962);963SFdrawStrings(win, dir, SFlistSize - (new - old),964SFlistSize - 1);965} else {966XCopyArea(967SFdisplay,968win,969win,970SFscrollGC,971SFlineToTextH,972SFlowerY,973SFentryWidth + SFlineToTextH,974(SFlistSize - (old - new)) * SFentryHeight,975SFlineToTextH,976SFlowerY + (old - new) * SFentryHeight977);978XClearArea(979SFdisplay,980win,981SFlineToTextH,982SFlowerY,983SFentryWidth + SFlineToTextH,984(old - new) * SFentryHeight,985False986);987SFdrawStrings(win, dir, 0, old - new);988}989} else {990XClearArea(991SFdisplay,992win,993SFlineToTextH,994SFlowerY,995SFentryWidth + SFlineToTextH,996SFlistSize * SFentryHeight,997False998);999SFdrawStrings(win, dir, 0, SFlistSize - 1);1000}1001}10021003/* ARGSUSED */1004static void1005SFvAreaSelectedCallback(Widget w, int n, int pnew)1006{1007SFDir *dir;1008int new;10091010dir = &(SFdirs[SFdirPtr + n]);10111012new = dir->vOrigin +1013(((double) pnew) / SFvScrollHeight) * dir->nEntries;10141015if (new > dir->nEntries - SFlistSize) {1016new = dir->nEntries - SFlistSize;1017}10181019if (new < 0) {1020new = 0;1021}10221023if (dir->nEntries) {1024float f;10251026f = ((double) new) / dir->nEntries;10271028XawScrollbarSetThumb(1029w,1030f,1031(float) (((double) ((dir->nEntries < SFlistSize) ?1032dir->nEntries : SFlistSize)) / dir->nEntries)1033);1034}10351036SFvSliderMovedCallback(w, n, new);1037}10381039/* ARGSUSED */1040static void1041SFhSliderMovedCallback(Widget w, int n, float *new)1042{1043SFDir *dir;1044int save;10451046dir = &(SFdirs[SFdirPtr + n]);1047save = dir->hOrigin;1048dir->hOrigin = (*new) * dir->nChars;1049if (dir->hOrigin == save) {1050return;1051}10521053SFdrawList(n, SF_DO_NOT_SCROLL);1054}10551056/* ARGSUSED */1057static void1058SFhAreaSelectedCallback(Widget w, int n, int pnew)1059{1060SFDir *dir;1061int new;10621063dir = &(SFdirs[SFdirPtr + n]);10641065new = dir->hOrigin +1066(((double) pnew) / SFhScrollWidth) * dir->nChars;10671068if (new > dir->nChars - SFcharsPerEntry) {1069new = dir->nChars - SFcharsPerEntry;1070}10711072if (new < 0) {1073new = 0;1074}10751076if (dir->nChars) {1077float f;10781079f = ((double) new) / dir->nChars;10801081XawScrollbarSetThumb(1082w,1083f,1084(float) (((double) ((dir->nChars < SFcharsPerEntry) ?1085dir->nChars : SFcharsPerEntry)) / dir->nChars)1086);10871088SFhSliderMovedCallback(w, n, &f);1089}1090}10911092/* ARGSUSED */1093static void1094SFpathSliderMovedCallback(Widget w, XtPointer client_data, float *new)1095{1096SFDir *dir;1097int n;1098XawTextPosition pos;1099int SFdirPtrSave;11001101SFdirPtrSave = SFdirPtr;1102SFdirPtr = (*new) * SFdirEnd;1103if (SFdirPtr == SFdirPtrSave) {1104return;1105}11061107SFdrawLists(SF_DO_SCROLL);11081109n = 2;1110while (SFdirPtr + n >= SFdirEnd) {1111n--;1112}11131114dir = &(SFdirs[SFdirPtr + n]);11151116pos = dir->path - SFcurrentPath;11171118if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {1119pos -= strlen(SFstartDir);1120if (pos < 0) {1121pos = 0;1122}1123}11241125XawTextSetInsertionPoint(selFileField, pos);1126}11271128/* ARGSUSED */11291130static void1131SFpathAreaSelectedCallback(Widget w, XtPointer client_data, int pnew)1132{1133int new;1134float f;11351136new = SFdirPtr + (((double) pnew) / SFpathScrollWidth) * SFdirEnd;11371138if (new > SFdirEnd - 3) {1139new = SFdirEnd - 3;1140}11411142if (new < 0) {1143new = 0;1144}11451146f = ((double) new) / SFdirEnd;11471148XawScrollbarSetThumb(1149w,1150f,1151(float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /1152SFdirEnd)1153);11541155SFpathSliderMovedCallback(w, (XtPointer) NULL, &f);1156}11571158static Boolean1159SFworkProc()1160{1161register SFDir *dir;1162register SFEntry *entry;11631164for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) {1165if (!(dir->nEntries)) {1166continue;1167}1168for (1169entry = &(dir->entries[dir->nEntries - 1]);1170entry >= dir->entries;1171entry--1172) {1173if (!(entry->statDone)) {1174(void) SFstatAndCheck(dir, entry);1175return False;1176}1177}1178}11791180SFworkProcAdded = 0;11811182return True;1183}118411851186static void1187SFfree(int i)1188{1189register SFDir *dir;1190register int j;11911192dir = &(SFdirs[i]);11931194for (j = dir->nEntries - 1; j >= 0; j--) {1195if (dir->entries[j].shown != dir->entries[j].real) {1196XtFree(dir->entries[j].shown);1197}1198XtFree(dir->entries[j].real);1199}12001201XtFree((char *) dir->entries);12021203XtFree(dir->dir);12041205dir->dir = NULL;1206}12071208static void1209SFstrdup(char **s1, char *s2)1210{1211*s1 = strcpy(XtMalloc((unsigned) (strlen(s2) + 1)), s2);1212}12131214static void1215SFunreadableDir(SFDir *dir)1216{1217char *cannotOpen = "<cannot open> ";12181219dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));1220dir->entries[0].statDone = 1;1221SFstrdup(&dir->entries[0].real, cannotOpen);1222dir->entries[0].shown = dir->entries[0].real;1223dir->nEntries = 1;1224dir->nChars = strlen(cannotOpen);1225}12261227static void SFtextChanged( void );12281229static void SFsetText(char *path)1230{1231XawTextBlock text;12321233text.firstPos = 0;1234text.length = strlen(path);1235text.ptr = path;1236text.format = FMT8BIT;12371238XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);1239XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));1240}12411242static void1243SFreplaceText(SFDir *dir, char *str)1244{1245int len;12461247*(dir->path) = 0;1248len = strlen(str);1249if (str[len - 1] == '/') {1250(void) strcat(SFcurrentPath, str);1251} else {1252(void) strncat(SFcurrentPath, str, len - 1);1253}1254if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {1255SFsetText(SFcurrentPath);1256} else {1257SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));1258}12591260SFtextChanged();1261}12621263static void1264SFexpand(char *str)1265{1266int len;1267int cmp;1268char *name, *growing;1269SFDir *dir;1270SFEntry *entry, *max;12711272len = strlen(str);12731274dir = &(SFdirs[SFdirEnd - 1]);12751276if (dir->beginSelection == -1) {1277SFstrdup(&str, str);1278SFreplaceText(dir, str);1279XtFree(str);1280return;1281} else if (dir->beginSelection == dir->endSelection) {1282SFreplaceText(dir, dir->entries[dir->beginSelection].shown);1283return;1284}12851286max = &(dir->entries[dir->endSelection + 1]);12871288name = dir->entries[dir->beginSelection].shown;1289SFstrdup(&growing, name);12901291cmp = 0;1292while (!cmp) {1293entry = &(dir->entries[dir->beginSelection]);1294while (entry < max) {1295if ((cmp = strncmp(growing, entry->shown, len))) {1296break;1297}1298entry++;1299}1300len++;1301}13021303/*1304* SFreplaceText() expects filename1305*/1306growing[len - 2] = ' ';13071308growing[len - 1] = 0;1309SFreplaceText(dir, growing);1310XtFree(growing);1311}13121313static int1314SFfindFile(SFDir *dir, char *str)1315{1316register int i, last, max;1317register char *name, save;1318SFEntry *entries;1319int len;1320int begin, end;1321int result;13221323len = strlen(str);13241325if (str[len - 1] == ' ') {1326SFexpand(str);1327return 1;1328} else if (str[len - 1] == '/') {1329len--;1330}13311332max = dir->nEntries;13331334entries = dir->entries;13351336i = 0;1337while (i < max) {1338name = entries[i].shown;1339last = strlen(name) - 1;1340save = name[last];1341name[last] = 0;13421343result = strncmp(str, name, len);13441345name[last] = save;1346if (result <= 0) {1347break;1348}1349i++;1350}1351begin = i;1352while (i < max) {1353name = entries[i].shown;1354last = strlen(name) - 1;1355save = name[last];1356name[last] = 0;13571358result = strncmp(str, name, len);13591360name[last] = save;1361if (result) {1362break;1363}1364i++;1365}1366end = i;13671368if (begin != end) {1369if (1370(dir->beginSelection != begin) ||1371(dir->endSelection != end - 1)1372) {1373dir->changed = 1;1374dir->beginSelection = begin;1375if (str[strlen(str) - 1] == '/') {1376dir->endSelection = begin;1377} else {1378dir->endSelection = end - 1;1379}1380}1381} else {1382if (dir->beginSelection != -1) {1383dir->changed = 1;1384dir->beginSelection = -1;1385dir->endSelection = -1;1386}1387}13881389if (1390SFdoNotTouchVorigin ||1391((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))1392) {1393SFdoNotTouchVorigin = 0;1394return 0;1395}13961397i = begin - 1;1398if (i > max - SFlistSize) {1399i = max - SFlistSize;1400}1401if (i < 0) {1402i = 0;1403}14041405if (dir->vOrigin != i) {1406dir->vOrigin = i;1407dir->changed = 1;1408}14091410return 0;1411}14121413static void1414SFunselect()1415{1416SFDir *dir;14171418dir = &(SFdirs[SFdirEnd - 1]);1419if (dir->beginSelection != -1) {1420dir->changed = 1;1421}1422dir->beginSelection = -1;1423dir->endSelection = -1;1424}14251426static int1427SFcompareLogins(const void *p, const void *q)1428{1429return strcmp(((const SFLogin *)p)->name, ((const SFLogin *)q)->name);1430}14311432static void1433SFgetHomeDirs()1434{1435struct passwd *pw;1436int alloc;1437int i;1438SFEntry *entries = NULL;1439int len;1440int maxChars;14411442{1443alloc = 1;1444i = 1;1445entries = (SFEntry *) XtMalloc(sizeof(SFEntry));1446SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));1447entries[0].real = XtMalloc(3);1448(void) strcpy(entries[0].real, "~");1449entries[0].shown = entries[0].real;1450entries[0].statDone = 1;1451SFlogins[0].name = "";1452pw = getpwuid((int) getuid());1453SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");1454maxChars = 0;1455}14561457(void) setpwent();14581459while ((pw = getpwent()) && (*(pw->pw_name))) {1460if (i >= alloc) {1461alloc *= 2;1462entries = (SFEntry *) XtRealloc(1463(char *) entries,1464(unsigned) (alloc * sizeof(SFEntry))1465);1466SFlogins = (SFLogin *) XtRealloc(1467(char *) SFlogins,1468(unsigned) (alloc * sizeof(SFLogin))1469);1470}1471len = strlen(pw->pw_name);1472entries[i].real = XtMalloc((unsigned) (len + 3));1473(void) strcat(strcpy(entries[i].real, "~"),1474pw->pw_name);1475entries[i].shown = entries[i].real;1476entries[i].statDone = 1;1477if (len > maxChars) {1478maxChars = len;1479}1480SFstrdup(&SFlogins[i].name, pw->pw_name);1481SFstrdup(&SFlogins[i].dir, pw->pw_dir);1482i++;1483}14841485SFhomeDir.dir = XtMalloc(1) ;1486SFhomeDir.dir[0] = 0 ;1487SFhomeDir.path = SFcurrentPath ;1488SFhomeDir.entries = entries ;1489SFhomeDir.nEntries = i ;1490SFhomeDir.vOrigin = 0 ; /* :-) */1491SFhomeDir.nChars = maxChars + 2 ;1492SFhomeDir.hOrigin = 0 ;1493SFhomeDir.changed = 1 ;1494SFhomeDir.beginSelection = -1 ;1495SFhomeDir.endSelection = -1 ;14961497qsort(entries, i, sizeof(SFEntry), SFcompareEntries);1498qsort(SFlogins, i, sizeof(SFLogin), SFcompareLogins);14991500for (i--; i >= 0; i--) {1501(void) strcat(entries[i].real, "/");1502}1503}15041505static int1506SFfindHomeDir(char *begin, char *end)1507{1508char save;1509char *theRest;1510int i;15111512save = *end;1513*end = 0;15141515for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {1516if (!strcmp(SFhomeDir.entries[i].real, begin)) {1517*end = save;1518SFstrdup(&theRest, end);1519(void) strcat(strcat(strcpy(SFcurrentPath,1520SFlogins[i].dir), "/"), theRest);1521XtFree(theRest);1522SFsetText(SFcurrentPath);1523SFtextChanged();1524return 1;1525}1526}15271528*end = save;15291530return 0;1531}15321533static void SFupdatePath()1534{1535static int alloc;1536static int wasTwiddle = 0;1537char *begin, *end;1538int i, j;1539int prevChange;1540int SFdirPtrSave, SFdirEndSave;1541SFDir *dir;15421543if (!SFdirs) {1544SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));1545dir = &(SFdirs[0]);1546SFstrdup(&dir->dir, "/");1547(void) SFchdir("/");1548(void) SFgetDir(dir);1549for (j = 1; j < alloc; j++) {1550SFdirs[j].dir = NULL;1551}1552dir->path = SFcurrentPath + 1;1553dir->vOrigin = 0;1554dir->hOrigin = 0;1555dir->changed = 1;1556dir->beginSelection = -1;1557dir->endSelection = -1;1558SFhomeDir.dir = NULL;1559}15601561SFdirEndSave = SFdirEnd;1562SFdirEnd = 1;15631564SFdirPtrSave = SFdirPtr;1565SFdirPtr = 0;15661567begin = NULL;15681569if (SFcurrentPath[0] == '~') {1570if (!SFtwiddle) {1571SFtwiddle = 1;1572dir = &(SFdirs[0]);1573SFrootDir = *dir;1574if (!SFhomeDir.dir) {1575SFgetHomeDirs();1576}1577*dir = SFhomeDir;1578dir->changed = 1;1579}1580end = SFcurrentPath;1581SFdoNotTouchDirPtr = 1;1582wasTwiddle = 1;1583} else {1584if (SFtwiddle) {1585SFtwiddle = 0;1586dir = &(SFdirs[0]);1587*dir = SFrootDir;1588dir->changed = 1;1589}1590end = SFcurrentPath + 1;1591}15921593i = 0;15941595prevChange = 0;15961597while (*end) {1598while (*end++ == '/') {1599;1600}1601end--;1602begin = end;1603while ((*end) && (*end++ != '/')) {1604;1605}1606if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {1607SFdirPtr = i - 1;1608if (SFdirPtr < 0) {1609SFdirPtr = 0;1610}1611}1612if (*begin) {1613if (*(end - 1) == '/') {1614char save = *end;16151616if (SFtwiddle) {1617if (SFfindHomeDir(begin, end)) {1618return;1619}1620}1621*end = 0;1622i++;1623SFdirEnd++;1624if (i >= alloc) {1625SFdirs = (SFDir *) XtRealloc(1626(char *) SFdirs,1627(unsigned) ((alloc *= 2) *1628sizeof(SFDir))1629);1630for (j = alloc / 2; j < alloc; j++) {1631SFdirs[j].dir = NULL;1632}1633}1634dir = &(SFdirs[i]);1635if (1636(!(dir->dir)) ||1637prevChange ||1638strcmp(dir->dir, begin)1639) {1640if (dir->dir) {1641SFfree(i);1642}1643prevChange = 1;1644SFstrdup(&dir->dir, begin);1645dir->path = end;1646dir->vOrigin = 0;1647dir->hOrigin = 0;1648dir->changed = 1;1649dir->beginSelection = -1;1650dir->endSelection = -1;1651(void) SFfindFile(dir - 1, begin);1652if (1653SFchdir(SFcurrentPath) ||1654SFgetDir(dir)1655) {1656SFunreadableDir(dir);1657break;1658}1659}1660*end = save;1661if (!save) {1662SFunselect();1663}1664} else {1665if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) {1666return;1667}1668}1669} else {1670SFunselect();1671}1672}16731674if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {1675SFunselect();1676}16771678for (i = SFdirEnd; i < alloc; i++) {1679if (SFdirs[i].dir) {1680SFfree(i);1681}1682}16831684if (SFdoNotTouchDirPtr) {1685if (wasTwiddle) {1686wasTwiddle = 0;1687SFdirPtr = SFdirEnd - 2;1688if (SFdirPtr < 0) {1689SFdirPtr = 0;1690}1691} else {1692SFdirPtr = SFdirPtrSave;1693}1694SFdoNotTouchDirPtr = 0;1695}16961697if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {1698XawScrollbarSetThumb(1699selFileHScroll,1700(float) (((double) SFdirPtr) / SFdirEnd),1701(float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /1702SFdirEnd)1703);1704}17051706if (SFdirPtr != SFdirPtrSave) {1707SFdrawLists(SF_DO_SCROLL);1708} else {1709for (i = 0; i < 3; i++) {1710if (SFdirPtr + i < SFdirEnd) {1711if (SFdirs[SFdirPtr + i].changed) {1712SFdirs[SFdirPtr + i].changed = 0;1713SFdrawList(i, SF_DO_SCROLL);1714}1715} else {1716SFclearList(i, SF_DO_SCROLL);1717}1718}1719}1720}172117221723/* ARGSUSED */1724static void1725SFbuttonPressList(Widget w, int n, XButtonPressedEvent *event)1726{1727SFbuttonPressed = 1;1728}17291730/* ARGSUSED */1731static void1732SFbuttonReleaseList(Widget w, int n, XButtonReleasedEvent *event)1733{1734SFDir *dir;17351736SFbuttonPressed = 0;17371738if (SFcurrentInvert[n] != -1) {1739if (n < 2) {1740SFdoNotTouchDirPtr = 1;1741}1742SFdoNotTouchVorigin = 1;1743dir = &(SFdirs[SFdirPtr + n]);1744SFreplaceText(1745dir,1746dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown1747);1748SFmotionList(w, n, (XMotionEvent *)event);1749}1750}17511752static int1753SFcheckDir(int n, SFDir *dir)1754{1755struct stat statBuf;1756int i;17571758if (1759(!stat(".", &statBuf)) &&1760(statBuf.st_mtime != dir->mtime)1761) {17621763/*1764* If the pointer is currently in the window that we are about1765* to update, we must warp it to prevent the user from1766* accidentally selecting the wrong file.1767*/1768if (SFcurrentInvert[n] != -1) {1769XWarpPointer(1770SFdisplay,1771None,1772XtWindow(selFileLists[n]),17730,17740,17750,17760,17770,177801779);1780}17811782for (i = dir->nEntries - 1; i >= 0; i--) {1783if (dir->entries[i].shown != dir->entries[i].real) {1784XtFree(dir->entries[i].shown);1785}1786XtFree(dir->entries[i].real);1787}1788XtFree((char *) dir->entries);1789if (SFgetDir(dir)) {1790SFunreadableDir(dir);1791}1792if (dir->vOrigin > dir->nEntries - SFlistSize) {1793dir->vOrigin = dir->nEntries - SFlistSize;1794}1795if (dir->vOrigin < 0) {1796dir->vOrigin = 0;1797}1798if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {1799dir->hOrigin = dir->nChars - SFcharsPerEntry;1800}1801if (dir->hOrigin < 0) {1802dir->hOrigin = 0;1803}1804dir->beginSelection = -1;1805dir->endSelection = -1;1806SFdoNotTouchVorigin = 1;1807if ((dir + 1)->dir) {1808(void) SFfindFile(dir, (dir + 1)->dir);1809} else {1810(void) SFfindFile(dir, dir->path);1811}18121813if (!SFworkProcAdded) {1814(void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);1815SFworkProcAdded = 1;1816}18171818return 1;1819}18201821return 0;1822}18231824static int1825SFcheckFiles(SFDir *dir)1826{1827int from, to;1828int result;1829char old, new;1830int i;1831char *str;1832int last;1833struct stat statBuf;18341835result = 0;18361837from = dir->vOrigin;1838to = dir->vOrigin + SFlistSize;1839if (to > dir->nEntries) {1840to = dir->nEntries;1841}18421843for (i = from; i < to; i++) {1844str = dir->entries[i].real;1845last = strlen(str) - 1;1846old = str[last];1847str[last] = 0;1848if (stat(str, &statBuf)) {1849new = ' ';1850} else {1851new = SFstatChar(&statBuf);1852}1853str[last] = new;1854if (new != old) {1855result = 1;1856}1857}18581859return result;1860}18611862static void1863SFdirModTimer(XtPointer cl, XtIntervalId *id)1864{1865static int n = -1;1866static int f = 0;1867char save;1868SFDir *dir;18691870if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {1871n++;1872if ((n > 2) || (SFdirPtr + n >= SFdirEnd)) {1873n = 0;1874f++;1875if ((f > 2) || (SFdirPtr + f >= SFdirEnd)) {1876f = 0;1877}1878}1879dir = &(SFdirs[SFdirPtr + n]);1880save = *(dir->path);1881*(dir->path) = 0;1882if (SFchdir(SFcurrentPath)) {1883*(dir->path) = save;18841885/*1886* force a re-read1887*/1888*(dir->dir) = 0;18891890SFupdatePath();1891} else {1892*(dir->path) = save;1893if (1894SFcheckDir(n, dir) ||1895((f == n) && SFcheckFiles(dir))1896) {1897SFdrawList(n, SF_DO_SCROLL);1898}1899}1900}19011902SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,1903SFdirModTimer, (XtPointer) NULL);1904}19051906/* Return a single character describing what kind of file STATBUF is. */19071908static char1909SFstatChar (struct stat *statBuf)1910{1911if (S_ISDIR (statBuf->st_mode)) {1912return '/';1913} else if (S_ISREG (statBuf->st_mode)) {1914return S_ISXXX (statBuf->st_mode) ? '*' : ' ';1915#ifdef S_ISSOCK1916} else if (S_ISSOCK (statBuf->st_mode)) {1917return '=';1918#endif /* S_ISSOCK */1919} else {1920return ' ';1921}1922}19231924/* ARGSUSED */1925static void1926SFexposeList(Widget w, XtPointer n, XEvent *event, Boolean *cont)1927{1928if ((event->type == NoExpose) || event->xexpose.count) {1929return;1930}19311932SFdrawList((ULong)n, SF_DO_NOT_SCROLL);1933}19341935/* ARGSUSED */1936static void1937SFmodVerifyCallback(Widget w, XtPointer client_data, XEvent *event, Boolean *cont)1938{1939char buf[2];19401941if (1942(XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&1943((*buf) == '\r')1944) {1945SFstatus = SEL_FILE_OK;1946} else {1947SFstatus = SEL_FILE_TEXT;1948}1949}19501951/* ARGSUSED */1952static void1953SFokCallback(Widget w, XtPointer cl, XtPointer cd)1954{1955SFstatus = SEL_FILE_OK;1956}19571958static XtCallbackRec SFokSelect[] = {1959{ SFokCallback, (XtPointer) NULL },1960{ NULL, (XtPointer) NULL },1961};19621963/* ARGSUSED */1964static void1965SFcancelCallback(Widget w, XtPointer cl, XtPointer cd)1966{1967SFstatus = SEL_FILE_CANCEL;1968}19691970static XtCallbackRec SFcancelSelect[] = {1971{ SFcancelCallback, (XtPointer) NULL },1972{ NULL, (XtPointer) NULL },1973};19741975static void1976SFhomeCallback(Widget w, XtPointer cl, XtPointer cd)1977{1978SFsetText("~/");1979SFtextChanged();1980}19811982static XtCallbackRec SFhomeSelect[] = {1983{ SFhomeCallback, (XtPointer) NULL },1984{ NULL, (XtPointer) NULL },1985};19861987/* ARGSUSED */1988static void1989SFdismissAction(Widget w, XEvent *event, String *params, Cardinal *num_params)1990{1991if (event->type == ClientMessage &&1992event->xclient.data.l[0] != SFwmDeleteWindow) return;19931994SFstatus = SEL_FILE_CANCEL;1995}19961997static XtActionsRec actions[] = {1998{"SelFileDismiss", SFdismissAction},1999};20002001/****************************************************************************2002**2003*F SFpositionWidget( <w> ) . . . . . . . . position widget under the cursor2004*/2005static void SFpositionWidget(Widget w)2006{2007Dimension width, height, b_width;2008Int dummyx, dummyy;2009Int x, y, max_x, max_y;2010UInt dummymask;2011Window root, child;20122013/* find out where the pointer is */2014XQueryPointer( XtDisplay(w), XtWindow(w), &root, &child, &x, &y,2015&dummyx, &dummyy, &dummymask );20162017/* get the dimensions of the widget */2018XtVaGetValues( w, XtNwidth, &width,2019XtNheight, &height,2020XtNborderWidth, &b_width,2021NULL );20222023/* calculate a nice position */2024width += 2 * b_width;2025height += 2 * b_width;2026x -= ( (Position) width/2 );2027y -= ( (Position) height/2 );20282029/* make sure that the widget lies within the screen boundaries */2030if ( x < 0 )2031x = 0;2032if ( x > (max_x = (Position) (XtScreen(w)->width - width)) )2033x = max_x;2034if (y < 0)2035y = 0;2036if ( y > (max_y = (Position) (XtScreen(w)->height - height)) )2037y = max_y;20382039/* set the x and y position in <w> */2040XtVaSetValues( w, XtNx, x, XtNy, y, NULL );2041}204220432044/****************************************************************************2045**2046*F SFtextChanged() . . . . . . . . . . . . . . . path text has been changed2047*/2048static void SFtextChanged()2049{2050if ( (SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~') )2051{2052(void) strcpy(SFcurrentPath, SFtextBuffer);2053SFtextPos = XawTextGetInsertionPoint(selFileField);2054}2055else2056{2057(void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);2058SFtextPos = XawTextGetInsertionPoint(selFileField)2059+ strlen(SFstartDir);2060}20612062if (!SFworkProcAdded) {2063(void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);2064SFworkProcAdded = 1;2065}2066SFupdatePath();2067}206820692070/****************************************************************************2071**2072*F SFcreateWidgets( <toplevel> ) . . . . . . . create file selector widgets2073*/2074static char *wmDeleteWindowTranslation =2075"<Message>WM_PROTOCOLS: SelFileDismiss()\n";20762077static void SFcreateWidgets ( Widget toplevel )2078{2079Long n;2080Int listWidth, listHeight;2081Int listSpacing = 10;2082Int scrollThickness = 15;2083Int hScrollX, hScrollY;2084Int vScrollX, vScrollY;2085Cursor xtermCursor;2086Cursor sbRightArrowCursor;2087Cursor dotCursor;20882089/* create a new toplevel shell */2090selFile = XtVaAppCreateShell(2091"XGap", "FileSelector",2092transientShellWidgetClass, SFdisplay,2093XtNtransientFor, (XtArgVal)toplevel,2094(String)NULL );20952096/* Add WM_DELETE_WINDOW protocol */2097XtAppAddActions( XtWidgetToApplicationContext(selFile),2098actions, XtNumber(actions) );2099XtOverrideTranslations( selFile,2100XtParseTranslationTable(wmDeleteWindowTranslation) );21012102/* create the file selector components */2103selFileForm = XtVaCreateManagedWidget(2104"selFileForm", formWidgetClass, selFile,2105XtNdefaultDistance, (XtArgVal)30,2106(String)NULL);21072108selFilePrompt = XtVaCreateManagedWidget(2109"selFilePrompt", labelWidgetClass, selFileForm,2110XtNlabel, (XtArgVal)"Enter a Filename",2111XtNresizable, (XtArgVal)True,2112XtNtop, (XtArgVal)XtChainTop,2113XtNbottom, (XtArgVal)XtChainTop,2114XtNleft, (XtArgVal)XtChainLeft,2115XtNright, (XtArgVal)XtChainLeft,2116XtNborderWidth, (XtArgVal)0,2117(String)NULL );2118XtVaGetValues( selFilePrompt,2119XtNforeground, (XtArgVal)&SFfore,2120XtNbackground, (XtArgVal)&SFback,2121(String)NULL );21222123/* initialize fonts */2124SFinitFont();21252126/* compute positions */2127SFentryWidth = 2*SFbesideText + SFcharsPerEntry*SFcharWidth;2128SFentryHeight = 2*SFaboveAndBelowText + SFcharHeight;21292130listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 12131+ scrollThickness;2132listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 12133+ SFlineToTextV + SFlistSize * SFentryHeight2134+ SFlineToTextV + 1 + scrollThickness;21352136SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;21372138hScrollX = -1;2139hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 12140+ SFlineToTextV + SFlistSize * SFentryHeight2141+ SFlineToTextV;2142SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;21432144vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;2145vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;2146SFvScrollHeight = 2*SFlineToTextV + SFlistSize * SFentryHeight;21472148SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;2149SFlowerY = 2*SFlineToTextV + SFentryHeight + SFlineToTextV + 1;2150SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 12151+ SFlineToTextV + SFlistSize * SFentryHeight - 1;21522153SFtextX = SFlineToTextH + SFbesideText;2154SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;21552156SFsegs[0].x1 = 0;2157SFsegs[0].y1 = vScrollY;2158SFsegs[0].x2 = vScrollX - 1;2159SFsegs[0].y2 = vScrollY;2160SFsegs[1].x1 = vScrollX;2161SFsegs[1].y1 = 0;2162SFsegs[1].x2 = vScrollX;2163SFsegs[1].y2 = vScrollY - 1;21642165SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;2166SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =2167SFlineToTextH + SFentryWidth - 1;21682169/* create more widgets */2170selFileField = XtVaCreateManagedWidget(2171"selFileField", asciiTextWidgetClass, selFileForm,2172XtNwidth, (XtArgVal)3*listWidth+2*listSpacing+4,2173XtNborderColor, (XtArgVal)SFfore,2174XtNfromVert, (XtArgVal)selFilePrompt,2175XtNvertDistance, (XtArgVal)10,2176XtNresizable, (XtArgVal)True,2177XtNtop, (XtArgVal)XtChainTop,2178XtNbottom, (XtArgVal)XtChainTop,2179XtNleft, (XtArgVal)XtChainLeft,2180XtNright, (XtArgVal)XtChainLeft,2181XtNstring, (XtArgVal)SFtextBuffer,2182XtNlength, (XtArgVal)MAXPATHLEN,2183XtNeditType, (XtArgVal)XawtextEdit,2184XtNwrap, (XtArgVal)XawtextWrapWord,2185XtNresize, (XtArgVal)XawtextResizeHeight,2186XtNuseStringInPlace, (XtArgVal)True,2187(String)NULL );2188XtOverrideTranslations( selFileField,2189XtParseTranslationTable(oneLineTextEditTranslations) );2190XtSetKeyboardFocus(selFileForm, selFileField);21912192selFileHScroll = XtVaCreateManagedWidget(2193"selFileHScroll", scrollbarWidgetClass, selFileForm,2194XtNorientation, (XtArgVal)XtorientHorizontal,2195XtNwidth, (XtArgVal)SFpathScrollWidth,2196XtNheight, (XtArgVal)scrollThickness,2197XtNborderColor, (XtArgVal)SFfore,2198XtNfromVert, (XtArgVal)selFileField,2199XtNvertDistance, (XtArgVal)30,2200XtNtop, (XtArgVal)XtChainTop,2201XtNbottom, (XtArgVal)XtChainTop,2202XtNleft, (XtArgVal)XtChainLeft,2203XtNright, (XtArgVal)XtChainLeft,2204(String)NULL );2205XtAddCallback( selFileHScroll, XtNjumpProc,2206(XtCallbackProc)SFpathSliderMovedCallback, (XtPointer) NULL);2207XtAddCallback( selFileHScroll, XtNscrollProc,2208(XtCallbackProc)SFpathAreaSelectedCallback, (XtPointer) NULL);22092210selFileLists[0] = XtVaCreateManagedWidget(2211"selFileList1", compositeWidgetClass, selFileForm,2212XtNwidth, (XtArgVal)listWidth,2213XtNheight, (XtArgVal)listHeight,2214XtNborderColor, (XtArgVal)SFfore,2215XtNfromVert, (XtArgVal)selFileHScroll,2216XtNvertDistance, (XtArgVal)10,2217XtNtop, (XtArgVal)XtChainTop,2218XtNbottom, (XtArgVal)XtChainTop,2219XtNleft, (XtArgVal)XtChainLeft,2220XtNright, (XtArgVal)XtChainLeft,2221(String)NULL );22222223selFileLists[1] = XtVaCreateManagedWidget(2224"selFileList2", compositeWidgetClass, selFileForm,2225XtNwidth, (XtArgVal)listWidth,2226XtNheight, (XtArgVal)listHeight,2227XtNborderColor, (XtArgVal)SFfore,2228XtNfromHoriz, (XtArgVal)selFileLists[0],2229XtNfromVert, (XtArgVal)selFileHScroll,2230XtNhorizDistance, (XtArgVal)listSpacing,2231XtNvertDistance, (XtArgVal)10,2232XtNtop, (XtArgVal)XtChainTop,2233XtNbottom, (XtArgVal)XtChainTop,2234XtNleft, (XtArgVal)XtChainLeft,2235XtNright, (XtArgVal)XtChainLeft,2236(String)NULL );2237selFileLists[2] = XtVaCreateManagedWidget(2238"selFileList3", compositeWidgetClass, selFileForm,2239XtNwidth, (XtArgVal)listWidth,2240XtNheight, (XtArgVal)listHeight,2241XtNborderColor, (XtArgVal)SFfore,2242XtNfromHoriz, (XtArgVal)selFileLists[1],2243XtNfromVert, (XtArgVal)selFileHScroll,2244XtNhorizDistance, (XtArgVal)listSpacing,2245XtNvertDistance, (XtArgVal)10,2246XtNtop, (XtArgVal)XtChainTop,2247XtNbottom, (XtArgVal)XtChainTop,2248XtNleft, (XtArgVal)XtChainLeft,2249XtNright, (XtArgVal)XtChainLeft,2250(String)NULL );22512252for ( n = 0; n < 3; n++ )2253{2254selFileVScrolls[n] = XtVaCreateManagedWidget(2255"selFileVScroll", scrollbarWidgetClass, selFileLists[n],2256XtNx, (XtArgVal)vScrollX,2257XtNy, (XtArgVal)vScrollY,2258XtNwidth, (XtArgVal)scrollThickness,2259XtNheight, (XtArgVal)SFvScrollHeight,2260XtNborderColor, (XtArgVal)SFfore,2261(String)NULL );2262XtAddCallback( selFileVScrolls[n], XtNjumpProc,2263(XtCallbackProc)SFvFloatSliderMovedCallback, (XtPointer) n );2264XtAddCallback( selFileVScrolls[n], XtNscrollProc,2265(XtCallbackProc)SFvAreaSelectedCallback, (XtPointer) n );22662267selFileHScrolls[n] = XtVaCreateManagedWidget(2268"selFileHScroll", scrollbarWidgetClass, selFileLists[n],2269XtNorientation, (XtArgVal)XtorientHorizontal,2270XtNx, (XtArgVal)hScrollX,2271XtNy, (XtArgVal)hScrollY,2272XtNwidth, (XtArgVal)SFhScrollWidth,2273XtNheight, (XtArgVal)scrollThickness,2274XtNborderColor, (XtArgVal)SFfore,2275(String)NULL );2276XtAddCallback( selFileHScrolls[n], XtNjumpProc,2277(XtCallbackProc)SFhSliderMovedCallback, (XtPointer) n );2278XtAddCallback( selFileHScrolls[n], XtNscrollProc,2279(XtCallbackProc)SFhAreaSelectedCallback, (XtPointer) n );2280}22812282selFileOK = XtVaCreateManagedWidget(2283"selFileOK", commandWidgetClass, selFileForm,2284XtNresizable, (XtArgVal)True,2285XtNcallback, (XtArgVal)SFokSelect,2286XtNborderColor, (XtArgVal)SFfore,2287XtNfromVert, (XtArgVal)(selFileLists[0]),2288XtNvertDistance, (XtArgVal)30,2289XtNtop, (XtArgVal)XtChainTop,2290XtNbottom, (XtArgVal)XtChainTop,2291XtNleft, (XtArgVal)XtChainLeft,2292XtNright, (XtArgVal)XtChainLeft,2293(String)NULL );2294selFileCancel = XtVaCreateManagedWidget(2295"selFileCancel", commandWidgetClass, selFileForm,2296XtNresizable, (XtArgVal)True,2297XtNcallback, (XtArgVal)SFcancelSelect,2298XtNborderColor, (XtArgVal)SFfore,2299XtNfromHoriz, (XtArgVal)selFileOK,2300XtNfromVert, (XtArgVal)selFileLists[0],2301XtNhorizDistance, (XtArgVal)30,2302XtNvertDistance, (XtArgVal)30,2303XtNtop, (XtArgVal)XtChainTop,2304XtNbottom, (XtArgVal)XtChainTop,2305XtNleft, (XtArgVal)XtChainLeft,2306XtNright, (XtArgVal)XtChainLeft,2307(String)NULL );2308selFileHome = XtVaCreateManagedWidget(2309"selFileHome", commandWidgetClass, selFileForm,2310XtNresizable, (XtArgVal)True,2311XtNcallback, (XtArgVal)SFhomeSelect,2312XtNborderColor, (XtArgVal)SFfore,2313XtNfromHoriz, (XtArgVal)selFileCancel,2314XtNfromVert, (XtArgVal)selFileLists[0],2315XtNhorizDistance, (XtArgVal)30,2316XtNvertDistance, (XtArgVal)30,2317XtNtop, (XtArgVal)XtChainTop,2318XtNbottom, (XtArgVal)XtChainTop,2319XtNleft, (XtArgVal)XtChainLeft,2320XtNright, (XtArgVal)XtChainLeft,2321(String)NULL );23222323/* realise toplevel */2324XtSetMappedWhenManaged( selFile, False );2325XtRealizeWidget(selFile);23262327/* Add WM_DELETE_WINDOW protocol */2328SFwmDeleteWindow = XInternAtom( SFdisplay, "WM_DELETE_WINDOW", False );2329XSetWMProtocols( SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1 );23302331/* create default graphic context */2332SFcreateGC();23332334/* create cursors */2335xtermCursor = XCreateFontCursor( SFdisplay, XC_xterm );2336sbRightArrowCursor = XCreateFontCursor( SFdisplay, XC_sb_right_arrow );2337dotCursor = XCreateFontCursor( SFdisplay, XC_dot );23382339XDefineCursor( SFdisplay, XtWindow(selFileOK), dotCursor );2340XDefineCursor( SFdisplay, XtWindow(selFileCancel), dotCursor );2341XDefineCursor( SFdisplay, XtWindow(selFileHome), dotCursor );2342XDefineCursor( SFdisplay, XtWindow(selFileForm), xtermCursor );2343XDefineCursor( SFdisplay, XtWindow(selFileField), xtermCursor );2344for (n = 0; n < 3; n++)2345XDefineCursor( SFdisplay, XtWindow(selFileLists[n]),2346sbRightArrowCursor);23472348/* set event handler */2349for ( n = 0; n < 3; n++ )2350{2351XtAddEventHandler( selFileLists[n], ExposureMask, True,2352(XtEventHandler)SFexposeList, (XtPointer) n );2353XtAddEventHandler( selFileLists[n], EnterWindowMask, False,2354(XtEventHandler)SFenterList, (XtPointer) n );2355XtAddEventHandler( selFileLists[n], LeaveWindowMask, False,2356(XtEventHandler)SFleaveList, (XtPointer) n );2357XtAddEventHandler( selFileLists[n], PointerMotionMask, False,2358(XtEventHandler)SFmotionList, (XtPointer) n );2359XtAddEventHandler( selFileLists[n], ButtonPressMask, False,2360(XtEventHandler)SFbuttonPressList, (XtPointer) n );2361XtAddEventHandler( selFileLists[n], ButtonReleaseMask, False,2362(XtEventHandler)SFbuttonReleaseList, (XtPointer) n );2363}2364XtAddEventHandler( selFileField, KeyPressMask, False,2365SFmodVerifyCallback, (XtPointer) NULL);2366SFapp = XtWidgetToApplicationContext(selFile);2367}236823692370/****************************************************************************2371**2372*F SFgetText() . . . . . . . . . . . . . . . . . . . . . copy user selection2373*/2374static String SFgetText ()2375{2376return strcpy( XtMalloc((strlen(SFtextBuffer)+1)), SFtextBuffer );2377}237823792380/****************************************************************************2381**2382*F SFprepareToReturn() . . . . . . . . . . remove grab, unmap file selector2383*/2384static void SFprepareToReturn ()2385{2386SFstatus = SEL_FILE_NULL;2387XtRemoveGrab(selFile);2388XtUnmapWidget(selFile);2389XtRemoveTimeOut(SFdirModTimerId);2390if ( SFchdir(SFstartDir) )2391XtAppWarning(SFapp,"XsraSelFile: can't return to current directory");2392}239323942395/****************************************************************************2396**2397*F XsraSelFile( <top>, <prompt>, <path>, <show>, <name> ) . . file selector2398*/2399Boolean XsraSelFile ( Widget toplevel, String prompt, String init_path,2400Int (*show_entry)( String, String*, struct stat* ), String *name_return )2401{2402XEvent event;24032404/* set nice prompt */2405if ( !prompt || !prompt[0] )2406prompt = "Enter Filename";24072408/* initialize widgets */2409if ( !SFdisplay )2410{2411SFdisplay = XtDisplay(toplevel);2412SFcreateWidgets(toplevel);2413}2414XtVaSetValues( selFilePrompt, XtNlabel, (XtArgVal)prompt, (String)NULL );24152416/* position widget under cursor */2417SFpositionWidget(selFile);2418XtMapWidget(selFile);24192420/* get current directory */2421if ( !getcwd(SFstartDir, MAXPATHLEN) ) {2422*SFstartDir = 0;2423XtAppWarning( SFapp, "XsraSelFile: can't get current directory" );2424}2425(void) strcat(SFstartDir, "/");2426(void) strcpy(SFcurrentDir, SFstartDir);24272428/* set init path */2429if (init_path)2430{2431if (init_path[0] == '/')2432{2433strcpy(SFcurrentPath, init_path);2434if ( strncmp( SFcurrentPath, SFstartDir, strlen(SFstartDir) ))2435SFsetText(SFcurrentPath);2436else2437SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));2438}2439else2440{2441strcat( strcpy( SFcurrentPath, SFstartDir ), init_path );2442SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));2443}2444}2445else2446(void) strcpy(SFcurrentPath, SFstartDir);24472448/* function to filter entries */2449SFfunc = show_entry;24502451/* force redisplay */2452SFtextChanged();24532454/* grab input for modal widget */2455XtAddGrab(selFile, True, True);24562457/* set time out function */2458SFdirModTimerId = XtAppAddTimeOut( SFapp, (unsigned long) 1000,2459SFdirModTimer, (XtPointer) 0 );24602461/* loop until user selects OK or CANCEL */2462while (1)2463{2464XtAppNextEvent( SFapp, &event );2465XtDispatchEvent(&event);2466switch (SFstatus)2467{2468case SEL_FILE_TEXT:2469SFstatus = SEL_FILE_NULL;2470SFtextChanged();2471break;2472case SEL_FILE_OK:2473*name_return = SFgetText();2474SFprepareToReturn();2475return True;2476case SEL_FILE_CANCEL:2477SFprepareToReturn();2478return False;2479case SEL_FILE_NULL:2480break;2481}2482}2483}24842485#endif248624872488/****************************************************************************2489**24902491*E selfile.h . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here2492*/249324942495