blob: 2d73885aa458bf992e5bb5f0934200e8ca595eb5 [file] [log] [blame]
/* 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 ((unsigned long)_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
}
static void
SFbuttonPressList(w, n, event)
Widget w UNUSED;
int n UNUSED;
XButtonPressedEvent *event UNUSED;
{
SFbuttonPressed = 1;
}
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;
}
static void
SFdirModTimer(cl, id)
XtPointer cl UNUSED;
XtIntervalId *id UNUSED;
{
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 < dir->beginSelection)
dir->beginSelection--;
if (idx <= dir->endSelection)
dir->endSelection--;
if (dir->beginSelection > dir->endSelection)
dir->beginSelection = dir->endSelection = -1;
if (idx < dir->vOrigin)
dir->vOrigin--;
XtFree(entry->real);
end = &(dir->entries[dir->nEntries - 1]);
for (e = entry; e < end; e++)
*e = *(e + 1);
if (!(--dir->nEntries))
return;
n = dir - &(SFdirs[SFdirPtr]);
if ((n < 0) || (n > 2))
return;
#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
}
static void SFwriteStatChar __ARGS((char *name, int last, struct stat *statBuf));
static void
SFwriteStatChar(name, last, statBuf)
char *name;
int last;
struct stat *statBuf;
{
name[last] = SFstatChar(statBuf);
}
static int SFstatAndCheck __ARGS((SFDir *dir, SFEntry *entry));
static int
SFstatAndCheck(dir, entry)
SFDir *dir;
SFEntry *entry;
{
struct stat statBuf;
char save;
int last;
/*
* must be restored before returning
*/
save = *(dir->path);
*(dir->path) = 0;
if (!SFchdir(SFcurrentPath))
{
last = strlen(entry->real) - 1;
entry->real[last] = 0;
entry->statDone = 1;
if ((!mch_stat(entry->real, &statBuf))
#ifdef S_IFLNK
|| (!mch_lstat(entry->real, &statBuf))
#endif
)
{
if (SFfunc)
{
char *shown;
shown = NULL;
if (SFfunc(entry->real, &shown, &statBuf))
{
if (shown)
{
int len;
len = strlen(shown);
entry->shown = XtMalloc((unsigned) (len + 2));
(void) strcpy(entry->shown, shown);
SFwriteStatChar(entry->shown, len, &statBuf);
entry->shown[len + 1] = 0;
}
}
else
{
SFdeleteEntry(dir, entry);
*(dir->path) = save;
return 1;
}
}
SFwriteStatChar(entry->real, last, &statBuf);
}
else
entry->real[last] = ' ';
}
*(dir->path) = save;
return 0;
}
static void
SFdrawStrings(w, dir, from, to)
Window w;
SFDir *dir;
int from;
int to;
{
int i;
SFEntry *entry;
int x;
x = SFtextX - dir->hOrigin * SFcharWidth;
if (dir->vOrigin + to >= dir->nEntries)
to = dir->nEntries - dir->vOrigin - 1;
for (i = from; i <= to; i++)
{
entry = &(dir->entries[dir->vOrigin + i]);
if (!(entry->statDone))
{
if (SFstatAndCheck(dir, entry))
{
if (dir->vOrigin + to >= dir->nEntries)
to = dir->nEntries - dir->vOrigin - 1;
i--;
continue;
}
}
#ifdef FEAT_XFONTSET
XmbDrawImageString(
SFdisplay,
w,
SFfont,
SFtextGC,
x,
SFtextYoffset + i * SFentryHeight,
entry->shown,
strlen(entry->shown));
#else
XDrawImageString(
SFdisplay,
w,
SFtextGC,
x,
SFtextYoffset + i * SFentryHeight,
entry->shown,
strlen(entry->shown));
#endif
if (dir->vOrigin + i == dir->beginSelection)
{
XDrawLine(
SFdisplay,
w,
SFlineGC,
SFlineToTextH + 1,
SFlowerY + i * SFentryHeight,
SFlineToTextH + SFentryWidth - 2,
SFlowerY + i * SFentryHeight);
}
if ((dir->vOrigin + i >= dir->beginSelection) &&
(dir->vOrigin + i <= dir->endSelection))
{
SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
SFlowerY + i * SFentryHeight;
SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
SFlowerY + (i + 1) * SFentryHeight - 1;
XDrawSegments(
SFdisplay,
w,
SFlineGC,
SFcompletionSegs,
2);
}
if (dir->vOrigin + i == dir->endSelection)
{
XDrawLine(
SFdisplay,
w,
SFlineGC,
SFlineToTextH + 1,
SFlowerY + (i + 1) * SFentryHeight - 1,
SFlineToTextH + SFentryWidth - 2,
SFlowerY + (i + 1) * SFentryHeight - 1);
}
}
}
static void
SFdrawList(n, doScroll)
int n;
int doScroll;
{
SFDir *dir;
Window w;
SFclearList(n, doScroll);
if (SFdirPtr + n < SFdirEnd)
{
dir = &(SFdirs[SFdirPtr + n]);
w = XtWindow(selFileLists[n]);
#ifdef FEAT_XFONTSET
XmbDrawImageString(
SFdisplay,
w,
SFfont,
SFtextGC,
SFtextX - dir->hOrigin * SFcharWidth,
SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
dir->dir,
strlen(dir->dir));
#else
XDrawImageString(
SFdisplay,
w,
SFtextGC,
SFtextX - dir->hOrigin * SFcharWidth,
SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
dir->dir,
strlen(dir->dir));
#endif
SFdrawStrings(w, dir, 0, SFlistSize - 1);
}
}
static void
SFdrawLists(doScroll)
int doScroll;
{
int i;
for (i = 0; i < 3; i++)
SFdrawList(i, doScroll);
}
static void
SFinvertEntry(n)
int n;
{
XFillRectangle(
SFdisplay,
XtWindow(selFileLists[n]),
SFinvertGC,
SFlineToTextH,
SFcurrentInvert[n] * SFentryHeight + SFlowerY,
SFentryWidth,
SFentryHeight);
}
static unsigned long SFscrollTimerInterval __ARGS((void));
static unsigned long
SFscrollTimerInterval()
{
static int maxVal = 200;
static int varyDist = 50;
static int minDist = 50;
int t;
int dist;
if (SFcurrentListY < SFlowerY)
dist = SFlowerY - SFcurrentListY;
else if (SFcurrentListY > SFupperY)
dist = SFcurrentListY - SFupperY;
else
return (unsigned long) 1;
t = maxVal - ((maxVal / varyDist) * (dist - minDist));
if (t < 1)
t = 1;
if (t > maxVal)
t = maxVal;
return (unsigned long)t;
}
static void SFscrollTimer __ARGS((XtPointer p, XtIntervalId *id));
static void
SFscrollTimer(p, id)
XtPointer p;
XtIntervalId *id UNUSED;
{
SFDir *dir;
int save;
int n;
n = (long)p;
dir = &(SFdirs[SFdirPtr + n]);
save = dir->vOrigin;
if (SFcurrentListY < SFlowerY)
{
if (dir->vOrigin > 0)
SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1);
}
else if (SFcurrentListY > SFupperY)
{
if (dir->vOrigin < dir->nEntries - SFlistSize)
SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1);
}
if (dir->vOrigin != save)
{
if (dir->nEntries)
{
#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
}
}
if (SFbuttonPressed)
SFscrollTimerId = XtAppAddTimeOut(SFapp,
SFscrollTimerInterval(), SFscrollTimer,
(XtPointer)(long_u)n);
}
static int
SFnewInvertEntry(n, event)
int n;
XMotionEvent *event;
{
int x, y;
int nw;
static int SFscrollTimerAdded = 0;
x = event->x;
y = event->y;
if (SFdirPtr + n >= SFdirEnd)
return -1;
if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY))
{
SFDir *dir = &(SFdirs[SFdirPtr + n]);
if (SFscrollTimerAdded)
{
SFscrollTimerAdded = 0;
XtRemoveTimeOut(SFscrollTimerId);
}
nw = (y - SFlowerY) / SFentryHeight;
if (dir->vOrigin + nw >= dir->nEntries)
return -1;
return nw;
}
else
{
if (SFbuttonPressed)
{
SFcurrentListY = y;
if (!SFscrollTimerAdded)
{
SFscrollTimerAdded = 1;
SFscrollTimerId = XtAppAddTimeOut(SFapp,
SFscrollTimerInterval(), SFscrollTimer,
(XtPointer)(long_u)n);
}
}
return -1;
}
}
static void
SFenterList(w, n, event)
Widget w UNUSED;
int n;
XEnterWindowEvent *event;
{
int nw;
/* sanity */
if (SFcurrentInvert[n] != -1)
{
SFinvertEntry(n);
SFcurrentInvert[n] = -1;
}
nw = SFnewInvertEntry(n, (XMotionEvent *) event);
if (nw != -1)
{
SFcurrentInvert[n] = nw;
SFinvertEntry(n);
}
}
static void
SFleaveList(w, n, event)
Widget w UNUSED;
int n;
XEvent *event UNUSED;
{
if (SFcurrentInvert[n] != -1)
{
SFinvertEntry(n);
SFcurrentInvert[n] = -1;
}
}
static void
SFmotionList(w, n, event)
Widget w UNUSED;
int n;
XMotionEvent *event;
{
int nw;
nw = SFnewInvertEntry(n, event);
if (nw != SFcurrentInvert[n])
{
if (SFcurrentInvert[n] != -1)
SFinvertEntry(n);
SFcurrentInvert[n] = nw;
if (nw != -1)
SFinvertEntry(n);
}
}
static void
SFvFloatSliderMovedCallback(w, n, fnew)
Widget w;
XtPointer n;
XtPointer fnew;
{
int nw;
nw = (*(float *)fnew) * SFdirs[SFdirPtr + (int)(long)n].nEntries;
SFvSliderMovedCallback(w, (int)(long)n, nw);
}
static void
SFvSliderMovedCallback(w, n, nw)
Widget w UNUSED;
int n;
int nw;
{
int old;
Window win;
SFDir *dir;
dir = &(SFdirs[SFdirPtr + n]);
old = dir->vOrigin;
dir->vOrigin = nw;
if (old == nw)
return;
win = XtWindow(selFileLists[n]);
if (ABS(nw - old) < SFlistSize)
{
if (nw > old)
{
XCopyArea(
SFdisplay,
win,
win,
SFscrollGC,
SFlineToTextH,
SFlowerY + (nw - old) * SFentryHeight,
SFentryWidth + SFlineToTextH,
(SFlistSize - (nw - old)) * SFentryHeight,
SFlineToTextH,
SFlowerY);
XClearArea(
SFdisplay,
win,
SFlineToTextH,
SFlowerY + (SFlistSize - (nw - old)) *
SFentryHeight,
SFentryWidth + SFlineToTextH,
(nw - old) * SFentryHeight,
False);
SFdrawStrings(win, dir, SFlistSize - (nw - old),
SFlistSize - 1);
}
else
{
XCopyArea(
SFdisplay,
win,
win,
SFscrollGC,
SFlineToTextH,
SFlowerY,
SFentryWidth + SFlineToTextH,
(SFlistSize - (old - nw)) * SFentryHeight,
SFlineToTextH,
SFlowerY + (old - nw) * SFentryHeight);
XClearArea(
SFdisplay,
win,
SFlineToTextH,
SFlowerY,
SFentryWidth + SFlineToTextH,
(old - nw) * SFentryHeight,
False);
SFdrawStrings(win, dir, 0, old - nw);
}
}
else
{
XClearArea(
SFdisplay,
win,
SFlineToTextH,
SFlowerY,
SFentryWidth + SFlineToTextH,
SFlistSize * SFentryHeight,
False);
SFdrawStrings(win, dir, 0, SFlistSize - 1);
}
}
static void
SFvAreaSelectedCallback(w, n, pnew)
Widget w;
XtPointer n;
XtPointer pnew;
{
SFDir *dir;
int nw = (int)(long)pnew;
dir = &(SFdirs[SFdirPtr + (int)(long)n]);
#ifdef FEAT_GUI_NEXTAW
if (nw < 0)
{
if (nw > -SFvScrollHeight)
nw = -1;
else
nw = -SFlistSize;
}
else if (nw > 0)
{
if (nw < SFvScrollHeight)
nw = 1;
else
nw = SFlistSize;
}
#endif
nw += dir->vOrigin;
if (nw > dir->nEntries - SFlistSize)
nw = dir->nEntries - SFlistSize;
if (nw < 0)
nw = 0;
if (dir->nEntries)
{
float f;
f = ((double) nw) / dir->nEntries;
#ifdef FEAT_GUI_NEXTAW
XawScrollbarSetThumb(
w,
f,
(float) (((double) ((dir->nEntries < SFlistSize) ?
dir->nEntries : SFlistSize)) / dir->nEntries));
#else
vim_XawScrollbarSetThumb(
w,
f,
(float) (((double) ((dir->nEntries < SFlistSize) ?
dir->nEntries : SFlistSize)) / dir->nEntries),
(double)dir->nEntries);
#endif
}
SFvSliderMovedCallback(w, (int)(long)n, nw);
}
static void
SFhSliderMovedCallback(w, n, nw)
Widget w UNUSED;
XtPointer n;
XtPointer nw;
{
SFDir *dir;
int save;
dir = &(SFdirs[SFdirPtr + (int)(long)n]);
save = dir->hOrigin;
dir->hOrigin = (*(float *)nw) * dir->nChars;
if (dir->hOrigin == save)
return;
SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
}
static void
SFhAreaSelectedCallback(w, n, pnew)
Widget w;
XtPointer n;
XtPointer pnew;
{
SFDir *dir;
int nw = (int)(long)pnew;
dir = &(SFdirs[SFdirPtr + (int)(long)n]);
#ifdef FEAT_GUI_NEXTAW
if (nw < 0)
{
if (nw > -SFhScrollWidth)
nw = -1;
else
nw = -SFcharsPerEntry;
}
else if (nw > 0)
{
if (nw < SFhScrollWidth)
nw = 1;
else
nw = SFcharsPerEntry;
}
#endif
nw += dir->hOrigin;
if (nw > dir->nChars - SFcharsPerEntry)
nw = dir->nChars - SFcharsPerEntry;
if (nw < 0)
nw = 0;
if (dir->nChars)
{
float f;
f = ((double) nw) / dir->nChars;
#ifdef FEAT_GUI_NEXTAW
XawScrollbarSetThumb(
w,
f,
(float) (((double) ((dir->nChars < SFcharsPerEntry) ?
dir->nChars : SFcharsPerEntry)) / dir->nChars));
#else
vim_XawScrollbarSetThumb(
w,
f,
(float) (((double) ((dir->nChars < SFcharsPerEntry) ?
dir->nChars : SFcharsPerEntry)) / dir->nChars),
(double)dir->nChars);
#endif
SFhSliderMovedCallback(w, n, (XtPointer)&f);
}
}
static void
SFpathSliderMovedCallback(w, client_data, nw)
Widget w UNUSED;
XtPointer client_data UNUSED;
XtPointer nw;
{
SFDir *dir;
int n;
XawTextPosition pos;
int SFdirPtrSave;
SFdirPtrSave = SFdirPtr;
SFdirPtr = (*(float *)nw) * SFdirEnd;
if (SFdirPtr == SFdirPtrSave)
return;
SFdrawLists(SF_DO_SCROLL);
n = 2;
while (SFdirPtr + n >= SFdirEnd)
n--;
dir = &(SFdirs[SFdirPtr + n]);
pos = dir->path - SFcurrentPath;
if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
{
pos -= strlen(SFstartDir);
if (pos < 0)
pos = 0;
}
XawTextSetInsertionPoint(selFileField, pos);
}
static void
SFpathAreaSelectedCallback(w, client_data, pnew)
Widget w;
XtPointer client_data UNUSED;
XtPointer pnew;
{
int nw = (int)(long)pnew;
float f;
#ifdef FEAT_GUI_NEXTAW
if (nw < 0)
{
if (nw > -SFpathScrollWidth)
nw = -1;
else
nw = -3;
}
else if (nw > 0)
{
if (nw < SFpathScrollWidth)
nw = 1;
else
nw = 3;
}
#endif
nw += SFdirPtr;
if (nw > SFdirEnd - 3)
nw = SFdirEnd - 3;
if (nw < 0)
nw = 0;
f = ((double) nw) / SFdirEnd;
#ifdef FEAT_GUI_NEXTAW
XawScrollbarSetThumb(
w,
f,
(float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd));
#else
vim_XawScrollbarSetThumb(
w,
f,
(float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd),
(double)SFdirEnd);
#endif
SFpathSliderMovedCallback(w, (XtPointer) NULL, (XtPointer)&f);
}
static Boolean
SFworkProc()
{
SFDir *dir;
SFEntry *entry;
for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
{
if (!(dir->nEntries))
continue;
for (entry = &(dir->entries[dir->nEntries - 1]);
entry >= dir->entries;
entry--)
{
if (!(entry->statDone))
{
(void)SFstatAndCheck(dir, entry);
return False;
}
}
}
SFworkProcAdded = 0;
return True;
}
/***************** Dir.c */
static int
SFcompareEntries(p, q)
const void *p;
const void *q;
{
return strcmp(((SFEntry *)p)->real, ((SFEntry *)q)->real);
}
static int
SFgetDir(dir)
SFDir *dir;
{
SFEntry *result = NULL;
int Alloc = 0;
int i;
DIR *dirp;
struct dirent *dp;
char *str;
int len;
int maxChars;
struct stat statBuf;
maxChars = strlen(dir->dir) - 1;
dir->entries = NULL;
dir->nEntries = 0;
dir->nChars = 0;
result = NULL;
i = 0;
dirp = opendir(".");
if (!dirp)
return 1;
(void)mch_stat(".", &statBuf);
dir->mtime = statBuf.st_mtime;
while ((dp = readdir(dirp)))
{
/* Ignore "." and ".." */
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
continue;
if (i >= Alloc)
{
Alloc = 2 * (Alloc + 1);
result = (SFEntry *) XtRealloc((char *) result,
(unsigned) (Alloc * sizeof(SFEntry)));
}
result[i].statDone = 0;
str = dp->d_name;
len = strlen(str);
result[i].real = XtMalloc((unsigned) (len + 2));
(void) strcat(strcpy(result[i].real, str), " ");
if (len > maxChars)
maxChars = len;
result[i].shown = result[i].real;
i++;
}
qsort((char *) result, (size_t) i, sizeof(SFEntry), SFcompareEntries);
dir->entries = result;
dir->nEntries = i;
dir->nChars = maxChars + 1;
closedir(dirp);
return 0;
}
/***************** SFinternal.h */
#include <sys/param.h>
#include <X11/cursorfont.h>
#include <X11/Composite.h>
#include <X11/Shell.h>
#ifdef FEAT_GUI_NEXTAW
# include <X11/neXtaw/Form.h>
# include <X11/neXtaw/Command.h>
# include <X11/neXtaw/Label.h>
#else
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Label.h>
#endif
static char *oneLineTextEditTranslations = "\
<Key>Return: redraw-display()\n\
Ctrl<Key>M: redraw-display()\n\
";
static void SFexposeList __ARGS((Widget w, XtPointer n, XEvent *event, Boolean *cont));
static void
SFexposeList(w, n, event, cont)
Widget w UNUSED;
XtPointer n;
XEvent *event;
Boolean *cont UNUSED;
{
if ((event->type == NoExpose) || event->xexpose.count)
return;
SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
}
static void SFmodVerifyCallback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont));
static void
SFmodVerifyCallback(w, client_data, event, cont)
Widget w UNUSED;
XtPointer client_data UNUSED;
XEvent *event;
Boolean *cont UNUSED;
{
char buf[2];
if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
((*buf) == '\r'))
SFstatus = SEL_FILE_OK;
else
SFstatus = SEL_FILE_TEXT;
}
static void SFokCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
static void
SFokCallback(w, cl, cd)
Widget w UNUSED;
XtPointer cl UNUSED;
XtPointer cd UNUSED;
{
SFstatus = SEL_FILE_OK;
}
static XtCallbackRec SFokSelect[] =
{
{ SFokCallback, (XtPointer) NULL },
{ NULL, (XtPointer) NULL },
};
static void SFcancelCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
static void
SFcancelCallback(w, cl, cd)
Widget w UNUSED;
XtPointer cl UNUSED;
XtPointer cd UNUSED;
{
SFstatus = SEL_FILE_CANCEL;
}
static XtCallbackRec SFcancelSelect[] =
{
{ SFcancelCallback, (XtPointer) NULL },
{ NULL, (XtPointer) NULL },
};
static void SFdismissAction __ARGS((Widget w, XEvent *event, String *params, Cardinal *num_params));
static void
SFdismissAction(w, event, params, num_params)
Widget w UNUSED;
XEvent *event;
String *params UNUSED;
Cardinal *num_params UNUSED;
{
if (event->type == ClientMessage
&& (Atom)event->xclient.data.l[0] != SFwmDeleteWindow)
return;
SFstatus = SEL_FILE_CANCEL;
}
static char *wmDeleteWindowTranslation = "\
<Message>WM_PROTOCOLS: SelFileDismiss()\n\
";
static XtActionsRec actions[] =
{
{"SelFileDismiss", SFdismissAction},
};
static void
SFsetColors(bg, fg, scroll_bg, scroll_fg)
guicolor_T bg;
guicolor_T fg;
guicolor_T scroll_bg;
guicolor_T scroll_fg;
{
if (selFileForm)
{
XtVaSetValues(selFileForm, XtNbackground, bg,
XtNforeground, fg,
XtNborderColor, bg,
NULL);
}
{
int i;
for (i = 0; i < 3; ++i)
{
if (selFileLists[i])
{
XtVaSetValues(selFileLists[i], XtNbackground, bg,
XtNforeground, fg,
XtNborderColor, fg,
NULL);
}
}
}
if (selFileOK)
{
XtVaSetValues(selFileOK, XtNbackground, bg,
XtNforeground, fg,
XtNborderColor, fg,
NULL);
}
if (selFileCancel)
{
XtVaSetValues(selFileCancel, XtNbackground, bg,
XtNforeground, fg,
XtNborderColor, fg,
NULL);
}
if (selFilePrompt)
{
XtVaSetValues(selFilePrompt, XtNbackground, bg,
XtNforeground, fg,
NULL);
}
if (gui.dpy)
{
XSetBackground(gui.dpy, SFtextGC, bg);
XSetForeground(gui.dpy, SFtextGC, fg);
XSetForeground(gui.dpy, SFlineGC, fg);
/* This is an xor GC, so combine the fg and background */
XSetBackground(gui.dpy, SFinvertGC, fg ^ bg);
XSetForeground(gui.dpy, SFinvertGC, fg ^ bg);
}
if (selFileHScroll)
{
XtVaSetValues(selFileHScroll, XtNbackground, scroll_bg,
XtNforeground, scroll_fg,
XtNborderColor, fg,
NULL);
}
{
int i;
for (i = 0; i < 3; i++)
{
XtVaSetValues(selFileVScrolls[i], XtNbackground, scroll_bg,
XtNforeground, scroll_fg,
XtNborderColor, fg,
NULL);
XtVaSetValues(selFileHScrolls[i], XtNbackground, scroll_bg,
XtNforeground, scroll_fg,
XtNborderColor, fg,
NULL);
}
}
}
static void
SFcreateWidgets(toplevel, prompt, ok, cancel)
Widget toplevel;
char *prompt;
char *ok;
char *cancel;
{
Cardinal n;
int listWidth, listHeight;
int listSpacing = 10;
int scrollThickness = 15;
int hScrollX, hScrollY;
int vScrollX, vScrollY;
selFile = XtVaAppCreateShell("selFile", "SelFile",
transientShellWidgetClass, SFdisplay,
XtNtransientFor, toplevel,
XtNtitle, prompt,
NULL);
/* Add WM_DELETE_WINDOW protocol */
XtAppAddActions(XtWidgetToApplicationContext(selFile),
actions, XtNumber(actions));
XtOverrideTranslations(selFile,
XtParseTranslationTable(wmDeleteWindowTranslation));
selFileForm = XtVaCreateManagedWidget("selFileForm",
formWidgetClass, selFile,
XtNdefaultDistance, 30,
XtNforeground, SFfore,
XtNbackground, SFback,
XtNborderColor, SFback,
NULL);
selFilePrompt = XtVaCreateManagedWidget("selFilePrompt",
labelWidgetClass, selFileForm,
XtNlabel, prompt,
XtNresizable, True,
XtNtop, XtChainTop,
XtNbottom, XtChainTop,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
XtNborderWidth, 0,
XtNforeground, SFfore,
XtNbackground, SFback,
NULL);
/*
XtVaGetValues(selFilePrompt,
XtNforeground, &SFfore,
XtNbackground, &SFback,
NULL);
*/
SFinitFont();
SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth +
SFbesideText;
SFentryHeight = SFaboveAndBelowText + SFcharHeight +
SFaboveAndBelowText;
listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
scrollThickness;
listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
SFlineToTextV + SFlistSize * SFentryHeight +
SFlineToTextV + 1 + scrollThickness;
SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;
hScrollX = -1;
hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
SFlineToTextV + SFlistSize * SFentryHeight +
SFlineToTextV;
SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
SFlineToTextV;
SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
SFlineToTextV;
SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
SFlineToTextV + SFlistSize * SFentryHeight - 1;
SFtextX = SFlineToTextH + SFbesideText;
SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
SFsegs[0].x1 = 0;
SFsegs[0].y1 = vScrollY;
SFsegs[0].x2 = vScrollX - 1;
SFsegs[0].y2 = vScrollY;
SFsegs[1].x1 = vScrollX;
SFsegs[1].y1 = 0;
SFsegs[1].x2 = vScrollX;
SFsegs[1].y2 = vScrollY - 1;
SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
SFlineToTextH + SFentryWidth - 1;
selFileField = XtVaCreateManagedWidget("selFileField",
asciiTextWidgetClass, selFileForm,
XtNwidth, 3 * listWidth + 2 * listSpacing + 4,
XtNborderColor, SFfore,
XtNfromVert, selFilePrompt,
XtNvertDistance, 10,
XtNresizable, True,
XtNtop, XtChainTop,
XtNbottom, XtChainTop,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
XtNstring, SFtextBuffer,
XtNlength, MAXPATHL,
XtNeditType, XawtextEdit,
XtNwrap, XawtextWrapWord,
XtNresize, XawtextResizeHeight,
XtNuseStringInPlace, True,
NULL);
XtOverrideTranslations(selFileField,
XtParseTranslationTable(oneLineTextEditTranslations));
XtSetKeyboardFocus(selFileForm, selFileField);
selFileHScroll = XtVaCreateManagedWidget("selFileHScroll",
#ifdef FEAT_GUI_NEXTAW
scrollbarWidgetClass, selFileForm,
#else
vim_scrollbarWidgetClass, selFileForm,
#endif
XtNorientation, XtorientHorizontal,
XtNwidth, SFpathScrollWidth,
XtNheight, scrollThickness,
XtNborderColor, SFfore,
XtNfromVert, selFileField,
XtNvertDistance, 30,
XtNtop, XtChainTop,
XtNbottom, XtChainTop,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
XtNforeground, gui.scroll_fg_pixel,
XtNbackground, gui.scroll_bg_pixel,
#ifndef FEAT_GUI_NEXTAW
XtNlimitThumb, 1,
#endif
NULL);
XtAddCallback(selFileHScroll, XtNjumpProc,
(XtCallbackProc) SFpathSliderMovedCallback, (XtPointer)NULL);
XtAddCallback(selFileHScroll, XtNscrollProc,
(XtCallbackProc) SFpathAreaSelectedCallback, (XtPointer)NULL);
selFileLists[0] = XtVaCreateManagedWidget("selFileList1",
compositeWidgetClass, selFileForm,
XtNwidth, listWidth,
XtNheight, listHeight,
XtNforeground, SFfore,
XtNbackground, SFback,
XtNborderColor, SFfore,
XtNfromVert, selFileHScroll,
XtNvertDistance, 10,
XtNtop, XtChainTop,
XtNbottom, XtChainTop,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
selFileLists[1] = XtVaCreateManagedWidget("selFileList2",
compositeWidgetClass, selFileForm,
XtNwidth, listWidth,
XtNheight, listHeight,
XtNforeground, SFfore,
XtNbackground, SFback,
XtNborderColor, SFfore,
XtNfromHoriz, selFileLists[0],
XtNfromVert, selFileHScroll,
XtNhorizDistance, listSpacing,
XtNvertDistance, 10,
XtNtop, XtChainTop,
XtNbottom, XtChainTop,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
selFileLists[2] = XtVaCreateManagedWidget("selFileList3",
compositeWidgetClass, selFileForm,
XtNwidth, listWidth,
XtNheight, listHeight,
XtNforeground, SFfore,
XtNbackground, SFback,
XtNborderColor, SFfore,
XtNfromHoriz, selFileLists[1],
XtNfromVert, selFileHScroll,
XtNhorizDistance, listSpacing,
XtNvertDistance, 10,
XtNtop, XtChainTop,
XtNbottom, XtChainTop,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
for (n = 0; n < 3; n++)
{
selFileVScrolls[n] = XtVaCreateManagedWidget("selFileVScroll",
#ifdef FEAT_GUI_NEXTAW
scrollbarWidgetClass, selFileLists[n],
#else
vim_scrollbarWidgetClass, selFileLists[n],
#endif
XtNx, vScrollX,
XtNy, vScrollY,
XtNwidth, scrollThickness,
XtNheight, SFvScrollHeight,
XtNborderColor, SFfore,
XtNforeground, gui.scroll_fg_pixel,
XtNbackground, gui.scroll_bg_pixel,
#ifndef FEAT_GUI_NEXTAW
XtNlimitThumb, 1,
#endif
NULL);
XtAddCallback(selFileVScrolls[n], XtNjumpProc,
(XtCallbackProc)SFvFloatSliderMovedCallback,
(XtPointer)(long_u)n);
XtAddCallback(selFileVScrolls[n], XtNscrollProc,
(XtCallbackProc)SFvAreaSelectedCallback, (XtPointer)(long_u)n);
selFileHScrolls[n] = XtVaCreateManagedWidget("selFileHScroll",
#ifdef FEAT_GUI_NEXTAW
scrollbarWidgetClass, selFileLists[n],
#else
vim_scrollbarWidgetClass, selFileLists[n],
#endif
XtNorientation, XtorientHorizontal,
XtNx, hScrollX,
XtNy, hScrollY,
XtNwidth, SFhScrollWidth,
XtNheight, scrollThickness,
XtNborderColor, SFfore,
XtNforeground, gui.scroll_fg_pixel,
XtNbackground, gui.scroll_bg_pixel,
#ifndef FEAT_GUI_NEXTAW
XtNlimitThumb, 1,
#endif
NULL);
XtAddCallback(selFileHScrolls[n], XtNjumpProc,
(XtCallbackProc)SFhSliderMovedCallback,
(XtPointer)(long_u)n);
XtAddCallback(selFileHScrolls[n], XtNscrollProc,
(XtCallbackProc)SFhAreaSelectedCallback, (XtPointer)(long_u)n);
}
selFileOK = XtVaCreateManagedWidget("selFileOK",
commandWidgetClass, selFileForm,
XtNlabel, ok,
XtNresizable, True,
XtNcallback, SFokSelect,
XtNforeground, SFfore,
XtNbackground, SFback,
XtNborderColor, SFfore,
XtNfromHoriz, selFileLists[0],
XtNfromVert, selFileLists[0],
XtNvertDistance, 30,
XtNtop, XtChainTop,
XtNbottom, XtChainTop,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
selFileCancel = XtVaCreateManagedWidget("selFileCancel",
commandWidgetClass, selFileForm,
XtNlabel, cancel,
XtNresizable, True,
XtNcallback, SFcancelSelect,
XtNforeground, SFfore,
XtNbackground, SFback,
XtNborderColor, SFfore,
XtNfromHoriz, selFileOK,
XtNfromVert, selFileLists[0],
XtNhorizDistance, 30,
XtNvertDistance, 30,
XtNtop, XtChainTop,
XtNbottom, XtChainTop,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
XtSetMappedWhenManaged(selFile, False);
XtRealizeWidget(selFile);
/* Add WM_DELETE_WINDOW protocol */
SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
SFcreateGC();
for (n = 0; n < 3; n++)
{
XtAddEventHandler(selFileLists[n], ExposureMask, True,
(XtEventHandler)SFexposeList, (XtPointer)(long_u)n);
XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
(XtEventHandler)SFenterList, (XtPointer)(long_u)n);
XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
(XtEventHandler)SFleaveList, (XtPointer)(long_u)n);
XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
(XtEventHandler)SFmotionList, (XtPointer)(long_u)n);
XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
(XtEventHandler)SFbuttonPressList, (XtPointer)(long_u)n);
XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
(XtEventHandler)SFbuttonReleaseList, (XtPointer)(long_u)n);
}
XtAddEventHandler(selFileField, KeyPressMask, False,
SFmodVerifyCallback, (XtPointer)NULL);
SFapp = XtWidgetToApplicationContext(selFile);
}
static void
SFtextChanged()
{
#if defined(FEAT_XFONTSET) && defined(XtNinternational)
if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
{
wchar_t *wcbuf=(wchar_t *)SFtextBuffer;
if ((wcbuf[0] == L'/') || (wcbuf[0] == L'~'))
{
(void) wcstombs(SFcurrentPath, wcbuf, MAXPATHL);
SFtextPos = XawTextGetInsertionPoint(selFileField);
}
else
{
strcpy(SFcurrentPath, SFstartDir);
(void) wcstombs(SFcurrentPath + strlen(SFcurrentPath), wcbuf, MAXPATHL);
SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
}
}
else
#endif
if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~'))
{
(void) strcpy(SFcurrentPath, SFtextBuffer);
SFtextPos = XawTextGetInsertionPoint(selFileField);
}
else
{
(void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
}
if (!SFworkProcAdded)
{
(void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
SFworkProcAdded = 1;
}
SFupdatePath();
}
static char *
SFgetText()
{
#if defined(FEAT_XFONTSET) && defined(XtNinternational)
char *buf;
if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
{
wchar_t *wcbuf;
int mbslength;
XtVaGetValues(selFileField,
XtNstring, &wcbuf,
NULL);
mbslength = wcstombs(NULL, wcbuf, 0);
/* Hack: some broken wcstombs() returns zero, just get a large buffer */
if (mbslength == 0 && wcbuf != NULL && wcbuf[0] != 0)
mbslength = MAXPATHL;
buf=(char *)XtMalloc(mbslength + 1);
wcstombs(buf, wcbuf, mbslength +1);
return buf;
}
#endif
return (char *)vim_strsave((char_u *)SFtextBuffer);
}
static void
SFprepareToReturn()
{
SFstatus = SEL_FILE_NULL;
XtRemoveGrab(selFile);
XtUnmapWidget(selFile);
XtRemoveTimeOut(SFdirModTimerId);
if (SFchdir(SFstartDir))
{
EMSG(_("E614: vim_SelFile: can't return to current directory"));
SFstatus = SEL_FILE_CANCEL;
}
}
char *
vim_SelFile(toplevel, prompt, init_path, show_entry, x, y, fg, bg, scroll_fg, scroll_bg)
Widget toplevel;
char *prompt;
char *init_path;
int (*show_entry)();
int x, y;
guicolor_T fg, bg;
guicolor_T scroll_fg, scroll_bg; /* The "Scrollbar" group colors */
{
static int firstTime = 1;
XEvent event;
char *name_return;
if (prompt == NULL)
prompt = _("Pathname:");
SFfore = fg;
SFback = bg;
if (mch_dirname((char_u *)SFstartDir, MAXPATHL) == FAIL)
{
EMSG(_("E615: vim_SelFile: can't get current directory"));
return NULL;
}
if (firstTime)
{
firstTime = 0;
SFdisplay = XtDisplay(toplevel);
SFcreateWidgets(toplevel, prompt, _("OK"), _("Cancel"));
}
else
{
XtVaSetValues(selFilePrompt, XtNlabel, prompt, NULL);
XtVaSetValues(selFile, XtNtitle, prompt, NULL);
SFsetColors(bg, fg, scroll_bg, scroll_fg);
}
XtVaSetValues(selFile, XtNx, x, XtNy, y, NULL);
XtMapWidget(selFile);
(void)strcat(SFstartDir, "/");
(void)strcpy(SFcurrentDir, SFstartDir);
if (init_path)
{
if (init_path[0] == '/')
{
(void)strcpy(SFcurrentPath, init_path);
if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
SFsetText(SFcurrentPath);
else
SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
}
else
{
(void)strcat(strcpy(SFcurrentPath, SFstartDir), init_path);
SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
}
}
else
(void)strcpy(SFcurrentPath, SFstartDir);
SFfunc = show_entry;
SFtextChanged();
XtAddGrab(selFile, True, True);
SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
SFdirModTimer, (XtPointer) NULL);
for (;;)
{
XtAppNextEvent(SFapp, &event);
XtDispatchEvent(&event);
switch (SFstatus)
{
case SEL_FILE_TEXT:
SFstatus = SEL_FILE_NULL;
SFtextChanged();
break;
case SEL_FILE_OK:
name_return = SFgetText();
SFprepareToReturn();
return name_return;
case SEL_FILE_CANCEL:
SFprepareToReturn();
return NULL;
case SEL_FILE_NULL:
break;
}
}
}
#endif /* FEAT_BROWSE */