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