Merge branch 'vim-with-runtime' into feat/persistent-undo
[vim_extended.git] / src / gui_at_fs.c
blob0206284b2a7181eb00e6726f8a56bf75ef6abeb2
1 /* vi:set ts=8 sts=4 sw=4: */
3 /*
4 * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
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.
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.
24 * Author: Erik M. van der Poel
25 * Software Research Associates, Inc., Tokyo, Japan
26 * erik@sra.co.jp
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
41 * Heavely modified for Vim by Bram Moolenaar
44 #include "vim.h"
46 /* Only include this when using the file browser */
48 #ifdef FEAT_BROWSE
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
55 #ifndef FEAT_GUI_NEXTAW
56 # include "gui_at_sb.h"
57 #endif
59 /***************** SFinternal.h */
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
73 #define SEL_FILE_CANCEL -1
74 #define SEL_FILE_OK 0
75 #define SEL_FILE_NULL 1
76 #define SEL_FILE_TEXT 2
78 #define SF_DO_SCROLL 1
79 #define SF_DO_NOT_SCROLL 0
81 typedef struct
83 int statDone;
84 char *real;
85 char *shown;
86 } SFEntry;
88 typedef struct
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;
103 static char SFstartDir[MAXPATHL],
104 SFcurrentPath[MAXPATHL],
105 SFcurrentDir[MAXPATHL];
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];
118 static Display *SFdisplay;
120 static int SFcharWidth, SFcharAscent, SFcharHeight;
122 static SFDir *SFdirs = NULL;
124 static int SFdirEnd;
125 static int SFdirPtr;
127 static Pixel SFfore, SFback;
129 static Atom SFwmDeleteWindow;
131 static XSegment SFsegs[2], SFcompletionSegs[2];
133 static XawTextPosition SFtextPos;
135 static int SFupperX, SFlowerY, SFupperY;
137 static int SFtextX, SFtextYoffset;
139 static int SFentryWidth, SFentryHeight;
141 static int SFlineToTextH = 3;
142 static int SFlineToTextV = 3;
144 static int SFbesideText = 3;
145 static int SFaboveAndBelowText = 2;
147 static int SFcharsPerEntry = 15;
149 static int SFlistSize = 10;
151 static int SFcurrentInvert[3] = { -1, -1, -1 };
153 static int SFworkProcAdded = 0;
155 static XtAppContext SFapp;
157 static int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
159 #ifdef FEAT_XFONTSET
160 static char SFtextBuffer[MAXPATHL*sizeof(wchar_t)];
161 #else
162 static char SFtextBuffer[MAXPATHL];
163 #endif
165 static int SFbuttonPressed = 0;
167 static XtIntervalId SFdirModTimerId;
169 static int (*SFfunc)();
171 static int SFstatus = SEL_FILE_NULL;
173 /***************** static functions */
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));
206 /***************** xstat.h */
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
218 #define S_ISXXX(m) ((m) & (S_IXUSR | S_IXGRP | S_IXOTH))
220 /***************** Path.c */
222 #include <pwd.h>
224 typedef struct
226 char *name;
227 char *dir;
228 } SFLogin;
230 static int SFdoNotTouchDirPtr = 0;
232 static int SFdoNotTouchVorigin = 0;
234 static SFDir SFrootDir, SFhomeDir;
236 static SFLogin *SFlogins;
238 static int SFtwiddle = 0;
240 static int SFchdir __ARGS((char *path));
242 static int
243 SFchdir(path)
244 char *path;
246 int result;
248 result = 0;
250 if (strcmp(path, SFcurrentDir))
252 result = mch_chdir(path);
253 if (!result)
254 (void) strcpy(SFcurrentDir, path);
257 return result;
260 static void SFfree __ARGS((int i));
262 static void
263 SFfree(i)
264 int i;
266 SFDir *dir;
267 int j;
269 dir = &(SFdirs[i]);
271 for (j = dir->nEntries - 1; j >= 0; j--)
273 if (dir->entries[j].shown != dir->entries[j].real)
274 XtFree(dir->entries[j].shown);
275 XtFree(dir->entries[j].real);
278 XtFree((char *)dir->entries);
279 XtFree(dir->dir);
281 dir->dir = NULL;
284 static void SFstrdup __ARGS((char **s1, char *s2));
286 static void
287 SFstrdup(s1, s2)
288 char **s1;
289 char *s2;
291 *s1 = strcpy(XtMalloc((unsigned)(strlen(s2) + 1)), s2);
294 static void SFunreadableDir __ARGS((SFDir *dir));
296 static void
297 SFunreadableDir(dir)
298 SFDir *dir;
300 char *cannotOpen = _("<cannot open> ");
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);
310 static void SFreplaceText __ARGS((SFDir *dir, char *str));
312 static void
313 SFreplaceText(dir, str)
314 SFDir *dir;
315 char *str;
317 int len;
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)]));
330 SFtextChanged();
333 static void SFexpand __ARGS((char *str));
335 static void
336 SFexpand(str)
337 char *str;
339 int len;
340 int cmp;
341 char *name, *growing;
342 SFDir *dir;
343 SFEntry *entry, *max;
345 len = strlen(str);
347 dir = &(SFdirs[SFdirEnd - 1]);
349 if (dir->beginSelection == -1)
351 SFstrdup(&str, str);
352 SFreplaceText(dir, str);
353 XtFree(str);
354 return;
356 else if (dir->beginSelection == dir->endSelection)
358 SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
359 return;
362 max = &(dir->entries[dir->endSelection + 1]);
364 name = dir->entries[dir->beginSelection].shown;
365 SFstrdup(&growing, name);
367 cmp = 0;
368 while (!cmp)
370 entry = &(dir->entries[dir->beginSelection]);
371 while (entry < max)
373 if ((cmp = strncmp(growing, entry->shown, len)))
374 break;
375 entry++;
377 len++;
381 * SFreplaceText() expects filename
383 growing[len - 2] = ' ';
385 growing[len - 1] = 0;
386 SFreplaceText(dir, growing);
387 XtFree(growing);
390 static int SFfindFile __ARGS((SFDir *dir, char *str));
392 static int
393 SFfindFile(dir, str)
394 SFDir *dir;
395 char *str;
397 int i, last, max;
398 char *name, save;
399 SFEntry *entries;
400 int len;
401 int begin, end;
402 int result;
404 len = strlen(str);
406 if (str[len - 1] == ' ')
408 SFexpand(str);
409 return 1;
411 else if (str[len - 1] == '/')
412 len--;
414 max = dir->nEntries;
416 entries = dir->entries;
418 i = 0;
419 while (i < max)
421 name = entries[i].shown;
422 last = strlen(name) - 1;
423 save = name[last];
424 name[last] = 0;
426 result = strncmp(str, name, len);
428 name[last] = save;
429 if (result <= 0)
430 break;
431 i++;
433 begin = i;
434 while (i < max)
436 name = entries[i].shown;
437 last = strlen(name) - 1;
438 save = name[last];
439 name[last] = 0;
441 result = strncmp(str, name, len);
443 name[last] = save;
444 if (result)
445 break;
446 i++;
448 end = i;
450 if (begin != end)
452 if ((dir->beginSelection != begin) || (dir->endSelection != end - 1))
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;
462 else if (dir->beginSelection != -1)
464 dir->changed = 1;
465 dir->beginSelection = -1;
466 dir->endSelection = -1;
469 if (SFdoNotTouchVorigin
470 || ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize)))
472 SFdoNotTouchVorigin = 0;
473 return 0;
476 i = begin - 1;
477 if (i > max - SFlistSize)
478 i = max - SFlistSize;
479 if (i < 0)
480 i = 0;
482 if (dir->vOrigin != i)
484 dir->vOrigin = i;
485 dir->changed = 1;
488 return 0;
491 static void SFunselect __ARGS((void));
493 static void
494 SFunselect()
496 SFDir *dir;
498 dir = &(SFdirs[SFdirEnd - 1]);
499 if (dir->beginSelection != -1)
500 dir->changed = 1;
501 dir->beginSelection = -1;
502 dir->endSelection = -1;
505 static int SFcompareLogins __ARGS((const void *p, const void *q));
507 static int
508 SFcompareLogins(p, q)
509 const void *p, *q;
511 return strcmp(((SFLogin *)p)->name, ((SFLogin *)q)->name);
514 static void SFgetHomeDirs __ARGS((void));
516 static void
517 SFgetHomeDirs()
519 struct passwd *pw;
520 int Alloc;
521 int i;
522 SFEntry *entries = NULL;
523 int len;
524 int maxChars;
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;
539 (void) setpwent();
541 while ((pw = getpwent()) && (*(pw->pw_name)))
543 if (i >= Alloc)
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)));
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++;
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;
575 qsort((char *)entries, (size_t)i, sizeof(SFEntry), SFcompareEntries);
576 qsort((char *)SFlogins, (size_t)i, sizeof(SFLogin), SFcompareLogins);
578 for (i--; i >= 0; i--)
579 (void)strcat(entries[i].real, "/");
582 static int SFfindHomeDir __ARGS((char *begin, char *end));
584 static int
585 SFfindHomeDir(begin, end)
586 char *begin, *end;
588 char save;
589 char *theRest;
590 int i;
592 save = *end;
593 *end = 0;
595 for (i = SFhomeDir.nEntries - 1; i >= 0; i--)
597 if (!strcmp(SFhomeDir.entries[i].real, begin))
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;
610 *end = save;
612 return 0;
615 static void
616 SFupdatePath()
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;
626 if (!SFdirs)
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;
644 SFdirEndSave = SFdirEnd;
645 SFdirEnd = 1;
647 SFdirPtrSave = SFdirPtr;
648 SFdirPtr = 0;
650 begin = NULL;
652 if (SFcurrentPath[0] == '~')
654 if (!SFtwiddle)
656 SFtwiddle = 1;
657 dir = &(SFdirs[0]);
658 SFrootDir = *dir;
659 if (!SFhomeDir.dir)
660 SFgetHomeDirs();
661 *dir = SFhomeDir;
662 dir->changed = 1;
664 end = SFcurrentPath;
665 SFdoNotTouchDirPtr = 1;
666 wasTwiddle = 1;
668 else
670 if (SFtwiddle)
672 SFtwiddle = 0;
673 dir = &(SFdirs[0]);
674 *dir = SFrootDir;
675 dir->changed = 1;
677 end = SFcurrentPath + 1;
680 i = 0;
682 prevChange = 0;
684 while (*end)
686 while (*end++ == '/')
688 end--;
689 begin = end;
690 while ((*end) && (*end++ != '/'))
692 if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/'))
694 SFdirPtr = i - 1;
695 if (SFdirPtr < 0)
696 SFdirPtr = 0;
698 if (*begin)
700 if (*(end - 1) == '/')
702 char save = *end;
704 if (SFtwiddle)
706 if (SFfindHomeDir(begin, end))
707 return;
709 *end = 0;
710 i++;
711 SFdirEnd++;
712 if (i >= Alloc)
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;
719 dir = &(SFdirs[i]);
720 if ((!(dir->dir)) || prevChange || strcmp(dir->dir, begin))
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))
735 SFunreadableDir(dir);
736 break;
739 *end = save;
740 if (!save)
741 SFunselect();
743 else
745 if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin))
746 return;
749 else
750 SFunselect();
753 if ((end == SFcurrentPath + 1) && (!SFtwiddle))
754 SFunselect();
756 for (i = SFdirEnd; i < Alloc; i++)
757 if (SFdirs[i].dir)
758 SFfree(i);
760 if (SFdoNotTouchDirPtr)
762 if (wasTwiddle)
764 wasTwiddle = 0;
765 SFdirPtr = SFdirEnd - 2;
766 if (SFdirPtr < 0)
767 SFdirPtr = 0;
769 else
770 SFdirPtr = SFdirPtrSave;
771 SFdoNotTouchDirPtr = 0;
774 if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave))
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
790 if (SFdirPtr != SFdirPtrSave)
791 SFdrawLists(SF_DO_SCROLL);
792 else
793 for (i = 0; i < 3; i++)
795 if (SFdirPtr + i < SFdirEnd)
797 if (SFdirs[SFdirPtr + i].changed)
799 SFdirs[SFdirPtr + i].changed = 0;
800 SFdrawList(i, SF_DO_SCROLL);
803 else
804 SFclearList(i, SF_DO_SCROLL);
808 #ifdef XtNinternational
809 static int
810 WcsLen(p)
811 wchar_t *p;
813 int i = 0;
814 while (*p++ != 0)
815 i++;
816 return i;
818 #endif
820 static void
821 SFsetText(path)
822 char *path;
824 XawTextBlock text;
826 text.firstPos = 0;
827 text.length = strlen(path);
828 text.ptr = path;
829 text.format = FMT8BIT;
831 #ifdef XtNinternational
832 if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
834 XawTextReplace(selFileField, (XawTextPosition)0,
835 (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0]), &text);
836 XawTextSetInsertionPoint(selFileField,
837 (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0]));
839 else
841 XawTextReplace(selFileField, (XawTextPosition)0,
842 (XawTextPosition)strlen(SFtextBuffer), &text);
843 XawTextSetInsertionPoint(selFileField,
844 (XawTextPosition)strlen(SFtextBuffer));
846 #else
847 XawTextReplace(selFileField, (XawTextPosition)0,
848 (XawTextPosition)strlen(SFtextBuffer), &text);
849 XawTextSetInsertionPoint(selFileField,
850 (XawTextPosition)strlen(SFtextBuffer));
851 #endif
854 static void
855 SFbuttonPressList(w, n, event)
856 Widget w UNUSED;
857 int n UNUSED;
858 XButtonPressedEvent *event UNUSED;
860 SFbuttonPressed = 1;
863 static void
864 SFbuttonReleaseList(w, n, event)
865 Widget w;
866 int n;
867 XButtonReleasedEvent *event;
869 SFDir *dir;
871 SFbuttonPressed = 0;
873 if (SFcurrentInvert[n] != -1)
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);
885 static int SFcheckDir __ARGS((int n, SFDir *dir));
887 static int
888 SFcheckDir(n, dir)
889 int n;
890 SFDir *dir;
892 struct stat statBuf;
893 int i;
895 if ((!mch_stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime))
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.
902 if (SFcurrentInvert[n] != -1)
904 XWarpPointer(
905 SFdisplay,
906 None,
907 XtWindow(selFileLists[n]),
916 for (i = dir->nEntries - 1; i >= 0; i--)
918 if (dir->entries[i].shown != dir->entries[i].real)
919 XtFree(dir->entries[i].shown);
920 XtFree(dir->entries[i].real);
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);
941 if (!SFworkProcAdded)
943 (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
944 SFworkProcAdded = 1;
946 return 1;
948 return 0;
951 static int SFcheckFiles __ARGS((SFDir *dir));
953 static int
954 SFcheckFiles(dir)
955 SFDir *dir;
957 int from, to;
958 int result;
959 char oldc, newc;
960 int i;
961 char *str;
962 int last;
963 struct stat statBuf;
965 result = 0;
967 from = dir->vOrigin;
968 to = dir->vOrigin + SFlistSize;
969 if (to > dir->nEntries)
970 to = dir->nEntries;
972 for (i = from; i < to; i++)
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;
987 return result;
990 static void
991 SFdirModTimer(cl, id)
992 XtPointer cl UNUSED;
993 XtIntervalId *id UNUSED;
995 static int n = -1;
996 static int f = 0;
997 char save;
998 SFDir *dir;
1000 if ((!SFtwiddle) && (SFdirPtr < SFdirEnd))
1002 n++;
1003 if ((n > 2) || (SFdirPtr + n >= SFdirEnd))
1005 n = 0;
1006 f++;
1007 if ((f > 2) || (SFdirPtr + f >= SFdirEnd))
1008 f = 0;
1010 dir = &(SFdirs[SFdirPtr + n]);
1011 save = *(dir->path);
1012 *(dir->path) = 0;
1013 if (SFchdir(SFcurrentPath))
1015 *(dir->path) = save;
1018 * force a re-read
1020 *(dir->dir) = 0;
1022 SFupdatePath();
1024 else
1026 *(dir->path) = save;
1027 if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir)))
1028 SFdrawList(n, SF_DO_SCROLL);
1032 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
1033 SFdirModTimer, (XtPointer) NULL);
1036 /* Return a single character describing what kind of file STATBUF is. */
1038 static char
1039 SFstatChar(statBuf)
1040 struct stat *statBuf;
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 ' ';
1053 /***************** Draw.c */
1055 #ifdef FEAT_GUI_NEXTAW
1056 # include <X11/neXtaw/Cardinals.h>
1057 #else
1058 # include <X11/Xaw/Cardinals.h>
1059 #endif
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
1067 #ifdef ABS
1068 # undef ABS
1069 #endif
1070 #define ABS(x) (((x) < 0) ? (-(x)) : (x))
1072 typedef struct
1074 char *fontname;
1075 } TextData;
1077 static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
1079 static XtResource textResources[] =
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
1090 #ifdef FEAT_XFONTSET
1091 static XFontSet SFfont;
1092 #else
1093 static XFontStruct *SFfont;
1094 #endif
1096 static int SFcurrentListY;
1098 static XtIntervalId SFscrollTimerId;
1100 static void SFinitFont __ARGS((void));
1102 static void
1103 SFinitFont()
1105 TextData *data;
1106 #ifdef FEAT_XFONTSET
1107 XFontSetExtents *extents;
1108 char **missing, *def_str;
1109 int num_missing;
1110 #endif
1112 data = XtNew(TextData);
1114 XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
1115 XtNumber(textResources), (Arg *) NULL, ZERO);
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)
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)
1133 EMSG2(_("E616: vim_SelFile: can't get font %s"), SF_DEFAULT_FONT);
1134 SFstatus = SEL_FILE_CANCEL;
1135 return;
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
1151 static void SFcreateGC __ARGS((void));
1153 static void
1154 SFcreateGC()
1156 XGCValues gcValues;
1157 XRectangle rectangles[1];
1159 gcValues.foreground = SFfore;
1161 SFlineGC = XtGetGC(
1162 selFileLists[0],
1163 (XtGCMask)GCForeground,
1164 &gcValues);
1166 SFscrollGC = XtGetGC(
1167 selFileLists[0],
1168 (XtGCMask)0,
1169 &gcValues);
1171 gcValues.function = GXxor;
1172 gcValues.foreground = SFfore ^ SFback;
1173 gcValues.background = SFfore ^ SFback;
1175 SFinvertGC = XtGetGC(
1176 selFileLists[0],
1177 (XtGCMask)GCFunction | GCForeground | GCBackground,
1178 &gcValues);
1180 gcValues.foreground = SFfore;
1181 gcValues.background = SFback;
1182 #ifndef FEAT_XFONTSET
1183 gcValues.font = SFfont->fid;
1184 #endif
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);
1196 rectangles[0].x = SFlineToTextH + SFbesideText;
1197 rectangles[0].y = 0;
1198 rectangles[0].width = SFcharsPerEntry * SFcharWidth;
1199 rectangles[0].height = SFupperY + 1;
1201 XSetClipRectangles(
1202 SFdisplay,
1203 SFtextGC,
1206 rectangles,
1208 Unsorted);
1211 static void
1212 SFclearList(n, doScroll)
1213 int n;
1214 int doScroll;
1216 SFDir *dir;
1218 SFcurrentInvert[n] = -1;
1220 XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
1222 XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2);
1224 if (doScroll)
1226 dir = &(SFdirs[SFdirPtr + n]);
1228 if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars)
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
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
1266 else
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
1286 static void SFdeleteEntry __ARGS((SFDir *dir, SFEntry *entry));
1288 static void
1289 SFdeleteEntry(dir, entry)
1290 SFDir *dir;
1291 SFEntry *entry;
1293 SFEntry *e;
1294 SFEntry *end;
1295 int n;
1296 int idx;
1298 idx = entry - dir->entries;
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;
1307 if (idx < dir->vOrigin)
1308 dir->vOrigin--;
1310 XtFree(entry->real);
1312 end = &(dir->entries[dir->nEntries - 1]);
1314 for (e = entry; e < end; e++)
1315 *e = *(e + 1);
1317 if (!(--dir->nEntries))
1318 return;
1320 n = dir - &(SFdirs[SFdirPtr]);
1321 if ((n < 0) || (n > 2))
1322 return;
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
1340 static void SFwriteStatChar __ARGS((char *name, int last, struct stat *statBuf));
1342 static void
1343 SFwriteStatChar(name, last, statBuf)
1344 char *name;
1345 int last;
1346 struct stat *statBuf;
1348 name[last] = SFstatChar(statBuf);
1351 static int SFstatAndCheck __ARGS((SFDir *dir, SFEntry *entry));
1353 static int
1354 SFstatAndCheck(dir, entry)
1355 SFDir *dir;
1356 SFEntry *entry;
1358 struct stat statBuf;
1359 char save;
1360 int last;
1363 * must be restored before returning
1365 save = *(dir->path);
1366 *(dir->path) = 0;
1368 if (!SFchdir(SFcurrentPath))
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
1379 if (SFfunc)
1381 char *shown;
1383 shown = NULL;
1384 if (SFfunc(entry->real, &shown, &statBuf))
1386 if (shown)
1388 int len;
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;
1397 else
1399 SFdeleteEntry(dir, entry);
1401 *(dir->path) = save;
1402 return 1;
1405 SFwriteStatChar(entry->real, last, &statBuf);
1407 else
1408 entry->real[last] = ' ';
1411 *(dir->path) = save;
1412 return 0;
1416 static void
1417 SFdrawStrings(w, dir, from, to)
1418 Window w;
1419 SFDir *dir;
1420 int from;
1421 int to;
1423 int i;
1424 SFEntry *entry;
1425 int x;
1427 x = SFtextX - dir->hOrigin * SFcharWidth;
1429 if (dir->vOrigin + to >= dir->nEntries)
1430 to = dir->nEntries - dir->vOrigin - 1;
1431 for (i = from; i <= to; i++)
1433 entry = &(dir->entries[dir->vOrigin + i]);
1434 if (!(entry->statDone))
1436 if (SFstatAndCheck(dir, entry))
1438 if (dir->vOrigin + to >= dir->nEntries)
1439 to = dir->nEntries - dir->vOrigin - 1;
1440 i--;
1441 continue;
1444 #ifdef FEAT_XFONTSET
1445 XmbDrawImageString(
1446 SFdisplay,
1448 SFfont,
1449 SFtextGC,
1451 SFtextYoffset + i * SFentryHeight,
1452 entry->shown,
1453 strlen(entry->shown));
1454 #else
1455 XDrawImageString(
1456 SFdisplay,
1458 SFtextGC,
1460 SFtextYoffset + i * SFentryHeight,
1461 entry->shown,
1462 strlen(entry->shown));
1463 #endif
1464 if (dir->vOrigin + i == dir->beginSelection)
1466 XDrawLine(
1467 SFdisplay,
1469 SFlineGC,
1470 SFlineToTextH + 1,
1471 SFlowerY + i * SFentryHeight,
1472 SFlineToTextH + SFentryWidth - 2,
1473 SFlowerY + i * SFentryHeight);
1475 if ((dir->vOrigin + i >= dir->beginSelection) &&
1476 (dir->vOrigin + i <= dir->endSelection))
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,
1485 SFlineGC,
1486 SFcompletionSegs,
1489 if (dir->vOrigin + i == dir->endSelection)
1491 XDrawLine(
1492 SFdisplay,
1494 SFlineGC,
1495 SFlineToTextH + 1,
1496 SFlowerY + (i + 1) * SFentryHeight - 1,
1497 SFlineToTextH + SFentryWidth - 2,
1498 SFlowerY + (i + 1) * SFentryHeight - 1);
1503 static void
1504 SFdrawList(n, doScroll)
1505 int n;
1506 int doScroll;
1508 SFDir *dir;
1509 Window w;
1511 SFclearList(n, doScroll);
1513 if (SFdirPtr + n < SFdirEnd)
1515 dir = &(SFdirs[SFdirPtr + n]);
1516 w = XtWindow(selFileLists[n]);
1517 #ifdef FEAT_XFONTSET
1518 XmbDrawImageString(
1519 SFdisplay,
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,
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);
1541 static void
1542 SFdrawLists(doScroll)
1543 int doScroll;
1545 int i;
1547 for (i = 0; i < 3; i++)
1548 SFdrawList(i, doScroll);
1551 static void
1552 SFinvertEntry(n)
1553 int n;
1555 XFillRectangle(
1556 SFdisplay,
1557 XtWindow(selFileLists[n]),
1558 SFinvertGC,
1559 SFlineToTextH,
1560 SFcurrentInvert[n] * SFentryHeight + SFlowerY,
1561 SFentryWidth,
1562 SFentryHeight);
1565 static unsigned long SFscrollTimerInterval __ARGS((void));
1567 static unsigned long
1568 SFscrollTimerInterval()
1570 static int maxVal = 200;
1571 static int varyDist = 50;
1572 static int minDist = 50;
1573 int t;
1574 int dist;
1576 if (SFcurrentListY < SFlowerY)
1577 dist = SFlowerY - SFcurrentListY;
1578 else if (SFcurrentListY > SFupperY)
1579 dist = SFcurrentListY - SFupperY;
1580 else
1581 return (unsigned long) 1;
1583 t = maxVal - ((maxVal / varyDist) * (dist - minDist));
1585 if (t < 1)
1586 t = 1;
1588 if (t > maxVal)
1589 t = maxVal;
1591 return (unsigned long)t;
1594 static void SFscrollTimer __ARGS((XtPointer p, XtIntervalId *id));
1596 static void
1597 SFscrollTimer(p, id)
1598 XtPointer p;
1599 XtIntervalId *id UNUSED;
1601 SFDir *dir;
1602 int save;
1603 int n;
1605 n = (long)p;
1607 dir = &(SFdirs[SFdirPtr + n]);
1608 save = dir->vOrigin;
1610 if (SFcurrentListY < SFlowerY)
1612 if (dir->vOrigin > 0)
1613 SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1);
1615 else if (SFcurrentListY > SFupperY)
1617 if (dir->vOrigin < dir->nEntries - SFlistSize)
1618 SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1);
1621 if (dir->vOrigin != save)
1623 if (dir->nEntries)
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
1642 if (SFbuttonPressed)
1643 SFscrollTimerId = XtAppAddTimeOut(SFapp,
1644 SFscrollTimerInterval(), SFscrollTimer, (XtPointer) n);
1647 static int
1648 SFnewInvertEntry(n, event)
1649 int n;
1650 XMotionEvent *event;
1652 int x, y;
1653 int nw;
1654 static int SFscrollTimerAdded = 0;
1656 x = event->x;
1657 y = event->y;
1659 if (SFdirPtr + n >= SFdirEnd)
1660 return -1;
1662 if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY))
1664 SFDir *dir = &(SFdirs[SFdirPtr + n]);
1666 if (SFscrollTimerAdded)
1668 SFscrollTimerAdded = 0;
1669 XtRemoveTimeOut(SFscrollTimerId);
1672 nw = (y - SFlowerY) / SFentryHeight;
1673 if (dir->vOrigin + nw >= dir->nEntries)
1674 return -1;
1675 return nw;
1677 else
1679 if (SFbuttonPressed)
1681 SFcurrentListY = y;
1682 if (!SFscrollTimerAdded)
1684 SFscrollTimerAdded = 1;
1685 SFscrollTimerId = XtAppAddTimeOut(SFapp,
1686 SFscrollTimerInterval(), SFscrollTimer,
1687 (XtPointer) n);
1690 return -1;
1694 static void
1695 SFenterList(w, n, event)
1696 Widget w UNUSED;
1697 int n;
1698 XEnterWindowEvent *event;
1700 int nw;
1702 /* sanity */
1703 if (SFcurrentInvert[n] != -1)
1705 SFinvertEntry(n);
1706 SFcurrentInvert[n] = -1;
1709 nw = SFnewInvertEntry(n, (XMotionEvent *) event);
1710 if (nw != -1)
1712 SFcurrentInvert[n] = nw;
1713 SFinvertEntry(n);
1717 static void
1718 SFleaveList(w, n, event)
1719 Widget w UNUSED;
1720 int n;
1721 XEvent *event UNUSED;
1723 if (SFcurrentInvert[n] != -1)
1725 SFinvertEntry(n);
1726 SFcurrentInvert[n] = -1;
1730 static void
1731 SFmotionList(w, n, event)
1732 Widget w UNUSED;
1733 int n;
1734 XMotionEvent *event;
1736 int nw;
1738 nw = SFnewInvertEntry(n, event);
1740 if (nw != SFcurrentInvert[n])
1742 if (SFcurrentInvert[n] != -1)
1743 SFinvertEntry(n);
1744 SFcurrentInvert[n] = nw;
1745 if (nw != -1)
1746 SFinvertEntry(n);
1750 static void
1751 SFvFloatSliderMovedCallback(w, n, fnew)
1752 Widget w;
1753 XtPointer n;
1754 XtPointer fnew;
1756 int nw;
1758 nw = (*(float *)fnew) * SFdirs[SFdirPtr + (int)(long)n].nEntries;
1759 SFvSliderMovedCallback(w, (int)(long)n, nw);
1762 static void
1763 SFvSliderMovedCallback(w, n, nw)
1764 Widget w UNUSED;
1765 int n;
1766 int nw;
1768 int old;
1769 Window win;
1770 SFDir *dir;
1772 dir = &(SFdirs[SFdirPtr + n]);
1774 old = dir->vOrigin;
1775 dir->vOrigin = nw;
1777 if (old == nw)
1778 return;
1780 win = XtWindow(selFileLists[n]);
1782 if (ABS(nw - old) < SFlistSize)
1784 if (nw > old)
1786 XCopyArea(
1787 SFdisplay,
1788 win,
1789 win,
1790 SFscrollGC,
1791 SFlineToTextH,
1792 SFlowerY + (nw - old) * SFentryHeight,
1793 SFentryWidth + SFlineToTextH,
1794 (SFlistSize - (nw - old)) * SFentryHeight,
1795 SFlineToTextH,
1796 SFlowerY);
1797 XClearArea(
1798 SFdisplay,
1799 win,
1800 SFlineToTextH,
1801 SFlowerY + (SFlistSize - (nw - old)) *
1802 SFentryHeight,
1803 SFentryWidth + SFlineToTextH,
1804 (nw - old) * SFentryHeight,
1805 False);
1806 SFdrawStrings(win, dir, SFlistSize - (nw - old),
1807 SFlistSize - 1);
1809 else
1811 XCopyArea(
1812 SFdisplay,
1813 win,
1814 win,
1815 SFscrollGC,
1816 SFlineToTextH,
1817 SFlowerY,
1818 SFentryWidth + SFlineToTextH,
1819 (SFlistSize - (old - nw)) * SFentryHeight,
1820 SFlineToTextH,
1821 SFlowerY + (old - nw) * SFentryHeight);
1822 XClearArea(
1823 SFdisplay,
1824 win,
1825 SFlineToTextH,
1826 SFlowerY,
1827 SFentryWidth + SFlineToTextH,
1828 (old - nw) * SFentryHeight,
1829 False);
1830 SFdrawStrings(win, dir, 0, old - nw);
1833 else
1835 XClearArea(
1836 SFdisplay,
1837 win,
1838 SFlineToTextH,
1839 SFlowerY,
1840 SFentryWidth + SFlineToTextH,
1841 SFlistSize * SFentryHeight,
1842 False);
1843 SFdrawStrings(win, dir, 0, SFlistSize - 1);
1847 static void
1848 SFvAreaSelectedCallback(w, n, pnew)
1849 Widget w;
1850 XtPointer n;
1851 XtPointer pnew;
1853 SFDir *dir;
1854 int nw = (int)(long)pnew;
1856 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1858 #ifdef FEAT_GUI_NEXTAW
1859 if (nw < 0)
1861 if (nw > -SFvScrollHeight)
1862 nw = -1;
1863 else
1864 nw = -SFlistSize;
1866 else if (nw > 0)
1868 if (nw < SFvScrollHeight)
1869 nw = 1;
1870 else
1871 nw = SFlistSize;
1873 #endif
1874 nw += dir->vOrigin;
1876 if (nw > dir->nEntries - SFlistSize)
1877 nw = dir->nEntries - SFlistSize;
1879 if (nw < 0)
1880 nw = 0;
1882 if (dir->nEntries)
1884 float f;
1886 f = ((double) nw) / dir->nEntries;
1888 #ifdef FEAT_GUI_NEXTAW
1889 XawScrollbarSetThumb(
1892 (float) (((double) ((dir->nEntries < SFlistSize) ?
1893 dir->nEntries : SFlistSize)) / dir->nEntries));
1894 #else
1895 vim_XawScrollbarSetThumb(
1898 (float) (((double) ((dir->nEntries < SFlistSize) ?
1899 dir->nEntries : SFlistSize)) / dir->nEntries),
1900 (double)dir->nEntries);
1901 #endif
1904 SFvSliderMovedCallback(w, (int)(long)n, nw);
1907 static void
1908 SFhSliderMovedCallback(w, n, nw)
1909 Widget w UNUSED;
1910 XtPointer n;
1911 XtPointer nw;
1913 SFDir *dir;
1914 int save;
1916 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1917 save = dir->hOrigin;
1918 dir->hOrigin = (*(float *)nw) * dir->nChars;
1919 if (dir->hOrigin == save)
1920 return;
1922 SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
1925 static void
1926 SFhAreaSelectedCallback(w, n, pnew)
1927 Widget w;
1928 XtPointer n;
1929 XtPointer pnew;
1931 SFDir *dir;
1932 int nw = (int)(long)pnew;
1934 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1936 #ifdef FEAT_GUI_NEXTAW
1937 if (nw < 0)
1939 if (nw > -SFhScrollWidth)
1940 nw = -1;
1941 else
1942 nw = -SFcharsPerEntry;
1944 else if (nw > 0)
1946 if (nw < SFhScrollWidth)
1947 nw = 1;
1948 else
1949 nw = SFcharsPerEntry;
1951 #endif
1952 nw += dir->hOrigin;
1954 if (nw > dir->nChars - SFcharsPerEntry)
1955 nw = dir->nChars - SFcharsPerEntry;
1957 if (nw < 0)
1958 nw = 0;
1960 if (dir->nChars)
1962 float f;
1964 f = ((double) nw) / dir->nChars;
1966 #ifdef FEAT_GUI_NEXTAW
1967 XawScrollbarSetThumb(
1970 (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
1971 dir->nChars : SFcharsPerEntry)) / dir->nChars));
1972 #else
1973 vim_XawScrollbarSetThumb(
1976 (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
1977 dir->nChars : SFcharsPerEntry)) / dir->nChars),
1978 (double)dir->nChars);
1979 #endif
1981 SFhSliderMovedCallback(w, n, (XtPointer)&f);
1985 static void
1986 SFpathSliderMovedCallback(w, client_data, nw)
1987 Widget w UNUSED;
1988 XtPointer client_data UNUSED;
1989 XtPointer nw;
1991 SFDir *dir;
1992 int n;
1993 XawTextPosition pos;
1994 int SFdirPtrSave;
1996 SFdirPtrSave = SFdirPtr;
1997 SFdirPtr = (*(float *)nw) * SFdirEnd;
1998 if (SFdirPtr == SFdirPtrSave)
1999 return;
2001 SFdrawLists(SF_DO_SCROLL);
2003 n = 2;
2004 while (SFdirPtr + n >= SFdirEnd)
2005 n--;
2007 dir = &(SFdirs[SFdirPtr + n]);
2009 pos = dir->path - SFcurrentPath;
2011 if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
2013 pos -= strlen(SFstartDir);
2014 if (pos < 0)
2015 pos = 0;
2018 XawTextSetInsertionPoint(selFileField, pos);
2021 static void
2022 SFpathAreaSelectedCallback(w, client_data, pnew)
2023 Widget w;
2024 XtPointer client_data UNUSED;
2025 XtPointer pnew;
2027 int nw = (int)(long)pnew;
2028 float f;
2030 #ifdef FEAT_GUI_NEXTAW
2031 if (nw < 0)
2033 if (nw > -SFpathScrollWidth)
2034 nw = -1;
2035 else
2036 nw = -3;
2038 else if (nw > 0)
2040 if (nw < SFpathScrollWidth)
2041 nw = 1;
2042 else
2043 nw = 3;
2045 #endif
2046 nw += SFdirPtr;
2048 if (nw > SFdirEnd - 3)
2049 nw = SFdirEnd - 3;
2051 if (nw < 0)
2052 nw = 0;
2054 f = ((double) nw) / SFdirEnd;
2056 #ifdef FEAT_GUI_NEXTAW
2057 XawScrollbarSetThumb(
2060 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd));
2061 #else
2062 vim_XawScrollbarSetThumb(
2065 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd),
2066 (double)SFdirEnd);
2067 #endif
2069 SFpathSliderMovedCallback(w, (XtPointer) NULL, (XtPointer)&f);
2072 static Boolean
2073 SFworkProc()
2075 SFDir *dir;
2076 SFEntry *entry;
2078 for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
2080 if (!(dir->nEntries))
2081 continue;
2082 for (entry = &(dir->entries[dir->nEntries - 1]);
2083 entry >= dir->entries;
2084 entry--)
2086 if (!(entry->statDone))
2088 (void)SFstatAndCheck(dir, entry);
2089 return False;
2094 SFworkProcAdded = 0;
2096 return True;
2099 /***************** Dir.c */
2101 static int
2102 SFcompareEntries(p, q)
2103 const void *p;
2104 const void *q;
2106 return strcmp(((SFEntry *)p)->real, ((SFEntry *)q)->real);
2109 static int
2110 SFgetDir(dir)
2111 SFDir *dir;
2113 SFEntry *result = NULL;
2114 int Alloc = 0;
2115 int i;
2116 DIR *dirp;
2117 struct dirent *dp;
2118 char *str;
2119 int len;
2120 int maxChars;
2121 struct stat statBuf;
2123 maxChars = strlen(dir->dir) - 1;
2125 dir->entries = NULL;
2126 dir->nEntries = 0;
2127 dir->nChars = 0;
2129 result = NULL;
2130 i = 0;
2132 dirp = opendir(".");
2133 if (!dirp)
2134 return 1;
2136 (void)mch_stat(".", &statBuf);
2137 dir->mtime = statBuf.st_mtime;
2139 while ((dp = readdir(dirp)))
2141 /* Ignore "." and ".." */
2142 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
2143 continue;
2144 if (i >= Alloc)
2146 Alloc = 2 * (Alloc + 1);
2147 result = (SFEntry *) XtRealloc((char *) result,
2148 (unsigned) (Alloc * sizeof(SFEntry)));
2150 result[i].statDone = 0;
2151 str = dp->d_name;
2152 len = strlen(str);
2153 result[i].real = XtMalloc((unsigned) (len + 2));
2154 (void) strcat(strcpy(result[i].real, str), " ");
2155 if (len > maxChars)
2156 maxChars = len;
2157 result[i].shown = result[i].real;
2158 i++;
2161 qsort((char *) result, (size_t) i, sizeof(SFEntry), SFcompareEntries);
2163 dir->entries = result;
2164 dir->nEntries = i;
2165 dir->nChars = maxChars + 1;
2167 closedir(dirp);
2169 return 0;
2172 /***************** SFinternal.h */
2174 #include <sys/param.h>
2175 #include <X11/cursorfont.h>
2176 #include <X11/Composite.h>
2177 #include <X11/Shell.h>
2178 #ifdef FEAT_GUI_NEXTAW
2179 # include <X11/neXtaw/Form.h>
2180 # include <X11/neXtaw/Command.h>
2181 # include <X11/neXtaw/Label.h>
2182 #else
2183 #include <X11/Xaw/Form.h>
2184 #include <X11/Xaw/Command.h>
2185 #include <X11/Xaw/Label.h>
2186 #endif
2188 static char *oneLineTextEditTranslations = "\
2189 <Key>Return: redraw-display()\n\
2190 Ctrl<Key>M: redraw-display()\n\
2193 static void SFexposeList __ARGS((Widget w, XtPointer n, XEvent *event, Boolean *cont));
2195 static void
2196 SFexposeList(w, n, event, cont)
2197 Widget w UNUSED;
2198 XtPointer n;
2199 XEvent *event;
2200 Boolean *cont UNUSED;
2202 if ((event->type == NoExpose) || event->xexpose.count)
2203 return;
2205 SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
2208 static void SFmodVerifyCallback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont));
2210 static void
2211 SFmodVerifyCallback(w, client_data, event, cont)
2212 Widget w UNUSED;
2213 XtPointer client_data UNUSED;
2214 XEvent *event;
2215 Boolean *cont UNUSED;
2217 char buf[2];
2219 if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
2220 ((*buf) == '\r'))
2221 SFstatus = SEL_FILE_OK;
2222 else
2223 SFstatus = SEL_FILE_TEXT;
2226 static void SFokCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
2228 static void
2229 SFokCallback(w, cl, cd)
2230 Widget w UNUSED;
2231 XtPointer cl UNUSED;
2232 XtPointer cd UNUSED;
2234 SFstatus = SEL_FILE_OK;
2237 static XtCallbackRec SFokSelect[] =
2239 { SFokCallback, (XtPointer) NULL },
2240 { NULL, (XtPointer) NULL },
2243 static void SFcancelCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
2245 static void
2246 SFcancelCallback(w, cl, cd)
2247 Widget w UNUSED;
2248 XtPointer cl UNUSED;
2249 XtPointer cd UNUSED;
2251 SFstatus = SEL_FILE_CANCEL;
2254 static XtCallbackRec SFcancelSelect[] =
2256 { SFcancelCallback, (XtPointer) NULL },
2257 { NULL, (XtPointer) NULL },
2260 static void SFdismissAction __ARGS((Widget w, XEvent *event, String *params, Cardinal *num_params));
2262 static void
2263 SFdismissAction(w, event, params, num_params)
2264 Widget w UNUSED;
2265 XEvent *event;
2266 String *params UNUSED;
2267 Cardinal *num_params UNUSED;
2269 if (event->type == ClientMessage
2270 && (Atom)event->xclient.data.l[0] != SFwmDeleteWindow)
2271 return;
2273 SFstatus = SEL_FILE_CANCEL;
2276 static char *wmDeleteWindowTranslation = "\
2277 <Message>WM_PROTOCOLS: SelFileDismiss()\n\
2280 static XtActionsRec actions[] =
2282 {"SelFileDismiss", SFdismissAction},
2285 static void
2286 SFsetColors(bg, fg, scroll_bg, scroll_fg)
2287 guicolor_T bg;
2288 guicolor_T fg;
2289 guicolor_T scroll_bg;
2290 guicolor_T scroll_fg;
2292 if (selFileForm)
2294 XtVaSetValues(selFileForm, XtNbackground, bg,
2295 XtNforeground, fg,
2296 XtNborderColor, bg,
2297 NULL);
2300 int i;
2302 for (i = 0; i < 3; ++i)
2304 if (selFileLists[i])
2306 XtVaSetValues(selFileLists[i], XtNbackground, bg,
2307 XtNforeground, fg,
2308 XtNborderColor, fg,
2309 NULL);
2313 if (selFileOK)
2315 XtVaSetValues(selFileOK, XtNbackground, bg,
2316 XtNforeground, fg,
2317 XtNborderColor, fg,
2318 NULL);
2320 if (selFileCancel)
2322 XtVaSetValues(selFileCancel, XtNbackground, bg,
2323 XtNforeground, fg,
2324 XtNborderColor, fg,
2325 NULL);
2327 if (selFilePrompt)
2329 XtVaSetValues(selFilePrompt, XtNbackground, bg,
2330 XtNforeground, fg,
2331 NULL);
2333 if (gui.dpy)
2335 XSetBackground(gui.dpy, SFtextGC, bg);
2336 XSetForeground(gui.dpy, SFtextGC, fg);
2337 XSetForeground(gui.dpy, SFlineGC, fg);
2339 /* This is an xor GC, so combine the fg and background */
2340 XSetBackground(gui.dpy, SFinvertGC, fg ^ bg);
2341 XSetForeground(gui.dpy, SFinvertGC, fg ^ bg);
2343 if (selFileHScroll)
2345 XtVaSetValues(selFileHScroll, XtNbackground, scroll_bg,
2346 XtNforeground, scroll_fg,
2347 XtNborderColor, fg,
2348 NULL);
2351 int i;
2353 for (i = 0; i < 3; i++)
2355 XtVaSetValues(selFileVScrolls[i], XtNbackground, scroll_bg,
2356 XtNforeground, scroll_fg,
2357 XtNborderColor, fg,
2358 NULL);
2359 XtVaSetValues(selFileHScrolls[i], XtNbackground, scroll_bg,
2360 XtNforeground, scroll_fg,
2361 XtNborderColor, fg,
2362 NULL);
2367 static void
2368 SFcreateWidgets(toplevel, prompt, ok, cancel)
2369 Widget toplevel;
2370 char *prompt;
2371 char *ok;
2372 char *cancel;
2374 Cardinal n;
2375 int listWidth, listHeight;
2376 int listSpacing = 10;
2377 int scrollThickness = 15;
2378 int hScrollX, hScrollY;
2379 int vScrollX, vScrollY;
2381 selFile = XtVaAppCreateShell("selFile", "SelFile",
2382 transientShellWidgetClass, SFdisplay,
2383 XtNtransientFor, toplevel,
2384 XtNtitle, prompt,
2385 NULL);
2387 /* Add WM_DELETE_WINDOW protocol */
2388 XtAppAddActions(XtWidgetToApplicationContext(selFile),
2389 actions, XtNumber(actions));
2390 XtOverrideTranslations(selFile,
2391 XtParseTranslationTable(wmDeleteWindowTranslation));
2393 selFileForm = XtVaCreateManagedWidget("selFileForm",
2394 formWidgetClass, selFile,
2395 XtNdefaultDistance, 30,
2396 XtNforeground, SFfore,
2397 XtNbackground, SFback,
2398 XtNborderColor, SFback,
2399 NULL);
2401 selFilePrompt = XtVaCreateManagedWidget("selFilePrompt",
2402 labelWidgetClass, selFileForm,
2403 XtNlabel, prompt,
2404 XtNresizable, True,
2405 XtNtop, XtChainTop,
2406 XtNbottom, XtChainTop,
2407 XtNleft, XtChainLeft,
2408 XtNright, XtChainLeft,
2409 XtNborderWidth, 0,
2410 XtNforeground, SFfore,
2411 XtNbackground, SFback,
2412 NULL);
2415 XtVaGetValues(selFilePrompt,
2416 XtNforeground, &SFfore,
2417 XtNbackground, &SFback,
2418 NULL);
2421 SFinitFont();
2423 SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth +
2424 SFbesideText;
2425 SFentryHeight = SFaboveAndBelowText + SFcharHeight +
2426 SFaboveAndBelowText;
2428 listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
2429 scrollThickness;
2430 listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2431 SFlineToTextV + SFlistSize * SFentryHeight +
2432 SFlineToTextV + 1 + scrollThickness;
2434 SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;
2436 hScrollX = -1;
2437 hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2438 SFlineToTextV + SFlistSize * SFentryHeight +
2439 SFlineToTextV;
2440 SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
2442 vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
2443 vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
2444 SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
2445 SFlineToTextV;
2447 SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
2448 SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2449 SFlineToTextV;
2450 SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2451 SFlineToTextV + SFlistSize * SFentryHeight - 1;
2453 SFtextX = SFlineToTextH + SFbesideText;
2454 SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
2456 SFsegs[0].x1 = 0;
2457 SFsegs[0].y1 = vScrollY;
2458 SFsegs[0].x2 = vScrollX - 1;
2459 SFsegs[0].y2 = vScrollY;
2460 SFsegs[1].x1 = vScrollX;
2461 SFsegs[1].y1 = 0;
2462 SFsegs[1].x2 = vScrollX;
2463 SFsegs[1].y2 = vScrollY - 1;
2465 SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
2466 SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
2467 SFlineToTextH + SFentryWidth - 1;
2469 selFileField = XtVaCreateManagedWidget("selFileField",
2470 asciiTextWidgetClass, selFileForm,
2471 XtNwidth, 3 * listWidth + 2 * listSpacing + 4,
2472 XtNborderColor, SFfore,
2473 XtNfromVert, selFilePrompt,
2474 XtNvertDistance, 10,
2475 XtNresizable, True,
2476 XtNtop, XtChainTop,
2477 XtNbottom, XtChainTop,
2478 XtNleft, XtChainLeft,
2479 XtNright, XtChainLeft,
2480 XtNstring, SFtextBuffer,
2481 XtNlength, MAXPATHL,
2482 XtNeditType, XawtextEdit,
2483 XtNwrap, XawtextWrapWord,
2484 XtNresize, XawtextResizeHeight,
2485 XtNuseStringInPlace, True,
2486 NULL);
2488 XtOverrideTranslations(selFileField,
2489 XtParseTranslationTable(oneLineTextEditTranslations));
2490 XtSetKeyboardFocus(selFileForm, selFileField);
2492 selFileHScroll = XtVaCreateManagedWidget("selFileHScroll",
2493 #ifdef FEAT_GUI_NEXTAW
2494 scrollbarWidgetClass, selFileForm,
2495 #else
2496 vim_scrollbarWidgetClass, selFileForm,
2497 #endif
2498 XtNorientation, XtorientHorizontal,
2499 XtNwidth, SFpathScrollWidth,
2500 XtNheight, scrollThickness,
2501 XtNborderColor, SFfore,
2502 XtNfromVert, selFileField,
2503 XtNvertDistance, 30,
2504 XtNtop, XtChainTop,
2505 XtNbottom, XtChainTop,
2506 XtNleft, XtChainLeft,
2507 XtNright, XtChainLeft,
2508 XtNforeground, gui.scroll_fg_pixel,
2509 XtNbackground, gui.scroll_bg_pixel,
2510 #ifndef FEAT_GUI_NEXTAW
2511 XtNlimitThumb, 1,
2512 #endif
2513 NULL);
2515 XtAddCallback(selFileHScroll, XtNjumpProc,
2516 (XtCallbackProc) SFpathSliderMovedCallback, (XtPointer)NULL);
2517 XtAddCallback(selFileHScroll, XtNscrollProc,
2518 (XtCallbackProc) SFpathAreaSelectedCallback, (XtPointer)NULL);
2520 selFileLists[0] = XtVaCreateManagedWidget("selFileList1",
2521 compositeWidgetClass, selFileForm,
2522 XtNwidth, listWidth,
2523 XtNheight, listHeight,
2524 XtNforeground, SFfore,
2525 XtNbackground, SFback,
2526 XtNborderColor, SFfore,
2527 XtNfromVert, selFileHScroll,
2528 XtNvertDistance, 10,
2529 XtNtop, XtChainTop,
2530 XtNbottom, XtChainTop,
2531 XtNleft, XtChainLeft,
2532 XtNright, XtChainLeft,
2533 NULL);
2535 selFileLists[1] = XtVaCreateManagedWidget("selFileList2",
2536 compositeWidgetClass, selFileForm,
2537 XtNwidth, listWidth,
2538 XtNheight, listHeight,
2539 XtNforeground, SFfore,
2540 XtNbackground, SFback,
2541 XtNborderColor, SFfore,
2542 XtNfromHoriz, selFileLists[0],
2543 XtNfromVert, selFileHScroll,
2544 XtNhorizDistance, listSpacing,
2545 XtNvertDistance, 10,
2546 XtNtop, XtChainTop,
2547 XtNbottom, XtChainTop,
2548 XtNleft, XtChainLeft,
2549 XtNright, XtChainLeft,
2550 NULL);
2552 selFileLists[2] = XtVaCreateManagedWidget("selFileList3",
2553 compositeWidgetClass, selFileForm,
2554 XtNwidth, listWidth,
2555 XtNheight, listHeight,
2556 XtNforeground, SFfore,
2557 XtNbackground, SFback,
2558 XtNborderColor, SFfore,
2559 XtNfromHoriz, selFileLists[1],
2560 XtNfromVert, selFileHScroll,
2561 XtNhorizDistance, listSpacing,
2562 XtNvertDistance, 10,
2563 XtNtop, XtChainTop,
2564 XtNbottom, XtChainTop,
2565 XtNleft, XtChainLeft,
2566 XtNright, XtChainLeft,
2567 NULL);
2569 for (n = 0; n < 3; n++)
2571 selFileVScrolls[n] = XtVaCreateManagedWidget("selFileVScroll",
2572 #ifdef FEAT_GUI_NEXTAW
2573 scrollbarWidgetClass, selFileLists[n],
2574 #else
2575 vim_scrollbarWidgetClass, selFileLists[n],
2576 #endif
2577 XtNx, vScrollX,
2578 XtNy, vScrollY,
2579 XtNwidth, scrollThickness,
2580 XtNheight, SFvScrollHeight,
2581 XtNborderColor, SFfore,
2582 XtNforeground, gui.scroll_fg_pixel,
2583 XtNbackground, gui.scroll_bg_pixel,
2584 #ifndef FEAT_GUI_NEXTAW
2585 XtNlimitThumb, 1,
2586 #endif
2587 NULL);
2589 XtAddCallback(selFileVScrolls[n], XtNjumpProc,
2590 (XtCallbackProc)SFvFloatSliderMovedCallback, (XtPointer)n);
2591 XtAddCallback(selFileVScrolls[n], XtNscrollProc,
2592 (XtCallbackProc)SFvAreaSelectedCallback, (XtPointer)n);
2594 selFileHScrolls[n] = XtVaCreateManagedWidget("selFileHScroll",
2595 #ifdef FEAT_GUI_NEXTAW
2596 scrollbarWidgetClass, selFileLists[n],
2597 #else
2598 vim_scrollbarWidgetClass, selFileLists[n],
2599 #endif
2600 XtNorientation, XtorientHorizontal,
2601 XtNx, hScrollX,
2602 XtNy, hScrollY,
2603 XtNwidth, SFhScrollWidth,
2604 XtNheight, scrollThickness,
2605 XtNborderColor, SFfore,
2606 XtNforeground, gui.scroll_fg_pixel,
2607 XtNbackground, gui.scroll_bg_pixel,
2608 #ifndef FEAT_GUI_NEXTAW
2609 XtNlimitThumb, 1,
2610 #endif
2611 NULL);
2613 XtAddCallback(selFileHScrolls[n], XtNjumpProc,
2614 (XtCallbackProc)SFhSliderMovedCallback, (XtPointer)n);
2615 XtAddCallback(selFileHScrolls[n], XtNscrollProc,
2616 (XtCallbackProc)SFhAreaSelectedCallback, (XtPointer)n);
2619 selFileOK = XtVaCreateManagedWidget("selFileOK",
2620 commandWidgetClass, selFileForm,
2621 XtNlabel, ok,
2622 XtNresizable, True,
2623 XtNcallback, SFokSelect,
2624 XtNforeground, SFfore,
2625 XtNbackground, SFback,
2626 XtNborderColor, SFfore,
2627 XtNfromHoriz, selFileLists[0],
2628 XtNfromVert, selFileLists[0],
2629 XtNvertDistance, 30,
2630 XtNtop, XtChainTop,
2631 XtNbottom, XtChainTop,
2632 XtNleft, XtChainLeft,
2633 XtNright, XtChainLeft,
2634 NULL);
2636 selFileCancel = XtVaCreateManagedWidget("selFileCancel",
2637 commandWidgetClass, selFileForm,
2638 XtNlabel, cancel,
2639 XtNresizable, True,
2640 XtNcallback, SFcancelSelect,
2641 XtNforeground, SFfore,
2642 XtNbackground, SFback,
2643 XtNborderColor, SFfore,
2644 XtNfromHoriz, selFileOK,
2645 XtNfromVert, selFileLists[0],
2646 XtNhorizDistance, 30,
2647 XtNvertDistance, 30,
2648 XtNtop, XtChainTop,
2649 XtNbottom, XtChainTop,
2650 XtNleft, XtChainLeft,
2651 XtNright, XtChainLeft,
2652 NULL);
2654 XtSetMappedWhenManaged(selFile, False);
2655 XtRealizeWidget(selFile);
2657 /* Add WM_DELETE_WINDOW protocol */
2658 SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
2659 XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
2661 SFcreateGC();
2663 for (n = 0; n < 3; n++)
2665 XtAddEventHandler(selFileLists[n], ExposureMask, True,
2666 (XtEventHandler)SFexposeList, (XtPointer)n);
2667 XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
2668 (XtEventHandler)SFenterList, (XtPointer)n);
2669 XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
2670 (XtEventHandler)SFleaveList, (XtPointer)n);
2671 XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
2672 (XtEventHandler)SFmotionList, (XtPointer)n);
2673 XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
2674 (XtEventHandler)SFbuttonPressList, (XtPointer)n);
2675 XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
2676 (XtEventHandler)SFbuttonReleaseList, (XtPointer)n);
2679 XtAddEventHandler(selFileField, KeyPressMask, False,
2680 SFmodVerifyCallback, (XtPointer)NULL);
2682 SFapp = XtWidgetToApplicationContext(selFile);
2685 static void
2686 SFtextChanged()
2688 #if defined(FEAT_XFONTSET) && defined(XtNinternational)
2689 if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
2691 wchar_t *wcbuf=(wchar_t *)SFtextBuffer;
2693 if ((wcbuf[0] == L'/') || (wcbuf[0] == L'~'))
2695 (void) wcstombs(SFcurrentPath, wcbuf, MAXPATHL);
2696 SFtextPos = XawTextGetInsertionPoint(selFileField);
2698 else
2700 strcpy(SFcurrentPath, SFstartDir);
2701 (void) wcstombs(SFcurrentPath + strlen(SFcurrentPath), wcbuf, MAXPATHL);
2703 SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
2706 else
2707 #endif
2708 if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~'))
2710 (void) strcpy(SFcurrentPath, SFtextBuffer);
2711 SFtextPos = XawTextGetInsertionPoint(selFileField);
2713 else
2715 (void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
2717 SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
2720 if (!SFworkProcAdded)
2722 (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
2723 SFworkProcAdded = 1;
2726 SFupdatePath();
2729 static char *
2730 SFgetText()
2732 #if defined(FEAT_XFONTSET) && defined(XtNinternational)
2733 char *buf;
2735 if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
2737 wchar_t *wcbuf;
2738 int mbslength;
2740 XtVaGetValues(selFileField,
2741 XtNstring, &wcbuf,
2742 NULL);
2743 mbslength = wcstombs(NULL, wcbuf, 0);
2744 /* Hack: some broken wcstombs() returns zero, just get a large buffer */
2745 if (mbslength == 0 && wcbuf != NULL && wcbuf[0] != 0)
2746 mbslength = MAXPATHL;
2747 buf=(char *)XtMalloc(mbslength + 1);
2748 wcstombs(buf, wcbuf, mbslength +1);
2749 return buf;
2751 #endif
2752 return (char *)vim_strsave((char_u *)SFtextBuffer);
2755 static void
2756 SFprepareToReturn()
2758 SFstatus = SEL_FILE_NULL;
2759 XtRemoveGrab(selFile);
2760 XtUnmapWidget(selFile);
2761 XtRemoveTimeOut(SFdirModTimerId);
2762 if (SFchdir(SFstartDir))
2764 EMSG(_("E614: vim_SelFile: can't return to current directory"));
2765 SFstatus = SEL_FILE_CANCEL;
2769 char *
2770 vim_SelFile(toplevel, prompt, init_path, show_entry, x, y, fg, bg, scroll_fg, scroll_bg)
2771 Widget toplevel;
2772 char *prompt;
2773 char *init_path;
2774 int (*show_entry)();
2775 int x, y;
2776 guicolor_T fg, bg;
2777 guicolor_T scroll_fg, scroll_bg; /* The "Scrollbar" group colors */
2779 static int firstTime = 1;
2780 XEvent event;
2781 char *name_return;
2783 if (prompt == NULL)
2784 prompt = _("Pathname:");
2785 SFfore = fg;
2786 SFback = bg;
2788 if (mch_dirname((char_u *)SFstartDir, MAXPATHL) == FAIL)
2790 EMSG(_("E615: vim_SelFile: can't get current directory"));
2791 return NULL;
2794 if (firstTime)
2796 firstTime = 0;
2797 SFdisplay = XtDisplay(toplevel);
2798 SFcreateWidgets(toplevel, prompt, _("OK"), _("Cancel"));
2800 else
2802 XtVaSetValues(selFilePrompt, XtNlabel, prompt, NULL);
2803 XtVaSetValues(selFile, XtNtitle, prompt, NULL);
2804 SFsetColors(bg, fg, scroll_bg, scroll_fg);
2807 XtVaSetValues(selFile, XtNx, x, XtNy, y, NULL);
2808 XtMapWidget(selFile);
2810 (void)strcat(SFstartDir, "/");
2811 (void)strcpy(SFcurrentDir, SFstartDir);
2813 if (init_path)
2815 if (init_path[0] == '/')
2817 (void)strcpy(SFcurrentPath, init_path);
2818 if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
2819 SFsetText(SFcurrentPath);
2820 else
2821 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
2823 else
2825 (void)strcat(strcpy(SFcurrentPath, SFstartDir), init_path);
2826 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
2829 else
2830 (void)strcpy(SFcurrentPath, SFstartDir);
2832 SFfunc = show_entry;
2834 SFtextChanged();
2836 XtAddGrab(selFile, True, True);
2838 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
2839 SFdirModTimer, (XtPointer) NULL);
2841 for (;;)
2843 XtAppNextEvent(SFapp, &event);
2844 XtDispatchEvent(&event);
2845 switch (SFstatus)
2847 case SEL_FILE_TEXT:
2848 SFstatus = SEL_FILE_NULL;
2849 SFtextChanged();
2850 break;
2851 case SEL_FILE_OK:
2852 name_return = SFgetText();
2853 SFprepareToReturn();
2854 return name_return;
2855 case SEL_FILE_CANCEL:
2856 SFprepareToReturn();
2857 return NULL;
2858 case SEL_FILE_NULL:
2859 break;
2863 #endif /* FEAT_BROWSE */