summaryrefslogtreecommitdiffstats
path: root/src/gui_at_fs.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
committerBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
commit071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch)
tree221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/gui_at_fs.c
parentb4210b3bc14e2918f153a7307530fbe6eba659e1 (diff)
updated for version 7.0001v7.0001
Diffstat (limited to 'src/gui_at_fs.c')
-rw-r--r--src/gui_at_fs.c2880
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