home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / gui_at_fs.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-04  |  61.1 KB  |  2,881 lines

  1. /* vi:set ts=8 sts=4 sw=4: */
  2.  
  3. /*
  4.  * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for any purpose and without fee is hereby granted, provided
  8.  * that the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of Software Research Associates not be used
  11.  * in advertising or publicity pertaining to distribution of the software
  12.  * without specific, written prior permission.  Software Research Associates
  13.  * makes no representations about the suitability of this software for any
  14.  * purpose.  It is provided "as is" without express or implied warranty.
  15.  *
  16.  * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  17.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  18.  * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
  19.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  20.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  21.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  22.  * PERFORMANCE OF THIS SOFTWARE.
  23.  *
  24.  * Author: Erik M. van der Poel
  25.  *       Software Research Associates, Inc., Tokyo, Japan
  26.  *       erik@sra.co.jp
  27.  */
  28. /*
  29.  * Author's addresses:
  30.  *    erik@sra.co.jp
  31.  *    erik%sra.co.jp@uunet.uu.net
  32.  *    erik%sra.co.jp@mcvax.uucp
  33.  *    try junet instead of co.jp
  34.  *    Erik M. van der Poel
  35.  *    Software Research Associates, Inc.
  36.  *    1-1-1 Hirakawa-cho, Chiyoda-ku
  37.  *    Tokyo 102 Japan. TEL +81-3-234-2692
  38.  */
  39.  
  40. /*
  41.  * Heavely modified for Vim by Bram Moolenaar
  42.  */
  43.  
  44. #include "vim.h"
  45.  
  46. /* Only include this when using the file browser */
  47.  
  48. #ifdef FEAT_BROWSE
  49.  
  50. /* Weird complication: for "make lint" Text.h doesn't combine with Xm.h */
  51. #if defined(FEAT_GUI_MOTIF) && defined(FMT8BIT)
  52. # undef FMT8BIT
  53. #endif
  54.  
  55. #ifndef FEAT_GUI_NEXTAW
  56. # include "gui_at_sb.h"
  57. #endif
  58.  
  59. /***************** SFinternal.h */
  60.  
  61. #include <X11/Intrinsic.h>
  62. #include <X11/StringDefs.h>
  63. #include <X11/Xos.h>
  64. #ifdef FEAT_GUI_NEXTAW
  65. # include <X11/neXtaw/Text.h>
  66. # include <X11/neXtaw/AsciiText.h>
  67. # include <X11/neXtaw/Scrollbar.h>
  68. #else
  69. # include <X11/Xaw/Text.h>
  70. # include <X11/Xaw/AsciiText.h>
  71. #endif
  72.  
  73. #define SEL_FILE_CANCEL        -1
  74. #define SEL_FILE_OK        0
  75. #define SEL_FILE_NULL        1
  76. #define SEL_FILE_TEXT        2
  77.  
  78. #define SF_DO_SCROLL        1
  79. #define SF_DO_NOT_SCROLL    0
  80.  
  81. typedef struct
  82. {
  83.     int        statDone;
  84.     char    *real;
  85.     char    *shown;
  86. } SFEntry;
  87.  
  88. typedef struct
  89. {
  90.     char    *dir;
  91.     char    *path;
  92.     SFEntry    *entries;
  93.     int        nEntries;
  94.     int        vOrigin;
  95.     int        nChars;
  96.     int        hOrigin;
  97.     int        changed;
  98.     int        beginSelection;
  99.     int        endSelection;
  100.     time_t    mtime;
  101. } SFDir;
  102.  
  103. static char    SFstartDir[MAXPATHL],
  104.         SFcurrentPath[MAXPATHL],
  105.         SFcurrentDir[MAXPATHL];
  106.  
  107. static Widget    selFile,
  108.         selFileField,
  109.         selFileForm,
  110.         selFileHScroll,
  111.         selFileHScrolls[3],
  112.         selFileLists[3],
  113.         selFileOK,
  114.         selFileCancel,
  115.         selFilePrompt,
  116.         selFileVScrolls[3];
  117.  
  118. static Display    *SFdisplay;
  119.  
  120. static int    SFcharWidth, SFcharAscent, SFcharHeight;
  121.  
  122. static SFDir    *SFdirs = NULL;
  123.  
  124. static int    SFdirEnd;
  125. static int    SFdirPtr;
  126.  
  127. static Pixel    SFfore, SFback;
  128.  
  129. static Atom    SFwmDeleteWindow;
  130.  
  131. static XSegment SFsegs[2], SFcompletionSegs[2];
  132.  
  133. static XawTextPosition SFtextPos;
  134.  
  135. static int    SFupperX, SFlowerY, SFupperY;
  136.  
  137. static int    SFtextX, SFtextYoffset;
  138.  
  139. static int    SFentryWidth, SFentryHeight;
  140.  
  141. static int    SFlineToTextH = 3;
  142. static int    SFlineToTextV = 3;
  143.  
  144. static int    SFbesideText = 3;
  145. static int    SFaboveAndBelowText = 2;
  146.  
  147. static int    SFcharsPerEntry = 15;
  148.  
  149. static int    SFlistSize = 10;
  150.  
  151. static int    SFcurrentInvert[3] = { -1, -1, -1 };
  152.  
  153. static int    SFworkProcAdded = 0;
  154.  
  155. static XtAppContext SFapp;
  156.  
  157. static int    SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
  158.  
  159. #ifdef FEAT_XFONTSET
  160. static char    SFtextBuffer[MAXPATHL*sizeof(wchar_t)];
  161. #else
  162. static char    SFtextBuffer[MAXPATHL];
  163. #endif
  164.  
  165. static int    SFbuttonPressed = 0;
  166.  
  167. static XtIntervalId SFdirModTimerId;
  168.  
  169. static int    (*SFfunc)();
  170.  
  171. static int    SFstatus = SEL_FILE_NULL;
  172.  
  173. /***************** static functions */
  174.  
  175. static void SFsetText __ARGS((char *path));
  176. static void SFtextChanged __ARGS((void));
  177. static char *SFgetText __ARGS((void));
  178. static void SFupdatePath __ARGS((void));
  179. static int SFgetDir __ARGS((SFDir *dir));
  180. static void SFdrawLists __ARGS((int doScroll));
  181. static void SFdrawList __ARGS((int n, int doScroll));
  182. static void SFclearList __ARGS((int n, int doScroll));
  183. static void SFbuttonPressList __ARGS((Widget w, int n, XButtonPressedEvent *event));
  184. static void SFbuttonReleaseList __ARGS((Widget w, int n, XButtonReleasedEvent *event));
  185. static void SFdirModTimer __ARGS((XtPointer cl, XtIntervalId *id));
  186. static char SFstatChar __ARGS((struct stat *statBuf));
  187. static void SFdrawStrings __ARGS((Window w, SFDir *dir, int from, int to));
  188. static int SFnewInvertEntry __ARGS((int n, XMotionEvent *event));
  189. static void SFinvertEntry __ARGS((int n));
  190. static void SFenterList __ARGS((Widget w, int n, XEnterWindowEvent *event));
  191. static void SFleaveList __ARGS((Widget w, int n, XEvent *event));
  192. static void SFmotionList __ARGS((Widget w, int n, XMotionEvent *event));
  193. static void SFvFloatSliderMovedCallback __ARGS((Widget w, XtPointer n, XtPointer fnew));
  194. static void SFvSliderMovedCallback __ARGS((Widget w, int n, int nw));
  195. static void SFvAreaSelectedCallback __ARGS((Widget w, XtPointer n, XtPointer pnew));
  196. static void SFhSliderMovedCallback __ARGS((Widget w, XtPointer n, XtPointer nw));
  197. static void SFhAreaSelectedCallback __ARGS((Widget w, XtPointer n, XtPointer pnew));
  198. static void SFpathSliderMovedCallback __ARGS((Widget w, XtPointer client_data, XtPointer nw));
  199. static void SFpathAreaSelectedCallback __ARGS((Widget w, XtPointer client_data, XtPointer pnew));
  200. static Boolean SFworkProc __ARGS((void));
  201. static int SFcompareEntries __ARGS((const void *p, const void *q));
  202. static void SFprepareToReturn __ARGS((void));
  203. static void SFcreateWidgets __ARGS((Widget toplevel, char *prompt, char *ok, char *cancel));
  204. static void SFsetColors __ARGS((guicolor_T bg, guicolor_T fg, guicolor_T scroll_bg, guicolor_T scrollfg));
  205.  
  206. /***************** xstat.h */
  207.  
  208. #ifndef S_IXUSR
  209. # define S_IXUSR 0100
  210. #endif
  211. #ifndef S_IXGRP
  212. # define S_IXGRP 0010
  213. #endif
  214. #ifndef S_IXOTH
  215. # define S_IXOTH 0001
  216. #endif
  217.  
  218. #define S_ISXXX(m) ((m) & (S_IXUSR | S_IXGRP | S_IXOTH))
  219.  
  220. /***************** Path.c */
  221.  
  222. #include <pwd.h>
  223.  
  224. typedef struct
  225. {
  226.     char    *name;
  227.     char    *dir;
  228. } SFLogin;
  229.  
  230. static int    SFdoNotTouchDirPtr = 0;
  231.  
  232. static int    SFdoNotTouchVorigin = 0;
  233.  
  234. static SFDir    SFrootDir, SFhomeDir;
  235.  
  236. static SFLogin    *SFlogins;
  237.  
  238. static int    SFtwiddle = 0;
  239.  
  240. static int SFchdir __ARGS((char *path));
  241.  
  242.     static int
  243. SFchdir(path)
  244.     char    *path;
  245. {
  246.     int        result;
  247.  
  248.     result = 0;
  249.  
  250.     if (strcmp(path, SFcurrentDir))
  251.     {
  252.     result = mch_chdir(path);
  253.     if (!result)
  254.         (void) strcpy(SFcurrentDir, path);
  255.     }
  256.  
  257.     return result;
  258. }
  259.  
  260. static void SFfree __ARGS((int i));
  261.  
  262.     static void
  263. SFfree(i)
  264.     int    i;
  265. {
  266.     SFDir    *dir;
  267.     int        j;
  268.  
  269.     dir = &(SFdirs[i]);
  270.  
  271.     for (j = dir->nEntries - 1; j >= 0; j--)
  272.     {
  273.     if (dir->entries[j].shown != dir->entries[j].real)
  274.         XtFree(dir->entries[j].shown);
  275.     XtFree(dir->entries[j].real);
  276.     }
  277.  
  278.     XtFree((char *)dir->entries);
  279.     XtFree(dir->dir);
  280.  
  281.     dir->dir = NULL;
  282. }
  283.  
  284. static void SFstrdup __ARGS((char **s1, char *s2));
  285.  
  286.     static void
  287. SFstrdup(s1, s2)
  288.     char    **s1;
  289.     char    *s2;
  290. {
  291.     *s1 = strcpy(XtMalloc((unsigned)(strlen(s2) + 1)), s2);
  292. }
  293.  
  294. static void SFunreadableDir __ARGS((SFDir *dir));
  295.  
  296.     static void
  297. SFunreadableDir(dir)
  298.     SFDir    *dir;
  299. {
  300.     char    *cannotOpen = _("<cannot open> ");
  301.  
  302.     dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
  303.     dir->entries[0].statDone = 1;
  304.     SFstrdup(&dir->entries[0].real, cannotOpen);
  305.     dir->entries[0].shown = dir->entries[0].real;
  306.     dir->nEntries = 1;
  307.     dir->nChars = strlen(cannotOpen);
  308. }
  309.  
  310. static void SFreplaceText __ARGS((SFDir *dir, char *str));
  311.  
  312.     static void
  313. SFreplaceText(dir, str)
  314.     SFDir    *dir;
  315.     char    *str;
  316. {
  317.     int    len;
  318.  
  319.     *(dir->path) = 0;
  320.     len = strlen(str);
  321.     if (str[len - 1] == '/')
  322.     (void) strcat(SFcurrentPath, str);
  323.     else
  324.     (void) strncat(SFcurrentPath, str, len - 1);
  325.     if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
  326.     SFsetText(SFcurrentPath);
  327.     else
  328.     SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
  329.  
  330.     SFtextChanged();
  331. }
  332.  
  333. static void SFexpand __ARGS((char *str));
  334.  
  335.     static void
  336. SFexpand(str)
  337.     char    *str;
  338. {
  339.     int        len;
  340.     int        cmp;
  341.     char    *name, *growing;
  342.     SFDir    *dir;
  343.     SFEntry    *entry, *max;
  344.  
  345.     len = strlen(str);
  346.  
  347.     dir = &(SFdirs[SFdirEnd - 1]);
  348.  
  349.     if (dir->beginSelection == -1)
  350.     {
  351.     SFstrdup(&str, str);
  352.     SFreplaceText(dir, str);
  353.     XtFree(str);
  354.     return;
  355.     }
  356.     else if (dir->beginSelection == dir->endSelection)
  357.     {
  358.     SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
  359.     return;
  360.     }
  361.  
  362.     max = &(dir->entries[dir->endSelection + 1]);
  363.  
  364.     name = dir->entries[dir->beginSelection].shown;
  365.     SFstrdup(&growing, name);
  366.  
  367.     cmp = 0;
  368.     while (!cmp)
  369.     {
  370.     entry = &(dir->entries[dir->beginSelection]);
  371.     while (entry < max)
  372.     {
  373.         if ((cmp = strncmp(growing, entry->shown, len)))
  374.         break;
  375.         entry++;
  376.     }
  377.     len++;
  378.     }
  379.  
  380.     /*
  381.      * SFreplaceText() expects filename
  382.      */
  383.     growing[len - 2] = ' ';
  384.  
  385.     growing[len - 1] = 0;
  386.     SFreplaceText(dir, growing);
  387.     XtFree(growing);
  388. }
  389.  
  390. static int SFfindFile __ARGS((SFDir *dir, char *str));
  391.  
  392.     static int
  393. SFfindFile(dir, str)
  394.     SFDir    *dir;
  395.     char    *str;
  396. {
  397.     int        i, last, max;
  398.     char    *name, save;
  399.     SFEntry    *entries;
  400.     int        len;
  401.     int        begin, end;
  402.     int        result;
  403.  
  404.     len = strlen(str);
  405.  
  406.     if (str[len - 1] == ' ')
  407.     {
  408.     SFexpand(str);
  409.     return 1;
  410.     }
  411.     else if (str[len - 1] == '/')
  412.     len--;
  413.  
  414.     max = dir->nEntries;
  415.  
  416.     entries = dir->entries;
  417.  
  418.     i = 0;
  419.     while (i < max)
  420.     {
  421.     name = entries[i].shown;
  422.     last = strlen(name) - 1;
  423.     save = name[last];
  424.     name[last] = 0;
  425.  
  426.     result = strncmp(str, name, len);
  427.  
  428.     name[last] = save;
  429.     if (result <= 0)
  430.         break;
  431.     i++;
  432.     }
  433.     begin = i;
  434.     while (i < max)
  435.     {
  436.     name = entries[i].shown;
  437.     last = strlen(name) - 1;
  438.     save = name[last];
  439.     name[last] = 0;
  440.  
  441.     result = strncmp(str, name, len);
  442.  
  443.     name[last] = save;
  444.     if (result)
  445.         break;
  446.     i++;
  447.     }
  448.     end = i;
  449.  
  450.     if (begin != end)
  451.     {
  452.     if ((dir->beginSelection != begin) || (dir->endSelection != end - 1))
  453.     {
  454.         dir->changed = 1;
  455.         dir->beginSelection = begin;
  456.         if (str[strlen(str) - 1] == '/')
  457.         dir->endSelection = begin;
  458.         else
  459.         dir->endSelection = end - 1;
  460.     }
  461.     }
  462.     else if (dir->beginSelection != -1)
  463.     {
  464.     dir->changed = 1;
  465.     dir->beginSelection = -1;
  466.     dir->endSelection = -1;
  467.     }
  468.  
  469.     if (SFdoNotTouchVorigin
  470.         || ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize)))
  471.     {
  472.     SFdoNotTouchVorigin = 0;
  473.     return 0;
  474.     }
  475.  
  476.     i = begin - 1;
  477.     if (i > max - SFlistSize)
  478.     i = max - SFlistSize;
  479.     if (i < 0)
  480.     i = 0;
  481.  
  482.     if (dir->vOrigin != i)
  483.     {
  484.     dir->vOrigin = i;
  485.     dir->changed = 1;
  486.     }
  487.  
  488.     return 0;
  489. }
  490.  
  491. static void SFunselect __ARGS((void));
  492.  
  493.     static void
  494. SFunselect()
  495. {
  496.     SFDir    *dir;
  497.  
  498.     dir = &(SFdirs[SFdirEnd - 1]);
  499.     if (dir->beginSelection != -1)
  500.     dir->changed = 1;
  501.     dir->beginSelection = -1;
  502.     dir->endSelection = -1;
  503. }
  504.  
  505. static int SFcompareLogins __ARGS((const void *p, const void *q));
  506.  
  507.     static int
  508. SFcompareLogins(p, q)
  509.     const void *p, *q;
  510. {
  511.     return strcmp(((SFLogin *)p)->name, ((SFLogin *)q)->name);
  512. }
  513.  
  514. static void SFgetHomeDirs __ARGS((void));
  515.  
  516.     static void
  517. SFgetHomeDirs()
  518. {
  519.     struct    passwd    *pw;
  520.     int        Alloc;
  521.     int        i;
  522.     SFEntry    *entries = NULL;
  523.     int        len;
  524.     int        maxChars;
  525.  
  526.     Alloc = 1;
  527.     i = 1;
  528.     entries = (SFEntry *)XtMalloc(sizeof(SFEntry));
  529.     SFlogins = (SFLogin *)XtMalloc(sizeof(SFLogin));
  530.     entries[0].real = XtMalloc(3);
  531.     (void) strcpy(entries[0].real, "~");
  532.     entries[0].shown = entries[0].real;
  533.     entries[0].statDone = 1;
  534.     SFlogins[0].name = "";
  535.     pw = getpwuid((int) getuid());
  536.     SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
  537.     maxChars = 0;
  538.  
  539.     (void) setpwent();
  540.  
  541.     while ((pw = getpwent()) && (*(pw->pw_name)))
  542.     {
  543.     if (i >= Alloc)
  544.     {
  545.         Alloc *= 2;
  546.         entries = (SFEntry *) XtRealloc((char *)entries,
  547.                      (unsigned)(Alloc * sizeof(SFEntry)));
  548.         SFlogins = (SFLogin *) XtRealloc((char *)SFlogins,
  549.                      (unsigned)(Alloc * sizeof(SFLogin)));
  550.     }
  551.     len = strlen(pw->pw_name);
  552.     entries[i].real = XtMalloc((unsigned) (len + 3));
  553.     (void) strcat(strcpy(entries[i].real, "~"), pw->pw_name);
  554.     entries[i].shown = entries[i].real;
  555.     entries[i].statDone = 1;
  556.     if (len > maxChars)
  557.         maxChars = len;
  558.     SFstrdup(&SFlogins[i].name, pw->pw_name);
  559.     SFstrdup(&SFlogins[i].dir, pw->pw_dir);
  560.     i++;
  561.     }
  562.  
  563.     SFhomeDir.dir        = XtMalloc(1);
  564.     SFhomeDir.dir[0]        = 0;
  565.     SFhomeDir.path        = SFcurrentPath;
  566.     SFhomeDir.entries        = entries;
  567.     SFhomeDir.nEntries        = i;
  568.     SFhomeDir.vOrigin        = 0;    /* :-) */
  569.     SFhomeDir.nChars        = maxChars + 2;
  570.     SFhomeDir.hOrigin        = 0;
  571.     SFhomeDir.changed        = 1;
  572.     SFhomeDir.beginSelection    = -1;
  573.     SFhomeDir.endSelection    = -1;
  574.  
  575.     qsort((char *)entries, (size_t)i, sizeof(SFEntry), SFcompareEntries);
  576.     qsort((char *)SFlogins, (size_t)i, sizeof(SFLogin), SFcompareLogins);
  577.  
  578.     for (i--; i >= 0; i--)
  579.     (void)strcat(entries[i].real, "/");
  580. }
  581.  
  582. static int SFfindHomeDir __ARGS((char *begin, char *end));
  583.  
  584.     static int
  585. SFfindHomeDir(begin, end)
  586.     char    *begin, *end;
  587. {
  588.     char    save;
  589.     char    *theRest;
  590.     int    i;
  591.  
  592.     save = *end;
  593.     *end = 0;
  594.  
  595.     for (i = SFhomeDir.nEntries - 1; i >= 0; i--)
  596.     {
  597.     if (!strcmp(SFhomeDir.entries[i].real, begin))
  598.     {
  599.         *end = save;
  600.         SFstrdup(&theRest, end);
  601.         (void) strcat(strcat(strcpy(SFcurrentPath,
  602.                     SFlogins[i].dir), "/"), theRest);
  603.         XtFree(theRest);
  604.         SFsetText(SFcurrentPath);
  605.         SFtextChanged();
  606.         return 1;
  607.     }
  608.     }
  609.  
  610.     *end = save;
  611.  
  612.     return 0;
  613. }
  614.  
  615.     static void
  616. SFupdatePath()
  617. {
  618.     static int    Alloc;
  619.     static int    wasTwiddle = 0;
  620.     char    *begin, *end;
  621.     int        i, j;
  622.     int        prevChange;
  623.     int        SFdirPtrSave, SFdirEndSave;
  624.     SFDir    *dir;
  625.  
  626.     if (!SFdirs)
  627.     {
  628.     SFdirs = (SFDir *) XtMalloc((Alloc = 10) * sizeof(SFDir));
  629.     dir = &(SFdirs[0]);
  630.     SFstrdup(&dir->dir, "/");
  631.     (void) SFchdir("/");
  632.     (void) SFgetDir(dir);
  633.     for (j = 1; j < Alloc; j++)
  634.         SFdirs[j].dir = NULL;
  635.     dir->path = SFcurrentPath + 1;
  636.     dir->vOrigin = 0;
  637.     dir->hOrigin = 0;
  638.     dir->changed = 1;
  639.     dir->beginSelection = -1;
  640.     dir->endSelection = -1;
  641.     SFhomeDir.dir = NULL;
  642.     }
  643.  
  644.     SFdirEndSave = SFdirEnd;
  645.     SFdirEnd = 1;
  646.  
  647.     SFdirPtrSave = SFdirPtr;
  648.     SFdirPtr = 0;
  649.  
  650.     begin = NULL;
  651.  
  652.     if (SFcurrentPath[0] == '~')
  653.     {
  654.     if (!SFtwiddle)
  655.     {
  656.         SFtwiddle = 1;
  657.         dir = &(SFdirs[0]);
  658.         SFrootDir = *dir;
  659.         if (!SFhomeDir.dir)
  660.         SFgetHomeDirs();
  661.         *dir = SFhomeDir;
  662.         dir->changed = 1;
  663.     }
  664.     end = SFcurrentPath;
  665.     SFdoNotTouchDirPtr = 1;
  666.     wasTwiddle = 1;
  667.     }
  668.     else
  669.     {
  670.     if (SFtwiddle)
  671.     {
  672.         SFtwiddle = 0;
  673.         dir = &(SFdirs[0]);
  674.         *dir = SFrootDir;
  675.         dir->changed = 1;
  676.     }
  677.     end = SFcurrentPath + 1;
  678.     }
  679.  
  680.     i = 0;
  681.  
  682.     prevChange = 0;
  683.  
  684.     while (*end)
  685.     {
  686.     while (*end++ == '/')
  687.         ;
  688.     end--;
  689.     begin = end;
  690.     while ((*end) && (*end++ != '/'))
  691.         ;
  692.     if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/'))
  693.     {
  694.         SFdirPtr = i - 1;
  695.         if (SFdirPtr < 0)
  696.         SFdirPtr = 0;
  697.     }
  698.     if (*begin)
  699.     {
  700.         if (*(end - 1) == '/')
  701.         {
  702.         char save = *end;
  703.  
  704.         if (SFtwiddle)
  705.         {
  706.             if (SFfindHomeDir(begin, end))
  707.             return;
  708.         }
  709.         *end = 0;
  710.         i++;
  711.         SFdirEnd++;
  712.         if (i >= Alloc)
  713.         {
  714.             SFdirs = (SFDir *) XtRealloc((char *) SFdirs,
  715.                     (unsigned)((Alloc *= 2) * sizeof(SFDir)));
  716.             for (j = Alloc / 2; j < Alloc; j++)
  717.             SFdirs[j].dir = NULL;
  718.         }
  719.         dir = &(SFdirs[i]);
  720.         if ((!(dir->dir)) || prevChange || strcmp(dir->dir, begin))
  721.         {
  722.             if (dir->dir)
  723.             SFfree(i);
  724.             prevChange = 1;
  725.             SFstrdup(&dir->dir, begin);
  726.             dir->path = end;
  727.             dir->vOrigin = 0;
  728.             dir->hOrigin = 0;
  729.             dir->changed = 1;
  730.             dir->beginSelection = -1;
  731.             dir->endSelection = -1;
  732.             (void)SFfindFile(dir - 1, begin);
  733.             if (SFchdir(SFcurrentPath) || SFgetDir(dir))
  734.             {
  735.             SFunreadableDir(dir);
  736.             break;
  737.             }
  738.         }
  739.         *end = save;
  740.         if (!save)
  741.             SFunselect();
  742.         }
  743.         else
  744.         {
  745.         if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin))
  746.             return;
  747.         }
  748.     }
  749.     else
  750.         SFunselect();
  751.     }
  752.  
  753.     if ((end == SFcurrentPath + 1) && (!SFtwiddle))
  754.     SFunselect();
  755.  
  756.     for (i = SFdirEnd; i < Alloc; i++)
  757.     if (SFdirs[i].dir)
  758.         SFfree(i);
  759.  
  760.     if (SFdoNotTouchDirPtr)
  761.     {
  762.     if (wasTwiddle)
  763.     {
  764.         wasTwiddle = 0;
  765.         SFdirPtr = SFdirEnd - 2;
  766.         if (SFdirPtr < 0)
  767.         SFdirPtr = 0;
  768.     }
  769.     else
  770.         SFdirPtr = SFdirPtrSave;
  771.     SFdoNotTouchDirPtr = 0;
  772.     }
  773.  
  774.     if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave))
  775.     {
  776. #ifdef FEAT_GUI_NEXTAW
  777.     XawScrollbarSetThumb( selFileHScroll,
  778.         (float) (((double) SFdirPtr) / SFdirEnd),
  779.         (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
  780.              SFdirEnd));
  781. #else
  782.     vim_XawScrollbarSetThumb( selFileHScroll,
  783.         (float) (((double) SFdirPtr) / SFdirEnd),
  784.         (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
  785.              SFdirEnd),
  786.         (double)SFdirEnd);
  787. #endif
  788.     }
  789.  
  790.     if (SFdirPtr != SFdirPtrSave)
  791.     SFdrawLists(SF_DO_SCROLL);
  792.     else
  793.     for (i = 0; i < 3; i++)
  794.     {
  795.         if (SFdirPtr + i < SFdirEnd)
  796.         {
  797.         if (SFdirs[SFdirPtr + i].changed)
  798.         {
  799.             SFdirs[SFdirPtr + i].changed = 0;
  800.             SFdrawList(i, SF_DO_SCROLL);
  801.         }
  802.         }
  803.         else
  804.         SFclearList(i, SF_DO_SCROLL);
  805.     }
  806. }
  807.  
  808. #ifdef XtNinternational
  809.     static int
  810. WcsLen(p)
  811.     wchar_t *p;
  812. {
  813.     int i = 0;
  814.     while (*p++ != 0)
  815.     i++;
  816.     return i;
  817. }
  818. #endif
  819.  
  820.     static void
  821. SFsetText(path)
  822.     char    *path;
  823. {
  824.     XawTextBlock    text;
  825.  
  826.     text.firstPos = 0;
  827.     text.length = strlen(path);
  828.     text.ptr = path;
  829.     text.format = FMT8BIT;
  830.  
  831. #ifdef XtNinternational
  832.     if (_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
  833.     {
  834.     XawTextReplace(selFileField, (XawTextPosition)0,
  835.                     (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0]), &text);
  836.     XawTextSetInsertionPoint(selFileField,
  837.                        (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0]));
  838.     }
  839.     else
  840.     {
  841.     XawTextReplace(selFileField, (XawTextPosition)0,
  842.                     (XawTextPosition)strlen(SFtextBuffer), &text);
  843.     XawTextSetInsertionPoint(selFileField,
  844.                        (XawTextPosition)strlen(SFtextBuffer));
  845.     }
  846. #else
  847.     XawTextReplace(selFileField, (XawTextPosition)0,
  848.                 (XawTextPosition)strlen(SFtextBuffer), &text);
  849.     XawTextSetInsertionPoint(selFileField,
  850.                        (XawTextPosition)strlen(SFtextBuffer));
  851. #endif
  852. }
  853.  
  854. /* ARGSUSED */
  855.     static void
  856. SFbuttonPressList(w, n, event)
  857.     Widget        w;
  858.     int            n;
  859.     XButtonPressedEvent    *event;
  860. {
  861.     SFbuttonPressed = 1;
  862. }
  863.  
  864. /* ARGSUSED */
  865.     static void
  866. SFbuttonReleaseList(w, n, event)
  867.     Widget         w;
  868.     int             n;
  869.     XButtonReleasedEvent *event;
  870. {
  871.     SFDir    *dir;
  872.  
  873.     SFbuttonPressed = 0;
  874.  
  875.     if (SFcurrentInvert[n] != -1)
  876.     {
  877.     if (n < 2)
  878.         SFdoNotTouchDirPtr = 1;
  879.     SFdoNotTouchVorigin = 1;
  880.     dir = &(SFdirs[SFdirPtr + n]);
  881.     SFreplaceText(dir,
  882.                dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown);
  883.     SFmotionList(w, n, (XMotionEvent *) event);
  884.     }
  885. }
  886.  
  887. static int SFcheckDir __ARGS((int n, SFDir *dir));
  888.  
  889.     static int
  890. SFcheckDir(n, dir)
  891.     int        n;
  892.     SFDir        *dir;
  893. {
  894.     struct stat    statBuf;
  895.     int        i;
  896.  
  897.     if ((!mch_stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime))
  898.     {
  899.     /*
  900.      * If the pointer is currently in the window that we are about
  901.      * to update, we must warp it to prevent the user from
  902.      * accidentally selecting the wrong file.
  903.      */
  904.     if (SFcurrentInvert[n] != -1)
  905.     {
  906.         XWarpPointer(
  907.             SFdisplay,
  908.             None,
  909.             XtWindow(selFileLists[n]),
  910.             0,
  911.             0,
  912.             0,
  913.             0,
  914.             0,
  915.             0);
  916.     }
  917.  
  918.     for (i = dir->nEntries - 1; i >= 0; i--)
  919.     {
  920.         if (dir->entries[i].shown != dir->entries[i].real)
  921.         XtFree(dir->entries[i].shown);
  922.         XtFree(dir->entries[i].real);
  923.     }
  924.     XtFree((char *) dir->entries);
  925.     if (SFgetDir(dir))
  926.         SFunreadableDir(dir);
  927.     if (dir->vOrigin > dir->nEntries - SFlistSize)
  928.         dir->vOrigin = dir->nEntries - SFlistSize;
  929.     if (dir->vOrigin < 0)
  930.         dir->vOrigin = 0;
  931.     if (dir->hOrigin > dir->nChars - SFcharsPerEntry)
  932.         dir->hOrigin = dir->nChars - SFcharsPerEntry;
  933.     if (dir->hOrigin < 0)
  934.         dir->hOrigin = 0;
  935.     dir->beginSelection = -1;
  936.     dir->endSelection = -1;
  937.     SFdoNotTouchVorigin = 1;
  938.     if ((dir + 1)->dir)
  939.         (void) SFfindFile(dir, (dir + 1)->dir);
  940.     else
  941.         (void) SFfindFile(dir, dir->path);
  942.  
  943.     if (!SFworkProcAdded)
  944.     {
  945.         (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
  946.         SFworkProcAdded = 1;
  947.     }
  948.     return 1;
  949.     }
  950.     return 0;
  951. }
  952.  
  953. static int SFcheckFiles __ARGS((SFDir *dir));
  954.  
  955.     static int
  956. SFcheckFiles(dir)
  957.     SFDir    *dir;
  958. {
  959.     int        from, to;
  960.     int        result;
  961.     char    oldc, newc;
  962.     int        i;
  963.     char    *str;
  964.     int        last;
  965.     struct stat    statBuf;
  966.  
  967.     result = 0;
  968.  
  969.     from = dir->vOrigin;
  970.     to = dir->vOrigin + SFlistSize;
  971.     if (to > dir->nEntries)
  972.     to = dir->nEntries;
  973.  
  974.     for (i = from; i < to; i++)
  975.     {
  976.     str = dir->entries[i].real;
  977.     last = strlen(str) - 1;
  978.     oldc = str[last];
  979.     str[last] = 0;
  980.     if (mch_stat(str, &statBuf))
  981.         newc = ' ';
  982.     else
  983.         newc = SFstatChar(&statBuf);
  984.     str[last] = newc;
  985.     if (newc != oldc)
  986.         result = 1;
  987.     }
  988.  
  989.     return result;
  990. }
  991.  
  992. /* ARGSUSED */
  993.     static void
  994. SFdirModTimer(cl, id)
  995.     XtPointer        cl;
  996.     XtIntervalId    *id;
  997. {
  998.     static int        n = -1;
  999.     static int        f = 0;
  1000.     char        save;
  1001.     SFDir        *dir;
  1002.  
  1003.     if ((!SFtwiddle) && (SFdirPtr < SFdirEnd))
  1004.     {
  1005.     n++;
  1006.     if ((n > 2) || (SFdirPtr + n >= SFdirEnd))
  1007.     {
  1008.         n = 0;
  1009.         f++;
  1010.         if ((f > 2) || (SFdirPtr + f >= SFdirEnd))
  1011.         f = 0;
  1012.     }
  1013.     dir = &(SFdirs[SFdirPtr + n]);
  1014.     save = *(dir->path);
  1015.     *(dir->path) = 0;
  1016.     if (SFchdir(SFcurrentPath))
  1017.     {
  1018.         *(dir->path) = save;
  1019.  
  1020.         /*
  1021.          * force a re-read
  1022.          */
  1023.         *(dir->dir) = 0;
  1024.  
  1025.         SFupdatePath();
  1026.     }
  1027.     else
  1028.     {
  1029.         *(dir->path) = save;
  1030.         if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir)))
  1031.         SFdrawList(n, SF_DO_SCROLL);
  1032.     }
  1033.     }
  1034.  
  1035.     SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
  1036.         SFdirModTimer, (XtPointer) NULL);
  1037. }
  1038.  
  1039. /* Return a single character describing what kind of file STATBUF is.  */
  1040.  
  1041.     static char
  1042. SFstatChar(statBuf)
  1043.     struct stat *statBuf;
  1044. {
  1045.     if (S_ISDIR (statBuf->st_mode))
  1046.     return '/';
  1047.     if (S_ISREG (statBuf->st_mode))
  1048.     return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
  1049. #ifdef S_ISSOCK
  1050.     if (S_ISSOCK (statBuf->st_mode))
  1051.     return '=';
  1052. #endif /* S_ISSOCK */
  1053.     return ' ';
  1054. }
  1055.  
  1056. /***************** Draw.c */
  1057.  
  1058. #ifdef FEAT_GUI_NEXTAW
  1059. # include <X11/neXtaw/Cardinals.h>
  1060. #else
  1061. # include <X11/Xaw/Cardinals.h>
  1062. #endif
  1063.  
  1064. #ifdef FEAT_XFONTSET
  1065. # define SF_DEFAULT_FONT "-misc-fixed-medium-r-normal--14-*"
  1066. #else
  1067. # define SF_DEFAULT_FONT "9x15"
  1068. #endif
  1069.  
  1070. #ifdef ABS
  1071. # undef ABS
  1072. #endif
  1073. #define ABS(x) (((x) < 0) ? (-(x)) : (x))
  1074.  
  1075. typedef struct
  1076. {
  1077.     char *fontname;
  1078. } TextData;
  1079.  
  1080. static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
  1081.  
  1082. static XtResource textResources[] =
  1083. {
  1084. #ifdef FEAT_XFONTSET
  1085.     {XtNfontSet, XtCFontSet, XtRString, sizeof (char *),
  1086.         XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT},
  1087. #else
  1088.     {XtNfont, XtCFont, XtRString, sizeof (char *),
  1089.         XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT},
  1090. #endif
  1091. };
  1092.  
  1093. #ifdef FEAT_XFONTSET
  1094. static XFontSet SFfont;
  1095. #else
  1096. static XFontStruct *SFfont;
  1097. #endif
  1098.  
  1099. static int SFcurrentListY;
  1100.  
  1101. static XtIntervalId SFscrollTimerId;
  1102.  
  1103. static void SFinitFont __ARGS((void));
  1104.  
  1105.     static void
  1106. SFinitFont()
  1107. {
  1108.     TextData    *data;
  1109. #ifdef FEAT_XFONTSET
  1110.     XFontSetExtents *extents;
  1111.     char **missing, *def_str;
  1112.     int  num_missing;
  1113. #endif
  1114.  
  1115.     data = XtNew(TextData);
  1116.  
  1117.     XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
  1118.         XtNumber(textResources), (Arg *) NULL, ZERO);
  1119.  
  1120. #ifdef FEAT_XFONTSET
  1121.     SFfont = XCreateFontSet(SFdisplay, data->fontname,
  1122.                 &missing, &num_missing, &def_str);
  1123. #else
  1124.     SFfont = XLoadQueryFont(SFdisplay, data->fontname);
  1125. #endif
  1126.     if (!SFfont)
  1127.     {
  1128. #ifdef FEAT_XFONTSET
  1129.     SFfont = XCreateFontSet(SFdisplay, SF_DEFAULT_FONT,
  1130.                         &missing, &num_missing, &def_str);
  1131. #else
  1132.     SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);
  1133. #endif
  1134.     if (!SFfont)
  1135.     {
  1136.         EMSG2(_("E616: vim_SelFile: can't get font %s"), SF_DEFAULT_FONT);
  1137.         SFstatus = SEL_FILE_CANCEL;
  1138.         return;
  1139.     }
  1140.     }
  1141.  
  1142. #ifdef FEAT_XFONTSET
  1143.     extents = XExtentsOfFontSet(SFfont);
  1144.     SFcharWidth = extents->max_logical_extent.width;
  1145.     SFcharAscent = -extents->max_logical_extent.y;
  1146.     SFcharHeight = extents->max_logical_extent.height;
  1147. #else
  1148.     SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;
  1149.     SFcharAscent = SFfont->max_bounds.ascent;
  1150.     SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;
  1151. #endif
  1152. }
  1153.  
  1154. static void SFcreateGC __ARGS((void));
  1155.  
  1156.     static void
  1157. SFcreateGC()
  1158. {
  1159.     XGCValues    gcValues;
  1160.     XRectangle    rectangles[1];
  1161.  
  1162.     gcValues.foreground = SFfore;
  1163.  
  1164.     SFlineGC = XtGetGC(
  1165.         selFileLists[0],
  1166.         (XtGCMask)GCForeground,
  1167.         &gcValues);
  1168.  
  1169.     SFscrollGC = XtGetGC(
  1170.         selFileLists[0],
  1171.         (XtGCMask)0,
  1172.         &gcValues);
  1173.  
  1174.     gcValues.function = GXxor;
  1175.     gcValues.foreground = SFfore ^ SFback;
  1176.     gcValues.background = SFfore ^ SFback;
  1177.  
  1178.     SFinvertGC = XtGetGC(
  1179.         selFileLists[0],
  1180.         (XtGCMask)GCFunction | GCForeground | GCBackground,
  1181.         &gcValues);
  1182.  
  1183.     gcValues.foreground = SFfore;
  1184.     gcValues.background = SFback;
  1185. #ifndef FEAT_XFONTSET
  1186.     gcValues.font = SFfont->fid;
  1187. #endif
  1188.  
  1189.     SFtextGC = XCreateGC(
  1190.         SFdisplay,
  1191.         XtWindow(selFileLists[0]),
  1192. #ifdef FEAT_XFONTSET
  1193.         (unsigned long)GCForeground | GCBackground,
  1194. #else
  1195.         (unsigned long)GCForeground | GCBackground | GCFont,
  1196. #endif
  1197.         &gcValues);
  1198.  
  1199.     rectangles[0].x = SFlineToTextH + SFbesideText;
  1200.     rectangles[0].y = 0;
  1201.     rectangles[0].width = SFcharsPerEntry * SFcharWidth;
  1202.     rectangles[0].height = SFupperY + 1;
  1203.  
  1204.     XSetClipRectangles(
  1205.         SFdisplay,
  1206.         SFtextGC,
  1207.         0,
  1208.         0,
  1209.         rectangles,
  1210.         1,
  1211.         Unsorted);
  1212. }
  1213.  
  1214.     static void
  1215. SFclearList(n, doScroll)
  1216.     int    n;
  1217.     int    doScroll;
  1218. {
  1219.     SFDir    *dir;
  1220.  
  1221.     SFcurrentInvert[n] = -1;
  1222.  
  1223.     XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
  1224.  
  1225.     XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2);
  1226.  
  1227.     if (doScroll)
  1228.     {
  1229.     dir = &(SFdirs[SFdirPtr + n]);
  1230.  
  1231.     if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars)
  1232.     {
  1233. #ifdef FEAT_GUI_NEXTAW
  1234.         XawScrollbarSetThumb(
  1235.             selFileVScrolls[n],
  1236.             (float) (((double) dir->vOrigin) /
  1237.                  dir->nEntries),
  1238.             (float) (((double) ((dir->nEntries < SFlistSize)
  1239.                     ? dir->nEntries : SFlistSize)) /
  1240.                  dir->nEntries));
  1241. #else
  1242.         vim_XawScrollbarSetThumb(
  1243.             selFileVScrolls[n],
  1244.             (float) (((double) dir->vOrigin) /
  1245.                  dir->nEntries),
  1246.             (float) (((double) ((dir->nEntries < SFlistSize)
  1247.                     ? dir->nEntries : SFlistSize)) /
  1248.                  dir->nEntries),
  1249.             (double)dir->nEntries);
  1250. #endif
  1251.  
  1252. #ifdef FEAT_GUI_NEXTAW
  1253.         XawScrollbarSetThumb(
  1254.             selFileHScrolls[n],
  1255.             (float) (((double) dir->hOrigin) / dir->nChars),
  1256.             (float) (((double) ((dir->nChars <
  1257.                      SFcharsPerEntry) ? dir->nChars :
  1258.                     SFcharsPerEntry)) / dir->nChars));
  1259. #else
  1260.         vim_XawScrollbarSetThumb(
  1261.             selFileHScrolls[n],
  1262.             (float) (((double) dir->hOrigin) / dir->nChars),
  1263.             (float) (((double) ((dir->nChars <
  1264.                      SFcharsPerEntry) ? dir->nChars :
  1265.                     SFcharsPerEntry)) / dir->nChars),
  1266.             (double)dir->nChars);
  1267. #endif
  1268.     }
  1269.     else
  1270.     {
  1271. #ifdef FEAT_GUI_NEXTAW
  1272.         XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
  1273.             (float) 1.0);
  1274. #else
  1275.         vim_XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
  1276.             (float) 1.0, 1.0);
  1277. #endif
  1278. #ifdef FEAT_GUI_NEXTAW
  1279.         XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
  1280.             (float) 1.0);
  1281. #else
  1282.         vim_XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
  1283.             (float) 1.0, 1.0);
  1284. #endif
  1285.     }
  1286.     }
  1287. }
  1288.  
  1289. static void SFdeleteEntry __ARGS((SFDir *dir, SFEntry *entry));
  1290.  
  1291.     static void
  1292. SFdeleteEntry(dir, entry)
  1293.     SFDir    *dir;
  1294.     SFEntry    *entry;
  1295. {
  1296.     SFEntry    *e;
  1297.     SFEntry    *end;
  1298.     int        n;
  1299.     int        idx;
  1300.  
  1301.     idx = entry - dir->entries;
  1302.  
  1303.     if (idx < dir->beginSelection)
  1304.     dir->beginSelection--;
  1305.     if (idx <= dir->endSelection)
  1306.     dir->endSelection--;
  1307.     if (dir->beginSelection > dir->endSelection)
  1308.     dir->beginSelection = dir->endSelection = -1;
  1309.  
  1310.     if (idx < dir->vOrigin)
  1311.     dir->vOrigin--;
  1312.  
  1313.     XtFree(entry->real);
  1314.  
  1315.     end = &(dir->entries[dir->nEntries - 1]);
  1316.  
  1317.     for (e = entry; e < end; e++)
  1318.     *e = *(e + 1);
  1319.  
  1320.     if (!(--dir->nEntries))
  1321.     return;
  1322.  
  1323.     n = dir - &(SFdirs[SFdirPtr]);
  1324.     if ((n < 0) || (n > 2))
  1325.     return;
  1326.  
  1327. #ifdef FEAT_GUI_NEXTAW
  1328.     XawScrollbarSetThumb(
  1329.         selFileVScrolls[n],
  1330.         (float) (((double) dir->vOrigin) / dir->nEntries),
  1331.         (float) (((double) ((dir->nEntries < SFlistSize) ?
  1332.                 dir->nEntries : SFlistSize)) / dir->nEntries));
  1333. #else
  1334.     vim_XawScrollbarSetThumb(
  1335.         selFileVScrolls[n],
  1336.         (float) (((double) dir->vOrigin) / dir->nEntries),
  1337.         (float) (((double) ((dir->nEntries < SFlistSize) ?
  1338.                 dir->nEntries : SFlistSize)) / dir->nEntries),
  1339.         (double)dir->nEntries);
  1340. #endif
  1341. }
  1342.  
  1343. static void SFwriteStatChar __ARGS((char *name, int last, struct stat *statBuf));
  1344.  
  1345.     static void
  1346. SFwriteStatChar(name, last, statBuf)
  1347.     char    *name;
  1348.     int        last;
  1349.     struct stat    *statBuf;
  1350. {
  1351.     name[last] = SFstatChar(statBuf);
  1352. }
  1353.  
  1354. static int SFstatAndCheck __ARGS((SFDir *dir, SFEntry *entry));
  1355.  
  1356.     static int
  1357. SFstatAndCheck(dir, entry)
  1358.     SFDir    *dir;
  1359.     SFEntry    *entry;
  1360. {
  1361.     struct stat    statBuf;
  1362.     char    save;
  1363.     int        last;
  1364.  
  1365.     /*
  1366.      * must be restored before returning
  1367.      */
  1368.     save = *(dir->path);
  1369.     *(dir->path) = 0;
  1370.  
  1371.     if (!SFchdir(SFcurrentPath))
  1372.     {
  1373.     last = strlen(entry->real) - 1;
  1374.     entry->real[last] = 0;
  1375.     entry->statDone = 1;
  1376.     if ((!mch_stat(entry->real, &statBuf))
  1377. #ifdef S_IFLNK
  1378.         || (!mch_lstat(entry->real, &statBuf))
  1379. #endif
  1380.        )
  1381.     {
  1382.         if (SFfunc)
  1383.         {
  1384.         char *shown;
  1385.  
  1386.         shown = NULL;
  1387.         if (SFfunc(entry->real, &shown, &statBuf))
  1388.         {
  1389.             if (shown)
  1390.             {
  1391.             int len;
  1392.  
  1393.             len = strlen(shown);
  1394.             entry->shown = XtMalloc((unsigned) (len + 2));
  1395.             (void) strcpy(entry->shown, shown);
  1396.             SFwriteStatChar(entry->shown, len, &statBuf);
  1397.             entry->shown[len + 1] = 0;
  1398.             }
  1399.         }
  1400.         else
  1401.         {
  1402.             SFdeleteEntry(dir, entry);
  1403.  
  1404.             *(dir->path) = save;
  1405.             return 1;
  1406.         }
  1407.         }
  1408.         SFwriteStatChar(entry->real, last, &statBuf);
  1409.     }
  1410.     else
  1411.         entry->real[last] = ' ';
  1412.     }
  1413.  
  1414.     *(dir->path) = save;
  1415.     return 0;
  1416. }
  1417.  
  1418.  
  1419.     static void
  1420. SFdrawStrings(w, dir, from, to)
  1421.     Window    w;
  1422.     SFDir    *dir;
  1423.     int        from;
  1424.     int        to;
  1425. {
  1426.     int        i;
  1427.     SFEntry    *entry;
  1428.     int        x;
  1429.  
  1430.     x = SFtextX - dir->hOrigin * SFcharWidth;
  1431.  
  1432.     if (dir->vOrigin + to >= dir->nEntries)
  1433.     to = dir->nEntries - dir->vOrigin - 1;
  1434.     for (i = from; i <= to; i++)
  1435.     {
  1436.     entry = &(dir->entries[dir->vOrigin + i]);
  1437.     if (!(entry->statDone))
  1438.     {
  1439.         if (SFstatAndCheck(dir, entry))
  1440.         {
  1441.         if (dir->vOrigin + to >= dir->nEntries)
  1442.             to = dir->nEntries - dir->vOrigin - 1;
  1443.         i--;
  1444.         continue;
  1445.         }
  1446.     }
  1447. #ifdef FEAT_XFONTSET
  1448.     XmbDrawImageString(
  1449.         SFdisplay,
  1450.         w,
  1451.         SFfont,
  1452.         SFtextGC,
  1453.         x,
  1454.         SFtextYoffset + i * SFentryHeight,
  1455.         entry->shown,
  1456.         strlen(entry->shown));
  1457. #else
  1458.     XDrawImageString(
  1459.         SFdisplay,
  1460.         w,
  1461.         SFtextGC,
  1462.         x,
  1463.         SFtextYoffset + i * SFentryHeight,
  1464.         entry->shown,
  1465.         strlen(entry->shown));
  1466. #endif
  1467.     if (dir->vOrigin + i == dir->beginSelection)
  1468.     {
  1469.         XDrawLine(
  1470.             SFdisplay,
  1471.             w,
  1472.             SFlineGC,
  1473.             SFlineToTextH + 1,
  1474.             SFlowerY + i * SFentryHeight,
  1475.             SFlineToTextH + SFentryWidth - 2,
  1476.             SFlowerY + i * SFentryHeight);
  1477.     }
  1478.     if ((dir->vOrigin + i >= dir->beginSelection) &&
  1479.         (dir->vOrigin + i <= dir->endSelection))
  1480.     {
  1481.         SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
  1482.         SFlowerY + i * SFentryHeight;
  1483.         SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
  1484.         SFlowerY + (i + 1) * SFentryHeight - 1;
  1485.         XDrawSegments(
  1486.             SFdisplay,
  1487.             w,
  1488.             SFlineGC,
  1489.             SFcompletionSegs,
  1490.             2);
  1491.     }
  1492.     if (dir->vOrigin + i == dir->endSelection)
  1493.     {
  1494.         XDrawLine(
  1495.             SFdisplay,
  1496.             w,
  1497.             SFlineGC,
  1498.             SFlineToTextH + 1,
  1499.             SFlowerY + (i + 1) * SFentryHeight - 1,
  1500.             SFlineToTextH + SFentryWidth - 2,
  1501.             SFlowerY + (i + 1) * SFentryHeight - 1);
  1502.     }
  1503.     }
  1504. }
  1505.  
  1506.     static void
  1507. SFdrawList(n, doScroll)
  1508.     int    n;
  1509.     int    doScroll;
  1510. {
  1511.     SFDir    *dir;
  1512.     Window    w;
  1513.  
  1514.     SFclearList(n, doScroll);
  1515.  
  1516.     if (SFdirPtr + n < SFdirEnd)
  1517.     {
  1518.     dir = &(SFdirs[SFdirPtr + n]);
  1519.     w = XtWindow(selFileLists[n]);
  1520. #ifdef FEAT_XFONTSET
  1521.     XmbDrawImageString(
  1522.         SFdisplay,
  1523.         w,
  1524.         SFfont,
  1525.         SFtextGC,
  1526.         SFtextX - dir->hOrigin * SFcharWidth,
  1527.         SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
  1528.         dir->dir,
  1529.         strlen(dir->dir));
  1530. #else
  1531.     XDrawImageString(
  1532.         SFdisplay,
  1533.         w,
  1534.         SFtextGC,
  1535.         SFtextX - dir->hOrigin * SFcharWidth,
  1536.         SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
  1537.         dir->dir,
  1538.         strlen(dir->dir));
  1539. #endif
  1540.     SFdrawStrings(w, dir, 0, SFlistSize - 1);
  1541.     }
  1542. }
  1543.  
  1544.     static void
  1545. SFdrawLists(doScroll)
  1546.     int    doScroll;
  1547. {
  1548.     int    i;
  1549.  
  1550.     for (i = 0; i < 3; i++)
  1551.     SFdrawList(i, doScroll);
  1552. }
  1553.  
  1554.     static void
  1555. SFinvertEntry(n)
  1556.     int        n;
  1557. {
  1558.     XFillRectangle(
  1559.         SFdisplay,
  1560.         XtWindow(selFileLists[n]),
  1561.         SFinvertGC,
  1562.         SFlineToTextH,
  1563.         SFcurrentInvert[n] * SFentryHeight + SFlowerY,
  1564.         SFentryWidth,
  1565.         SFentryHeight);
  1566. }
  1567.  
  1568. static unsigned long SFscrollTimerInterval __ARGS((void));
  1569.  
  1570.     static unsigned long
  1571. SFscrollTimerInterval()
  1572. {
  1573.     static int    maxVal = 200;
  1574.     static int    varyDist = 50;
  1575.     static int    minDist = 50;
  1576.     int        t;
  1577.     int        dist;
  1578.  
  1579.     if (SFcurrentListY < SFlowerY)
  1580.     dist = SFlowerY - SFcurrentListY;
  1581.     else if (SFcurrentListY > SFupperY)
  1582.     dist = SFcurrentListY - SFupperY;
  1583.     else
  1584.     return (unsigned long) 1;
  1585.  
  1586.     t = maxVal - ((maxVal / varyDist) * (dist - minDist));
  1587.  
  1588.     if (t < 1)
  1589.     t = 1;
  1590.  
  1591.     if (t > maxVal)
  1592.     t = maxVal;
  1593.  
  1594.     return (unsigned long)t;
  1595. }
  1596.  
  1597. static void SFscrollTimer __ARGS((XtPointer p, XtIntervalId *id));
  1598.  
  1599. /* ARGSUSED */
  1600.     static void
  1601. SFscrollTimer(p, id)
  1602.     XtPointer        p;
  1603.     XtIntervalId    *id;
  1604. {
  1605.     SFDir    *dir;
  1606.     int        save;
  1607.     int        n;
  1608.  
  1609.     n = (long)p;
  1610.  
  1611.     dir = &(SFdirs[SFdirPtr + n]);
  1612.     save = dir->vOrigin;
  1613.  
  1614.     if (SFcurrentListY < SFlowerY)
  1615.     {
  1616.     if (dir->vOrigin > 0)
  1617.         SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1);
  1618.     }
  1619.     else if (SFcurrentListY > SFupperY)
  1620.     {
  1621.     if (dir->vOrigin < dir->nEntries - SFlistSize)
  1622.         SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1);
  1623.     }
  1624.  
  1625.     if (dir->vOrigin != save)
  1626.     {
  1627.     if (dir->nEntries)
  1628.     {
  1629. #ifdef FEAT_GUI_NEXTAW
  1630.         XawScrollbarSetThumb(
  1631.             selFileVScrolls[n],
  1632.             (float) (((double) dir->vOrigin) / dir->nEntries),
  1633.             (float) (((double) ((dir->nEntries < SFlistSize) ?
  1634.                 dir->nEntries : SFlistSize)) / dir->nEntries));
  1635. #else
  1636.         vim_XawScrollbarSetThumb(
  1637.             selFileVScrolls[n],
  1638.             (float) (((double) dir->vOrigin) / dir->nEntries),
  1639.             (float) (((double) ((dir->nEntries < SFlistSize) ?
  1640.                 dir->nEntries : SFlistSize)) / dir->nEntries),
  1641.             (double)dir->nEntries);
  1642. #endif
  1643.     }
  1644.     }
  1645.  
  1646.     if (SFbuttonPressed)
  1647.     SFscrollTimerId = XtAppAddTimeOut(SFapp,
  1648.                SFscrollTimerInterval(), SFscrollTimer, (XtPointer) n);
  1649. }
  1650.  
  1651.     static int
  1652. SFnewInvertEntry(n, event)
  1653.     int            n;
  1654.     XMotionEvent    *event;
  1655. {
  1656.     int            x, y;
  1657.     int            nw;
  1658.     static int        SFscrollTimerAdded = 0;
  1659.  
  1660.     x = event->x;
  1661.     y = event->y;
  1662.  
  1663.     if (SFdirPtr + n >= SFdirEnd)
  1664.     return -1;
  1665.  
  1666.     if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY))
  1667.     {
  1668.     SFDir *dir = &(SFdirs[SFdirPtr + n]);
  1669.  
  1670.     if (SFscrollTimerAdded)
  1671.     {
  1672.         SFscrollTimerAdded = 0;
  1673.         XtRemoveTimeOut(SFscrollTimerId);
  1674.     }
  1675.  
  1676.     nw = (y - SFlowerY) / SFentryHeight;
  1677.     if (dir->vOrigin + nw >= dir->nEntries)
  1678.         return -1;
  1679.     return nw;
  1680.     }
  1681.     else
  1682.     {
  1683.     if (SFbuttonPressed)
  1684.     {
  1685.         SFcurrentListY = y;
  1686.         if (!SFscrollTimerAdded)
  1687.         {
  1688.         SFscrollTimerAdded = 1;
  1689.         SFscrollTimerId = XtAppAddTimeOut(SFapp,
  1690.             SFscrollTimerInterval(), SFscrollTimer,
  1691.             (XtPointer) n);
  1692.         }
  1693.     }
  1694.     return -1;
  1695.     }
  1696. }
  1697.  
  1698. /* ARGSUSED */
  1699.     static void
  1700. SFenterList(w, n, event)
  1701.     Widget        w;
  1702.     int            n;
  1703.     XEnterWindowEvent    *event;
  1704. {
  1705.     int            nw;
  1706.  
  1707.     /* sanity */
  1708.     if (SFcurrentInvert[n] != -1)
  1709.     {
  1710.     SFinvertEntry(n);
  1711.     SFcurrentInvert[n] = -1;
  1712.     }
  1713.  
  1714.     nw = SFnewInvertEntry(n, (XMotionEvent *) event);
  1715.     if (nw != -1)
  1716.     {
  1717.     SFcurrentInvert[n] = nw;
  1718.     SFinvertEntry(n);
  1719.     }
  1720. }
  1721.  
  1722. /* ARGSUSED */
  1723.     static void
  1724. SFleaveList(w, n, event)
  1725.     Widget    w;
  1726.     int        n;
  1727.     XEvent    *event;
  1728. {
  1729.     if (SFcurrentInvert[n] != -1)
  1730.     {
  1731.     SFinvertEntry(n);
  1732.     SFcurrentInvert[n] = -1;
  1733.     }
  1734. }
  1735.  
  1736. /* ARGSUSED */
  1737.     static void
  1738. SFmotionList(w, n, event)
  1739.     Widget        w;
  1740.     int            n;
  1741.     XMotionEvent    *event;
  1742. {
  1743.     int        nw;
  1744.  
  1745.     nw = SFnewInvertEntry(n, event);
  1746.  
  1747.     if (nw != SFcurrentInvert[n])
  1748.     {
  1749.     if (SFcurrentInvert[n] != -1)
  1750.         SFinvertEntry(n);
  1751.     SFcurrentInvert[n] = nw;
  1752.     if (nw != -1)
  1753.         SFinvertEntry(n);
  1754.     }
  1755. }
  1756.  
  1757. /* ARGSUSED */
  1758.     static void
  1759. SFvFloatSliderMovedCallback(w, n, fnew)
  1760.     Widget    w;
  1761.     XtPointer    n;
  1762.     XtPointer    fnew;
  1763. {
  1764.     int        nw;
  1765.  
  1766.     nw = (*(float *)fnew) * SFdirs[SFdirPtr + (int)(long)n].nEntries;
  1767.     SFvSliderMovedCallback(w, (int)(long)n, nw);
  1768. }
  1769.  
  1770. /* ARGSUSED */
  1771.     static void
  1772. SFvSliderMovedCallback(w, n, nw)
  1773.     Widget    w;
  1774.     int        n;
  1775.     int        nw;
  1776. {
  1777.     int        old;
  1778.     Window    win;
  1779.     SFDir    *dir;
  1780.  
  1781.     dir = &(SFdirs[SFdirPtr + n]);
  1782.  
  1783.     old = dir->vOrigin;
  1784.     dir->vOrigin = nw;
  1785.  
  1786.     if (old == nw)
  1787.     return;
  1788.  
  1789.     win = XtWindow(selFileLists[n]);
  1790.  
  1791.     if (ABS(nw - old) < SFlistSize)
  1792.     {
  1793.     if (nw > old)
  1794.     {
  1795.         XCopyArea(
  1796.             SFdisplay,
  1797.             win,
  1798.             win,
  1799.             SFscrollGC,
  1800.             SFlineToTextH,
  1801.             SFlowerY + (nw - old) * SFentryHeight,
  1802.             SFentryWidth + SFlineToTextH,
  1803.             (SFlistSize - (nw - old)) * SFentryHeight,
  1804.             SFlineToTextH,
  1805.             SFlowerY);
  1806.         XClearArea(
  1807.             SFdisplay,
  1808.             win,
  1809.             SFlineToTextH,
  1810.             SFlowerY + (SFlistSize - (nw - old)) *
  1811.             SFentryHeight,
  1812.             SFentryWidth + SFlineToTextH,
  1813.             (nw - old) * SFentryHeight,
  1814.             False);
  1815.         SFdrawStrings(win, dir, SFlistSize - (nw - old),
  1816.             SFlistSize - 1);
  1817.     }
  1818.     else
  1819.     {
  1820.         XCopyArea(
  1821.             SFdisplay,
  1822.             win,
  1823.             win,
  1824.             SFscrollGC,
  1825.             SFlineToTextH,
  1826.             SFlowerY,
  1827.             SFentryWidth + SFlineToTextH,
  1828.             (SFlistSize - (old - nw)) * SFentryHeight,
  1829.             SFlineToTextH,
  1830.             SFlowerY + (old - nw) * SFentryHeight);
  1831.         XClearArea(
  1832.             SFdisplay,
  1833.             win,
  1834.             SFlineToTextH,
  1835.             SFlowerY,
  1836.             SFentryWidth + SFlineToTextH,
  1837.             (old - nw) * SFentryHeight,
  1838.             False);
  1839.         SFdrawStrings(win, dir, 0, old - nw);
  1840.     }
  1841.     }
  1842.     else
  1843.     {
  1844.     XClearArea(
  1845.         SFdisplay,
  1846.         win,
  1847.         SFlineToTextH,
  1848.         SFlowerY,
  1849.         SFentryWidth + SFlineToTextH,
  1850.         SFlistSize * SFentryHeight,
  1851.         False);
  1852.     SFdrawStrings(win, dir, 0, SFlistSize - 1);
  1853.     }
  1854. }
  1855.  
  1856. /* ARGSUSED */
  1857.     static void
  1858. SFvAreaSelectedCallback(w, n, pnew)
  1859.     Widget        w;
  1860.     XtPointer    n;
  1861.     XtPointer    pnew;
  1862. {
  1863.     SFDir    *dir;
  1864.     int        nw;
  1865.  
  1866.     dir = &(SFdirs[SFdirPtr + (int)(long)n]);
  1867.  
  1868. #ifdef FEAT_GUI_NEXTAW
  1869.     if ((int)(long)pnew < 0)
  1870.     {
  1871.     if ((int)(long)pnew > -SFvScrollHeight)
  1872.         (int)(long)pnew = -1;
  1873.     else
  1874.         (int)(long)pnew = -SFlistSize;
  1875.     }
  1876.     else if ((int)(long)pnew > 0)
  1877.     {
  1878.     if ((int)(long)pnew < SFvScrollHeight)
  1879.         (int)(long)pnew = 1;
  1880.     else
  1881.         (int)(long)pnew = SFlistSize;
  1882.     }
  1883. #endif
  1884.     nw = dir->vOrigin + (int)(long)pnew;
  1885.  
  1886.     if (nw > dir->nEntries - SFlistSize)
  1887.     nw = dir->nEntries - SFlistSize;
  1888.  
  1889.     if (nw < 0)
  1890.     nw = 0;
  1891.  
  1892.     if (dir->nEntries)
  1893.     {
  1894.     float    f;
  1895.  
  1896.     f = ((double) nw) / dir->nEntries;
  1897.  
  1898. #ifdef FEAT_GUI_NEXTAW
  1899.     XawScrollbarSetThumb(
  1900.         w,
  1901.         f,
  1902.         (float) (((double) ((dir->nEntries < SFlistSize) ?
  1903.                 dir->nEntries : SFlistSize)) / dir->nEntries));
  1904. #else
  1905.     vim_XawScrollbarSetThumb(
  1906.         w,
  1907.         f,
  1908.         (float) (((double) ((dir->nEntries < SFlistSize) ?
  1909.                 dir->nEntries : SFlistSize)) / dir->nEntries),
  1910.         (double)dir->nEntries);
  1911. #endif
  1912.     }
  1913.  
  1914.     SFvSliderMovedCallback(w, (int)(long)n, nw);
  1915. }
  1916.  
  1917. /* ARGSUSED */
  1918.     static void
  1919. SFhSliderMovedCallback(w, n, nw)
  1920.     Widget    w;
  1921.     XtPointer    n;
  1922.     XtPointer    nw;
  1923. {
  1924.     SFDir    *dir;
  1925.     int    save;
  1926.  
  1927.     dir = &(SFdirs[SFdirPtr + (int)(long)n]);
  1928.     save = dir->hOrigin;
  1929.     dir->hOrigin = (*(float *)nw) * dir->nChars;
  1930.     if (dir->hOrigin == save)
  1931.     return;
  1932.  
  1933.     SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
  1934. }
  1935.  
  1936. /* ARGSUSED */
  1937.     static void
  1938. SFhAreaSelectedCallback(w, n, pnew)
  1939.     Widget        w;
  1940.     XtPointer    n;
  1941.     XtPointer    pnew;
  1942. {
  1943.     SFDir    *dir;
  1944.     int        nw;
  1945.  
  1946.     dir = &(SFdirs[SFdirPtr + (int)(long)n]);
  1947.  
  1948. #ifdef FEAT_GUI_NEXTAW
  1949.     if ((int)(long)pnew < 0)
  1950.     {
  1951.     if ((int)(long)pnew > -SFhScrollWidth)
  1952.         (int)(long)pnew = -1;
  1953.     else
  1954.         (int)(long)pnew = -SFcharsPerEntry;
  1955.     }
  1956.     else if ((int)(long)pnew > 0)
  1957.     {
  1958.     if ((int)(long)pnew < SFhScrollWidth)
  1959.         (int)(long)pnew = 1;
  1960.     else
  1961.         (int)(long)pnew = SFcharsPerEntry;
  1962.     }
  1963. #endif
  1964.     nw = dir->hOrigin + (int)(long)pnew;
  1965.  
  1966.     if (nw > dir->nChars - SFcharsPerEntry)
  1967.     nw = dir->nChars - SFcharsPerEntry;
  1968.  
  1969.     if (nw < 0)
  1970.     nw = 0;
  1971.  
  1972.     if (dir->nChars)
  1973.     {
  1974.     float    f;
  1975.  
  1976.     f = ((double) nw) / dir->nChars;
  1977.  
  1978. #ifdef FEAT_GUI_NEXTAW
  1979.     XawScrollbarSetThumb(
  1980.         w,
  1981.         f,
  1982.         (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
  1983.                    dir->nChars : SFcharsPerEntry)) / dir->nChars));
  1984. #else
  1985.     vim_XawScrollbarSetThumb(
  1986.         w,
  1987.         f,
  1988.         (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
  1989.                    dir->nChars : SFcharsPerEntry)) / dir->nChars),
  1990.         (double)dir->nChars);
  1991. #endif
  1992.  
  1993.     SFhSliderMovedCallback(w, n, (XtPointer)&f);
  1994.     }
  1995. }
  1996.  
  1997. /* ARGSUSED */
  1998.     static void
  1999. SFpathSliderMovedCallback(w, client_data, nw)
  2000.     Widget        w;
  2001.     XtPointer    client_data;
  2002.     XtPointer    nw;
  2003. {
  2004.     SFDir        *dir;
  2005.     int            n;
  2006.     XawTextPosition    pos;
  2007.     int            SFdirPtrSave;
  2008.  
  2009.     SFdirPtrSave = SFdirPtr;
  2010.     SFdirPtr = (*(float *)nw) * SFdirEnd;
  2011.     if (SFdirPtr == SFdirPtrSave)
  2012.     return;
  2013.  
  2014.     SFdrawLists(SF_DO_SCROLL);
  2015.  
  2016.     n = 2;
  2017.     while (SFdirPtr + n >= SFdirEnd)
  2018.     n--;
  2019.  
  2020.     dir = &(SFdirs[SFdirPtr + n]);
  2021.  
  2022.     pos = dir->path - SFcurrentPath;
  2023.  
  2024.     if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
  2025.     {
  2026.     pos -= strlen(SFstartDir);
  2027.     if (pos < 0)
  2028.         pos = 0;
  2029.     }
  2030.  
  2031.     XawTextSetInsertionPoint(selFileField, pos);
  2032. }
  2033.  
  2034. /* ARGSUSED */
  2035.     static void
  2036. SFpathAreaSelectedCallback(w, client_data, pnew)
  2037.     Widget    w;
  2038.     XtPointer    client_data;
  2039.     XtPointer    pnew;
  2040. {
  2041.     int        nw;
  2042.     float    f;
  2043.  
  2044. #ifdef FEAT_GUI_NEXTAW
  2045.     if ((int)(long)pnew < 0)
  2046.     {
  2047.     if ((int)(long)pnew > -SFpathScrollWidth)
  2048.         (int)(long)pnew = -1;
  2049.     else
  2050.         (int)(long)pnew = -3;
  2051.     }
  2052.     else if ((int)(long)pnew > 0)
  2053.     {
  2054.     if ((int)(long)pnew < SFpathScrollWidth)
  2055.         (int)(long)pnew = 1;
  2056.     else
  2057.         (int)(long)pnew = 3;
  2058.     }
  2059. #endif
  2060.     nw = SFdirPtr + (int)(long)pnew;
  2061.  
  2062.     if (nw > SFdirEnd - 3)
  2063.     nw = SFdirEnd - 3;
  2064.  
  2065.     if (nw < 0)
  2066.     nw = 0;
  2067.  
  2068.     f = ((double) nw) / SFdirEnd;
  2069.  
  2070. #ifdef FEAT_GUI_NEXTAW
  2071.     XawScrollbarSetThumb(
  2072.         w,
  2073.         f,
  2074.         (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd));
  2075. #else
  2076.     vim_XawScrollbarSetThumb(
  2077.         w,
  2078.         f,
  2079.         (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd),
  2080.         (double)SFdirEnd);
  2081. #endif
  2082.  
  2083.     SFpathSliderMovedCallback(w, (XtPointer) NULL, (XtPointer)&f);
  2084. }
  2085.  
  2086.     static Boolean
  2087. SFworkProc()
  2088. {
  2089.     SFDir    *dir;
  2090.     SFEntry    *entry;
  2091.  
  2092.     for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
  2093.     {
  2094.     if (!(dir->nEntries))
  2095.         continue;
  2096.     for (entry = &(dir->entries[dir->nEntries - 1]);
  2097.         entry >= dir->entries;
  2098.         entry--)
  2099.     {
  2100.         if (!(entry->statDone))
  2101.         {
  2102.         (void)SFstatAndCheck(dir, entry);
  2103.         return False;
  2104.         }
  2105.     }
  2106.     }
  2107.  
  2108.     SFworkProcAdded = 0;
  2109.  
  2110.     return True;
  2111. }
  2112.  
  2113. /***************** Dir.c */
  2114.  
  2115.     static int
  2116. SFcompareEntries(p, q)
  2117.     const void    *p;
  2118.     const void    *q;
  2119. {
  2120.     return strcmp(((SFEntry *)p)->real, ((SFEntry *)q)->real);
  2121. }
  2122.  
  2123.     static int
  2124. SFgetDir(dir)
  2125.     SFDir    *dir;
  2126. {
  2127.     SFEntry        *result = NULL;
  2128.     int            Alloc = 0;
  2129.     int            i;
  2130.     DIR            *dirp;
  2131.     struct dirent    *dp;
  2132.     char        *str;
  2133.     int            len;
  2134.     int            maxChars;
  2135.     struct stat        statBuf;
  2136.  
  2137.     maxChars = strlen(dir->dir) - 1;
  2138.  
  2139.     dir->entries = NULL;
  2140.     dir->nEntries = 0;
  2141.     dir->nChars = 0;
  2142.  
  2143.     result = NULL;
  2144.     i = 0;
  2145.  
  2146.     dirp = opendir(".");
  2147.     if (!dirp)
  2148.     return 1;
  2149.  
  2150.     (void)mch_stat(".", &statBuf);
  2151.     dir->mtime = statBuf.st_mtime;
  2152.  
  2153.     while ((dp = readdir(dirp)))
  2154.     {
  2155.     /* Ignore "." and ".." */
  2156.     if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
  2157.         continue;
  2158.     if (i >= Alloc)
  2159.     {
  2160.         Alloc = 2 * (Alloc + 1);
  2161.         result = (SFEntry *) XtRealloc((char *) result,
  2162.             (unsigned) (Alloc * sizeof(SFEntry)));
  2163.     }
  2164.     result[i].statDone = 0;
  2165.     str = dp->d_name;
  2166.     len = strlen(str);
  2167.     result[i].real = XtMalloc((unsigned) (len + 2));
  2168.     (void) strcat(strcpy(result[i].real, str), " ");
  2169.     if (len > maxChars)
  2170.         maxChars = len;
  2171.     result[i].shown = result[i].real;
  2172.     i++;
  2173.     }
  2174.  
  2175.     qsort((char *) result, (size_t) i, sizeof(SFEntry), SFcompareEntries);
  2176.  
  2177.     dir->entries = result;
  2178.     dir->nEntries = i;
  2179.     dir->nChars = maxChars + 1;
  2180.  
  2181.     closedir(dirp);
  2182.  
  2183.     return 0;
  2184. }
  2185.  
  2186. /***************** SFinternal.h */
  2187.  
  2188. #include <sys/param.h>
  2189. #include <X11/cursorfont.h>
  2190. #include <X11/Composite.h>
  2191. #include <X11/Shell.h>
  2192. #ifdef FEAT_GUI_NEXTAW
  2193. # include <X11/neXtaw/Form.h>
  2194. # include <X11/neXtaw/Command.h>
  2195. # include <X11/neXtaw/Label.h>
  2196. #else
  2197. #include <X11/Xaw/Form.h>
  2198. #include <X11/Xaw/Command.h>
  2199. #include <X11/Xaw/Label.h>
  2200. #endif
  2201.  
  2202. static char *oneLineTextEditTranslations = "\
  2203.     <Key>Return:    redraw-display()\n\
  2204.     Ctrl<Key>M:    redraw-display()\n\
  2205. ";
  2206.  
  2207. static void SFexposeList __ARGS((Widget w, XtPointer n, XEvent *event, Boolean *cont));
  2208.  
  2209. /* ARGSUSED */
  2210.     static void
  2211. SFexposeList(w, n, event, cont)
  2212.     Widget    w;
  2213.     XtPointer    n;
  2214.     XEvent    *event;
  2215.     Boolean    *cont;
  2216. {
  2217.     if ((event->type == NoExpose) || event->xexpose.count)
  2218.     return;
  2219.  
  2220.     SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
  2221. }
  2222.  
  2223. static void SFmodVerifyCallback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont));
  2224.  
  2225. /* ARGSUSED */
  2226.     static void
  2227. SFmodVerifyCallback(w, client_data, event, cont)
  2228.     Widget        w;
  2229.     XtPointer        client_data;
  2230.     XEvent        *event;
  2231.     Boolean        *cont;
  2232. {
  2233.     char    buf[2];
  2234.  
  2235.     if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
  2236.         ((*buf) == '\r'))
  2237.     SFstatus = SEL_FILE_OK;
  2238.     else
  2239.     SFstatus = SEL_FILE_TEXT;
  2240. }
  2241.  
  2242. static void SFokCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
  2243.  
  2244. /* ARGSUSED */
  2245.     static void
  2246. SFokCallback(w, cl, cd)
  2247.     Widget    w;
  2248.     XtPointer    cl, cd;
  2249. {
  2250.     SFstatus = SEL_FILE_OK;
  2251. }
  2252.  
  2253. static XtCallbackRec SFokSelect[] =
  2254. {
  2255.     { SFokCallback, (XtPointer) NULL },
  2256.     { NULL, (XtPointer) NULL },
  2257. };
  2258.  
  2259. static void SFcancelCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
  2260.  
  2261. /* ARGSUSED */
  2262.     static void
  2263. SFcancelCallback(w, cl, cd)
  2264.     Widget    w;
  2265.     XtPointer    cl, cd;
  2266. {
  2267.     SFstatus = SEL_FILE_CANCEL;
  2268. }
  2269.  
  2270. static XtCallbackRec SFcancelSelect[] =
  2271. {
  2272.     { SFcancelCallback, (XtPointer) NULL },
  2273.     { NULL, (XtPointer) NULL },
  2274. };
  2275.  
  2276. static void SFdismissAction __ARGS((Widget w, XEvent *event, String *params, Cardinal *num_params));
  2277.  
  2278. /* ARGSUSED */
  2279.     static void
  2280. SFdismissAction(w, event, params, num_params)
  2281.     Widget    w;
  2282.     XEvent *event;
  2283.     String *params;
  2284.     Cardinal *num_params;
  2285. {
  2286.     if (event->type == ClientMessage &&
  2287.         event->xclient.data.l[0] != SFwmDeleteWindow)
  2288.     return;
  2289.  
  2290.     SFstatus = SEL_FILE_CANCEL;
  2291. }
  2292.  
  2293. static char *wmDeleteWindowTranslation = "\
  2294.     <Message>WM_PROTOCOLS:    SelFileDismiss()\n\
  2295. ";
  2296.  
  2297. static XtActionsRec actions[] =
  2298. {
  2299.     {"SelFileDismiss",    SFdismissAction},
  2300. };
  2301.  
  2302.     static void
  2303. SFsetColors(bg, fg, scroll_bg, scroll_fg)
  2304.     guicolor_T    bg;
  2305.     guicolor_T    fg;
  2306.     guicolor_T    scroll_bg;
  2307.     guicolor_T    scroll_fg;
  2308. {
  2309.     if (selFileForm)
  2310.     {
  2311.     XtVaSetValues(selFileForm, XtNbackground,  bg,
  2312.                    XtNforeground,  fg,
  2313.                    XtNborderColor, bg,
  2314.                    NULL);
  2315.     }
  2316.     {
  2317.     int i;
  2318.  
  2319.     for (i = 0; i < 3; ++i)
  2320.     {
  2321.         if (selFileLists[i])
  2322.         {
  2323.         XtVaSetValues(selFileLists[i], XtNbackground,  bg,
  2324.                            XtNforeground,  fg,
  2325.                            XtNborderColor, fg,
  2326.                            NULL);
  2327.         }
  2328.     }
  2329.     }
  2330.     if (selFileOK)
  2331.     {
  2332.     XtVaSetValues(selFileOK, XtNbackground,  bg,
  2333.                  XtNforeground,  fg,
  2334.                  XtNborderColor, fg,
  2335.                  NULL);
  2336.     }
  2337.     if (selFileCancel)
  2338.     {
  2339.     XtVaSetValues(selFileCancel, XtNbackground, bg,
  2340.                      XtNforeground, fg,
  2341.                      XtNborderColor, fg,
  2342.                      NULL);
  2343.     }
  2344.     if (selFilePrompt)
  2345.     {
  2346.     XtVaSetValues(selFilePrompt, XtNbackground, bg,
  2347.                      XtNforeground, fg,
  2348.                      NULL);
  2349.     }
  2350.     if (gui.dpy)
  2351.     {
  2352.     XSetBackground(gui.dpy, SFtextGC, bg);
  2353.     XSetForeground(gui.dpy, SFtextGC, fg);
  2354.     XSetForeground(gui.dpy, SFlineGC, fg);
  2355.  
  2356.     /* This is an xor GC, so combine the fg and background */
  2357.     XSetBackground(gui.dpy, SFinvertGC, fg ^ bg);
  2358.     XSetForeground(gui.dpy, SFinvertGC, fg ^ bg);
  2359.     }
  2360.     if (selFileHScroll)
  2361.     {
  2362.     XtVaSetValues(selFileHScroll, XtNbackground, scroll_bg,
  2363.                       XtNforeground, scroll_fg,
  2364.                       XtNborderColor, fg,
  2365.                       NULL);
  2366.     }
  2367.     {
  2368.     int i;
  2369.  
  2370.     for (i = 0; i < 3; i++)
  2371.     {
  2372.         XtVaSetValues(selFileVScrolls[i], XtNbackground, scroll_bg,
  2373.                           XtNforeground, scroll_fg,
  2374.                           XtNborderColor, fg,
  2375.                           NULL);
  2376.         XtVaSetValues(selFileHScrolls[i], XtNbackground, scroll_bg,
  2377.                           XtNforeground, scroll_fg,
  2378.                           XtNborderColor, fg,
  2379.                           NULL);
  2380.     }
  2381.     }
  2382. }
  2383.  
  2384.     static void
  2385. SFcreateWidgets(toplevel, prompt, ok, cancel)
  2386.     Widget    toplevel;
  2387.     char    *prompt;
  2388.     char    *ok;
  2389.     char    *cancel;
  2390. {
  2391.     Cardinal    n;
  2392.     int        listWidth, listHeight;
  2393.     int        listSpacing = 10;
  2394.     int        scrollThickness = 15;
  2395.     int        hScrollX, hScrollY;
  2396.     int        vScrollX, vScrollY;
  2397.  
  2398.     selFile = XtVaAppCreateShell("selFile", "SelFile",
  2399.         transientShellWidgetClass, SFdisplay,
  2400.         XtNtransientFor, toplevel,
  2401.         XtNtitle, prompt,
  2402.         NULL);
  2403.  
  2404.     /* Add WM_DELETE_WINDOW protocol */
  2405.     XtAppAddActions(XtWidgetToApplicationContext(selFile),
  2406.         actions, XtNumber(actions));
  2407.     XtOverrideTranslations(selFile,
  2408.         XtParseTranslationTable(wmDeleteWindowTranslation));
  2409.  
  2410.     selFileForm = XtVaCreateManagedWidget("selFileForm",
  2411.         formWidgetClass, selFile,
  2412.         XtNdefaultDistance, 30,
  2413.         XtNforeground, SFfore,
  2414.         XtNbackground, SFback,
  2415.         XtNborderColor, SFback,
  2416.         NULL);
  2417.  
  2418.     selFilePrompt = XtVaCreateManagedWidget("selFilePrompt",
  2419.         labelWidgetClass, selFileForm,
  2420.         XtNlabel, prompt,
  2421.         XtNresizable, True,
  2422.         XtNtop, XtChainTop,
  2423.         XtNbottom, XtChainTop,
  2424.         XtNleft, XtChainLeft,
  2425.         XtNright, XtChainLeft,
  2426.         XtNborderWidth, 0,
  2427.         XtNforeground, SFfore,
  2428.         XtNbackground, SFback,
  2429.         NULL);
  2430.  
  2431.     /*
  2432.     XtVaGetValues(selFilePrompt,
  2433.         XtNforeground, &SFfore,
  2434.         XtNbackground, &SFback,
  2435.         NULL);
  2436.     */
  2437.  
  2438.     SFinitFont();
  2439.  
  2440.     SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth +
  2441.     SFbesideText;
  2442.     SFentryHeight = SFaboveAndBelowText + SFcharHeight +
  2443.     SFaboveAndBelowText;
  2444.  
  2445.     listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
  2446.     scrollThickness;
  2447.     listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
  2448.     SFlineToTextV + SFlistSize * SFentryHeight +
  2449.     SFlineToTextV + 1 + scrollThickness;
  2450.  
  2451.     SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;
  2452.  
  2453.     hScrollX = -1;
  2454.     hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
  2455.     SFlineToTextV + SFlistSize * SFentryHeight +
  2456.     SFlineToTextV;
  2457.     SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
  2458.  
  2459.     vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
  2460.     vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
  2461.     SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
  2462.     SFlineToTextV;
  2463.  
  2464.     SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
  2465.     SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
  2466.     SFlineToTextV;
  2467.     SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
  2468.     SFlineToTextV + SFlistSize * SFentryHeight - 1;
  2469.  
  2470.     SFtextX = SFlineToTextH + SFbesideText;
  2471.     SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
  2472.  
  2473.     SFsegs[0].x1 = 0;
  2474.     SFsegs[0].y1 = vScrollY;
  2475.     SFsegs[0].x2 = vScrollX - 1;
  2476.     SFsegs[0].y2 = vScrollY;
  2477.     SFsegs[1].x1 = vScrollX;
  2478.     SFsegs[1].y1 = 0;
  2479.     SFsegs[1].x2 = vScrollX;
  2480.     SFsegs[1].y2 = vScrollY - 1;
  2481.  
  2482.     SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
  2483.     SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
  2484.     SFlineToTextH + SFentryWidth - 1;
  2485.  
  2486.     selFileField = XtVaCreateManagedWidget("selFileField",
  2487.         asciiTextWidgetClass, selFileForm,
  2488.         XtNwidth, 3 * listWidth + 2 * listSpacing + 4,
  2489.         XtNborderColor, SFfore,
  2490.         XtNfromVert, selFilePrompt,
  2491.         XtNvertDistance, 10,
  2492.         XtNresizable, True,
  2493.         XtNtop, XtChainTop,
  2494.         XtNbottom, XtChainTop,
  2495.         XtNleft, XtChainLeft,
  2496.         XtNright, XtChainLeft,
  2497.         XtNstring, SFtextBuffer,
  2498.         XtNlength, MAXPATHL,
  2499.         XtNeditType, XawtextEdit,
  2500.         XtNwrap, XawtextWrapWord,
  2501.         XtNresize, XawtextResizeHeight,
  2502.         XtNuseStringInPlace, True,
  2503.         NULL);
  2504.  
  2505.     XtOverrideTranslations(selFileField,
  2506.         XtParseTranslationTable(oneLineTextEditTranslations));
  2507.     XtSetKeyboardFocus(selFileForm, selFileField);
  2508.  
  2509.     selFileHScroll = XtVaCreateManagedWidget("selFileHScroll",
  2510. #ifdef FEAT_GUI_NEXTAW
  2511.         scrollbarWidgetClass, selFileForm,
  2512. #else
  2513.         vim_scrollbarWidgetClass, selFileForm,
  2514. #endif
  2515.         XtNorientation, XtorientHorizontal,
  2516.         XtNwidth, SFpathScrollWidth,
  2517.         XtNheight, scrollThickness,
  2518.         XtNborderColor, SFfore,
  2519.         XtNfromVert, selFileField,
  2520.         XtNvertDistance, 30,
  2521.         XtNtop, XtChainTop,
  2522.         XtNbottom, XtChainTop,
  2523.         XtNleft, XtChainLeft,
  2524.         XtNright, XtChainLeft,
  2525.         XtNforeground, gui.scroll_fg_pixel,
  2526.         XtNbackground, gui.scroll_bg_pixel,
  2527. #ifndef FEAT_GUI_NEXTAW
  2528.         XtNlimitThumb, 1,
  2529. #endif
  2530.         NULL);
  2531.  
  2532.     XtAddCallback(selFileHScroll, XtNjumpProc,
  2533.         (XtCallbackProc) SFpathSliderMovedCallback, (XtPointer)NULL);
  2534.     XtAddCallback(selFileHScroll, XtNscrollProc,
  2535.         (XtCallbackProc) SFpathAreaSelectedCallback, (XtPointer)NULL);
  2536.  
  2537.     selFileLists[0] = XtVaCreateManagedWidget("selFileList1",
  2538.         compositeWidgetClass, selFileForm,
  2539.         XtNwidth, listWidth,
  2540.         XtNheight, listHeight,
  2541.         XtNforeground,  SFfore,
  2542.         XtNbackground,  SFback,
  2543.         XtNborderColor, SFfore,
  2544.         XtNfromVert, selFileHScroll,
  2545.         XtNvertDistance, 10,
  2546.         XtNtop, XtChainTop,
  2547.         XtNbottom, XtChainTop,
  2548.         XtNleft, XtChainLeft,
  2549.         XtNright, XtChainLeft,
  2550.         NULL);
  2551.  
  2552.     selFileLists[1] = XtVaCreateManagedWidget("selFileList2",
  2553.         compositeWidgetClass, selFileForm,
  2554.         XtNwidth, listWidth,
  2555.         XtNheight, listHeight,
  2556.         XtNforeground,  SFfore,
  2557.         XtNbackground,  SFback,
  2558.         XtNborderColor, SFfore,
  2559.         XtNfromHoriz, selFileLists[0],
  2560.         XtNfromVert, selFileHScroll,
  2561.         XtNhorizDistance, listSpacing,
  2562.         XtNvertDistance, 10,
  2563.         XtNtop, XtChainTop,
  2564.         XtNbottom, XtChainTop,
  2565.         XtNleft, XtChainLeft,
  2566.         XtNright, XtChainLeft,
  2567.         NULL);
  2568.  
  2569.     selFileLists[2] = XtVaCreateManagedWidget("selFileList3",
  2570.         compositeWidgetClass, selFileForm,
  2571.         XtNwidth, listWidth,
  2572.         XtNheight, listHeight,
  2573.         XtNforeground,  SFfore,
  2574.         XtNbackground,  SFback,
  2575.         XtNborderColor, SFfore,
  2576.         XtNfromHoriz, selFileLists[1],
  2577.         XtNfromVert, selFileHScroll,
  2578.         XtNhorizDistance, listSpacing,
  2579.         XtNvertDistance, 10,
  2580.         XtNtop, XtChainTop,
  2581.         XtNbottom, XtChainTop,
  2582.         XtNleft, XtChainLeft,
  2583.         XtNright, XtChainLeft,
  2584.         NULL);
  2585.  
  2586.     for (n = 0; n < 3; n++)
  2587.     {
  2588.     selFileVScrolls[n] = XtVaCreateManagedWidget("selFileVScroll",
  2589. #ifdef FEAT_GUI_NEXTAW
  2590.             scrollbarWidgetClass, selFileLists[n],
  2591. #else
  2592.             vim_scrollbarWidgetClass, selFileLists[n],
  2593. #endif
  2594.             XtNx, vScrollX,
  2595.             XtNy, vScrollY,
  2596.             XtNwidth, scrollThickness,
  2597.             XtNheight, SFvScrollHeight,
  2598.             XtNborderColor, SFfore,
  2599.             XtNforeground, gui.scroll_fg_pixel,
  2600.             XtNbackground, gui.scroll_bg_pixel,
  2601. #ifndef FEAT_GUI_NEXTAW
  2602.             XtNlimitThumb, 1,
  2603. #endif
  2604.             NULL);
  2605.  
  2606.     XtAddCallback(selFileVScrolls[n], XtNjumpProc,
  2607.         (XtCallbackProc)SFvFloatSliderMovedCallback, (XtPointer)n);
  2608.     XtAddCallback(selFileVScrolls[n], XtNscrollProc,
  2609.         (XtCallbackProc)SFvAreaSelectedCallback, (XtPointer)n);
  2610.  
  2611.     selFileHScrolls[n] = XtVaCreateManagedWidget("selFileHScroll",
  2612. #ifdef FEAT_GUI_NEXTAW
  2613.             scrollbarWidgetClass, selFileLists[n],
  2614. #else
  2615.             vim_scrollbarWidgetClass, selFileLists[n],
  2616. #endif
  2617.             XtNorientation, XtorientHorizontal,
  2618.             XtNx, hScrollX,
  2619.             XtNy, hScrollY,
  2620.             XtNwidth, SFhScrollWidth,
  2621.             XtNheight, scrollThickness,
  2622.             XtNborderColor, SFfore,
  2623.             XtNforeground, gui.scroll_fg_pixel,
  2624.             XtNbackground, gui.scroll_bg_pixel,
  2625. #ifndef FEAT_GUI_NEXTAW
  2626.             XtNlimitThumb, 1,
  2627. #endif
  2628.             NULL);
  2629.  
  2630.     XtAddCallback(selFileHScrolls[n], XtNjumpProc,
  2631.         (XtCallbackProc)SFhSliderMovedCallback, (XtPointer)n);
  2632.     XtAddCallback(selFileHScrolls[n], XtNscrollProc,
  2633.         (XtCallbackProc)SFhAreaSelectedCallback, (XtPointer)n);
  2634.     }
  2635.  
  2636.     selFileOK = XtVaCreateManagedWidget("selFileOK",
  2637.         commandWidgetClass, selFileForm,
  2638.         XtNlabel, ok,
  2639.         XtNresizable, True,
  2640.         XtNcallback, SFokSelect,
  2641.         XtNforeground,  SFfore,
  2642.         XtNbackground,  SFback,
  2643.         XtNborderColor, SFfore,
  2644.         XtNfromHoriz, selFileLists[0],
  2645.         XtNfromVert, selFileLists[0],
  2646.         XtNvertDistance, 30,
  2647.         XtNtop, XtChainTop,
  2648.         XtNbottom, XtChainTop,
  2649.         XtNleft, XtChainLeft,
  2650.         XtNright, XtChainLeft,
  2651.         NULL);
  2652.  
  2653.     selFileCancel = XtVaCreateManagedWidget("selFileCancel",
  2654.         commandWidgetClass, selFileForm,
  2655.         XtNlabel, cancel,
  2656.         XtNresizable, True,
  2657.         XtNcallback, SFcancelSelect,
  2658.         XtNforeground,  SFfore,
  2659.         XtNbackground,  SFback,
  2660.         XtNborderColor, SFfore,
  2661.         XtNfromHoriz, selFileOK,
  2662.         XtNfromVert, selFileLists[0],
  2663.         XtNhorizDistance, 30,
  2664.         XtNvertDistance, 30,
  2665.         XtNtop, XtChainTop,
  2666.         XtNbottom, XtChainTop,
  2667.         XtNleft, XtChainLeft,
  2668.         XtNright, XtChainLeft,
  2669.         NULL);
  2670.  
  2671.     XtSetMappedWhenManaged(selFile, False);
  2672.     XtRealizeWidget(selFile);
  2673.  
  2674.     /* Add WM_DELETE_WINDOW protocol */
  2675.     SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
  2676.     XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
  2677.  
  2678.     SFcreateGC();
  2679.  
  2680.     for (n = 0; n < 3; n++)
  2681.     {
  2682.     XtAddEventHandler(selFileLists[n], ExposureMask, True,
  2683.         (XtEventHandler)SFexposeList, (XtPointer)n);
  2684.     XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
  2685.         (XtEventHandler)SFenterList, (XtPointer)n);
  2686.     XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
  2687.         (XtEventHandler)SFleaveList, (XtPointer)n);
  2688.     XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
  2689.         (XtEventHandler)SFmotionList, (XtPointer)n);
  2690.     XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
  2691.         (XtEventHandler)SFbuttonPressList, (XtPointer)n);
  2692.     XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
  2693.         (XtEventHandler)SFbuttonReleaseList, (XtPointer)n);
  2694.     }
  2695.  
  2696.     XtAddEventHandler(selFileField, KeyPressMask, False,
  2697.                        SFmodVerifyCallback, (XtPointer)NULL);
  2698.  
  2699.     SFapp = XtWidgetToApplicationContext(selFile);
  2700. }
  2701.  
  2702.     static void
  2703. SFtextChanged()
  2704. {
  2705. #if defined(FEAT_XFONTSET) && defined(XtNinternational)
  2706.     if (_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
  2707.     {
  2708.     wchar_t *wcbuf=(wchar_t *)SFtextBuffer;
  2709.  
  2710.     if ((wcbuf[0] == L'/') || (wcbuf[0] == L'~'))
  2711.     {
  2712.         (void) wcstombs(SFcurrentPath, wcbuf, MAXPATHL);
  2713.         SFtextPos = XawTextGetInsertionPoint(selFileField);
  2714.     }
  2715.     else
  2716.     {
  2717.         strcpy(SFcurrentPath, SFstartDir);
  2718.         (void) wcstombs(SFcurrentPath + strlen(SFcurrentPath), wcbuf, MAXPATHL);
  2719.  
  2720.         SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
  2721.     }
  2722.     }
  2723.     else
  2724. #endif
  2725.     if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~'))
  2726.     {
  2727.     (void) strcpy(SFcurrentPath, SFtextBuffer);
  2728.     SFtextPos = XawTextGetInsertionPoint(selFileField);
  2729.     }
  2730.     else
  2731.     {
  2732.     (void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
  2733.  
  2734.     SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
  2735.     }
  2736.  
  2737.     if (!SFworkProcAdded)
  2738.     {
  2739.     (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
  2740.     SFworkProcAdded = 1;
  2741.     }
  2742.  
  2743.     SFupdatePath();
  2744. }
  2745.  
  2746.     static char *
  2747. SFgetText()
  2748. {
  2749. #if defined(FEAT_XFONTSET) && defined(XtNinternational)
  2750.     char *buf;
  2751.  
  2752.     if (_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
  2753.     {
  2754.     wchar_t *wcbuf;
  2755.     int mbslength;
  2756.  
  2757.     XtVaGetValues(selFileField,
  2758.         XtNstring, &wcbuf,
  2759.     NULL);
  2760.     mbslength = wcstombs(NULL, wcbuf, 0);
  2761.     /* Hack: some broken wcstombs() returns zero, just get a large buffer */
  2762.     if (mbslength == 0 && wcbuf != NULL && wcbuf[0] != 0)
  2763.         mbslength = MAXPATHL;
  2764.     buf=(char *)XtMalloc(mbslength + 1);
  2765.     wcstombs(buf, wcbuf, mbslength +1);
  2766.     return buf;
  2767.     }
  2768. #endif
  2769.     return (char *)vim_strsave((char_u *)SFtextBuffer);
  2770. }
  2771.  
  2772.     static void
  2773. SFprepareToReturn()
  2774. {
  2775.     SFstatus = SEL_FILE_NULL;
  2776.     XtRemoveGrab(selFile);
  2777.     XtUnmapWidget(selFile);
  2778.     XtRemoveTimeOut(SFdirModTimerId);
  2779.     if (SFchdir(SFstartDir))
  2780.     {
  2781.     EMSG(_("E614: vim_SelFile: can't return to current directory"));
  2782.     SFstatus = SEL_FILE_CANCEL;
  2783.     }
  2784. }
  2785.  
  2786.     char *
  2787. vim_SelFile(toplevel, prompt, init_path, show_entry, x, y, fg, bg, scroll_fg, scroll_bg)
  2788.     Widget    toplevel;
  2789.     char    *prompt;
  2790.     char    *init_path;
  2791.     int        (*show_entry)();
  2792.     int        x, y;
  2793.     guicolor_T    fg, bg;
  2794.     guicolor_T    scroll_fg, scroll_bg; /* The "Scrollbar" group colors */
  2795. {
  2796.     static int    firstTime = 1;
  2797.     XEvent    event;
  2798.     char    *name_return;
  2799.  
  2800.     if (prompt == NULL)
  2801.     prompt = _("Pathname:");
  2802.     SFfore = fg;
  2803.     SFback = bg;
  2804.  
  2805.     if (mch_dirname((char_u *)SFstartDir, MAXPATHL) == FAIL)
  2806.     {
  2807.     EMSG(_("E615: vim_SelFile: can't get current directory"));
  2808.     return NULL;
  2809.     }
  2810.  
  2811.     if (firstTime)
  2812.     {
  2813.     firstTime = 0;
  2814.     SFdisplay = XtDisplay(toplevel);
  2815.     SFcreateWidgets(toplevel, prompt, _("OK"), _("Cancel"));
  2816.     }
  2817.     else
  2818.     {
  2819.     XtVaSetValues(selFilePrompt, XtNlabel, prompt, NULL);
  2820.     XtVaSetValues(selFile, XtNtitle, prompt, NULL);
  2821.     SFsetColors(bg, fg, scroll_bg, scroll_fg);
  2822.     }
  2823.  
  2824.     XtVaSetValues(selFile, XtNx, x, XtNy, y, NULL);
  2825.     XtMapWidget(selFile);
  2826.  
  2827.     (void)strcat(SFstartDir, "/");
  2828.     (void)strcpy(SFcurrentDir, SFstartDir);
  2829.  
  2830.     if (init_path)
  2831.     {
  2832.     if (init_path[0] == '/')
  2833.     {
  2834.         (void)strcpy(SFcurrentPath, init_path);
  2835.         if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
  2836.         SFsetText(SFcurrentPath);
  2837.         else
  2838.         SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
  2839.     }
  2840.     else
  2841.     {
  2842.         (void)strcat(strcpy(SFcurrentPath, SFstartDir), init_path);
  2843.         SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
  2844.     }
  2845.     }
  2846.     else
  2847.     (void)strcpy(SFcurrentPath, SFstartDir);
  2848.  
  2849.     SFfunc = show_entry;
  2850.  
  2851.     SFtextChanged();
  2852.  
  2853.     XtAddGrab(selFile, True, True);
  2854.  
  2855.     SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
  2856.         SFdirModTimer, (XtPointer) NULL);
  2857.  
  2858.     while (1)
  2859.     {
  2860.     XtAppNextEvent(SFapp, &event);
  2861.     XtDispatchEvent(&event);
  2862.     switch (SFstatus)
  2863.     {
  2864.         case SEL_FILE_TEXT:
  2865.         SFstatus = SEL_FILE_NULL;
  2866.         SFtextChanged();
  2867.         break;
  2868.         case SEL_FILE_OK:
  2869.         name_return = SFgetText();
  2870.         SFprepareToReturn();
  2871.         return name_return;
  2872.         case SEL_FILE_CANCEL:
  2873.         SFprepareToReturn();
  2874.         return NULL;
  2875.         case SEL_FILE_NULL:
  2876.         break;
  2877.     }
  2878.     }
  2879. }
  2880. #endif /* FEAT_BROWSE */
  2881.