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