ODB Editor protocol (aka 'external editor') support
[MacVim.git] / src / gui_at_fs.c
blobae68575266010dddacc4dac7718e45a8b8bb0240
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 (_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 /* ARGSUSED */
855 static void
856 SFbuttonPressList(w, n, event)
857 Widget w;
858 int n;
859 XButtonPressedEvent *event;
861 SFbuttonPressed = 1;
864 /* ARGSUSED */
865 static void
866 SFbuttonReleaseList(w, n, event)
867 Widget w;
868 int n;
869 XButtonReleasedEvent *event;
871 SFDir *dir;
873 SFbuttonPressed = 0;
875 if (SFcurrentInvert[n] != -1)
877 if (n < 2)
878 SFdoNotTouchDirPtr = 1;
879 SFdoNotTouchVorigin = 1;
880 dir = &(SFdirs[SFdirPtr + n]);
881 SFreplaceText(dir,
882 dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown);
883 SFmotionList(w, n, (XMotionEvent *) event);
887 static int SFcheckDir __ARGS((int n, SFDir *dir));
889 static int
890 SFcheckDir(n, dir)
891 int n;
892 SFDir *dir;
894 struct stat statBuf;
895 int i;
897 if ((!mch_stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime))
900 * If the pointer is currently in the window that we are about
901 * to update, we must warp it to prevent the user from
902 * accidentally selecting the wrong file.
904 if (SFcurrentInvert[n] != -1)
906 XWarpPointer(
907 SFdisplay,
908 None,
909 XtWindow(selFileLists[n]),
918 for (i = dir->nEntries - 1; i >= 0; i--)
920 if (dir->entries[i].shown != dir->entries[i].real)
921 XtFree(dir->entries[i].shown);
922 XtFree(dir->entries[i].real);
924 XtFree((char *) dir->entries);
925 if (SFgetDir(dir))
926 SFunreadableDir(dir);
927 if (dir->vOrigin > dir->nEntries - SFlistSize)
928 dir->vOrigin = dir->nEntries - SFlistSize;
929 if (dir->vOrigin < 0)
930 dir->vOrigin = 0;
931 if (dir->hOrigin > dir->nChars - SFcharsPerEntry)
932 dir->hOrigin = dir->nChars - SFcharsPerEntry;
933 if (dir->hOrigin < 0)
934 dir->hOrigin = 0;
935 dir->beginSelection = -1;
936 dir->endSelection = -1;
937 SFdoNotTouchVorigin = 1;
938 if ((dir + 1)->dir)
939 (void) SFfindFile(dir, (dir + 1)->dir);
940 else
941 (void) SFfindFile(dir, dir->path);
943 if (!SFworkProcAdded)
945 (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
946 SFworkProcAdded = 1;
948 return 1;
950 return 0;
953 static int SFcheckFiles __ARGS((SFDir *dir));
955 static int
956 SFcheckFiles(dir)
957 SFDir *dir;
959 int from, to;
960 int result;
961 char oldc, newc;
962 int i;
963 char *str;
964 int last;
965 struct stat statBuf;
967 result = 0;
969 from = dir->vOrigin;
970 to = dir->vOrigin + SFlistSize;
971 if (to > dir->nEntries)
972 to = dir->nEntries;
974 for (i = from; i < to; i++)
976 str = dir->entries[i].real;
977 last = strlen(str) - 1;
978 oldc = str[last];
979 str[last] = 0;
980 if (mch_stat(str, &statBuf))
981 newc = ' ';
982 else
983 newc = SFstatChar(&statBuf);
984 str[last] = newc;
985 if (newc != oldc)
986 result = 1;
989 return result;
992 /* ARGSUSED */
993 static void
994 SFdirModTimer(cl, id)
995 XtPointer cl;
996 XtIntervalId *id;
998 static int n = -1;
999 static int f = 0;
1000 char save;
1001 SFDir *dir;
1003 if ((!SFtwiddle) && (SFdirPtr < SFdirEnd))
1005 n++;
1006 if ((n > 2) || (SFdirPtr + n >= SFdirEnd))
1008 n = 0;
1009 f++;
1010 if ((f > 2) || (SFdirPtr + f >= SFdirEnd))
1011 f = 0;
1013 dir = &(SFdirs[SFdirPtr + n]);
1014 save = *(dir->path);
1015 *(dir->path) = 0;
1016 if (SFchdir(SFcurrentPath))
1018 *(dir->path) = save;
1021 * force a re-read
1023 *(dir->dir) = 0;
1025 SFupdatePath();
1027 else
1029 *(dir->path) = save;
1030 if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir)))
1031 SFdrawList(n, SF_DO_SCROLL);
1035 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
1036 SFdirModTimer, (XtPointer) NULL);
1039 /* Return a single character describing what kind of file STATBUF is. */
1041 static char
1042 SFstatChar(statBuf)
1043 struct stat *statBuf;
1045 if (S_ISDIR (statBuf->st_mode))
1046 return '/';
1047 if (S_ISREG (statBuf->st_mode))
1048 return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
1049 #ifdef S_ISSOCK
1050 if (S_ISSOCK (statBuf->st_mode))
1051 return '=';
1052 #endif /* S_ISSOCK */
1053 return ' ';
1056 /***************** Draw.c */
1058 #ifdef FEAT_GUI_NEXTAW
1059 # include <X11/neXtaw/Cardinals.h>
1060 #else
1061 # include <X11/Xaw/Cardinals.h>
1062 #endif
1064 #ifdef FEAT_XFONTSET
1065 # define SF_DEFAULT_FONT "-misc-fixed-medium-r-normal--14-*"
1066 #else
1067 # define SF_DEFAULT_FONT "9x15"
1068 #endif
1070 #ifdef ABS
1071 # undef ABS
1072 #endif
1073 #define ABS(x) (((x) < 0) ? (-(x)) : (x))
1075 typedef struct
1077 char *fontname;
1078 } TextData;
1080 static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
1082 static XtResource textResources[] =
1084 #ifdef FEAT_XFONTSET
1085 {XtNfontSet, XtCFontSet, XtRString, sizeof (char *),
1086 XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT},
1087 #else
1088 {XtNfont, XtCFont, XtRString, sizeof (char *),
1089 XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT},
1090 #endif
1093 #ifdef FEAT_XFONTSET
1094 static XFontSet SFfont;
1095 #else
1096 static XFontStruct *SFfont;
1097 #endif
1099 static int SFcurrentListY;
1101 static XtIntervalId SFscrollTimerId;
1103 static void SFinitFont __ARGS((void));
1105 static void
1106 SFinitFont()
1108 TextData *data;
1109 #ifdef FEAT_XFONTSET
1110 XFontSetExtents *extents;
1111 char **missing, *def_str;
1112 int num_missing;
1113 #endif
1115 data = XtNew(TextData);
1117 XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
1118 XtNumber(textResources), (Arg *) NULL, ZERO);
1120 #ifdef FEAT_XFONTSET
1121 SFfont = XCreateFontSet(SFdisplay, data->fontname,
1122 &missing, &num_missing, &def_str);
1123 #else
1124 SFfont = XLoadQueryFont(SFdisplay, data->fontname);
1125 #endif
1126 if (!SFfont)
1128 #ifdef FEAT_XFONTSET
1129 SFfont = XCreateFontSet(SFdisplay, SF_DEFAULT_FONT,
1130 &missing, &num_missing, &def_str);
1131 #else
1132 SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);
1133 #endif
1134 if (!SFfont)
1136 EMSG2(_("E616: vim_SelFile: can't get font %s"), SF_DEFAULT_FONT);
1137 SFstatus = SEL_FILE_CANCEL;
1138 return;
1142 #ifdef FEAT_XFONTSET
1143 extents = XExtentsOfFontSet(SFfont);
1144 SFcharWidth = extents->max_logical_extent.width;
1145 SFcharAscent = -extents->max_logical_extent.y;
1146 SFcharHeight = extents->max_logical_extent.height;
1147 #else
1148 SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;
1149 SFcharAscent = SFfont->max_bounds.ascent;
1150 SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;
1151 #endif
1154 static void SFcreateGC __ARGS((void));
1156 static void
1157 SFcreateGC()
1159 XGCValues gcValues;
1160 XRectangle rectangles[1];
1162 gcValues.foreground = SFfore;
1164 SFlineGC = XtGetGC(
1165 selFileLists[0],
1166 (XtGCMask)GCForeground,
1167 &gcValues);
1169 SFscrollGC = XtGetGC(
1170 selFileLists[0],
1171 (XtGCMask)0,
1172 &gcValues);
1174 gcValues.function = GXxor;
1175 gcValues.foreground = SFfore ^ SFback;
1176 gcValues.background = SFfore ^ SFback;
1178 SFinvertGC = XtGetGC(
1179 selFileLists[0],
1180 (XtGCMask)GCFunction | GCForeground | GCBackground,
1181 &gcValues);
1183 gcValues.foreground = SFfore;
1184 gcValues.background = SFback;
1185 #ifndef FEAT_XFONTSET
1186 gcValues.font = SFfont->fid;
1187 #endif
1189 SFtextGC = XCreateGC(
1190 SFdisplay,
1191 XtWindow(selFileLists[0]),
1192 #ifdef FEAT_XFONTSET
1193 (unsigned long)GCForeground | GCBackground,
1194 #else
1195 (unsigned long)GCForeground | GCBackground | GCFont,
1196 #endif
1197 &gcValues);
1199 rectangles[0].x = SFlineToTextH + SFbesideText;
1200 rectangles[0].y = 0;
1201 rectangles[0].width = SFcharsPerEntry * SFcharWidth;
1202 rectangles[0].height = SFupperY + 1;
1204 XSetClipRectangles(
1205 SFdisplay,
1206 SFtextGC,
1209 rectangles,
1211 Unsorted);
1214 static void
1215 SFclearList(n, doScroll)
1216 int n;
1217 int doScroll;
1219 SFDir *dir;
1221 SFcurrentInvert[n] = -1;
1223 XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
1225 XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2);
1227 if (doScroll)
1229 dir = &(SFdirs[SFdirPtr + n]);
1231 if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars)
1233 #ifdef FEAT_GUI_NEXTAW
1234 XawScrollbarSetThumb(
1235 selFileVScrolls[n],
1236 (float) (((double) dir->vOrigin) /
1237 dir->nEntries),
1238 (float) (((double) ((dir->nEntries < SFlistSize)
1239 ? dir->nEntries : SFlistSize)) /
1240 dir->nEntries));
1241 #else
1242 vim_XawScrollbarSetThumb(
1243 selFileVScrolls[n],
1244 (float) (((double) dir->vOrigin) /
1245 dir->nEntries),
1246 (float) (((double) ((dir->nEntries < SFlistSize)
1247 ? dir->nEntries : SFlistSize)) /
1248 dir->nEntries),
1249 (double)dir->nEntries);
1250 #endif
1252 #ifdef FEAT_GUI_NEXTAW
1253 XawScrollbarSetThumb(
1254 selFileHScrolls[n],
1255 (float) (((double) dir->hOrigin) / dir->nChars),
1256 (float) (((double) ((dir->nChars <
1257 SFcharsPerEntry) ? dir->nChars :
1258 SFcharsPerEntry)) / dir->nChars));
1259 #else
1260 vim_XawScrollbarSetThumb(
1261 selFileHScrolls[n],
1262 (float) (((double) dir->hOrigin) / dir->nChars),
1263 (float) (((double) ((dir->nChars <
1264 SFcharsPerEntry) ? dir->nChars :
1265 SFcharsPerEntry)) / dir->nChars),
1266 (double)dir->nChars);
1267 #endif
1269 else
1271 #ifdef FEAT_GUI_NEXTAW
1272 XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
1273 (float) 1.0);
1274 #else
1275 vim_XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
1276 (float) 1.0, 1.0);
1277 #endif
1278 #ifdef FEAT_GUI_NEXTAW
1279 XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
1280 (float) 1.0);
1281 #else
1282 vim_XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
1283 (float) 1.0, 1.0);
1284 #endif
1289 static void SFdeleteEntry __ARGS((SFDir *dir, SFEntry *entry));
1291 static void
1292 SFdeleteEntry(dir, entry)
1293 SFDir *dir;
1294 SFEntry *entry;
1296 SFEntry *e;
1297 SFEntry *end;
1298 int n;
1299 int idx;
1301 idx = entry - dir->entries;
1303 if (idx < dir->beginSelection)
1304 dir->beginSelection--;
1305 if (idx <= dir->endSelection)
1306 dir->endSelection--;
1307 if (dir->beginSelection > dir->endSelection)
1308 dir->beginSelection = dir->endSelection = -1;
1310 if (idx < dir->vOrigin)
1311 dir->vOrigin--;
1313 XtFree(entry->real);
1315 end = &(dir->entries[dir->nEntries - 1]);
1317 for (e = entry; e < end; e++)
1318 *e = *(e + 1);
1320 if (!(--dir->nEntries))
1321 return;
1323 n = dir - &(SFdirs[SFdirPtr]);
1324 if ((n < 0) || (n > 2))
1325 return;
1327 #ifdef FEAT_GUI_NEXTAW
1328 XawScrollbarSetThumb(
1329 selFileVScrolls[n],
1330 (float) (((double) dir->vOrigin) / dir->nEntries),
1331 (float) (((double) ((dir->nEntries < SFlistSize) ?
1332 dir->nEntries : SFlistSize)) / dir->nEntries));
1333 #else
1334 vim_XawScrollbarSetThumb(
1335 selFileVScrolls[n],
1336 (float) (((double) dir->vOrigin) / dir->nEntries),
1337 (float) (((double) ((dir->nEntries < SFlistSize) ?
1338 dir->nEntries : SFlistSize)) / dir->nEntries),
1339 (double)dir->nEntries);
1340 #endif
1343 static void SFwriteStatChar __ARGS((char *name, int last, struct stat *statBuf));
1345 static void
1346 SFwriteStatChar(name, last, statBuf)
1347 char *name;
1348 int last;
1349 struct stat *statBuf;
1351 name[last] = SFstatChar(statBuf);
1354 static int SFstatAndCheck __ARGS((SFDir *dir, SFEntry *entry));
1356 static int
1357 SFstatAndCheck(dir, entry)
1358 SFDir *dir;
1359 SFEntry *entry;
1361 struct stat statBuf;
1362 char save;
1363 int last;
1366 * must be restored before returning
1368 save = *(dir->path);
1369 *(dir->path) = 0;
1371 if (!SFchdir(SFcurrentPath))
1373 last = strlen(entry->real) - 1;
1374 entry->real[last] = 0;
1375 entry->statDone = 1;
1376 if ((!mch_stat(entry->real, &statBuf))
1377 #ifdef S_IFLNK
1378 || (!mch_lstat(entry->real, &statBuf))
1379 #endif
1382 if (SFfunc)
1384 char *shown;
1386 shown = NULL;
1387 if (SFfunc(entry->real, &shown, &statBuf))
1389 if (shown)
1391 int len;
1393 len = strlen(shown);
1394 entry->shown = XtMalloc((unsigned) (len + 2));
1395 (void) strcpy(entry->shown, shown);
1396 SFwriteStatChar(entry->shown, len, &statBuf);
1397 entry->shown[len + 1] = 0;
1400 else
1402 SFdeleteEntry(dir, entry);
1404 *(dir->path) = save;
1405 return 1;
1408 SFwriteStatChar(entry->real, last, &statBuf);
1410 else
1411 entry->real[last] = ' ';
1414 *(dir->path) = save;
1415 return 0;
1419 static void
1420 SFdrawStrings(w, dir, from, to)
1421 Window w;
1422 SFDir *dir;
1423 int from;
1424 int to;
1426 int i;
1427 SFEntry *entry;
1428 int x;
1430 x = SFtextX - dir->hOrigin * SFcharWidth;
1432 if (dir->vOrigin + to >= dir->nEntries)
1433 to = dir->nEntries - dir->vOrigin - 1;
1434 for (i = from; i <= to; i++)
1436 entry = &(dir->entries[dir->vOrigin + i]);
1437 if (!(entry->statDone))
1439 if (SFstatAndCheck(dir, entry))
1441 if (dir->vOrigin + to >= dir->nEntries)
1442 to = dir->nEntries - dir->vOrigin - 1;
1443 i--;
1444 continue;
1447 #ifdef FEAT_XFONTSET
1448 XmbDrawImageString(
1449 SFdisplay,
1451 SFfont,
1452 SFtextGC,
1454 SFtextYoffset + i * SFentryHeight,
1455 entry->shown,
1456 strlen(entry->shown));
1457 #else
1458 XDrawImageString(
1459 SFdisplay,
1461 SFtextGC,
1463 SFtextYoffset + i * SFentryHeight,
1464 entry->shown,
1465 strlen(entry->shown));
1466 #endif
1467 if (dir->vOrigin + i == dir->beginSelection)
1469 XDrawLine(
1470 SFdisplay,
1472 SFlineGC,
1473 SFlineToTextH + 1,
1474 SFlowerY + i * SFentryHeight,
1475 SFlineToTextH + SFentryWidth - 2,
1476 SFlowerY + i * SFentryHeight);
1478 if ((dir->vOrigin + i >= dir->beginSelection) &&
1479 (dir->vOrigin + i <= dir->endSelection))
1481 SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
1482 SFlowerY + i * SFentryHeight;
1483 SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
1484 SFlowerY + (i + 1) * SFentryHeight - 1;
1485 XDrawSegments(
1486 SFdisplay,
1488 SFlineGC,
1489 SFcompletionSegs,
1492 if (dir->vOrigin + i == dir->endSelection)
1494 XDrawLine(
1495 SFdisplay,
1497 SFlineGC,
1498 SFlineToTextH + 1,
1499 SFlowerY + (i + 1) * SFentryHeight - 1,
1500 SFlineToTextH + SFentryWidth - 2,
1501 SFlowerY + (i + 1) * SFentryHeight - 1);
1506 static void
1507 SFdrawList(n, doScroll)
1508 int n;
1509 int doScroll;
1511 SFDir *dir;
1512 Window w;
1514 SFclearList(n, doScroll);
1516 if (SFdirPtr + n < SFdirEnd)
1518 dir = &(SFdirs[SFdirPtr + n]);
1519 w = XtWindow(selFileLists[n]);
1520 #ifdef FEAT_XFONTSET
1521 XmbDrawImageString(
1522 SFdisplay,
1524 SFfont,
1525 SFtextGC,
1526 SFtextX - dir->hOrigin * SFcharWidth,
1527 SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
1528 dir->dir,
1529 strlen(dir->dir));
1530 #else
1531 XDrawImageString(
1532 SFdisplay,
1534 SFtextGC,
1535 SFtextX - dir->hOrigin * SFcharWidth,
1536 SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
1537 dir->dir,
1538 strlen(dir->dir));
1539 #endif
1540 SFdrawStrings(w, dir, 0, SFlistSize - 1);
1544 static void
1545 SFdrawLists(doScroll)
1546 int doScroll;
1548 int i;
1550 for (i = 0; i < 3; i++)
1551 SFdrawList(i, doScroll);
1554 static void
1555 SFinvertEntry(n)
1556 int n;
1558 XFillRectangle(
1559 SFdisplay,
1560 XtWindow(selFileLists[n]),
1561 SFinvertGC,
1562 SFlineToTextH,
1563 SFcurrentInvert[n] * SFentryHeight + SFlowerY,
1564 SFentryWidth,
1565 SFentryHeight);
1568 static unsigned long SFscrollTimerInterval __ARGS((void));
1570 static unsigned long
1571 SFscrollTimerInterval()
1573 static int maxVal = 200;
1574 static int varyDist = 50;
1575 static int minDist = 50;
1576 int t;
1577 int dist;
1579 if (SFcurrentListY < SFlowerY)
1580 dist = SFlowerY - SFcurrentListY;
1581 else if (SFcurrentListY > SFupperY)
1582 dist = SFcurrentListY - SFupperY;
1583 else
1584 return (unsigned long) 1;
1586 t = maxVal - ((maxVal / varyDist) * (dist - minDist));
1588 if (t < 1)
1589 t = 1;
1591 if (t > maxVal)
1592 t = maxVal;
1594 return (unsigned long)t;
1597 static void SFscrollTimer __ARGS((XtPointer p, XtIntervalId *id));
1599 /* ARGSUSED */
1600 static void
1601 SFscrollTimer(p, id)
1602 XtPointer p;
1603 XtIntervalId *id;
1605 SFDir *dir;
1606 int save;
1607 int n;
1609 n = (long)p;
1611 dir = &(SFdirs[SFdirPtr + n]);
1612 save = dir->vOrigin;
1614 if (SFcurrentListY < SFlowerY)
1616 if (dir->vOrigin > 0)
1617 SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1);
1619 else if (SFcurrentListY > SFupperY)
1621 if (dir->vOrigin < dir->nEntries - SFlistSize)
1622 SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1);
1625 if (dir->vOrigin != save)
1627 if (dir->nEntries)
1629 #ifdef FEAT_GUI_NEXTAW
1630 XawScrollbarSetThumb(
1631 selFileVScrolls[n],
1632 (float) (((double) dir->vOrigin) / dir->nEntries),
1633 (float) (((double) ((dir->nEntries < SFlistSize) ?
1634 dir->nEntries : SFlistSize)) / dir->nEntries));
1635 #else
1636 vim_XawScrollbarSetThumb(
1637 selFileVScrolls[n],
1638 (float) (((double) dir->vOrigin) / dir->nEntries),
1639 (float) (((double) ((dir->nEntries < SFlistSize) ?
1640 dir->nEntries : SFlistSize)) / dir->nEntries),
1641 (double)dir->nEntries);
1642 #endif
1646 if (SFbuttonPressed)
1647 SFscrollTimerId = XtAppAddTimeOut(SFapp,
1648 SFscrollTimerInterval(), SFscrollTimer, (XtPointer) n);
1651 static int
1652 SFnewInvertEntry(n, event)
1653 int n;
1654 XMotionEvent *event;
1656 int x, y;
1657 int nw;
1658 static int SFscrollTimerAdded = 0;
1660 x = event->x;
1661 y = event->y;
1663 if (SFdirPtr + n >= SFdirEnd)
1664 return -1;
1666 if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY))
1668 SFDir *dir = &(SFdirs[SFdirPtr + n]);
1670 if (SFscrollTimerAdded)
1672 SFscrollTimerAdded = 0;
1673 XtRemoveTimeOut(SFscrollTimerId);
1676 nw = (y - SFlowerY) / SFentryHeight;
1677 if (dir->vOrigin + nw >= dir->nEntries)
1678 return -1;
1679 return nw;
1681 else
1683 if (SFbuttonPressed)
1685 SFcurrentListY = y;
1686 if (!SFscrollTimerAdded)
1688 SFscrollTimerAdded = 1;
1689 SFscrollTimerId = XtAppAddTimeOut(SFapp,
1690 SFscrollTimerInterval(), SFscrollTimer,
1691 (XtPointer) n);
1694 return -1;
1698 /* ARGSUSED */
1699 static void
1700 SFenterList(w, n, event)
1701 Widget w;
1702 int n;
1703 XEnterWindowEvent *event;
1705 int nw;
1707 /* sanity */
1708 if (SFcurrentInvert[n] != -1)
1710 SFinvertEntry(n);
1711 SFcurrentInvert[n] = -1;
1714 nw = SFnewInvertEntry(n, (XMotionEvent *) event);
1715 if (nw != -1)
1717 SFcurrentInvert[n] = nw;
1718 SFinvertEntry(n);
1722 /* ARGSUSED */
1723 static void
1724 SFleaveList(w, n, event)
1725 Widget w;
1726 int n;
1727 XEvent *event;
1729 if (SFcurrentInvert[n] != -1)
1731 SFinvertEntry(n);
1732 SFcurrentInvert[n] = -1;
1736 /* ARGSUSED */
1737 static void
1738 SFmotionList(w, n, event)
1739 Widget w;
1740 int n;
1741 XMotionEvent *event;
1743 int nw;
1745 nw = SFnewInvertEntry(n, event);
1747 if (nw != SFcurrentInvert[n])
1749 if (SFcurrentInvert[n] != -1)
1750 SFinvertEntry(n);
1751 SFcurrentInvert[n] = nw;
1752 if (nw != -1)
1753 SFinvertEntry(n);
1757 /* ARGSUSED */
1758 static void
1759 SFvFloatSliderMovedCallback(w, n, fnew)
1760 Widget w;
1761 XtPointer n;
1762 XtPointer fnew;
1764 int nw;
1766 nw = (*(float *)fnew) * SFdirs[SFdirPtr + (int)(long)n].nEntries;
1767 SFvSliderMovedCallback(w, (int)(long)n, nw);
1770 /* ARGSUSED */
1771 static void
1772 SFvSliderMovedCallback(w, n, nw)
1773 Widget w;
1774 int n;
1775 int nw;
1777 int old;
1778 Window win;
1779 SFDir *dir;
1781 dir = &(SFdirs[SFdirPtr + n]);
1783 old = dir->vOrigin;
1784 dir->vOrigin = nw;
1786 if (old == nw)
1787 return;
1789 win = XtWindow(selFileLists[n]);
1791 if (ABS(nw - old) < SFlistSize)
1793 if (nw > old)
1795 XCopyArea(
1796 SFdisplay,
1797 win,
1798 win,
1799 SFscrollGC,
1800 SFlineToTextH,
1801 SFlowerY + (nw - old) * SFentryHeight,
1802 SFentryWidth + SFlineToTextH,
1803 (SFlistSize - (nw - old)) * SFentryHeight,
1804 SFlineToTextH,
1805 SFlowerY);
1806 XClearArea(
1807 SFdisplay,
1808 win,
1809 SFlineToTextH,
1810 SFlowerY + (SFlistSize - (nw - old)) *
1811 SFentryHeight,
1812 SFentryWidth + SFlineToTextH,
1813 (nw - old) * SFentryHeight,
1814 False);
1815 SFdrawStrings(win, dir, SFlistSize - (nw - old),
1816 SFlistSize - 1);
1818 else
1820 XCopyArea(
1821 SFdisplay,
1822 win,
1823 win,
1824 SFscrollGC,
1825 SFlineToTextH,
1826 SFlowerY,
1827 SFentryWidth + SFlineToTextH,
1828 (SFlistSize - (old - nw)) * SFentryHeight,
1829 SFlineToTextH,
1830 SFlowerY + (old - nw) * SFentryHeight);
1831 XClearArea(
1832 SFdisplay,
1833 win,
1834 SFlineToTextH,
1835 SFlowerY,
1836 SFentryWidth + SFlineToTextH,
1837 (old - nw) * SFentryHeight,
1838 False);
1839 SFdrawStrings(win, dir, 0, old - nw);
1842 else
1844 XClearArea(
1845 SFdisplay,
1846 win,
1847 SFlineToTextH,
1848 SFlowerY,
1849 SFentryWidth + SFlineToTextH,
1850 SFlistSize * SFentryHeight,
1851 False);
1852 SFdrawStrings(win, dir, 0, SFlistSize - 1);
1856 /* ARGSUSED */
1857 static void
1858 SFvAreaSelectedCallback(w, n, pnew)
1859 Widget w;
1860 XtPointer n;
1861 XtPointer pnew;
1863 SFDir *dir;
1864 int nw = (int)(long)pnew;
1866 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1868 #ifdef FEAT_GUI_NEXTAW
1869 if (nw < 0)
1871 if (nw > -SFvScrollHeight)
1872 nw = -1;
1873 else
1874 nw = -SFlistSize;
1876 else if (nw > 0)
1878 if (nw < SFvScrollHeight)
1879 nw = 1;
1880 else
1881 nw = SFlistSize;
1883 #endif
1884 nw += dir->vOrigin;
1886 if (nw > dir->nEntries - SFlistSize)
1887 nw = dir->nEntries - SFlistSize;
1889 if (nw < 0)
1890 nw = 0;
1892 if (dir->nEntries)
1894 float f;
1896 f = ((double) nw) / dir->nEntries;
1898 #ifdef FEAT_GUI_NEXTAW
1899 XawScrollbarSetThumb(
1902 (float) (((double) ((dir->nEntries < SFlistSize) ?
1903 dir->nEntries : SFlistSize)) / dir->nEntries));
1904 #else
1905 vim_XawScrollbarSetThumb(
1908 (float) (((double) ((dir->nEntries < SFlistSize) ?
1909 dir->nEntries : SFlistSize)) / dir->nEntries),
1910 (double)dir->nEntries);
1911 #endif
1914 SFvSliderMovedCallback(w, (int)(long)n, nw);
1917 /* ARGSUSED */
1918 static void
1919 SFhSliderMovedCallback(w, n, nw)
1920 Widget w;
1921 XtPointer n;
1922 XtPointer nw;
1924 SFDir *dir;
1925 int save;
1927 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1928 save = dir->hOrigin;
1929 dir->hOrigin = (*(float *)nw) * dir->nChars;
1930 if (dir->hOrigin == save)
1931 return;
1933 SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
1936 /* ARGSUSED */
1937 static void
1938 SFhAreaSelectedCallback(w, n, pnew)
1939 Widget w;
1940 XtPointer n;
1941 XtPointer pnew;
1943 SFDir *dir;
1944 int nw = (int)(long)pnew;
1946 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1948 #ifdef FEAT_GUI_NEXTAW
1949 if (nw < 0)
1951 if (nw > -SFhScrollWidth)
1952 nw = -1;
1953 else
1954 nw = -SFcharsPerEntry;
1956 else if (nw > 0)
1958 if (nw < SFhScrollWidth)
1959 nw = 1;
1960 else
1961 nw = SFcharsPerEntry;
1963 #endif
1964 nw += dir->hOrigin;
1966 if (nw > dir->nChars - SFcharsPerEntry)
1967 nw = dir->nChars - SFcharsPerEntry;
1969 if (nw < 0)
1970 nw = 0;
1972 if (dir->nChars)
1974 float f;
1976 f = ((double) nw) / dir->nChars;
1978 #ifdef FEAT_GUI_NEXTAW
1979 XawScrollbarSetThumb(
1982 (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
1983 dir->nChars : SFcharsPerEntry)) / dir->nChars));
1984 #else
1985 vim_XawScrollbarSetThumb(
1988 (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
1989 dir->nChars : SFcharsPerEntry)) / dir->nChars),
1990 (double)dir->nChars);
1991 #endif
1993 SFhSliderMovedCallback(w, n, (XtPointer)&f);
1997 /* ARGSUSED */
1998 static void
1999 SFpathSliderMovedCallback(w, client_data, nw)
2000 Widget w;
2001 XtPointer client_data;
2002 XtPointer nw;
2004 SFDir *dir;
2005 int n;
2006 XawTextPosition pos;
2007 int SFdirPtrSave;
2009 SFdirPtrSave = SFdirPtr;
2010 SFdirPtr = (*(float *)nw) * SFdirEnd;
2011 if (SFdirPtr == SFdirPtrSave)
2012 return;
2014 SFdrawLists(SF_DO_SCROLL);
2016 n = 2;
2017 while (SFdirPtr + n >= SFdirEnd)
2018 n--;
2020 dir = &(SFdirs[SFdirPtr + n]);
2022 pos = dir->path - SFcurrentPath;
2024 if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
2026 pos -= strlen(SFstartDir);
2027 if (pos < 0)
2028 pos = 0;
2031 XawTextSetInsertionPoint(selFileField, pos);
2034 /* ARGSUSED */
2035 static void
2036 SFpathAreaSelectedCallback(w, client_data, pnew)
2037 Widget w;
2038 XtPointer client_data;
2039 XtPointer pnew;
2041 int nw = (int)(long)pnew;
2042 float f;
2044 #ifdef FEAT_GUI_NEXTAW
2045 if (nw < 0)
2047 if (nw > -SFpathScrollWidth)
2048 nw = -1;
2049 else
2050 nw = -3;
2052 else if (nw > 0)
2054 if (nw < SFpathScrollWidth)
2055 nw = 1;
2056 else
2057 nw = 3;
2059 #endif
2060 nw += SFdirPtr;
2062 if (nw > SFdirEnd - 3)
2063 nw = SFdirEnd - 3;
2065 if (nw < 0)
2066 nw = 0;
2068 f = ((double) nw) / SFdirEnd;
2070 #ifdef FEAT_GUI_NEXTAW
2071 XawScrollbarSetThumb(
2074 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd));
2075 #else
2076 vim_XawScrollbarSetThumb(
2079 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd),
2080 (double)SFdirEnd);
2081 #endif
2083 SFpathSliderMovedCallback(w, (XtPointer) NULL, (XtPointer)&f);
2086 static Boolean
2087 SFworkProc()
2089 SFDir *dir;
2090 SFEntry *entry;
2092 for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
2094 if (!(dir->nEntries))
2095 continue;
2096 for (entry = &(dir->entries[dir->nEntries - 1]);
2097 entry >= dir->entries;
2098 entry--)
2100 if (!(entry->statDone))
2102 (void)SFstatAndCheck(dir, entry);
2103 return False;
2108 SFworkProcAdded = 0;
2110 return True;
2113 /***************** Dir.c */
2115 static int
2116 SFcompareEntries(p, q)
2117 const void *p;
2118 const void *q;
2120 return strcmp(((SFEntry *)p)->real, ((SFEntry *)q)->real);
2123 static int
2124 SFgetDir(dir)
2125 SFDir *dir;
2127 SFEntry *result = NULL;
2128 int Alloc = 0;
2129 int i;
2130 DIR *dirp;
2131 struct dirent *dp;
2132 char *str;
2133 int len;
2134 int maxChars;
2135 struct stat statBuf;
2137 maxChars = strlen(dir->dir) - 1;
2139 dir->entries = NULL;
2140 dir->nEntries = 0;
2141 dir->nChars = 0;
2143 result = NULL;
2144 i = 0;
2146 dirp = opendir(".");
2147 if (!dirp)
2148 return 1;
2150 (void)mch_stat(".", &statBuf);
2151 dir->mtime = statBuf.st_mtime;
2153 while ((dp = readdir(dirp)))
2155 /* Ignore "." and ".." */
2156 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
2157 continue;
2158 if (i >= Alloc)
2160 Alloc = 2 * (Alloc + 1);
2161 result = (SFEntry *) XtRealloc((char *) result,
2162 (unsigned) (Alloc * sizeof(SFEntry)));
2164 result[i].statDone = 0;
2165 str = dp->d_name;
2166 len = strlen(str);
2167 result[i].real = XtMalloc((unsigned) (len + 2));
2168 (void) strcat(strcpy(result[i].real, str), " ");
2169 if (len > maxChars)
2170 maxChars = len;
2171 result[i].shown = result[i].real;
2172 i++;
2175 qsort((char *) result, (size_t) i, sizeof(SFEntry), SFcompareEntries);
2177 dir->entries = result;
2178 dir->nEntries = i;
2179 dir->nChars = maxChars + 1;
2181 closedir(dirp);
2183 return 0;
2186 /***************** SFinternal.h */
2188 #include <sys/param.h>
2189 #include <X11/cursorfont.h>
2190 #include <X11/Composite.h>
2191 #include <X11/Shell.h>
2192 #ifdef FEAT_GUI_NEXTAW
2193 # include <X11/neXtaw/Form.h>
2194 # include <X11/neXtaw/Command.h>
2195 # include <X11/neXtaw/Label.h>
2196 #else
2197 #include <X11/Xaw/Form.h>
2198 #include <X11/Xaw/Command.h>
2199 #include <X11/Xaw/Label.h>
2200 #endif
2202 static char *oneLineTextEditTranslations = "\
2203 <Key>Return: redraw-display()\n\
2204 Ctrl<Key>M: redraw-display()\n\
2207 static void SFexposeList __ARGS((Widget w, XtPointer n, XEvent *event, Boolean *cont));
2209 /* ARGSUSED */
2210 static void
2211 SFexposeList(w, n, event, cont)
2212 Widget w;
2213 XtPointer n;
2214 XEvent *event;
2215 Boolean *cont;
2217 if ((event->type == NoExpose) || event->xexpose.count)
2218 return;
2220 SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
2223 static void SFmodVerifyCallback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont));
2225 /* ARGSUSED */
2226 static void
2227 SFmodVerifyCallback(w, client_data, event, cont)
2228 Widget w;
2229 XtPointer client_data;
2230 XEvent *event;
2231 Boolean *cont;
2233 char buf[2];
2235 if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
2236 ((*buf) == '\r'))
2237 SFstatus = SEL_FILE_OK;
2238 else
2239 SFstatus = SEL_FILE_TEXT;
2242 static void SFokCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
2244 /* ARGSUSED */
2245 static void
2246 SFokCallback(w, cl, cd)
2247 Widget w;
2248 XtPointer cl, cd;
2250 SFstatus = SEL_FILE_OK;
2253 static XtCallbackRec SFokSelect[] =
2255 { SFokCallback, (XtPointer) NULL },
2256 { NULL, (XtPointer) NULL },
2259 static void SFcancelCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
2261 /* ARGSUSED */
2262 static void
2263 SFcancelCallback(w, cl, cd)
2264 Widget w;
2265 XtPointer cl, cd;
2267 SFstatus = SEL_FILE_CANCEL;
2270 static XtCallbackRec SFcancelSelect[] =
2272 { SFcancelCallback, (XtPointer) NULL },
2273 { NULL, (XtPointer) NULL },
2276 static void SFdismissAction __ARGS((Widget w, XEvent *event, String *params, Cardinal *num_params));
2278 /* ARGSUSED */
2279 static void
2280 SFdismissAction(w, event, params, num_params)
2281 Widget w;
2282 XEvent *event;
2283 String *params;
2284 Cardinal *num_params;
2286 if (event->type == ClientMessage &&
2287 event->xclient.data.l[0] != SFwmDeleteWindow)
2288 return;
2290 SFstatus = SEL_FILE_CANCEL;
2293 static char *wmDeleteWindowTranslation = "\
2294 <Message>WM_PROTOCOLS: SelFileDismiss()\n\
2297 static XtActionsRec actions[] =
2299 {"SelFileDismiss", SFdismissAction},
2302 static void
2303 SFsetColors(bg, fg, scroll_bg, scroll_fg)
2304 guicolor_T bg;
2305 guicolor_T fg;
2306 guicolor_T scroll_bg;
2307 guicolor_T scroll_fg;
2309 if (selFileForm)
2311 XtVaSetValues(selFileForm, XtNbackground, bg,
2312 XtNforeground, fg,
2313 XtNborderColor, bg,
2314 NULL);
2317 int i;
2319 for (i = 0; i < 3; ++i)
2321 if (selFileLists[i])
2323 XtVaSetValues(selFileLists[i], XtNbackground, bg,
2324 XtNforeground, fg,
2325 XtNborderColor, fg,
2326 NULL);
2330 if (selFileOK)
2332 XtVaSetValues(selFileOK, XtNbackground, bg,
2333 XtNforeground, fg,
2334 XtNborderColor, fg,
2335 NULL);
2337 if (selFileCancel)
2339 XtVaSetValues(selFileCancel, XtNbackground, bg,
2340 XtNforeground, fg,
2341 XtNborderColor, fg,
2342 NULL);
2344 if (selFilePrompt)
2346 XtVaSetValues(selFilePrompt, XtNbackground, bg,
2347 XtNforeground, fg,
2348 NULL);
2350 if (gui.dpy)
2352 XSetBackground(gui.dpy, SFtextGC, bg);
2353 XSetForeground(gui.dpy, SFtextGC, fg);
2354 XSetForeground(gui.dpy, SFlineGC, fg);
2356 /* This is an xor GC, so combine the fg and background */
2357 XSetBackground(gui.dpy, SFinvertGC, fg ^ bg);
2358 XSetForeground(gui.dpy, SFinvertGC, fg ^ bg);
2360 if (selFileHScroll)
2362 XtVaSetValues(selFileHScroll, XtNbackground, scroll_bg,
2363 XtNforeground, scroll_fg,
2364 XtNborderColor, fg,
2365 NULL);
2368 int i;
2370 for (i = 0; i < 3; i++)
2372 XtVaSetValues(selFileVScrolls[i], XtNbackground, scroll_bg,
2373 XtNforeground, scroll_fg,
2374 XtNborderColor, fg,
2375 NULL);
2376 XtVaSetValues(selFileHScrolls[i], XtNbackground, scroll_bg,
2377 XtNforeground, scroll_fg,
2378 XtNborderColor, fg,
2379 NULL);
2384 static void
2385 SFcreateWidgets(toplevel, prompt, ok, cancel)
2386 Widget toplevel;
2387 char *prompt;
2388 char *ok;
2389 char *cancel;
2391 Cardinal n;
2392 int listWidth, listHeight;
2393 int listSpacing = 10;
2394 int scrollThickness = 15;
2395 int hScrollX, hScrollY;
2396 int vScrollX, vScrollY;
2398 selFile = XtVaAppCreateShell("selFile", "SelFile",
2399 transientShellWidgetClass, SFdisplay,
2400 XtNtransientFor, toplevel,
2401 XtNtitle, prompt,
2402 NULL);
2404 /* Add WM_DELETE_WINDOW protocol */
2405 XtAppAddActions(XtWidgetToApplicationContext(selFile),
2406 actions, XtNumber(actions));
2407 XtOverrideTranslations(selFile,
2408 XtParseTranslationTable(wmDeleteWindowTranslation));
2410 selFileForm = XtVaCreateManagedWidget("selFileForm",
2411 formWidgetClass, selFile,
2412 XtNdefaultDistance, 30,
2413 XtNforeground, SFfore,
2414 XtNbackground, SFback,
2415 XtNborderColor, SFback,
2416 NULL);
2418 selFilePrompt = XtVaCreateManagedWidget("selFilePrompt",
2419 labelWidgetClass, selFileForm,
2420 XtNlabel, prompt,
2421 XtNresizable, True,
2422 XtNtop, XtChainTop,
2423 XtNbottom, XtChainTop,
2424 XtNleft, XtChainLeft,
2425 XtNright, XtChainLeft,
2426 XtNborderWidth, 0,
2427 XtNforeground, SFfore,
2428 XtNbackground, SFback,
2429 NULL);
2432 XtVaGetValues(selFilePrompt,
2433 XtNforeground, &SFfore,
2434 XtNbackground, &SFback,
2435 NULL);
2438 SFinitFont();
2440 SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth +
2441 SFbesideText;
2442 SFentryHeight = SFaboveAndBelowText + SFcharHeight +
2443 SFaboveAndBelowText;
2445 listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
2446 scrollThickness;
2447 listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2448 SFlineToTextV + SFlistSize * SFentryHeight +
2449 SFlineToTextV + 1 + scrollThickness;
2451 SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;
2453 hScrollX = -1;
2454 hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2455 SFlineToTextV + SFlistSize * SFentryHeight +
2456 SFlineToTextV;
2457 SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
2459 vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
2460 vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
2461 SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
2462 SFlineToTextV;
2464 SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
2465 SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2466 SFlineToTextV;
2467 SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2468 SFlineToTextV + SFlistSize * SFentryHeight - 1;
2470 SFtextX = SFlineToTextH + SFbesideText;
2471 SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
2473 SFsegs[0].x1 = 0;
2474 SFsegs[0].y1 = vScrollY;
2475 SFsegs[0].x2 = vScrollX - 1;
2476 SFsegs[0].y2 = vScrollY;
2477 SFsegs[1].x1 = vScrollX;
2478 SFsegs[1].y1 = 0;
2479 SFsegs[1].x2 = vScrollX;
2480 SFsegs[1].y2 = vScrollY - 1;
2482 SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
2483 SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
2484 SFlineToTextH + SFentryWidth - 1;
2486 selFileField = XtVaCreateManagedWidget("selFileField",
2487 asciiTextWidgetClass, selFileForm,
2488 XtNwidth, 3 * listWidth + 2 * listSpacing + 4,
2489 XtNborderColor, SFfore,
2490 XtNfromVert, selFilePrompt,
2491 XtNvertDistance, 10,
2492 XtNresizable, True,
2493 XtNtop, XtChainTop,
2494 XtNbottom, XtChainTop,
2495 XtNleft, XtChainLeft,
2496 XtNright, XtChainLeft,
2497 XtNstring, SFtextBuffer,
2498 XtNlength, MAXPATHL,
2499 XtNeditType, XawtextEdit,
2500 XtNwrap, XawtextWrapWord,
2501 XtNresize, XawtextResizeHeight,
2502 XtNuseStringInPlace, True,
2503 NULL);
2505 XtOverrideTranslations(selFileField,
2506 XtParseTranslationTable(oneLineTextEditTranslations));
2507 XtSetKeyboardFocus(selFileForm, selFileField);
2509 selFileHScroll = XtVaCreateManagedWidget("selFileHScroll",
2510 #ifdef FEAT_GUI_NEXTAW
2511 scrollbarWidgetClass, selFileForm,
2512 #else
2513 vim_scrollbarWidgetClass, selFileForm,
2514 #endif
2515 XtNorientation, XtorientHorizontal,
2516 XtNwidth, SFpathScrollWidth,
2517 XtNheight, scrollThickness,
2518 XtNborderColor, SFfore,
2519 XtNfromVert, selFileField,
2520 XtNvertDistance, 30,
2521 XtNtop, XtChainTop,
2522 XtNbottom, XtChainTop,
2523 XtNleft, XtChainLeft,
2524 XtNright, XtChainLeft,
2525 XtNforeground, gui.scroll_fg_pixel,
2526 XtNbackground, gui.scroll_bg_pixel,
2527 #ifndef FEAT_GUI_NEXTAW
2528 XtNlimitThumb, 1,
2529 #endif
2530 NULL);
2532 XtAddCallback(selFileHScroll, XtNjumpProc,
2533 (XtCallbackProc) SFpathSliderMovedCallback, (XtPointer)NULL);
2534 XtAddCallback(selFileHScroll, XtNscrollProc,
2535 (XtCallbackProc) SFpathAreaSelectedCallback, (XtPointer)NULL);
2537 selFileLists[0] = XtVaCreateManagedWidget("selFileList1",
2538 compositeWidgetClass, selFileForm,
2539 XtNwidth, listWidth,
2540 XtNheight, listHeight,
2541 XtNforeground, SFfore,
2542 XtNbackground, SFback,
2543 XtNborderColor, SFfore,
2544 XtNfromVert, selFileHScroll,
2545 XtNvertDistance, 10,
2546 XtNtop, XtChainTop,
2547 XtNbottom, XtChainTop,
2548 XtNleft, XtChainLeft,
2549 XtNright, XtChainLeft,
2550 NULL);
2552 selFileLists[1] = XtVaCreateManagedWidget("selFileList2",
2553 compositeWidgetClass, selFileForm,
2554 XtNwidth, listWidth,
2555 XtNheight, listHeight,
2556 XtNforeground, SFfore,
2557 XtNbackground, SFback,
2558 XtNborderColor, SFfore,
2559 XtNfromHoriz, selFileLists[0],
2560 XtNfromVert, selFileHScroll,
2561 XtNhorizDistance, listSpacing,
2562 XtNvertDistance, 10,
2563 XtNtop, XtChainTop,
2564 XtNbottom, XtChainTop,
2565 XtNleft, XtChainLeft,
2566 XtNright, XtChainLeft,
2567 NULL);
2569 selFileLists[2] = XtVaCreateManagedWidget("selFileList3",
2570 compositeWidgetClass, selFileForm,
2571 XtNwidth, listWidth,
2572 XtNheight, listHeight,
2573 XtNforeground, SFfore,
2574 XtNbackground, SFback,
2575 XtNborderColor, SFfore,
2576 XtNfromHoriz, selFileLists[1],
2577 XtNfromVert, selFileHScroll,
2578 XtNhorizDistance, listSpacing,
2579 XtNvertDistance, 10,
2580 XtNtop, XtChainTop,
2581 XtNbottom, XtChainTop,
2582 XtNleft, XtChainLeft,
2583 XtNright, XtChainLeft,
2584 NULL);
2586 for (n = 0; n < 3; n++)
2588 selFileVScrolls[n] = XtVaCreateManagedWidget("selFileVScroll",
2589 #ifdef FEAT_GUI_NEXTAW
2590 scrollbarWidgetClass, selFileLists[n],
2591 #else
2592 vim_scrollbarWidgetClass, selFileLists[n],
2593 #endif
2594 XtNx, vScrollX,
2595 XtNy, vScrollY,
2596 XtNwidth, scrollThickness,
2597 XtNheight, SFvScrollHeight,
2598 XtNborderColor, SFfore,
2599 XtNforeground, gui.scroll_fg_pixel,
2600 XtNbackground, gui.scroll_bg_pixel,
2601 #ifndef FEAT_GUI_NEXTAW
2602 XtNlimitThumb, 1,
2603 #endif
2604 NULL);
2606 XtAddCallback(selFileVScrolls[n], XtNjumpProc,
2607 (XtCallbackProc)SFvFloatSliderMovedCallback, (XtPointer)n);
2608 XtAddCallback(selFileVScrolls[n], XtNscrollProc,
2609 (XtCallbackProc)SFvAreaSelectedCallback, (XtPointer)n);
2611 selFileHScrolls[n] = XtVaCreateManagedWidget("selFileHScroll",
2612 #ifdef FEAT_GUI_NEXTAW
2613 scrollbarWidgetClass, selFileLists[n],
2614 #else
2615 vim_scrollbarWidgetClass, selFileLists[n],
2616 #endif
2617 XtNorientation, XtorientHorizontal,
2618 XtNx, hScrollX,
2619 XtNy, hScrollY,
2620 XtNwidth, SFhScrollWidth,
2621 XtNheight, scrollThickness,
2622 XtNborderColor, SFfore,
2623 XtNforeground, gui.scroll_fg_pixel,
2624 XtNbackground, gui.scroll_bg_pixel,
2625 #ifndef FEAT_GUI_NEXTAW
2626 XtNlimitThumb, 1,
2627 #endif
2628 NULL);
2630 XtAddCallback(selFileHScrolls[n], XtNjumpProc,
2631 (XtCallbackProc)SFhSliderMovedCallback, (XtPointer)n);
2632 XtAddCallback(selFileHScrolls[n], XtNscrollProc,
2633 (XtCallbackProc)SFhAreaSelectedCallback, (XtPointer)n);
2636 selFileOK = XtVaCreateManagedWidget("selFileOK",
2637 commandWidgetClass, selFileForm,
2638 XtNlabel, ok,
2639 XtNresizable, True,
2640 XtNcallback, SFokSelect,
2641 XtNforeground, SFfore,
2642 XtNbackground, SFback,
2643 XtNborderColor, SFfore,
2644 XtNfromHoriz, selFileLists[0],
2645 XtNfromVert, selFileLists[0],
2646 XtNvertDistance, 30,
2647 XtNtop, XtChainTop,
2648 XtNbottom, XtChainTop,
2649 XtNleft, XtChainLeft,
2650 XtNright, XtChainLeft,
2651 NULL);
2653 selFileCancel = XtVaCreateManagedWidget("selFileCancel",
2654 commandWidgetClass, selFileForm,
2655 XtNlabel, cancel,
2656 XtNresizable, True,
2657 XtNcallback, SFcancelSelect,
2658 XtNforeground, SFfore,
2659 XtNbackground, SFback,
2660 XtNborderColor, SFfore,
2661 XtNfromHoriz, selFileOK,
2662 XtNfromVert, selFileLists[0],
2663 XtNhorizDistance, 30,
2664 XtNvertDistance, 30,
2665 XtNtop, XtChainTop,
2666 XtNbottom, XtChainTop,
2667 XtNleft, XtChainLeft,
2668 XtNright, XtChainLeft,
2669 NULL);
2671 XtSetMappedWhenManaged(selFile, False);
2672 XtRealizeWidget(selFile);
2674 /* Add WM_DELETE_WINDOW protocol */
2675 SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
2676 XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
2678 SFcreateGC();
2680 for (n = 0; n < 3; n++)
2682 XtAddEventHandler(selFileLists[n], ExposureMask, True,
2683 (XtEventHandler)SFexposeList, (XtPointer)n);
2684 XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
2685 (XtEventHandler)SFenterList, (XtPointer)n);
2686 XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
2687 (XtEventHandler)SFleaveList, (XtPointer)n);
2688 XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
2689 (XtEventHandler)SFmotionList, (XtPointer)n);
2690 XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
2691 (XtEventHandler)SFbuttonPressList, (XtPointer)n);
2692 XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
2693 (XtEventHandler)SFbuttonReleaseList, (XtPointer)n);
2696 XtAddEventHandler(selFileField, KeyPressMask, False,
2697 SFmodVerifyCallback, (XtPointer)NULL);
2699 SFapp = XtWidgetToApplicationContext(selFile);
2702 static void
2703 SFtextChanged()
2705 #if defined(FEAT_XFONTSET) && defined(XtNinternational)
2706 if (_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
2708 wchar_t *wcbuf=(wchar_t *)SFtextBuffer;
2710 if ((wcbuf[0] == L'/') || (wcbuf[0] == L'~'))
2712 (void) wcstombs(SFcurrentPath, wcbuf, MAXPATHL);
2713 SFtextPos = XawTextGetInsertionPoint(selFileField);
2715 else
2717 strcpy(SFcurrentPath, SFstartDir);
2718 (void) wcstombs(SFcurrentPath + strlen(SFcurrentPath), wcbuf, MAXPATHL);
2720 SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
2723 else
2724 #endif
2725 if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~'))
2727 (void) strcpy(SFcurrentPath, SFtextBuffer);
2728 SFtextPos = XawTextGetInsertionPoint(selFileField);
2730 else
2732 (void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
2734 SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
2737 if (!SFworkProcAdded)
2739 (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
2740 SFworkProcAdded = 1;
2743 SFupdatePath();
2746 static char *
2747 SFgetText()
2749 #if defined(FEAT_XFONTSET) && defined(XtNinternational)
2750 char *buf;
2752 if (_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
2754 wchar_t *wcbuf;
2755 int mbslength;
2757 XtVaGetValues(selFileField,
2758 XtNstring, &wcbuf,
2759 NULL);
2760 mbslength = wcstombs(NULL, wcbuf, 0);
2761 /* Hack: some broken wcstombs() returns zero, just get a large buffer */
2762 if (mbslength == 0 && wcbuf != NULL && wcbuf[0] != 0)
2763 mbslength = MAXPATHL;
2764 buf=(char *)XtMalloc(mbslength + 1);
2765 wcstombs(buf, wcbuf, mbslength +1);
2766 return buf;
2768 #endif
2769 return (char *)vim_strsave((char_u *)SFtextBuffer);
2772 static void
2773 SFprepareToReturn()
2775 SFstatus = SEL_FILE_NULL;
2776 XtRemoveGrab(selFile);
2777 XtUnmapWidget(selFile);
2778 XtRemoveTimeOut(SFdirModTimerId);
2779 if (SFchdir(SFstartDir))
2781 EMSG(_("E614: vim_SelFile: can't return to current directory"));
2782 SFstatus = SEL_FILE_CANCEL;
2786 char *
2787 vim_SelFile(toplevel, prompt, init_path, show_entry, x, y, fg, bg, scroll_fg, scroll_bg)
2788 Widget toplevel;
2789 char *prompt;
2790 char *init_path;
2791 int (*show_entry)();
2792 int x, y;
2793 guicolor_T fg, bg;
2794 guicolor_T scroll_fg, scroll_bg; /* The "Scrollbar" group colors */
2796 static int firstTime = 1;
2797 XEvent event;
2798 char *name_return;
2800 if (prompt == NULL)
2801 prompt = _("Pathname:");
2802 SFfore = fg;
2803 SFback = bg;
2805 if (mch_dirname((char_u *)SFstartDir, MAXPATHL) == FAIL)
2807 EMSG(_("E615: vim_SelFile: can't get current directory"));
2808 return NULL;
2811 if (firstTime)
2813 firstTime = 0;
2814 SFdisplay = XtDisplay(toplevel);
2815 SFcreateWidgets(toplevel, prompt, _("OK"), _("Cancel"));
2817 else
2819 XtVaSetValues(selFilePrompt, XtNlabel, prompt, NULL);
2820 XtVaSetValues(selFile, XtNtitle, prompt, NULL);
2821 SFsetColors(bg, fg, scroll_bg, scroll_fg);
2824 XtVaSetValues(selFile, XtNx, x, XtNy, y, NULL);
2825 XtMapWidget(selFile);
2827 (void)strcat(SFstartDir, "/");
2828 (void)strcpy(SFcurrentDir, SFstartDir);
2830 if (init_path)
2832 if (init_path[0] == '/')
2834 (void)strcpy(SFcurrentPath, init_path);
2835 if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
2836 SFsetText(SFcurrentPath);
2837 else
2838 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
2840 else
2842 (void)strcat(strcpy(SFcurrentPath, SFstartDir), init_path);
2843 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
2846 else
2847 (void)strcpy(SFcurrentPath, SFstartDir);
2849 SFfunc = show_entry;
2851 SFtextChanged();
2853 XtAddGrab(selFile, True, True);
2855 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
2856 SFdirModTimer, (XtPointer) NULL);
2858 for (;;)
2860 XtAppNextEvent(SFapp, &event);
2861 XtDispatchEvent(&event);
2862 switch (SFstatus)
2864 case SEL_FILE_TEXT:
2865 SFstatus = SEL_FILE_NULL;
2866 SFtextChanged();
2867 break;
2868 case SEL_FILE_OK:
2869 name_return = SFgetText();
2870 SFprepareToReturn();
2871 return name_return;
2872 case SEL_FILE_CANCEL:
2873 SFprepareToReturn();
2874 return NULL;
2875 case SEL_FILE_NULL:
2876 break;
2880 #endif /* FEAT_BROWSE */