xref: /vim-8.2.3635/src/gui_at_fs.c (revision 2bf24176)
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  *	   [email protected]
27  */
28 /*
29  * Author's addresses:
30  *	[email protected]
31  *	erik%[email protected]
32  *	erik%[email protected]
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 ((unsigned long)_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     static void
855 SFbuttonPressList(w, n, event)
856     Widget		w UNUSED;
857     int			n UNUSED;
858     XButtonPressedEvent	*event UNUSED;
859 {
860     SFbuttonPressed = 1;
861 }
862 
863     static void
864 SFbuttonReleaseList(w, n, event)
865     Widget		 w;
866     int			 n;
867     XButtonReleasedEvent *event;
868 {
869     SFDir	*dir;
870 
871     SFbuttonPressed = 0;
872 
873     if (SFcurrentInvert[n] != -1)
874     {
875 	if (n < 2)
876 	    SFdoNotTouchDirPtr = 1;
877 	SFdoNotTouchVorigin = 1;
878 	dir = &(SFdirs[SFdirPtr + n]);
879 	SFreplaceText(dir,
880 		       dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown);
881 	SFmotionList(w, n, (XMotionEvent *) event);
882     }
883 }
884 
885 static int SFcheckDir __ARGS((int n, SFDir *dir));
886 
887     static int
888 SFcheckDir(n, dir)
889     int		n;
890     SFDir		*dir;
891 {
892     struct stat	statBuf;
893     int		i;
894 
895     if ((!mch_stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime))
896     {
897 	/*
898 	 * If the pointer is currently in the window that we are about
899 	 * to update, we must warp it to prevent the user from
900 	 * accidentally selecting the wrong file.
901 	 */
902 	if (SFcurrentInvert[n] != -1)
903 	{
904 	    XWarpPointer(
905 		    SFdisplay,
906 		    None,
907 		    XtWindow(selFileLists[n]),
908 		    0,
909 		    0,
910 		    0,
911 		    0,
912 		    0,
913 		    0);
914 	}
915 
916 	for (i = dir->nEntries - 1; i >= 0; i--)
917 	{
918 	    if (dir->entries[i].shown != dir->entries[i].real)
919 		XtFree(dir->entries[i].shown);
920 	    XtFree(dir->entries[i].real);
921 	}
922 	XtFree((char *) dir->entries);
923 	if (SFgetDir(dir))
924 	    SFunreadableDir(dir);
925 	if (dir->vOrigin > dir->nEntries - SFlistSize)
926 	    dir->vOrigin = dir->nEntries - SFlistSize;
927 	if (dir->vOrigin < 0)
928 	    dir->vOrigin = 0;
929 	if (dir->hOrigin > dir->nChars - SFcharsPerEntry)
930 	    dir->hOrigin = dir->nChars - SFcharsPerEntry;
931 	if (dir->hOrigin < 0)
932 	    dir->hOrigin = 0;
933 	dir->beginSelection = -1;
934 	dir->endSelection = -1;
935 	SFdoNotTouchVorigin = 1;
936 	if ((dir + 1)->dir)
937 	    (void) SFfindFile(dir, (dir + 1)->dir);
938 	else
939 	    (void) SFfindFile(dir, dir->path);
940 
941 	if (!SFworkProcAdded)
942 	{
943 	    (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
944 	    SFworkProcAdded = 1;
945 	}
946 	return 1;
947     }
948     return 0;
949 }
950 
951 static int SFcheckFiles __ARGS((SFDir *dir));
952 
953     static int
954 SFcheckFiles(dir)
955 	SFDir	*dir;
956 {
957     int		from, to;
958     int		result;
959     char	oldc, newc;
960     int		i;
961     char	*str;
962     int		last;
963     struct stat	statBuf;
964 
965     result = 0;
966 
967     from = dir->vOrigin;
968     to = dir->vOrigin + SFlistSize;
969     if (to > dir->nEntries)
970 	to = dir->nEntries;
971 
972     for (i = from; i < to; i++)
973     {
974 	str = dir->entries[i].real;
975 	last = strlen(str) - 1;
976 	oldc = str[last];
977 	str[last] = 0;
978 	if (mch_stat(str, &statBuf))
979 	    newc = ' ';
980 	else
981 	    newc = SFstatChar(&statBuf);
982 	str[last] = newc;
983 	if (newc != oldc)
984 	    result = 1;
985     }
986 
987     return result;
988 }
989 
990     static void
991 SFdirModTimer(cl, id)
992     XtPointer		cl UNUSED;
993     XtIntervalId	*id UNUSED;
994 {
995     static int		n = -1;
996     static int		f = 0;
997     char		save;
998     SFDir		*dir;
999 
1000     if ((!SFtwiddle) && (SFdirPtr < SFdirEnd))
1001     {
1002 	n++;
1003 	if ((n > 2) || (SFdirPtr + n >= SFdirEnd))
1004 	{
1005 	    n = 0;
1006 	    f++;
1007 	    if ((f > 2) || (SFdirPtr + f >= SFdirEnd))
1008 		f = 0;
1009 	}
1010 	dir = &(SFdirs[SFdirPtr + n]);
1011 	save = *(dir->path);
1012 	*(dir->path) = 0;
1013 	if (SFchdir(SFcurrentPath))
1014 	{
1015 	    *(dir->path) = save;
1016 
1017 	    /*
1018 	     * force a re-read
1019 	     */
1020 	    *(dir->dir) = 0;
1021 
1022 	    SFupdatePath();
1023 	}
1024 	else
1025 	{
1026 	    *(dir->path) = save;
1027 	    if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir)))
1028 		SFdrawList(n, SF_DO_SCROLL);
1029 	}
1030     }
1031 
1032     SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
1033 	    SFdirModTimer, (XtPointer) NULL);
1034 }
1035 
1036 /* Return a single character describing what kind of file STATBUF is.  */
1037 
1038     static char
1039 SFstatChar(statBuf)
1040     struct stat *statBuf;
1041 {
1042     if (S_ISDIR (statBuf->st_mode))
1043 	return '/';
1044     if (S_ISREG (statBuf->st_mode))
1045 	return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
1046 #ifdef S_ISSOCK
1047     if (S_ISSOCK (statBuf->st_mode))
1048 	return '=';
1049 #endif /* S_ISSOCK */
1050     return ' ';
1051 }
1052 
1053 /***************** Draw.c */
1054 
1055 #ifdef FEAT_GUI_NEXTAW
1056 # include <X11/neXtaw/Cardinals.h>
1057 #else
1058 # include <X11/Xaw/Cardinals.h>
1059 #endif
1060 
1061 #ifdef FEAT_XFONTSET
1062 # define SF_DEFAULT_FONT "-misc-fixed-medium-r-normal--14-*"
1063 #else
1064 # define SF_DEFAULT_FONT "9x15"
1065 #endif
1066 
1067 #ifdef ABS
1068 # undef ABS
1069 #endif
1070 #define ABS(x) (((x) < 0) ? (-(x)) : (x))
1071 
1072 typedef struct
1073 {
1074     char *fontname;
1075 } TextData;
1076 
1077 static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
1078 
1079 static XtResource textResources[] =
1080 {
1081 #ifdef FEAT_XFONTSET
1082 	{XtNfontSet, XtCFontSet, XtRString, sizeof (char *),
1083 		XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT},
1084 #else
1085 	{XtNfont, XtCFont, XtRString, sizeof (char *),
1086 		XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT},
1087 #endif
1088 };
1089 
1090 #ifdef FEAT_XFONTSET
1091 static XFontSet SFfont;
1092 #else
1093 static XFontStruct *SFfont;
1094 #endif
1095 
1096 static int SFcurrentListY;
1097 
1098 static XtIntervalId SFscrollTimerId;
1099 
1100 static void SFinitFont __ARGS((void));
1101 
1102     static void
1103 SFinitFont()
1104 {
1105     TextData	*data;
1106 #ifdef FEAT_XFONTSET
1107     XFontSetExtents *extents;
1108     char **missing, *def_str;
1109     int  num_missing;
1110 #endif
1111 
1112     data = XtNew(TextData);
1113 
1114     XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
1115 	    XtNumber(textResources), (Arg *) NULL, ZERO);
1116 
1117 #ifdef FEAT_XFONTSET
1118     SFfont = XCreateFontSet(SFdisplay, data->fontname,
1119 			    &missing, &num_missing, &def_str);
1120 #else
1121     SFfont = XLoadQueryFont(SFdisplay, data->fontname);
1122 #endif
1123     if (!SFfont)
1124     {
1125 #ifdef FEAT_XFONTSET
1126 	SFfont = XCreateFontSet(SFdisplay, SF_DEFAULT_FONT,
1127 					    &missing, &num_missing, &def_str);
1128 #else
1129 	SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);
1130 #endif
1131 	if (!SFfont)
1132 	{
1133 	    EMSG2(_("E616: vim_SelFile: can't get font %s"), SF_DEFAULT_FONT);
1134 	    SFstatus = SEL_FILE_CANCEL;
1135 	    return;
1136 	}
1137     }
1138 
1139 #ifdef FEAT_XFONTSET
1140     extents = XExtentsOfFontSet(SFfont);
1141     SFcharWidth = extents->max_logical_extent.width;
1142     SFcharAscent = -extents->max_logical_extent.y;
1143     SFcharHeight = extents->max_logical_extent.height;
1144 #else
1145     SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;
1146     SFcharAscent = SFfont->max_bounds.ascent;
1147     SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;
1148 #endif
1149 }
1150 
1151 static void SFcreateGC __ARGS((void));
1152 
1153     static void
1154 SFcreateGC()
1155 {
1156     XGCValues	gcValues;
1157     XRectangle	rectangles[1];
1158 
1159     gcValues.foreground = SFfore;
1160 
1161     SFlineGC = XtGetGC(
1162 	    selFileLists[0],
1163 	    (XtGCMask)GCForeground,
1164 	    &gcValues);
1165 
1166     SFscrollGC = XtGetGC(
1167 	    selFileLists[0],
1168 	    (XtGCMask)0,
1169 	    &gcValues);
1170 
1171     gcValues.function = GXxor;
1172     gcValues.foreground = SFfore ^ SFback;
1173     gcValues.background = SFfore ^ SFback;
1174 
1175     SFinvertGC = XtGetGC(
1176 	    selFileLists[0],
1177 	    (XtGCMask)GCFunction | GCForeground | GCBackground,
1178 	    &gcValues);
1179 
1180     gcValues.foreground = SFfore;
1181     gcValues.background = SFback;
1182 #ifndef FEAT_XFONTSET
1183     gcValues.font = SFfont->fid;
1184 #endif
1185 
1186     SFtextGC = XCreateGC(
1187 	    SFdisplay,
1188 	    XtWindow(selFileLists[0]),
1189 #ifdef FEAT_XFONTSET
1190 	    (unsigned long)GCForeground | GCBackground,
1191 #else
1192 	    (unsigned long)GCForeground | GCBackground | GCFont,
1193 #endif
1194 	    &gcValues);
1195 
1196     rectangles[0].x = SFlineToTextH + SFbesideText;
1197     rectangles[0].y = 0;
1198     rectangles[0].width = SFcharsPerEntry * SFcharWidth;
1199     rectangles[0].height = SFupperY + 1;
1200 
1201     XSetClipRectangles(
1202 	    SFdisplay,
1203 	    SFtextGC,
1204 	    0,
1205 	    0,
1206 	    rectangles,
1207 	    1,
1208 	    Unsorted);
1209 }
1210 
1211     static void
1212 SFclearList(n, doScroll)
1213     int	n;
1214     int	doScroll;
1215 {
1216     SFDir	*dir;
1217 
1218     SFcurrentInvert[n] = -1;
1219 
1220     XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
1221 
1222     XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2);
1223 
1224     if (doScroll)
1225     {
1226 	dir = &(SFdirs[SFdirPtr + n]);
1227 
1228 	if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars)
1229 	{
1230 #ifdef FEAT_GUI_NEXTAW
1231 	    XawScrollbarSetThumb(
1232 		    selFileVScrolls[n],
1233 		    (float) (((double) dir->vOrigin) /
1234 			     dir->nEntries),
1235 		    (float) (((double) ((dir->nEntries < SFlistSize)
1236 					? dir->nEntries : SFlistSize)) /
1237 			     dir->nEntries));
1238 #else
1239 	    vim_XawScrollbarSetThumb(
1240 		    selFileVScrolls[n],
1241 		    (float) (((double) dir->vOrigin) /
1242 			     dir->nEntries),
1243 		    (float) (((double) ((dir->nEntries < SFlistSize)
1244 					? dir->nEntries : SFlistSize)) /
1245 			     dir->nEntries),
1246 		    (double)dir->nEntries);
1247 #endif
1248 
1249 #ifdef FEAT_GUI_NEXTAW
1250 	    XawScrollbarSetThumb(
1251 		    selFileHScrolls[n],
1252 		    (float) (((double) dir->hOrigin) / dir->nChars),
1253 		    (float) (((double) ((dir->nChars <
1254 					 SFcharsPerEntry) ? dir->nChars :
1255 					SFcharsPerEntry)) / dir->nChars));
1256 #else
1257 	    vim_XawScrollbarSetThumb(
1258 		    selFileHScrolls[n],
1259 		    (float) (((double) dir->hOrigin) / dir->nChars),
1260 		    (float) (((double) ((dir->nChars <
1261 					 SFcharsPerEntry) ? dir->nChars :
1262 					SFcharsPerEntry)) / dir->nChars),
1263 		    (double)dir->nChars);
1264 #endif
1265 	}
1266 	else
1267 	{
1268 #ifdef FEAT_GUI_NEXTAW
1269 	    XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
1270 		    (float) 1.0);
1271 #else
1272 	    vim_XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
1273 		    (float) 1.0, 1.0);
1274 #endif
1275 #ifdef FEAT_GUI_NEXTAW
1276 	    XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
1277 		    (float) 1.0);
1278 #else
1279 	    vim_XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
1280 		    (float) 1.0, 1.0);
1281 #endif
1282 	}
1283     }
1284 }
1285 
1286 static void SFdeleteEntry __ARGS((SFDir *dir, SFEntry *entry));
1287 
1288     static void
1289 SFdeleteEntry(dir, entry)
1290     SFDir	*dir;
1291     SFEntry	*entry;
1292 {
1293     SFEntry	*e;
1294     SFEntry	*end;
1295     int		n;
1296     int		idx;
1297 
1298     idx = entry - dir->entries;
1299 
1300     if (idx < dir->beginSelection)
1301 	dir->beginSelection--;
1302     if (idx <= dir->endSelection)
1303 	dir->endSelection--;
1304     if (dir->beginSelection > dir->endSelection)
1305 	dir->beginSelection = dir->endSelection = -1;
1306 
1307     if (idx < dir->vOrigin)
1308 	dir->vOrigin--;
1309 
1310     XtFree(entry->real);
1311 
1312     end = &(dir->entries[dir->nEntries - 1]);
1313 
1314     for (e = entry; e < end; e++)
1315 	*e = *(e + 1);
1316 
1317     if (!(--dir->nEntries))
1318 	return;
1319 
1320     n = dir - &(SFdirs[SFdirPtr]);
1321     if ((n < 0) || (n > 2))
1322 	return;
1323 
1324 #ifdef FEAT_GUI_NEXTAW
1325     XawScrollbarSetThumb(
1326 	    selFileVScrolls[n],
1327 	    (float) (((double) dir->vOrigin) / dir->nEntries),
1328 	    (float) (((double) ((dir->nEntries < SFlistSize) ?
1329 				dir->nEntries : SFlistSize)) / dir->nEntries));
1330 #else
1331     vim_XawScrollbarSetThumb(
1332 	    selFileVScrolls[n],
1333 	    (float) (((double) dir->vOrigin) / dir->nEntries),
1334 	    (float) (((double) ((dir->nEntries < SFlistSize) ?
1335 				dir->nEntries : SFlistSize)) / dir->nEntries),
1336 	    (double)dir->nEntries);
1337 #endif
1338 }
1339 
1340 static void SFwriteStatChar __ARGS((char *name, int last, struct stat *statBuf));
1341 
1342     static void
1343 SFwriteStatChar(name, last, statBuf)
1344     char	*name;
1345     int		last;
1346     struct stat	*statBuf;
1347 {
1348     name[last] = SFstatChar(statBuf);
1349 }
1350 
1351 static int SFstatAndCheck __ARGS((SFDir *dir, SFEntry *entry));
1352 
1353     static int
1354 SFstatAndCheck(dir, entry)
1355     SFDir	*dir;
1356     SFEntry	*entry;
1357 {
1358     struct stat	statBuf;
1359     char	save;
1360     int		last;
1361 
1362     /*
1363      * must be restored before returning
1364      */
1365     save = *(dir->path);
1366     *(dir->path) = 0;
1367 
1368     if (!SFchdir(SFcurrentPath))
1369     {
1370 	last = strlen(entry->real) - 1;
1371 	entry->real[last] = 0;
1372 	entry->statDone = 1;
1373 	if ((!mch_stat(entry->real, &statBuf))
1374 #ifdef S_IFLNK
1375 		|| (!mch_lstat(entry->real, &statBuf))
1376 #endif
1377 	   )
1378 	{
1379 	    if (SFfunc)
1380 	    {
1381 		char *shown;
1382 
1383 		shown = NULL;
1384 		if (SFfunc(entry->real, &shown, &statBuf))
1385 		{
1386 		    if (shown)
1387 		    {
1388 			int len;
1389 
1390 			len = strlen(shown);
1391 			entry->shown = XtMalloc((unsigned) (len + 2));
1392 			(void) strcpy(entry->shown, shown);
1393 			SFwriteStatChar(entry->shown, len, &statBuf);
1394 			entry->shown[len + 1] = 0;
1395 		    }
1396 		}
1397 		else
1398 		{
1399 		    SFdeleteEntry(dir, entry);
1400 
1401 		    *(dir->path) = save;
1402 		    return 1;
1403 		}
1404 	    }
1405 	    SFwriteStatChar(entry->real, last, &statBuf);
1406 	}
1407 	else
1408 	    entry->real[last] = ' ';
1409     }
1410 
1411     *(dir->path) = save;
1412     return 0;
1413 }
1414 
1415 
1416     static void
1417 SFdrawStrings(w, dir, from, to)
1418     Window	w;
1419     SFDir	*dir;
1420     int		from;
1421     int		to;
1422 {
1423     int		i;
1424     SFEntry	*entry;
1425     int		x;
1426 
1427     x = SFtextX - dir->hOrigin * SFcharWidth;
1428 
1429     if (dir->vOrigin + to >= dir->nEntries)
1430 	to = dir->nEntries - dir->vOrigin - 1;
1431     for (i = from; i <= to; i++)
1432     {
1433 	entry = &(dir->entries[dir->vOrigin + i]);
1434 	if (!(entry->statDone))
1435 	{
1436 	    if (SFstatAndCheck(dir, entry))
1437 	    {
1438 		if (dir->vOrigin + to >= dir->nEntries)
1439 		    to = dir->nEntries - dir->vOrigin - 1;
1440 		i--;
1441 		continue;
1442 	    }
1443 	}
1444 #ifdef FEAT_XFONTSET
1445 	XmbDrawImageString(
1446 		SFdisplay,
1447 		w,
1448 		SFfont,
1449 		SFtextGC,
1450 		x,
1451 		SFtextYoffset + i * SFentryHeight,
1452 		entry->shown,
1453 		strlen(entry->shown));
1454 #else
1455 	XDrawImageString(
1456 		SFdisplay,
1457 		w,
1458 		SFtextGC,
1459 		x,
1460 		SFtextYoffset + i * SFentryHeight,
1461 		entry->shown,
1462 		strlen(entry->shown));
1463 #endif
1464 	if (dir->vOrigin + i == dir->beginSelection)
1465 	{
1466 	    XDrawLine(
1467 		    SFdisplay,
1468 		    w,
1469 		    SFlineGC,
1470 		    SFlineToTextH + 1,
1471 		    SFlowerY + i * SFentryHeight,
1472 		    SFlineToTextH + SFentryWidth - 2,
1473 		    SFlowerY + i * SFentryHeight);
1474 	}
1475 	if ((dir->vOrigin + i >= dir->beginSelection) &&
1476 		(dir->vOrigin + i <= dir->endSelection))
1477 	{
1478 	    SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
1479 		SFlowerY + i * SFentryHeight;
1480 	    SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
1481 		SFlowerY + (i + 1) * SFentryHeight - 1;
1482 	    XDrawSegments(
1483 		    SFdisplay,
1484 		    w,
1485 		    SFlineGC,
1486 		    SFcompletionSegs,
1487 		    2);
1488 	}
1489 	if (dir->vOrigin + i == dir->endSelection)
1490 	{
1491 	    XDrawLine(
1492 		    SFdisplay,
1493 		    w,
1494 		    SFlineGC,
1495 		    SFlineToTextH + 1,
1496 		    SFlowerY + (i + 1) * SFentryHeight - 1,
1497 		    SFlineToTextH + SFentryWidth - 2,
1498 		    SFlowerY + (i + 1) * SFentryHeight - 1);
1499 	}
1500     }
1501 }
1502 
1503     static void
1504 SFdrawList(n, doScroll)
1505     int	n;
1506     int	doScroll;
1507 {
1508     SFDir	*dir;
1509     Window	w;
1510 
1511     SFclearList(n, doScroll);
1512 
1513     if (SFdirPtr + n < SFdirEnd)
1514     {
1515 	dir = &(SFdirs[SFdirPtr + n]);
1516 	w = XtWindow(selFileLists[n]);
1517 #ifdef FEAT_XFONTSET
1518 	XmbDrawImageString(
1519 		SFdisplay,
1520 		w,
1521 		SFfont,
1522 		SFtextGC,
1523 		SFtextX - dir->hOrigin * SFcharWidth,
1524 		SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
1525 		dir->dir,
1526 		strlen(dir->dir));
1527 #else
1528 	XDrawImageString(
1529 		SFdisplay,
1530 		w,
1531 		SFtextGC,
1532 		SFtextX - dir->hOrigin * SFcharWidth,
1533 		SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
1534 		dir->dir,
1535 		strlen(dir->dir));
1536 #endif
1537 	SFdrawStrings(w, dir, 0, SFlistSize - 1);
1538     }
1539 }
1540 
1541     static void
1542 SFdrawLists(doScroll)
1543     int	doScroll;
1544 {
1545     int	i;
1546 
1547     for (i = 0; i < 3; i++)
1548 	SFdrawList(i, doScroll);
1549 }
1550 
1551     static void
1552 SFinvertEntry(n)
1553     int		n;
1554 {
1555     XFillRectangle(
1556 	    SFdisplay,
1557 	    XtWindow(selFileLists[n]),
1558 	    SFinvertGC,
1559 	    SFlineToTextH,
1560 	    SFcurrentInvert[n] * SFentryHeight + SFlowerY,
1561 	    SFentryWidth,
1562 	    SFentryHeight);
1563 }
1564 
1565 static unsigned long SFscrollTimerInterval __ARGS((void));
1566 
1567     static unsigned long
1568 SFscrollTimerInterval()
1569 {
1570     static int	maxVal = 200;
1571     static int	varyDist = 50;
1572     static int	minDist = 50;
1573     int		t;
1574     int		dist;
1575 
1576     if (SFcurrentListY < SFlowerY)
1577 	dist = SFlowerY - SFcurrentListY;
1578     else if (SFcurrentListY > SFupperY)
1579 	dist = SFcurrentListY - SFupperY;
1580     else
1581 	return (unsigned long) 1;
1582 
1583     t = maxVal - ((maxVal / varyDist) * (dist - minDist));
1584 
1585     if (t < 1)
1586 	t = 1;
1587 
1588     if (t > maxVal)
1589 	t = maxVal;
1590 
1591     return (unsigned long)t;
1592 }
1593 
1594 static void SFscrollTimer __ARGS((XtPointer p, XtIntervalId *id));
1595 
1596     static void
1597 SFscrollTimer(p, id)
1598     XtPointer		p;
1599     XtIntervalId	*id UNUSED;
1600 {
1601     SFDir	*dir;
1602     int		save;
1603     int		n;
1604 
1605     n = (long)p;
1606 
1607     dir = &(SFdirs[SFdirPtr + n]);
1608     save = dir->vOrigin;
1609 
1610     if (SFcurrentListY < SFlowerY)
1611     {
1612 	if (dir->vOrigin > 0)
1613 	    SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1);
1614     }
1615     else if (SFcurrentListY > SFupperY)
1616     {
1617 	if (dir->vOrigin < dir->nEntries - SFlistSize)
1618 	    SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1);
1619     }
1620 
1621     if (dir->vOrigin != save)
1622     {
1623 	if (dir->nEntries)
1624 	{
1625 #ifdef FEAT_GUI_NEXTAW
1626 	    XawScrollbarSetThumb(
1627 		    selFileVScrolls[n],
1628 		    (float) (((double) dir->vOrigin) / dir->nEntries),
1629 		    (float) (((double) ((dir->nEntries < SFlistSize) ?
1630 				dir->nEntries : SFlistSize)) / dir->nEntries));
1631 #else
1632 	    vim_XawScrollbarSetThumb(
1633 		    selFileVScrolls[n],
1634 		    (float) (((double) dir->vOrigin) / dir->nEntries),
1635 		    (float) (((double) ((dir->nEntries < SFlistSize) ?
1636 				dir->nEntries : SFlistSize)) / dir->nEntries),
1637 		    (double)dir->nEntries);
1638 #endif
1639 	}
1640     }
1641 
1642     if (SFbuttonPressed)
1643 	SFscrollTimerId = XtAppAddTimeOut(SFapp,
1644 		       SFscrollTimerInterval(), SFscrollTimer,
1645 		       (XtPointer)(long_u)n);
1646 }
1647 
1648     static int
1649 SFnewInvertEntry(n, event)
1650     int			n;
1651     XMotionEvent	*event;
1652 {
1653     int			x, y;
1654     int			nw;
1655     static int		SFscrollTimerAdded = 0;
1656 
1657     x = event->x;
1658     y = event->y;
1659 
1660     if (SFdirPtr + n >= SFdirEnd)
1661 	return -1;
1662 
1663     if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY))
1664     {
1665 	SFDir *dir = &(SFdirs[SFdirPtr + n]);
1666 
1667 	if (SFscrollTimerAdded)
1668 	{
1669 	    SFscrollTimerAdded = 0;
1670 	    XtRemoveTimeOut(SFscrollTimerId);
1671 	}
1672 
1673 	nw = (y - SFlowerY) / SFentryHeight;
1674 	if (dir->vOrigin + nw >= dir->nEntries)
1675 	    return -1;
1676 	return nw;
1677     }
1678     else
1679     {
1680 	if (SFbuttonPressed)
1681 	{
1682 	    SFcurrentListY = y;
1683 	    if (!SFscrollTimerAdded)
1684 	    {
1685 		SFscrollTimerAdded = 1;
1686 		SFscrollTimerId = XtAppAddTimeOut(SFapp,
1687 			SFscrollTimerInterval(), SFscrollTimer,
1688 			(XtPointer)(long_u)n);
1689 	    }
1690 	}
1691 	return -1;
1692     }
1693 }
1694 
1695     static void
1696 SFenterList(w, n, event)
1697     Widget		w UNUSED;
1698     int			n;
1699     XEnterWindowEvent	*event;
1700 {
1701     int			nw;
1702 
1703     /* sanity */
1704     if (SFcurrentInvert[n] != -1)
1705     {
1706 	SFinvertEntry(n);
1707 	SFcurrentInvert[n] = -1;
1708     }
1709 
1710     nw = SFnewInvertEntry(n, (XMotionEvent *) event);
1711     if (nw != -1)
1712     {
1713 	SFcurrentInvert[n] = nw;
1714 	SFinvertEntry(n);
1715     }
1716 }
1717 
1718     static void
1719 SFleaveList(w, n, event)
1720     Widget	w UNUSED;
1721     int		n;
1722     XEvent	*event UNUSED;
1723 {
1724     if (SFcurrentInvert[n] != -1)
1725     {
1726 	SFinvertEntry(n);
1727 	SFcurrentInvert[n] = -1;
1728     }
1729 }
1730 
1731     static void
1732 SFmotionList(w, n, event)
1733     Widget		w UNUSED;
1734     int			n;
1735     XMotionEvent	*event;
1736 {
1737     int		nw;
1738 
1739     nw = SFnewInvertEntry(n, event);
1740 
1741     if (nw != SFcurrentInvert[n])
1742     {
1743 	if (SFcurrentInvert[n] != -1)
1744 	    SFinvertEntry(n);
1745 	SFcurrentInvert[n] = nw;
1746 	if (nw != -1)
1747 	    SFinvertEntry(n);
1748     }
1749 }
1750 
1751     static void
1752 SFvFloatSliderMovedCallback(w, n, fnew)
1753     Widget	w;
1754     XtPointer	n;
1755     XtPointer	fnew;
1756 {
1757     int		nw;
1758 
1759     nw = (*(float *)fnew) * SFdirs[SFdirPtr + (int)(long)n].nEntries;
1760     SFvSliderMovedCallback(w, (int)(long)n, nw);
1761 }
1762 
1763     static void
1764 SFvSliderMovedCallback(w, n, nw)
1765     Widget	w UNUSED;
1766     int		n;
1767     int		nw;
1768 {
1769     int		old;
1770     Window	win;
1771     SFDir	*dir;
1772 
1773     dir = &(SFdirs[SFdirPtr + n]);
1774 
1775     old = dir->vOrigin;
1776     dir->vOrigin = nw;
1777 
1778     if (old == nw)
1779 	return;
1780 
1781     win = XtWindow(selFileLists[n]);
1782 
1783     if (ABS(nw - old) < SFlistSize)
1784     {
1785 	if (nw > old)
1786 	{
1787 	    XCopyArea(
1788 		    SFdisplay,
1789 		    win,
1790 		    win,
1791 		    SFscrollGC,
1792 		    SFlineToTextH,
1793 		    SFlowerY + (nw - old) * SFentryHeight,
1794 		    SFentryWidth + SFlineToTextH,
1795 		    (SFlistSize - (nw - old)) * SFentryHeight,
1796 		    SFlineToTextH,
1797 		    SFlowerY);
1798 	    XClearArea(
1799 		    SFdisplay,
1800 		    win,
1801 		    SFlineToTextH,
1802 		    SFlowerY + (SFlistSize - (nw - old)) *
1803 		    SFentryHeight,
1804 		    SFentryWidth + SFlineToTextH,
1805 		    (nw - old) * SFentryHeight,
1806 		    False);
1807 	    SFdrawStrings(win, dir, SFlistSize - (nw - old),
1808 		    SFlistSize - 1);
1809 	}
1810 	else
1811 	{
1812 	    XCopyArea(
1813 		    SFdisplay,
1814 		    win,
1815 		    win,
1816 		    SFscrollGC,
1817 		    SFlineToTextH,
1818 		    SFlowerY,
1819 		    SFentryWidth + SFlineToTextH,
1820 		    (SFlistSize - (old - nw)) * SFentryHeight,
1821 		    SFlineToTextH,
1822 		    SFlowerY + (old - nw) * SFentryHeight);
1823 	    XClearArea(
1824 		    SFdisplay,
1825 		    win,
1826 		    SFlineToTextH,
1827 		    SFlowerY,
1828 		    SFentryWidth + SFlineToTextH,
1829 		    (old - nw) * SFentryHeight,
1830 		    False);
1831 	    SFdrawStrings(win, dir, 0, old - nw);
1832 	}
1833     }
1834     else
1835     {
1836 	XClearArea(
1837 		SFdisplay,
1838 		win,
1839 		SFlineToTextH,
1840 		SFlowerY,
1841 		SFentryWidth + SFlineToTextH,
1842 		SFlistSize * SFentryHeight,
1843 		False);
1844 	SFdrawStrings(win, dir, 0, SFlistSize - 1);
1845     }
1846 }
1847 
1848     static void
1849 SFvAreaSelectedCallback(w, n, pnew)
1850     Widget	w;
1851     XtPointer	n;
1852     XtPointer	pnew;
1853 {
1854     SFDir	*dir;
1855     int		nw = (int)(long)pnew;
1856 
1857     dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1858 
1859 #ifdef FEAT_GUI_NEXTAW
1860     if (nw < 0)
1861     {
1862 	if (nw > -SFvScrollHeight)
1863 	    nw = -1;
1864 	else
1865 	    nw = -SFlistSize;
1866     }
1867     else if (nw > 0)
1868     {
1869 	if (nw < SFvScrollHeight)
1870 	    nw = 1;
1871 	else
1872 	    nw = SFlistSize;
1873     }
1874 #endif
1875     nw += dir->vOrigin;
1876 
1877     if (nw > dir->nEntries - SFlistSize)
1878 	nw = dir->nEntries - SFlistSize;
1879 
1880     if (nw < 0)
1881 	nw = 0;
1882 
1883     if (dir->nEntries)
1884     {
1885 	float	f;
1886 
1887 	f = ((double) nw) / dir->nEntries;
1888 
1889 #ifdef FEAT_GUI_NEXTAW
1890 	XawScrollbarSetThumb(
1891 		w,
1892 		f,
1893 		(float) (((double) ((dir->nEntries < SFlistSize) ?
1894 				dir->nEntries : SFlistSize)) / dir->nEntries));
1895 #else
1896 	vim_XawScrollbarSetThumb(
1897 		w,
1898 		f,
1899 		(float) (((double) ((dir->nEntries < SFlistSize) ?
1900 				dir->nEntries : SFlistSize)) / dir->nEntries),
1901 		(double)dir->nEntries);
1902 #endif
1903     }
1904 
1905     SFvSliderMovedCallback(w, (int)(long)n, nw);
1906 }
1907 
1908     static void
1909 SFhSliderMovedCallback(w, n, nw)
1910     Widget	w UNUSED;
1911     XtPointer	n;
1912     XtPointer	nw;
1913 {
1914     SFDir	*dir;
1915     int	save;
1916 
1917     dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1918     save = dir->hOrigin;
1919     dir->hOrigin = (*(float *)nw) * dir->nChars;
1920     if (dir->hOrigin == save)
1921 	return;
1922 
1923     SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
1924 }
1925 
1926     static void
1927 SFhAreaSelectedCallback(w, n, pnew)
1928     Widget	w;
1929     XtPointer	n;
1930     XtPointer	pnew;
1931 {
1932     SFDir	*dir;
1933     int		nw = (int)(long)pnew;
1934 
1935     dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1936 
1937 #ifdef FEAT_GUI_NEXTAW
1938     if (nw < 0)
1939     {
1940 	if (nw > -SFhScrollWidth)
1941 	    nw = -1;
1942 	else
1943 	    nw = -SFcharsPerEntry;
1944     }
1945     else if (nw > 0)
1946     {
1947 	if (nw < SFhScrollWidth)
1948 	    nw = 1;
1949 	else
1950 	    nw = SFcharsPerEntry;
1951     }
1952 #endif
1953     nw += dir->hOrigin;
1954 
1955     if (nw > dir->nChars - SFcharsPerEntry)
1956 	nw = dir->nChars - SFcharsPerEntry;
1957 
1958     if (nw < 0)
1959 	nw = 0;
1960 
1961     if (dir->nChars)
1962     {
1963 	float	f;
1964 
1965 	f = ((double) nw) / dir->nChars;
1966 
1967 #ifdef FEAT_GUI_NEXTAW
1968 	XawScrollbarSetThumb(
1969 		w,
1970 		f,
1971 		(float) (((double) ((dir->nChars < SFcharsPerEntry) ?
1972 			       dir->nChars : SFcharsPerEntry)) / dir->nChars));
1973 #else
1974 	vim_XawScrollbarSetThumb(
1975 		w,
1976 		f,
1977 		(float) (((double) ((dir->nChars < SFcharsPerEntry) ?
1978 			       dir->nChars : SFcharsPerEntry)) / dir->nChars),
1979 		(double)dir->nChars);
1980 #endif
1981 
1982 	SFhSliderMovedCallback(w, n, (XtPointer)&f);
1983     }
1984 }
1985 
1986     static void
1987 SFpathSliderMovedCallback(w, client_data, nw)
1988     Widget	w UNUSED;
1989     XtPointer	client_data UNUSED;
1990     XtPointer	nw;
1991 {
1992     SFDir		*dir;
1993     int			n;
1994     XawTextPosition	pos;
1995     int			SFdirPtrSave;
1996 
1997     SFdirPtrSave = SFdirPtr;
1998     SFdirPtr = (*(float *)nw) * SFdirEnd;
1999     if (SFdirPtr == SFdirPtrSave)
2000 	return;
2001 
2002     SFdrawLists(SF_DO_SCROLL);
2003 
2004     n = 2;
2005     while (SFdirPtr + n >= SFdirEnd)
2006 	n--;
2007 
2008     dir = &(SFdirs[SFdirPtr + n]);
2009 
2010     pos = dir->path - SFcurrentPath;
2011 
2012     if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
2013     {
2014 	pos -= strlen(SFstartDir);
2015 	if (pos < 0)
2016 	    pos = 0;
2017     }
2018 
2019     XawTextSetInsertionPoint(selFileField, pos);
2020 }
2021 
2022     static void
2023 SFpathAreaSelectedCallback(w, client_data, pnew)
2024     Widget	w;
2025     XtPointer	client_data UNUSED;
2026     XtPointer	pnew;
2027 {
2028     int		nw = (int)(long)pnew;
2029     float	f;
2030 
2031 #ifdef FEAT_GUI_NEXTAW
2032     if (nw < 0)
2033     {
2034 	if (nw > -SFpathScrollWidth)
2035 	    nw = -1;
2036 	else
2037 	    nw = -3;
2038     }
2039     else if (nw > 0)
2040     {
2041 	if (nw < SFpathScrollWidth)
2042 	    nw = 1;
2043 	else
2044 	    nw = 3;
2045     }
2046 #endif
2047     nw += SFdirPtr;
2048 
2049     if (nw > SFdirEnd - 3)
2050 	nw = SFdirEnd - 3;
2051 
2052     if (nw < 0)
2053 	nw = 0;
2054 
2055     f = ((double) nw) / SFdirEnd;
2056 
2057 #ifdef FEAT_GUI_NEXTAW
2058     XawScrollbarSetThumb(
2059 	    w,
2060 	    f,
2061 	    (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd));
2062 #else
2063     vim_XawScrollbarSetThumb(
2064 	    w,
2065 	    f,
2066 	    (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd),
2067 	    (double)SFdirEnd);
2068 #endif
2069 
2070     SFpathSliderMovedCallback(w, (XtPointer) NULL, (XtPointer)&f);
2071 }
2072 
2073     static Boolean
2074 SFworkProc()
2075 {
2076     SFDir	*dir;
2077     SFEntry	*entry;
2078 
2079     for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
2080     {
2081 	if (!(dir->nEntries))
2082 	    continue;
2083 	for (entry = &(dir->entries[dir->nEntries - 1]);
2084 		entry >= dir->entries;
2085 		entry--)
2086 	{
2087 	    if (!(entry->statDone))
2088 	    {
2089 		(void)SFstatAndCheck(dir, entry);
2090 		return False;
2091 	    }
2092 	}
2093     }
2094 
2095     SFworkProcAdded = 0;
2096 
2097     return True;
2098 }
2099 
2100 /***************** Dir.c */
2101 
2102     static int
2103 SFcompareEntries(p, q)
2104     const void	*p;
2105     const void	*q;
2106 {
2107     return strcmp(((SFEntry *)p)->real, ((SFEntry *)q)->real);
2108 }
2109 
2110     static int
2111 SFgetDir(dir)
2112     SFDir	*dir;
2113 {
2114     SFEntry		*result = NULL;
2115     int			Alloc = 0;
2116     int			i;
2117     DIR			*dirp;
2118     struct dirent	*dp;
2119     char		*str;
2120     int			len;
2121     int			maxChars;
2122     struct stat		statBuf;
2123 
2124     maxChars = strlen(dir->dir) - 1;
2125 
2126     dir->entries = NULL;
2127     dir->nEntries = 0;
2128     dir->nChars = 0;
2129 
2130     result = NULL;
2131     i = 0;
2132 
2133     dirp = opendir(".");
2134     if (!dirp)
2135 	return 1;
2136 
2137     (void)mch_stat(".", &statBuf);
2138     dir->mtime = statBuf.st_mtime;
2139 
2140     while ((dp = readdir(dirp)))
2141     {
2142 	/* Ignore "." and ".." */
2143 	if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
2144 	    continue;
2145 	if (i >= Alloc)
2146 	{
2147 	    Alloc = 2 * (Alloc + 1);
2148 	    result = (SFEntry *) XtRealloc((char *) result,
2149 		    (unsigned) (Alloc * sizeof(SFEntry)));
2150 	}
2151 	result[i].statDone = 0;
2152 	str = dp->d_name;
2153 	len = strlen(str);
2154 	result[i].real = XtMalloc((unsigned) (len + 2));
2155 	(void) strcat(strcpy(result[i].real, str), " ");
2156 	if (len > maxChars)
2157 	    maxChars = len;
2158 	result[i].shown = result[i].real;
2159 	i++;
2160     }
2161 
2162     qsort((char *) result, (size_t) i, sizeof(SFEntry), SFcompareEntries);
2163 
2164     dir->entries = result;
2165     dir->nEntries = i;
2166     dir->nChars = maxChars + 1;
2167 
2168     closedir(dirp);
2169 
2170     return 0;
2171 }
2172 
2173 /***************** SFinternal.h */
2174 
2175 #include <sys/param.h>
2176 #include <X11/cursorfont.h>
2177 #include <X11/Composite.h>
2178 #include <X11/Shell.h>
2179 #ifdef FEAT_GUI_NEXTAW
2180 # include <X11/neXtaw/Form.h>
2181 # include <X11/neXtaw/Command.h>
2182 # include <X11/neXtaw/Label.h>
2183 #else
2184 #include <X11/Xaw/Form.h>
2185 #include <X11/Xaw/Command.h>
2186 #include <X11/Xaw/Label.h>
2187 #endif
2188 
2189 static char *oneLineTextEditTranslations = "\
2190 	<Key>Return:	redraw-display()\n\
2191 	Ctrl<Key>M:	redraw-display()\n\
2192 ";
2193 
2194 static void SFexposeList __ARGS((Widget w, XtPointer n, XEvent *event, Boolean *cont));
2195 
2196     static void
2197 SFexposeList(w, n, event, cont)
2198     Widget	w UNUSED;
2199     XtPointer	n;
2200     XEvent	*event;
2201     Boolean	*cont UNUSED;
2202 {
2203     if ((event->type == NoExpose) || event->xexpose.count)
2204 	return;
2205 
2206     SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
2207 }
2208 
2209 static void SFmodVerifyCallback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont));
2210 
2211     static void
2212 SFmodVerifyCallback(w, client_data, event, cont)
2213     Widget		w UNUSED;
2214     XtPointer		client_data UNUSED;
2215     XEvent		*event;
2216     Boolean		*cont UNUSED;
2217 {
2218     char	buf[2];
2219 
2220     if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
2221 	    ((*buf) == '\r'))
2222 	SFstatus = SEL_FILE_OK;
2223     else
2224 	SFstatus = SEL_FILE_TEXT;
2225 }
2226 
2227 static void SFokCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
2228 
2229     static void
2230 SFokCallback(w, cl, cd)
2231     Widget	w UNUSED;
2232     XtPointer	cl UNUSED;
2233     XtPointer	cd UNUSED;
2234 {
2235     SFstatus = SEL_FILE_OK;
2236 }
2237 
2238 static XtCallbackRec SFokSelect[] =
2239 {
2240     { SFokCallback, (XtPointer) NULL },
2241     { NULL, (XtPointer) NULL },
2242 };
2243 
2244 static void SFcancelCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
2245 
2246     static void
2247 SFcancelCallback(w, cl, cd)
2248     Widget	w UNUSED;
2249     XtPointer	cl UNUSED;
2250     XtPointer	cd UNUSED;
2251 {
2252     SFstatus = SEL_FILE_CANCEL;
2253 }
2254 
2255 static XtCallbackRec SFcancelSelect[] =
2256 {
2257     { SFcancelCallback, (XtPointer) NULL },
2258     { NULL, (XtPointer) NULL },
2259 };
2260 
2261 static void SFdismissAction __ARGS((Widget w, XEvent *event, String *params, Cardinal *num_params));
2262 
2263     static void
2264 SFdismissAction(w, event, params, num_params)
2265     Widget	w UNUSED;
2266     XEvent	*event;
2267     String	*params UNUSED;
2268     Cardinal	*num_params UNUSED;
2269 {
2270     if (event->type == ClientMessage
2271 	    && (Atom)event->xclient.data.l[0] != SFwmDeleteWindow)
2272 	return;
2273 
2274     SFstatus = SEL_FILE_CANCEL;
2275 }
2276 
2277 static char *wmDeleteWindowTranslation = "\
2278 	<Message>WM_PROTOCOLS:	SelFileDismiss()\n\
2279 ";
2280 
2281 static XtActionsRec actions[] =
2282 {
2283     {"SelFileDismiss",	SFdismissAction},
2284 };
2285 
2286     static void
2287 SFsetColors(bg, fg, scroll_bg, scroll_fg)
2288     guicolor_T	bg;
2289     guicolor_T	fg;
2290     guicolor_T	scroll_bg;
2291     guicolor_T	scroll_fg;
2292 {
2293     if (selFileForm)
2294     {
2295 	XtVaSetValues(selFileForm, XtNbackground,  bg,
2296 				   XtNforeground,  fg,
2297 				   XtNborderColor, bg,
2298 				   NULL);
2299     }
2300     {
2301 	int i;
2302 
2303 	for (i = 0; i < 3; ++i)
2304 	{
2305 	    if (selFileLists[i])
2306 	    {
2307 		XtVaSetValues(selFileLists[i], XtNbackground,  bg,
2308 					       XtNforeground,  fg,
2309 					       XtNborderColor, fg,
2310 					       NULL);
2311 	    }
2312 	}
2313     }
2314     if (selFileOK)
2315     {
2316 	XtVaSetValues(selFileOK, XtNbackground,  bg,
2317 				 XtNforeground,  fg,
2318 				 XtNborderColor, fg,
2319 				 NULL);
2320     }
2321     if (selFileCancel)
2322     {
2323 	XtVaSetValues(selFileCancel, XtNbackground, bg,
2324 				     XtNforeground, fg,
2325 				     XtNborderColor, fg,
2326 				     NULL);
2327     }
2328     if (selFilePrompt)
2329     {
2330 	XtVaSetValues(selFilePrompt, XtNbackground, bg,
2331 				     XtNforeground, fg,
2332 				     NULL);
2333     }
2334     if (gui.dpy)
2335     {
2336 	XSetBackground(gui.dpy, SFtextGC, bg);
2337 	XSetForeground(gui.dpy, SFtextGC, fg);
2338 	XSetForeground(gui.dpy, SFlineGC, fg);
2339 
2340 	/* This is an xor GC, so combine the fg and background */
2341 	XSetBackground(gui.dpy, SFinvertGC, fg ^ bg);
2342 	XSetForeground(gui.dpy, SFinvertGC, fg ^ bg);
2343     }
2344     if (selFileHScroll)
2345     {
2346 	XtVaSetValues(selFileHScroll, XtNbackground, scroll_bg,
2347 				      XtNforeground, scroll_fg,
2348 				      XtNborderColor, fg,
2349 				      NULL);
2350     }
2351     {
2352 	int i;
2353 
2354 	for (i = 0; i < 3; i++)
2355 	{
2356 	    XtVaSetValues(selFileVScrolls[i], XtNbackground, scroll_bg,
2357 					      XtNforeground, scroll_fg,
2358 					      XtNborderColor, fg,
2359 					      NULL);
2360 	    XtVaSetValues(selFileHScrolls[i], XtNbackground, scroll_bg,
2361 					      XtNforeground, scroll_fg,
2362 					      XtNborderColor, fg,
2363 					      NULL);
2364 	}
2365     }
2366 }
2367 
2368     static void
2369 SFcreateWidgets(toplevel, prompt, ok, cancel)
2370     Widget	toplevel;
2371     char	*prompt;
2372     char	*ok;
2373     char	*cancel;
2374 {
2375     Cardinal	n;
2376     int		listWidth, listHeight;
2377     int		listSpacing = 10;
2378     int		scrollThickness = 15;
2379     int		hScrollX, hScrollY;
2380     int		vScrollX, vScrollY;
2381 
2382     selFile = XtVaAppCreateShell("selFile", "SelFile",
2383 		transientShellWidgetClass, SFdisplay,
2384 		XtNtransientFor, toplevel,
2385 		XtNtitle, prompt,
2386 		NULL);
2387 
2388     /* Add WM_DELETE_WINDOW protocol */
2389     XtAppAddActions(XtWidgetToApplicationContext(selFile),
2390 	    actions, XtNumber(actions));
2391     XtOverrideTranslations(selFile,
2392 	    XtParseTranslationTable(wmDeleteWindowTranslation));
2393 
2394     selFileForm = XtVaCreateManagedWidget("selFileForm",
2395 		formWidgetClass, selFile,
2396 		XtNdefaultDistance, 30,
2397 		XtNforeground, SFfore,
2398 		XtNbackground, SFback,
2399 		XtNborderColor, SFback,
2400 		NULL);
2401 
2402     selFilePrompt = XtVaCreateManagedWidget("selFilePrompt",
2403 		labelWidgetClass, selFileForm,
2404 		XtNlabel, prompt,
2405 		XtNresizable, True,
2406 		XtNtop, XtChainTop,
2407 		XtNbottom, XtChainTop,
2408 		XtNleft, XtChainLeft,
2409 		XtNright, XtChainLeft,
2410 		XtNborderWidth, 0,
2411 		XtNforeground, SFfore,
2412 		XtNbackground, SFback,
2413 		NULL);
2414 
2415     /*
2416     XtVaGetValues(selFilePrompt,
2417 		XtNforeground, &SFfore,
2418 		XtNbackground, &SFback,
2419 		NULL);
2420     */
2421 
2422     SFinitFont();
2423 
2424     SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth +
2425 	SFbesideText;
2426     SFentryHeight = SFaboveAndBelowText + SFcharHeight +
2427 	SFaboveAndBelowText;
2428 
2429     listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
2430 	scrollThickness;
2431     listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2432 	SFlineToTextV + SFlistSize * SFentryHeight +
2433 	SFlineToTextV + 1 + scrollThickness;
2434 
2435     SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;
2436 
2437     hScrollX = -1;
2438     hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2439 	SFlineToTextV + SFlistSize * SFentryHeight +
2440 	SFlineToTextV;
2441     SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
2442 
2443     vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
2444     vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
2445     SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
2446 	SFlineToTextV;
2447 
2448     SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
2449     SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2450 	SFlineToTextV;
2451     SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2452 	SFlineToTextV + SFlistSize * SFentryHeight - 1;
2453 
2454     SFtextX = SFlineToTextH + SFbesideText;
2455     SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
2456 
2457     SFsegs[0].x1 = 0;
2458     SFsegs[0].y1 = vScrollY;
2459     SFsegs[0].x2 = vScrollX - 1;
2460     SFsegs[0].y2 = vScrollY;
2461     SFsegs[1].x1 = vScrollX;
2462     SFsegs[1].y1 = 0;
2463     SFsegs[1].x2 = vScrollX;
2464     SFsegs[1].y2 = vScrollY - 1;
2465 
2466     SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
2467     SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
2468 	SFlineToTextH + SFentryWidth - 1;
2469 
2470     selFileField = XtVaCreateManagedWidget("selFileField",
2471 		asciiTextWidgetClass, selFileForm,
2472 		XtNwidth, 3 * listWidth + 2 * listSpacing + 4,
2473 		XtNborderColor, SFfore,
2474 		XtNfromVert, selFilePrompt,
2475 		XtNvertDistance, 10,
2476 		XtNresizable, True,
2477 		XtNtop, XtChainTop,
2478 		XtNbottom, XtChainTop,
2479 		XtNleft, XtChainLeft,
2480 		XtNright, XtChainLeft,
2481 		XtNstring, SFtextBuffer,
2482 		XtNlength, MAXPATHL,
2483 		XtNeditType, XawtextEdit,
2484 		XtNwrap, XawtextWrapWord,
2485 		XtNresize, XawtextResizeHeight,
2486 		XtNuseStringInPlace, True,
2487 		NULL);
2488 
2489     XtOverrideTranslations(selFileField,
2490 	    XtParseTranslationTable(oneLineTextEditTranslations));
2491     XtSetKeyboardFocus(selFileForm, selFileField);
2492 
2493     selFileHScroll = XtVaCreateManagedWidget("selFileHScroll",
2494 #ifdef FEAT_GUI_NEXTAW
2495 		scrollbarWidgetClass, selFileForm,
2496 #else
2497 		vim_scrollbarWidgetClass, selFileForm,
2498 #endif
2499 		XtNorientation, XtorientHorizontal,
2500 		XtNwidth, SFpathScrollWidth,
2501 		XtNheight, scrollThickness,
2502 		XtNborderColor, SFfore,
2503 		XtNfromVert, selFileField,
2504 		XtNvertDistance, 30,
2505 		XtNtop, XtChainTop,
2506 		XtNbottom, XtChainTop,
2507 		XtNleft, XtChainLeft,
2508 		XtNright, XtChainLeft,
2509 		XtNforeground, gui.scroll_fg_pixel,
2510 		XtNbackground, gui.scroll_bg_pixel,
2511 #ifndef FEAT_GUI_NEXTAW
2512 		XtNlimitThumb, 1,
2513 #endif
2514 		NULL);
2515 
2516     XtAddCallback(selFileHScroll, XtNjumpProc,
2517 	    (XtCallbackProc) SFpathSliderMovedCallback, (XtPointer)NULL);
2518     XtAddCallback(selFileHScroll, XtNscrollProc,
2519 	    (XtCallbackProc) SFpathAreaSelectedCallback, (XtPointer)NULL);
2520 
2521     selFileLists[0] = XtVaCreateManagedWidget("selFileList1",
2522 		compositeWidgetClass, selFileForm,
2523 		XtNwidth, listWidth,
2524 		XtNheight, listHeight,
2525 		XtNforeground,  SFfore,
2526 		XtNbackground,  SFback,
2527 		XtNborderColor, SFfore,
2528 		XtNfromVert, selFileHScroll,
2529 		XtNvertDistance, 10,
2530 		XtNtop, XtChainTop,
2531 		XtNbottom, XtChainTop,
2532 		XtNleft, XtChainLeft,
2533 		XtNright, XtChainLeft,
2534 		NULL);
2535 
2536     selFileLists[1] = XtVaCreateManagedWidget("selFileList2",
2537 		compositeWidgetClass, selFileForm,
2538 		XtNwidth, listWidth,
2539 		XtNheight, listHeight,
2540 		XtNforeground,  SFfore,
2541 		XtNbackground,  SFback,
2542 		XtNborderColor, SFfore,
2543 		XtNfromHoriz, selFileLists[0],
2544 		XtNfromVert, selFileHScroll,
2545 		XtNhorizDistance, listSpacing,
2546 		XtNvertDistance, 10,
2547 		XtNtop, XtChainTop,
2548 		XtNbottom, XtChainTop,
2549 		XtNleft, XtChainLeft,
2550 		XtNright, XtChainLeft,
2551 		NULL);
2552 
2553     selFileLists[2] = XtVaCreateManagedWidget("selFileList3",
2554 		compositeWidgetClass, selFileForm,
2555 		XtNwidth, listWidth,
2556 		XtNheight, listHeight,
2557 		XtNforeground,  SFfore,
2558 		XtNbackground,  SFback,
2559 		XtNborderColor, SFfore,
2560 		XtNfromHoriz, selFileLists[1],
2561 		XtNfromVert, selFileHScroll,
2562 		XtNhorizDistance, listSpacing,
2563 		XtNvertDistance, 10,
2564 		XtNtop, XtChainTop,
2565 		XtNbottom, XtChainTop,
2566 		XtNleft, XtChainLeft,
2567 		XtNright, XtChainLeft,
2568 		NULL);
2569 
2570     for (n = 0; n < 3; n++)
2571     {
2572 	selFileVScrolls[n] = XtVaCreateManagedWidget("selFileVScroll",
2573 #ifdef FEAT_GUI_NEXTAW
2574 		    scrollbarWidgetClass, selFileLists[n],
2575 #else
2576 		    vim_scrollbarWidgetClass, selFileLists[n],
2577 #endif
2578 		    XtNx, vScrollX,
2579 		    XtNy, vScrollY,
2580 		    XtNwidth, scrollThickness,
2581 		    XtNheight, SFvScrollHeight,
2582 		    XtNborderColor, SFfore,
2583 		    XtNforeground, gui.scroll_fg_pixel,
2584 		    XtNbackground, gui.scroll_bg_pixel,
2585 #ifndef FEAT_GUI_NEXTAW
2586 		    XtNlimitThumb, 1,
2587 #endif
2588 		    NULL);
2589 
2590 	XtAddCallback(selFileVScrolls[n], XtNjumpProc,
2591 		(XtCallbackProc)SFvFloatSliderMovedCallback,
2592 		(XtPointer)(long_u)n);
2593 	XtAddCallback(selFileVScrolls[n], XtNscrollProc,
2594 		(XtCallbackProc)SFvAreaSelectedCallback, (XtPointer)(long_u)n);
2595 
2596 	selFileHScrolls[n] = XtVaCreateManagedWidget("selFileHScroll",
2597 #ifdef FEAT_GUI_NEXTAW
2598 		    scrollbarWidgetClass, selFileLists[n],
2599 #else
2600 		    vim_scrollbarWidgetClass, selFileLists[n],
2601 #endif
2602 		    XtNorientation, XtorientHorizontal,
2603 		    XtNx, hScrollX,
2604 		    XtNy, hScrollY,
2605 		    XtNwidth, SFhScrollWidth,
2606 		    XtNheight, scrollThickness,
2607 		    XtNborderColor, SFfore,
2608 		    XtNforeground, gui.scroll_fg_pixel,
2609 		    XtNbackground, gui.scroll_bg_pixel,
2610 #ifndef FEAT_GUI_NEXTAW
2611 		    XtNlimitThumb, 1,
2612 #endif
2613 		    NULL);
2614 
2615 	XtAddCallback(selFileHScrolls[n], XtNjumpProc,
2616 		(XtCallbackProc)SFhSliderMovedCallback,
2617 		(XtPointer)(long_u)n);
2618 	XtAddCallback(selFileHScrolls[n], XtNscrollProc,
2619 		(XtCallbackProc)SFhAreaSelectedCallback, (XtPointer)(long_u)n);
2620     }
2621 
2622     selFileOK = XtVaCreateManagedWidget("selFileOK",
2623 		commandWidgetClass, selFileForm,
2624 		XtNlabel, ok,
2625 		XtNresizable, True,
2626 		XtNcallback, SFokSelect,
2627 		XtNforeground,  SFfore,
2628 		XtNbackground,  SFback,
2629 		XtNborderColor, SFfore,
2630 		XtNfromHoriz, selFileLists[0],
2631 		XtNfromVert, selFileLists[0],
2632 		XtNvertDistance, 30,
2633 		XtNtop, XtChainTop,
2634 		XtNbottom, XtChainTop,
2635 		XtNleft, XtChainLeft,
2636 		XtNright, XtChainLeft,
2637 		NULL);
2638 
2639     selFileCancel = XtVaCreateManagedWidget("selFileCancel",
2640 		commandWidgetClass, selFileForm,
2641 		XtNlabel, cancel,
2642 		XtNresizable, True,
2643 		XtNcallback, SFcancelSelect,
2644 		XtNforeground,  SFfore,
2645 		XtNbackground,  SFback,
2646 		XtNborderColor, SFfore,
2647 		XtNfromHoriz, selFileOK,
2648 		XtNfromVert, selFileLists[0],
2649 		XtNhorizDistance, 30,
2650 		XtNvertDistance, 30,
2651 		XtNtop, XtChainTop,
2652 		XtNbottom, XtChainTop,
2653 		XtNleft, XtChainLeft,
2654 		XtNright, XtChainLeft,
2655 		NULL);
2656 
2657     XtSetMappedWhenManaged(selFile, False);
2658     XtRealizeWidget(selFile);
2659 
2660     /* Add WM_DELETE_WINDOW protocol */
2661     SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
2662     XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
2663 
2664     SFcreateGC();
2665 
2666     for (n = 0; n < 3; n++)
2667     {
2668 	XtAddEventHandler(selFileLists[n], ExposureMask, True,
2669 		(XtEventHandler)SFexposeList, (XtPointer)(long_u)n);
2670 	XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
2671 		(XtEventHandler)SFenterList, (XtPointer)(long_u)n);
2672 	XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
2673 		(XtEventHandler)SFleaveList, (XtPointer)(long_u)n);
2674 	XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
2675 		(XtEventHandler)SFmotionList, (XtPointer)(long_u)n);
2676 	XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
2677 		(XtEventHandler)SFbuttonPressList, (XtPointer)(long_u)n);
2678 	XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
2679 		(XtEventHandler)SFbuttonReleaseList, (XtPointer)(long_u)n);
2680     }
2681 
2682     XtAddEventHandler(selFileField, KeyPressMask, False,
2683 				       SFmodVerifyCallback, (XtPointer)NULL);
2684 
2685     SFapp = XtWidgetToApplicationContext(selFile);
2686 }
2687 
2688     static void
2689 SFtextChanged()
2690 {
2691 #if defined(FEAT_XFONTSET) && defined(XtNinternational)
2692     if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
2693     {
2694 	wchar_t *wcbuf=(wchar_t *)SFtextBuffer;
2695 
2696 	if ((wcbuf[0] == L'/') || (wcbuf[0] == L'~'))
2697 	{
2698 	    (void) wcstombs(SFcurrentPath, wcbuf, MAXPATHL);
2699 	    SFtextPos = XawTextGetInsertionPoint(selFileField);
2700 	}
2701 	else
2702 	{
2703 	    strcpy(SFcurrentPath, SFstartDir);
2704 	    (void) wcstombs(SFcurrentPath + strlen(SFcurrentPath), wcbuf, MAXPATHL);
2705 
2706 	    SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
2707 	}
2708     }
2709     else
2710 #endif
2711     if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~'))
2712     {
2713 	(void) strcpy(SFcurrentPath, SFtextBuffer);
2714 	SFtextPos = XawTextGetInsertionPoint(selFileField);
2715     }
2716     else
2717     {
2718 	(void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
2719 
2720 	SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
2721     }
2722 
2723     if (!SFworkProcAdded)
2724     {
2725 	(void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
2726 	SFworkProcAdded = 1;
2727     }
2728 
2729     SFupdatePath();
2730 }
2731 
2732     static char *
2733 SFgetText()
2734 {
2735 #if defined(FEAT_XFONTSET) && defined(XtNinternational)
2736     char *buf;
2737 
2738     if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
2739     {
2740 	wchar_t *wcbuf;
2741 	int mbslength;
2742 
2743 	XtVaGetValues(selFileField,
2744 	    XtNstring, &wcbuf,
2745 	NULL);
2746 	mbslength = wcstombs(NULL, wcbuf, 0);
2747 	/* Hack: some broken wcstombs() returns zero, just get a large buffer */
2748 	if (mbslength == 0 && wcbuf != NULL && wcbuf[0] != 0)
2749 	    mbslength = MAXPATHL;
2750 	buf=(char *)XtMalloc(mbslength + 1);
2751 	wcstombs(buf, wcbuf, mbslength +1);
2752 	return buf;
2753     }
2754 #endif
2755     return (char *)vim_strsave((char_u *)SFtextBuffer);
2756 }
2757 
2758     static void
2759 SFprepareToReturn()
2760 {
2761     SFstatus = SEL_FILE_NULL;
2762     XtRemoveGrab(selFile);
2763     XtUnmapWidget(selFile);
2764     XtRemoveTimeOut(SFdirModTimerId);
2765     if (SFchdir(SFstartDir))
2766     {
2767 	EMSG(_("E614: vim_SelFile: can't return to current directory"));
2768 	SFstatus = SEL_FILE_CANCEL;
2769     }
2770 }
2771 
2772     char *
2773 vim_SelFile(toplevel, prompt, init_path, show_entry, x, y, fg, bg, scroll_fg, scroll_bg)
2774     Widget	toplevel;
2775     char	*prompt;
2776     char	*init_path;
2777     int		(*show_entry)();
2778     int		x, y;
2779     guicolor_T	fg, bg;
2780     guicolor_T	scroll_fg, scroll_bg; /* The "Scrollbar" group colors */
2781 {
2782     static int	firstTime = 1;
2783     XEvent	event;
2784     char	*name_return;
2785 
2786     if (prompt == NULL)
2787 	prompt = _("Pathname:");
2788     SFfore = fg;
2789     SFback = bg;
2790 
2791     if (mch_dirname((char_u *)SFstartDir, MAXPATHL) == FAIL)
2792     {
2793 	EMSG(_("E615: vim_SelFile: can't get current directory"));
2794 	return NULL;
2795     }
2796 
2797     if (firstTime)
2798     {
2799 	firstTime = 0;
2800 	SFdisplay = XtDisplay(toplevel);
2801 	SFcreateWidgets(toplevel, prompt, _("OK"), _("Cancel"));
2802     }
2803     else
2804     {
2805 	XtVaSetValues(selFilePrompt, XtNlabel, prompt, NULL);
2806 	XtVaSetValues(selFile, XtNtitle, prompt, NULL);
2807 	SFsetColors(bg, fg, scroll_bg, scroll_fg);
2808     }
2809 
2810     XtVaSetValues(selFile, XtNx, x, XtNy, y, NULL);
2811     XtMapWidget(selFile);
2812 
2813     (void)strcat(SFstartDir, "/");
2814     (void)strcpy(SFcurrentDir, SFstartDir);
2815 
2816     if (init_path)
2817     {
2818 	if (init_path[0] == '/')
2819 	{
2820 	    (void)strcpy(SFcurrentPath, init_path);
2821 	    if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
2822 		SFsetText(SFcurrentPath);
2823 	    else
2824 		SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
2825 	}
2826 	else
2827 	{
2828 	    (void)strcat(strcpy(SFcurrentPath, SFstartDir), init_path);
2829 	    SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
2830 	}
2831     }
2832     else
2833 	(void)strcpy(SFcurrentPath, SFstartDir);
2834 
2835     SFfunc = show_entry;
2836 
2837     SFtextChanged();
2838 
2839     XtAddGrab(selFile, True, True);
2840 
2841     SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
2842 	    SFdirModTimer, (XtPointer) NULL);
2843 
2844     for (;;)
2845     {
2846 	XtAppNextEvent(SFapp, &event);
2847 	XtDispatchEvent(&event);
2848 	switch (SFstatus)
2849 	{
2850 	    case SEL_FILE_TEXT:
2851 		SFstatus = SEL_FILE_NULL;
2852 		SFtextChanged();
2853 		break;
2854 	    case SEL_FILE_OK:
2855 		name_return = SFgetText();
2856 		SFprepareToReturn();
2857 		return name_return;
2858 	    case SEL_FILE_CANCEL:
2859 		SFprepareToReturn();
2860 		return NULL;
2861 	    case SEL_FILE_NULL:
2862 		break;
2863 	}
2864     }
2865 }
2866 #endif /* FEAT_BROWSE */
2867