diff options
author | Bram Moolenaar <Bram@vim.org> | 2004-06-13 20:20:40 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2004-06-13 20:20:40 +0000 |
commit | 071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch) | |
tree | 221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/gui_at_fs.c | |
parent | b4210b3bc14e2918f153a7307530fbe6eba659e1 (diff) |
updated for version 7.0001v7.0001
Diffstat (limited to 'src/gui_at_fs.c')
-rw-r--r-- | src/gui_at_fs.c | 2880 |
1 files changed, 2880 insertions, 0 deletions
diff --git a/src/gui_at_fs.c b/src/gui_at_fs.c new file mode 100644 index 0000000000..474967ecbf --- /dev/null +++ b/src/gui_at_fs.c @@ -0,0 +1,2880 @@ +/* vi:set ts=8 sts=4 sw=4: */ + +/* + * 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 addresses: + * erik@sra.co.jp + * erik%sra.co.jp@uunet.uu.net + * erik%sra.co.jp@mcvax.uucp + * try junet instead of co.jp + * Erik M. van der Poel + * Software Research Associates, Inc. + * 1-1-1 Hirakawa-cho, Chiyoda-ku + * Tokyo 102 Japan. TEL +81-3-234-2692 + */ + +/* + * Heavely modified for Vim by Bram Moolenaar + */ + +#include "vim.h" + +/* Only include this when using the file browser */ + +#ifdef FEAT_BROWSE + +/* Weird complication: for "make lint" Text.h doesn't combine with Xm.h */ +#if defined(FEAT_GUI_MOTIF) && defined(FMT8BIT) +# undef FMT8BIT +#endif + +#ifndef FEAT_GUI_NEXTAW +# include "gui_at_sb.h" +#endif + +/***************** SFinternal.h */ + +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Xos.h> +#ifdef FEAT_GUI_NEXTAW +# include <X11/neXtaw/Text.h> +# include <X11/neXtaw/AsciiText.h> +# include <X11/neXtaw/Scrollbar.h> +#else +# include <X11/Xaw/Text.h> +# include <X11/Xaw/AsciiText.h> +#endif + +#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 + +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; + +static char SFstartDir[MAXPATHL], + SFcurrentPath[MAXPATHL], + SFcurrentDir[MAXPATHL]; + +static Widget selFile, + selFileField, + selFileForm, + selFileHScroll, + selFileHScrolls[3], + selFileLists[3], + selFileOK, + selFileCancel, + selFilePrompt, + selFileVScrolls[3]; + +static Display *SFdisplay; + +static int SFcharWidth, SFcharAscent, SFcharHeight; + +static SFDir *SFdirs = NULL; + +static int SFdirEnd; +static int SFdirPtr; + +static Pixel SFfore, SFback; + +static Atom SFwmDeleteWindow; + +static XSegment SFsegs[2], SFcompletionSegs[2]; + +static XawTextPosition SFtextPos; + +static int SFupperX, SFlowerY, SFupperY; + +static int SFtextX, SFtextYoffset; + +static int SFentryWidth, SFentryHeight; + +static int SFlineToTextH = 3; +static int SFlineToTextV = 3; + +static int SFbesideText = 3; +static int SFaboveAndBelowText = 2; + +static int SFcharsPerEntry = 15; + +static int SFlistSize = 10; + +static int SFcurrentInvert[3] = { -1, -1, -1 }; + +static int SFworkProcAdded = 0; + +static XtAppContext SFapp; + +static int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth; + +#ifdef FEAT_XFONTSET +static char SFtextBuffer[MAXPATHL*sizeof(wchar_t)]; +#else +static char SFtextBuffer[MAXPATHL]; +#endif + +static int SFbuttonPressed = 0; + +static XtIntervalId SFdirModTimerId; + +static int (*SFfunc)(); + +static int SFstatus = SEL_FILE_NULL; + +/***************** static functions */ + +static void SFsetText __ARGS((char *path)); +static void SFtextChanged __ARGS((void)); +static char *SFgetText __ARGS((void)); +static void SFupdatePath __ARGS((void)); +static int SFgetDir __ARGS((SFDir *dir)); +static void SFdrawLists __ARGS((int doScroll)); +static void SFdrawList __ARGS((int n, int doScroll)); +static void SFclearList __ARGS((int n, int doScroll)); +static void SFbuttonPressList __ARGS((Widget w, int n, XButtonPressedEvent *event)); +static void SFbuttonReleaseList __ARGS((Widget w, int n, XButtonReleasedEvent *event)); +static void SFdirModTimer __ARGS((XtPointer cl, XtIntervalId *id)); +static char SFstatChar __ARGS((struct stat *statBuf)); +static void SFdrawStrings __ARGS((Window w, SFDir *dir, int from, int to)); +static int SFnewInvertEntry __ARGS((int n, XMotionEvent *event)); +static void SFinvertEntry __ARGS((int n)); +static void SFenterList __ARGS((Widget w, int n, XEnterWindowEvent *event)); +static void SFleaveList __ARGS((Widget w, int n, XEvent *event)); +static void SFmotionList __ARGS((Widget w, int n, XMotionEvent *event)); +static void SFvFloatSliderMovedCallback __ARGS((Widget w, XtPointer n, XtPointer fnew)); +static void SFvSliderMovedCallback __ARGS((Widget w, int n, int nw)); +static void SFvAreaSelectedCallback __ARGS((Widget w, XtPointer n, XtPointer pnew)); +static void SFhSliderMovedCallback __ARGS((Widget w, XtPointer n, XtPointer nw)); +static void SFhAreaSelectedCallback __ARGS((Widget w, XtPointer n, XtPointer pnew)); +static void SFpathSliderMovedCallback __ARGS((Widget w, XtPointer client_data, XtPointer nw)); +static void SFpathAreaSelectedCallback __ARGS((Widget w, XtPointer client_data, XtPointer pnew)); +static Boolean SFworkProc __ARGS((void)); +static int SFcompareEntries __ARGS((const void *p, const void *q)); +static void SFprepareToReturn __ARGS((void)); +static void SFcreateWidgets __ARGS((Widget toplevel, char *prompt, char *ok, char *cancel)); +static void SFsetColors __ARGS((guicolor_T bg, guicolor_T fg, guicolor_T scroll_bg, guicolor_T scrollfg)); + +/***************** xstat.h */ + +#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)) + +/***************** Path.c */ + +#include <pwd.h> + +typedef struct +{ + char *name; + char *dir; +} SFLogin; + +static int SFdoNotTouchDirPtr = 0; + +static int SFdoNotTouchVorigin = 0; + +static SFDir SFrootDir, SFhomeDir; + +static SFLogin *SFlogins; + +static int SFtwiddle = 0; + +static int SFchdir __ARGS((char *path)); + + static int +SFchdir(path) + char *path; +{ + int result; + + result = 0; + + if (strcmp(path, SFcurrentDir)) + { + result = mch_chdir(path); + if (!result) + (void) strcpy(SFcurrentDir, path); + } + + return result; +} + +static void SFfree __ARGS((int i)); + + static void +SFfree(i) + int i; +{ + SFDir *dir; + 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 void SFstrdup __ARGS((char **s1, char *s2)); + + static void +SFstrdup(s1, s2) + char **s1; + char *s2; +{ + *s1 = strcpy(XtMalloc((unsigned)(strlen(s2) + 1)), s2); +} + +static void SFunreadableDir __ARGS((SFDir *dir)); + + static void +SFunreadableDir(dir) + SFDir *dir; +{ + char *cannotOpen = _("<cannot open> "); + + 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); +} + +static void SFreplaceText __ARGS((SFDir *dir, char *str)); + + static void +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 __ARGS((char *str)); + + 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 __ARGS((SFDir *dir, char *str)); + + static int +SFfindFile(dir, str) + SFDir *dir; + char *str; +{ + int i, last, max; + 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; + + result = strncmp(str, name, len); + + 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; + + result = strncmp(str, name, len); + + 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 void SFunselect __ARGS((void)); + + static void +SFunselect() +{ + SFDir *dir; + + dir = &(SFdirs[SFdirEnd - 1]); + if (dir->beginSelection != -1) + dir->changed = 1; + dir->beginSelection = -1; + dir->endSelection = -1; +} + +static int SFcompareLogins __ARGS((const void *p, const void *q)); + + static int +SFcompareLogins(p, q) + const void *p, *q; +{ + return strcmp(((SFLogin *)p)->name, ((SFLogin *)q)->name); +} + +static void SFgetHomeDirs __ARGS((void)); + + static void +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; + + qsort((char *)entries, (size_t)i, sizeof(SFEntry), SFcompareEntries); + qsort((char *)SFlogins, (size_t)i, sizeof(SFLogin), SFcompareLogins); + + for (i--; i >= 0; i--) + (void)strcat(entries[i].real, "/"); +} + +static int SFfindHomeDir __ARGS((char *begin, char *end)); + + 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; +} + + static void +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 - 2; + if (SFdirPtr < 0) + SFdirPtr = 0; + } + else + SFdirPtr = SFdirPtrSave; + SFdoNotTouchDirPtr = 0; + } + + if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) + { +#ifdef FEAT_GUI_NEXTAW + XawScrollbarSetThumb( selFileHScroll, + (float) (((double) SFdirPtr) / SFdirEnd), + (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / + SFdirEnd)); +#else + vim_XawScrollbarSetThumb( selFileHScroll, + (float) (((double) SFdirPtr) / SFdirEnd), + (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / + SFdirEnd), + (double)SFdirEnd); +#endif + } + + if (SFdirPtr != SFdirPtrSave) + SFdrawLists(SF_DO_SCROLL); + else + for (i = 0; i < 3; 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); + } +} + +#ifdef XtNinternational + static int +WcsLen(p) + wchar_t *p; +{ + int i = 0; + while (*p++ != 0) + i++; + return i; +} +#endif + + static void +SFsetText(path) + char *path; +{ + XawTextBlock text; + + text.firstPos = 0; + text.length = strlen(path); + text.ptr = path; + text.format = FMT8BIT; + +#ifdef XtNinternational + if (_XawTextFormat((TextWidget)selFileField) == XawFmtWide) + { + XawTextReplace(selFileField, (XawTextPosition)0, + (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0]), &text); + XawTextSetInsertionPoint(selFileField, + (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0])); + } + else + { + XawTextReplace(selFileField, (XawTextPosition)0, + (XawTextPosition)strlen(SFtextBuffer), &text); + XawTextSetInsertionPoint(selFileField, + (XawTextPosition)strlen(SFtextBuffer)); + } +#else + XawTextReplace(selFileField, (XawTextPosition)0, + (XawTextPosition)strlen(SFtextBuffer), &text); + XawTextSetInsertionPoint(selFileField, + (XawTextPosition)strlen(SFtextBuffer)); +#endif +} + +/* ARGSUSED */ + static void +SFbuttonPressList(w, n, event) + Widget w; + int n; + XButtonPressedEvent *event; +{ + SFbuttonPressed = 1; +} + +/* ARGSUSED */ + static 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, (XMotionEvent *) event); + } +} + +static int SFcheckDir __ARGS((int n, SFDir *dir)); + + static int +SFcheckDir(n, dir) + int n; + SFDir *dir; +{ + struct stat statBuf; + int i; + + if ((!mch_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, (XtWorkProc)SFworkProc, NULL); + SFworkProcAdded = 1; + } + return 1; + } + return 0; +} + +static int SFcheckFiles __ARGS((SFDir *dir)); + + static int +SFcheckFiles(dir) + SFDir *dir; +{ + int from, to; + int result; + char oldc, newc; + 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; + oldc = str[last]; + str[last] = 0; + if (mch_stat(str, &statBuf)) + newc = ' '; + else + newc = SFstatChar(&statBuf); + str[last] = newc; + if (newc != oldc) + result = 1; + } + + return result; +} + +/* ARGSUSED */ + static 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 > 2) || (SFdirPtr + n >= SFdirEnd)) + { + n = 0; + f++; + if ((f > 2) || (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. */ + + static char +SFstatChar(statBuf) + struct stat *statBuf; +{ + if (S_ISDIR (statBuf->st_mode)) + return '/'; + if (S_ISREG (statBuf->st_mode)) + return S_ISXXX (statBuf->st_mode) ? '*' : ' '; +#ifdef S_ISSOCK + if (S_ISSOCK (statBuf->st_mode)) + return '='; +#endif /* S_ISSOCK */ + return ' '; +} + +/***************** Draw.c */ + +#ifdef FEAT_GUI_NEXTAW +# include <X11/neXtaw/Cardinals.h> +#else +# include <X11/Xaw/Cardinals.h> +#endif + +#ifdef FEAT_XFONTSET +# define SF_DEFAULT_FONT "-misc-fixed-medium-r-normal--14-*" +#else +# define SF_DEFAULT_FONT "9x15" +#endif + +#ifdef ABS +# undef ABS +#endif +#define ABS(x) (((x) < 0) ? (-(x)) : (x)) + +typedef struct +{ + char *fontname; +} TextData; + +static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC; + +static XtResource textResources[] = +{ +#ifdef FEAT_XFONTSET + {XtNfontSet, XtCFontSet, XtRString, sizeof (char *), + XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT}, +#else + {XtNfont, XtCFont, XtRString, sizeof (char *), + XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT}, +#endif +}; + +#ifdef FEAT_XFONTSET +static XFontSet SFfont; +#else +static XFontStruct *SFfont; +#endif + +static int SFcurrentListY; + +static XtIntervalId SFscrollTimerId; + +static void SFinitFont __ARGS((void)); + + static void +SFinitFont() +{ + TextData *data; +#ifdef FEAT_XFONTSET + XFontSetExtents *extents; + char **missing, *def_str; + int num_missing; +#endif + + data = XtNew(TextData); + + XtGetApplicationResources(selFileForm, (XtPointer) data, textResources, + XtNumber(textResources), (Arg *) NULL, ZERO); + +#ifdef FEAT_XFONTSET + SFfont = XCreateFontSet(SFdisplay, data->fontname, + &missing, &num_missing, &def_str); +#else + SFfont = XLoadQueryFont(SFdisplay, data->fontname); +#endif + if (!SFfont) + { +#ifdef FEAT_XFONTSET + SFfont = XCreateFontSet(SFdisplay, SF_DEFAULT_FONT, + &missing, &num_missing, &def_str); +#else + SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT); +#endif + if (!SFfont) + { + EMSG2(_("E616: vim_SelFile: can't get font %s"), SF_DEFAULT_FONT); + SFstatus = SEL_FILE_CANCEL; + return; + } + } + +#ifdef FEAT_XFONTSET + extents = XExtentsOfFontSet(SFfont); + SFcharWidth = extents->max_logical_extent.width; + SFcharAscent = -extents->max_logical_extent.y; + SFcharHeight = extents->max_logical_extent.height; +#else + SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2; + SFcharAscent = SFfont->max_bounds.ascent; + SFcharHeight = SFcharAscent + SFfont->max_bounds.descent; +#endif +} + +static void SFcreateGC __ARGS((void)); + + static void +SFcreateGC() +{ + XGCValues gcValues; + XRectangle rectangles[1]; + + gcValues.foreground = SFfore; + + SFlineGC = XtGetGC( + selFileLists[0], + (XtGCMask)GCForeground, + &gcValues); + + SFscrollGC = XtGetGC( + selFileLists[0], + (XtGCMask)0, + &gcValues); + + gcValues.function = GXxor; + gcValues.foreground = SFfore ^ SFback; + gcValues.background = SFfore ^ SFback; + + SFinvertGC = XtGetGC( + selFileLists[0], + (XtGCMask)GCFunction | GCForeground | GCBackground, + &gcValues); + + gcValues.foreground = SFfore; + gcValues.background = SFback; +#ifndef FEAT_XFONTSET + gcValues.font = SFfont->fid; +#endif + + SFtextGC = XCreateGC( + SFdisplay, + XtWindow(selFileLists[0]), +#ifdef FEAT_XFONTSET + (unsigned long)GCForeground | GCBackground, +#else + (unsigned long)GCForeground | GCBackground | GCFont, +#endif + &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); +} + + static void +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) + { +#ifdef FEAT_GUI_NEXTAW + XawScrollbarSetThumb( + selFileVScrolls[n], + (float) (((double) dir->vOrigin) / + dir->nEntries), + (float) (((double) ((dir->nEntries < SFlistSize) + ? dir->nEntries : SFlistSize)) / + dir->nEntries)); +#else + vim_XawScrollbarSetThumb( + selFileVScrolls[n], + (float) (((double) dir->vOrigin) / + dir->nEntries), + (float) (((double) ((dir->nEntries < SFlistSize) + ? dir->nEntries : SFlistSize)) / + dir->nEntries), + (double)dir->nEntries); +#endif + +#ifdef FEAT_GUI_NEXTAW + XawScrollbarSetThumb( + selFileHScrolls[n], + (float) (((double) dir->hOrigin) / dir->nChars), + (float) (((double) ((dir->nChars < + SFcharsPerEntry) ? dir->nChars : + SFcharsPerEntry)) / dir->nChars)); +#else + vim_XawScrollbarSetThumb( + selFileHScrolls[n], + (float) (((double) dir->hOrigin) / dir->nChars), + (float) (((double) ((dir->nChars < + SFcharsPerEntry) ? dir->nChars : + SFcharsPerEntry)) / dir->nChars), + (double)dir->nChars); +#endif + } + else + { +#ifdef FEAT_GUI_NEXTAW + XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0, + (float) 1.0); +#else + vim_XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0, + (float) 1.0, 1.0); +#endif +#ifdef FEAT_GUI_NEXTAW + XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0, + (float) 1.0); +#else + vim_XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0, + (float) 1.0, 1.0); +#endif + } + } +} + +static void SFdeleteEntry __ARGS((SFDir *dir, SFEntry *entry)); + + static void +SFdeleteEntry(dir, entry) + SFDir *dir; + SFEntry *entry; +{ + SFEntry *e; + SFEntry *end; + int n; + int idx; + + idx = entry - dir->entries; + + if (idx < d |