comparison src/gui_at_fs.c @ 7:3fc0f57ecb91 v7.0001

updated for version 7.0001
author vimboss
date Sun, 13 Jun 2004 20:20:40 +0000
parents
children aa550d9d2403
comparison
equal deleted inserted replaced
6:c2daee826b8f 7:3fc0f57ecb91
1 /* vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
5 *
6 * Permission to use, copy, modify, and distribute this software and its
7 * documentation for any purpose and without fee is hereby granted, provided
8 * that the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Software Research Associates not be used
11 * in advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. Software Research Associates
13 * makes no representations about the suitability of this software for any
14 * purpose. It is provided "as is" without express or implied warranty.
15 *
16 * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
18 * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
19 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
20 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
21 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 *
24 * Author: Erik M. van der Poel
25 * Software Research Associates, Inc., Tokyo, Japan
26 * erik@sra.co.jp
27 */
28 /*
29 * Author's addresses:
30 * erik@sra.co.jp
31 * erik%sra.co.jp@uunet.uu.net
32 * erik%sra.co.jp@mcvax.uucp
33 * try junet instead of co.jp
34 * Erik M. van der Poel
35 * Software Research Associates, Inc.
36 * 1-1-1 Hirakawa-cho, Chiyoda-ku
37 * Tokyo 102 Japan. TEL +81-3-234-2692
38 */
39
40 /*
41 * Heavely modified for Vim by Bram Moolenaar
42 */
43
44 #include "vim.h"
45
46 /* Only include this when using the file browser */
47
48 #ifdef FEAT_BROWSE
49
50 /* Weird complication: for "make lint" Text.h doesn't combine with Xm.h */
51 #if defined(FEAT_GUI_MOTIF) && defined(FMT8BIT)
52 # undef FMT8BIT
53 #endif
54
55 #ifndef FEAT_GUI_NEXTAW
56 # include "gui_at_sb.h"
57 #endif
58
59 /***************** SFinternal.h */
60
61 #include <X11/Intrinsic.h>
62 #include <X11/StringDefs.h>
63 #include <X11/Xos.h>
64 #ifdef FEAT_GUI_NEXTAW
65 # include <X11/neXtaw/Text.h>
66 # include <X11/neXtaw/AsciiText.h>
67 # include <X11/neXtaw/Scrollbar.h>
68 #else
69 # include <X11/Xaw/Text.h>
70 # include <X11/Xaw/AsciiText.h>
71 #endif
72
73 #define SEL_FILE_CANCEL -1
74 #define SEL_FILE_OK 0
75 #define SEL_FILE_NULL 1
76 #define SEL_FILE_TEXT 2
77
78 #define SF_DO_SCROLL 1
79 #define SF_DO_NOT_SCROLL 0
80
81 typedef struct
82 {
83 int statDone;
84 char *real;
85 char *shown;
86 } SFEntry;
87
88 typedef struct
89 {
90 char *dir;
91 char *path;
92 SFEntry *entries;
93 int nEntries;
94 int vOrigin;
95 int nChars;
96 int hOrigin;
97 int changed;
98 int beginSelection;
99 int endSelection;
100 time_t mtime;
101 } SFDir;
102
103 static char SFstartDir[MAXPATHL],
104 SFcurrentPath[MAXPATHL],
105 SFcurrentDir[MAXPATHL];
106
107 static Widget selFile,
108 selFileField,
109 selFileForm,
110 selFileHScroll,
111 selFileHScrolls[3],
112 selFileLists[3],
113 selFileOK,
114 selFileCancel,
115 selFilePrompt,
116 selFileVScrolls[3];
117
118 static Display *SFdisplay;
119
120 static int SFcharWidth, SFcharAscent, SFcharHeight;
121
122 static SFDir *SFdirs = NULL;
123
124 static int SFdirEnd;
125 static int SFdirPtr;
126
127 static Pixel SFfore, SFback;
128
129 static Atom SFwmDeleteWindow;
130
131 static XSegment SFsegs[2], SFcompletionSegs[2];
132
133 static XawTextPosition SFtextPos;
134
135 static int SFupperX, SFlowerY, SFupperY;
136
137 static int SFtextX, SFtextYoffset;
138
139 static int SFentryWidth, SFentryHeight;
140
141 static int SFlineToTextH = 3;
142 static int SFlineToTextV = 3;
143
144 static int SFbesideText = 3;
145 static int SFaboveAndBelowText = 2;
146
147 static int SFcharsPerEntry = 15;
148
149 static int SFlistSize = 10;
150
151 static int SFcurrentInvert[3] = { -1, -1, -1 };
152
153 static int SFworkProcAdded = 0;
154
155 static XtAppContext SFapp;
156
157 static int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
158
159 #ifdef FEAT_XFONTSET
160 static char SFtextBuffer[MAXPATHL*sizeof(wchar_t)];
161 #else
162 static char SFtextBuffer[MAXPATHL];
163 #endif
164
165 static int SFbuttonPressed = 0;
166
167 static XtIntervalId SFdirModTimerId;
168
169 static int (*SFfunc)();
170
171 static int SFstatus = SEL_FILE_NULL;
172
173 /***************** static functions */
174
175 static void SFsetText __ARGS((char *path));
176 static void SFtextChanged __ARGS((void));
177 static char *SFgetText __ARGS((void));
178 static void SFupdatePath __ARGS((void));
179 static int SFgetDir __ARGS((SFDir *dir));
180 static void SFdrawLists __ARGS((int doScroll));
181 static void SFdrawList __ARGS((int n, int doScroll));
182 static void SFclearList __ARGS((int n, int doScroll));
183 static void SFbuttonPressList __ARGS((Widget w, int n, XButtonPressedEvent *event));
184 static void SFbuttonReleaseList __ARGS((Widget w, int n, XButtonReleasedEvent *event));
185 static void SFdirModTimer __ARGS((XtPointer cl, XtIntervalId *id));
186 static char SFstatChar __ARGS((struct stat *statBuf));
187 static void SFdrawStrings __ARGS((Window w, SFDir *dir, int from, int to));
188 static int SFnewInvertEntry __ARGS((int n, XMotionEvent *event));
189 static void SFinvertEntry __ARGS((int n));
190 static void SFenterList __ARGS((Widget w, int n, XEnterWindowEvent *event));
191 static void SFleaveList __ARGS((Widget w, int n, XEvent *event));
192 static void SFmotionList __ARGS((Widget w, int n, XMotionEvent *event));
193 static void SFvFloatSliderMovedCallback __ARGS((Widget w, XtPointer n, XtPointer fnew));
194 static void SFvSliderMovedCallback __ARGS((Widget w, int n, int nw));
195 static void SFvAreaSelectedCallback __ARGS((Widget w, XtPointer n, XtPointer pnew));
196 static void SFhSliderMovedCallback __ARGS((Widget w, XtPointer n, XtPointer nw));
197 static void SFhAreaSelectedCallback __ARGS((Widget w, XtPointer n, XtPointer pnew));
198 static void SFpathSliderMovedCallback __ARGS((Widget w, XtPointer client_data, XtPointer nw));
199 static void SFpathAreaSelectedCallback __ARGS((Widget w, XtPointer client_data, XtPointer pnew));
200 static Boolean SFworkProc __ARGS((void));
201 static int SFcompareEntries __ARGS((const void *p, const void *q));
202 static void SFprepareToReturn __ARGS((void));
203 static void SFcreateWidgets __ARGS((Widget toplevel, char *prompt, char *ok, char *cancel));
204 static void SFsetColors __ARGS((guicolor_T bg, guicolor_T fg, guicolor_T scroll_bg, guicolor_T scrollfg));
205
206 /***************** xstat.h */
207
208 #ifndef S_IXUSR
209 # define S_IXUSR 0100
210 #endif
211 #ifndef S_IXGRP
212 # define S_IXGRP 0010
213 #endif
214 #ifndef S_IXOTH
215 # define S_IXOTH 0001
216 #endif
217
218 #define S_ISXXX(m) ((m) & (S_IXUSR | S_IXGRP | S_IXOTH))
219
220 /***************** Path.c */
221
222 #include <pwd.h>
223
224 typedef struct
225 {
226 char *name;
227 char *dir;
228 } SFLogin;
229
230 static int SFdoNotTouchDirPtr = 0;
231
232 static int SFdoNotTouchVorigin = 0;
233
234 static SFDir SFrootDir, SFhomeDir;
235
236 static SFLogin *SFlogins;
237
238 static int SFtwiddle = 0;
239
240 static int SFchdir __ARGS((char *path));
241
242 static int
243 SFchdir(path)
244 char *path;
245 {
246 int result;
247
248 result = 0;
249
250 if (strcmp(path, SFcurrentDir))
251 {
252 result = mch_chdir(path);
253 if (!result)
254 (void) strcpy(SFcurrentDir, path);
255 }
256
257 return result;
258 }
259
260 static void SFfree __ARGS((int i));
261
262 static void
263 SFfree(i)
264 int i;
265 {
266 SFDir *dir;
267 int j;
268
269 dir = &(SFdirs[i]);
270
271 for (j = dir->nEntries - 1; j >= 0; j--)
272 {
273 if (dir->entries[j].shown != dir->entries[j].real)
274 XtFree(dir->entries[j].shown);
275 XtFree(dir->entries[j].real);
276 }
277
278 XtFree((char *)dir->entries);
279 XtFree(dir->dir);
280
281 dir->dir = NULL;
282 }
283
284 static void SFstrdup __ARGS((char **s1, char *s2));
285
286 static void
287 SFstrdup(s1, s2)
288 char **s1;
289 char *s2;
290 {
291 *s1 = strcpy(XtMalloc((unsigned)(strlen(s2) + 1)), s2);
292 }
293
294 static void SFunreadableDir __ARGS((SFDir *dir));
295
296 static void
297 SFunreadableDir(dir)
298 SFDir *dir;
299 {
300 char *cannotOpen = _("<cannot open> ");
301
302 dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
303 dir->entries[0].statDone = 1;
304 SFstrdup(&dir->entries[0].real, cannotOpen);
305 dir->entries[0].shown = dir->entries[0].real;
306 dir->nEntries = 1;
307 dir->nChars = strlen(cannotOpen);
308 }
309
310 static void SFreplaceText __ARGS((SFDir *dir, char *str));
311
312 static void
313 SFreplaceText(dir, str)
314 SFDir *dir;
315 char *str;
316 {
317 int len;
318
319 *(dir->path) = 0;
320 len = strlen(str);
321 if (str[len - 1] == '/')
322 (void) strcat(SFcurrentPath, str);
323 else
324 (void) strncat(SFcurrentPath, str, len - 1);
325 if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
326 SFsetText(SFcurrentPath);
327 else
328 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
329
330 SFtextChanged();
331 }
332
333 static void SFexpand __ARGS((char *str));
334
335 static void
336 SFexpand(str)
337 char *str;
338 {
339 int len;
340 int cmp;
341 char *name, *growing;
342 SFDir *dir;
343 SFEntry *entry, *max;
344
345 len = strlen(str);
346
347 dir = &(SFdirs[SFdirEnd - 1]);
348
349 if (dir->beginSelection == -1)
350 {
351 SFstrdup(&str, str);
352 SFreplaceText(dir, str);
353 XtFree(str);
354 return;
355 }
356 else if (dir->beginSelection == dir->endSelection)
357 {
358 SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
359 return;
360 }
361
362 max = &(dir->entries[dir->endSelection + 1]);
363
364 name = dir->entries[dir->beginSelection].shown;
365 SFstrdup(&growing, name);
366
367 cmp = 0;
368 while (!cmp)
369 {
370 entry = &(dir->entries[dir->beginSelection]);
371 while (entry < max)
372 {
373 if ((cmp = strncmp(growing, entry->shown, len)))
374 break;
375 entry++;
376 }
377 len++;
378 }
379
380 /*
381 * SFreplaceText() expects filename
382 */
383 growing[len - 2] = ' ';
384
385 growing[len - 1] = 0;
386 SFreplaceText(dir, growing);
387 XtFree(growing);
388 }
389
390 static int SFfindFile __ARGS((SFDir *dir, char *str));
391
392 static int
393 SFfindFile(dir, str)
394 SFDir *dir;
395 char *str;
396 {
397 int i, last, max;
398 char *name, save;
399 SFEntry *entries;
400 int len;
401 int begin, end;
402 int result;
403
404 len = strlen(str);
405
406 if (str[len - 1] == ' ')
407 {
408 SFexpand(str);
409 return 1;
410 }
411 else if (str[len - 1] == '/')
412 len--;
413
414 max = dir->nEntries;
415
416 entries = dir->entries;
417
418 i = 0;
419 while (i < max)
420 {
421 name = entries[i].shown;
422 last = strlen(name) - 1;
423 save = name[last];
424 name[last] = 0;
425
426 result = strncmp(str, name, len);
427
428 name[last] = save;
429 if (result <= 0)
430 break;
431 i++;
432 }
433 begin = i;
434 while (i < max)
435 {
436 name = entries[i].shown;
437 last = strlen(name) - 1;
438 save = name[last];
439 name[last] = 0;
440
441 result = strncmp(str, name, len);
442
443 name[last] = save;
444 if (result)
445 break;
446 i++;
447 }
448 end = i;
449
450 if (begin != end)
451 {
452 if ((dir->beginSelection != begin) || (dir->endSelection != end - 1))
453 {
454 dir->changed = 1;
455 dir->beginSelection = begin;
456 if (str[strlen(str) - 1] == '/')
457 dir->endSelection = begin;
458 else
459 dir->endSelection = end - 1;
460 }
461 }
462 else if (dir->beginSelection != -1)
463 {
464 dir->changed = 1;
465 dir->beginSelection = -1;
466 dir->endSelection = -1;
467 }
468
469 if (SFdoNotTouchVorigin
470 || ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize)))
471 {
472 SFdoNotTouchVorigin = 0;
473 return 0;
474 }
475
476 i = begin - 1;
477 if (i > max - SFlistSize)
478 i = max - SFlistSize;
479 if (i < 0)
480 i = 0;
481
482 if (dir->vOrigin != i)
483 {
484 dir->vOrigin = i;
485 dir->changed = 1;
486 }
487
488 return 0;
489 }
490
491 static void SFunselect __ARGS((void));
492
493 static void
494 SFunselect()
495 {
496 SFDir *dir;
497
498 dir = &(SFdirs[SFdirEnd - 1]);
499 if (dir->beginSelection != -1)
500 dir->changed = 1;
501 dir->beginSelection = -1;
502 dir->endSelection = -1;
503 }
504
505 static int SFcompareLogins __ARGS((const void *p, const void *q));
506
507 static int
508 SFcompareLogins(p, q)
509 const void *p, *q;
510 {
511 return strcmp(((SFLogin *)p)->name, ((SFLogin *)q)->name);
512 }
513
514 static void SFgetHomeDirs __ARGS((void));
515
516 static void
517 SFgetHomeDirs()
518 {
519 struct passwd *pw;
520 int Alloc;
521 int i;
522 SFEntry *entries = NULL;
523 int len;
524 int maxChars;
525
526 Alloc = 1;
527 i = 1;
528 entries = (SFEntry *)XtMalloc(sizeof(SFEntry));
529 SFlogins = (SFLogin *)XtMalloc(sizeof(SFLogin));
530 entries[0].real = XtMalloc(3);
531 (void) strcpy(entries[0].real, "~");
532 entries[0].shown = entries[0].real;
533 entries[0].statDone = 1;
534 SFlogins[0].name = "";
535 pw = getpwuid((int) getuid());
536 SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
537 maxChars = 0;
538
539 (void) setpwent();
540
541 while ((pw = getpwent()) && (*(pw->pw_name)))
542 {
543 if (i >= Alloc)
544 {
545 Alloc *= 2;
546 entries = (SFEntry *) XtRealloc((char *)entries,
547 (unsigned)(Alloc * sizeof(SFEntry)));
548 SFlogins = (SFLogin *) XtRealloc((char *)SFlogins,
549 (unsigned)(Alloc * sizeof(SFLogin)));
550 }
551 len = strlen(pw->pw_name);
552 entries[i].real = XtMalloc((unsigned) (len + 3));
553 (void) strcat(strcpy(entries[i].real, "~"), pw->pw_name);
554 entries[i].shown = entries[i].real;
555 entries[i].statDone = 1;
556 if (len > maxChars)
557 maxChars = len;
558 SFstrdup(&SFlogins[i].name, pw->pw_name);
559 SFstrdup(&SFlogins[i].dir, pw->pw_dir);
560 i++;
561 }
562
563 SFhomeDir.dir = XtMalloc(1);
564 SFhomeDir.dir[0] = 0;
565 SFhomeDir.path = SFcurrentPath;
566 SFhomeDir.entries = entries;
567 SFhomeDir.nEntries = i;
568 SFhomeDir.vOrigin = 0; /* :-) */
569 SFhomeDir.nChars = maxChars + 2;
570 SFhomeDir.hOrigin = 0;
571 SFhomeDir.changed = 1;
572 SFhomeDir.beginSelection = -1;
573 SFhomeDir.endSelection = -1;
574
575 qsort((char *)entries, (size_t)i, sizeof(SFEntry), SFcompareEntries);
576 qsort((char *)SFlogins, (size_t)i, sizeof(SFLogin), SFcompareLogins);
577
578 for (i--; i >= 0; i--)
579 (void)strcat(entries[i].real, "/");
580 }
581
582 static int SFfindHomeDir __ARGS((char *begin, char *end));
583
584 static int
585 SFfindHomeDir(begin, end)
586 char *begin, *end;
587 {
588 char save;
589 char *theRest;
590 int i;
591
592 save = *end;
593 *end = 0;
594
595 for (i = SFhomeDir.nEntries - 1; i >= 0; i--)
596 {
597 if (!strcmp(SFhomeDir.entries[i].real, begin))
598 {
599 *end = save;
600 SFstrdup(&theRest, end);
601 (void) strcat(strcat(strcpy(SFcurrentPath,
602 SFlogins[i].dir), "/"), theRest);
603 XtFree(theRest);
604 SFsetText(SFcurrentPath);
605 SFtextChanged();
606 return 1;
607 }
608 }
609
610 *end = save;
611
612 return 0;
613 }
614
615 static void
616 SFupdatePath()
617 {
618 static int Alloc;
619 static int wasTwiddle = 0;
620 char *begin, *end;
621 int i, j;
622 int prevChange;
623 int SFdirPtrSave, SFdirEndSave;
624 SFDir *dir;
625
626 if (!SFdirs)
627 {
628 SFdirs = (SFDir *) XtMalloc((Alloc = 10) * sizeof(SFDir));
629 dir = &(SFdirs[0]);
630 SFstrdup(&dir->dir, "/");
631 (void) SFchdir("/");
632 (void) SFgetDir(dir);
633 for (j = 1; j < Alloc; j++)
634 SFdirs[j].dir = NULL;
635 dir->path = SFcurrentPath + 1;
636 dir->vOrigin = 0;
637 dir->hOrigin = 0;
638 dir->changed = 1;
639 dir->beginSelection = -1;
640 dir->endSelection = -1;
641 SFhomeDir.dir = NULL;
642 }
643
644 SFdirEndSave = SFdirEnd;
645 SFdirEnd = 1;
646
647 SFdirPtrSave = SFdirPtr;
648 SFdirPtr = 0;
649
650 begin = NULL;
651
652 if (SFcurrentPath[0] == '~')
653 {
654 if (!SFtwiddle)
655 {
656 SFtwiddle = 1;
657 dir = &(SFdirs[0]);
658 SFrootDir = *dir;
659 if (!SFhomeDir.dir)
660 SFgetHomeDirs();
661 *dir = SFhomeDir;
662 dir->changed = 1;
663 }
664 end = SFcurrentPath;
665 SFdoNotTouchDirPtr = 1;
666 wasTwiddle = 1;
667 }
668 else
669 {
670 if (SFtwiddle)
671 {
672 SFtwiddle = 0;
673 dir = &(SFdirs[0]);
674 *dir = SFrootDir;
675 dir->changed = 1;
676 }
677 end = SFcurrentPath + 1;
678 }
679
680 i = 0;
681
682 prevChange = 0;
683
684 while (*end)
685 {
686 while (*end++ == '/')
687 ;
688 end--;
689 begin = end;
690 while ((*end) && (*end++ != '/'))
691 ;
692 if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/'))
693 {
694 SFdirPtr = i - 1;
695 if (SFdirPtr < 0)
696 SFdirPtr = 0;
697 }
698 if (*begin)
699 {
700 if (*(end - 1) == '/')
701 {
702 char save = *end;
703
704 if (SFtwiddle)
705 {
706 if (SFfindHomeDir(begin, end))
707 return;
708 }
709 *end = 0;
710 i++;
711 SFdirEnd++;
712 if (i >= Alloc)
713 {
714 SFdirs = (SFDir *) XtRealloc((char *) SFdirs,
715 (unsigned)((Alloc *= 2) * sizeof(SFDir)));
716 for (j = Alloc / 2; j < Alloc; j++)
717 SFdirs[j].dir = NULL;
718 }
719 dir = &(SFdirs[i]);
720 if ((!(dir->dir)) || prevChange || strcmp(dir->dir, begin))
721 {
722 if (dir->dir)
723 SFfree(i);
724 prevChange = 1;
725 SFstrdup(&dir->dir, begin);
726 dir->path = end;
727 dir->vOrigin = 0;
728 dir->hOrigin = 0;
729 dir->changed = 1;
730 dir->beginSelection = -1;
731 dir->endSelection = -1;
732 (void)SFfindFile(dir - 1, begin);
733 if (SFchdir(SFcurrentPath) || SFgetDir(dir))
734 {
735 SFunreadableDir(dir);
736 break;
737 }
738 }
739 *end = save;
740 if (!save)
741 SFunselect();
742 }
743 else
744 {
745 if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin))
746 return;
747 }
748 }
749 else
750 SFunselect();
751 }
752
753 if ((end == SFcurrentPath + 1) && (!SFtwiddle))
754 SFunselect();
755
756 for (i = SFdirEnd; i < Alloc; i++)
757 if (SFdirs[i].dir)
758 SFfree(i);
759
760 if (SFdoNotTouchDirPtr)
761 {
762 if (wasTwiddle)
763 {
764 wasTwiddle = 0;
765 SFdirPtr = SFdirEnd - 2;
766 if (SFdirPtr < 0)
767 SFdirPtr = 0;
768 }
769 else
770 SFdirPtr = SFdirPtrSave;
771 SFdoNotTouchDirPtr = 0;
772 }
773
774 if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave))
775 {
776 #ifdef FEAT_GUI_NEXTAW
777 XawScrollbarSetThumb( selFileHScroll,
778 (float) (((double) SFdirPtr) / SFdirEnd),
779 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
780 SFdirEnd));
781 #else
782 vim_XawScrollbarSetThumb( selFileHScroll,
783 (float) (((double) SFdirPtr) / SFdirEnd),
784 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
785 SFdirEnd),
786 (double)SFdirEnd);
787 #endif
788 }
789
790 if (SFdirPtr != SFdirPtrSave)
791 SFdrawLists(SF_DO_SCROLL);
792 else
793 for (i = 0; i < 3; i++)
794 {
795 if (SFdirPtr + i < SFdirEnd)
796 {
797 if (SFdirs[SFdirPtr + i].changed)
798 {
799 SFdirs[SFdirPtr + i].changed = 0;
800 SFdrawList(i, SF_DO_SCROLL);
801 }
802 }
803 else
804 SFclearList(i, SF_DO_SCROLL);
805 }
806 }
807
808 #ifdef XtNinternational
809 static int
810 WcsLen(p)
811 wchar_t *p;
812 {
813 int i = 0;
814 while (*p++ != 0)
815 i++;
816 return i;
817 }
818 #endif
819
820 static void
821 SFsetText(path)
822 char *path;
823 {
824 XawTextBlock text;
825
826 text.firstPos = 0;
827 text.length = strlen(path);
828 text.ptr = path;
829 text.format = FMT8BIT;
830
831 #ifdef XtNinternational
832 if (_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
833 {
834 XawTextReplace(selFileField, (XawTextPosition)0,
835 (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0]), &text);
836 XawTextSetInsertionPoint(selFileField,
837 (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0]));
838 }
839 else
840 {
841 XawTextReplace(selFileField, (XawTextPosition)0,
842 (XawTextPosition)strlen(SFtextBuffer), &text);
843 XawTextSetInsertionPoint(selFileField,
844 (XawTextPosition)strlen(SFtextBuffer));
845 }
846 #else
847 XawTextReplace(selFileField, (XawTextPosition)0,
848 (XawTextPosition)strlen(SFtextBuffer), &text);
849 XawTextSetInsertionPoint(selFileField,
850 (XawTextPosition)strlen(SFtextBuffer));
851 #endif
852 }
853
854 /* ARGSUSED */
855 static void
856 SFbuttonPressList(w, n, event)
857 Widget w;
858 int n;
859 XButtonPressedEvent *event;
860 {
861 SFbuttonPressed = 1;
862 }
863
864 /* ARGSUSED */
865 static void
866 SFbuttonReleaseList(w, n, event)
867 Widget w;
868 int n;
869 XButtonReleasedEvent *event;
870 {
871 SFDir *dir;
872
873 SFbuttonPressed = 0;
874
875 if (SFcurrentInvert[n] != -1)
876 {
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);
884 }
885 }
886
887 static int SFcheckDir __ARGS((int n, SFDir *dir));
888
889 static int
890 SFcheckDir(n, dir)
891 int n;
892 SFDir *dir;
893 {
894 struct stat statBuf;
895 int i;
896
897 if ((!mch_stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime))
898 {
899 /*
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.
903 */
904 if (SFcurrentInvert[n] != -1)
905 {
906 XWarpPointer(
907 SFdisplay,
908 None,
909 XtWindow(selFileLists[n]),
910 0,
911 0,
912 0,
913 0,
914 0,
915 0);
916 }
917
918 for (i = dir->nEntries - 1; i >= 0; i--)
919 {
920 if (dir->entries[i].shown != dir->entries[i].real)
921 XtFree(dir->entries[i].shown);
922 XtFree(dir->entries[i].real);
923 }
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);
942
943 if (!SFworkProcAdded)
944 {
945 (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
946 SFworkProcAdded = 1;
947 }
948 return 1;
949 }
950 return 0;
951 }
952
953 static int SFcheckFiles __ARGS((SFDir *dir));
954
955 static int
956 SFcheckFiles(dir)
957 SFDir *dir;
958 {
959 int from, to;
960 int result;
961 char oldc, newc;
962 int i;
963 char *str;
964 int last;
965 struct stat statBuf;
966
967 result = 0;
968
969 from = dir->vOrigin;
970 to = dir->vOrigin + SFlistSize;
971 if (to > dir->nEntries)
972 to = dir->nEntries;
973
974 for (i = from; i < to; i++)
975 {
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;
987 }
988
989 return result;
990 }
991
992 /* ARGSUSED */
993 static void
994 SFdirModTimer(cl, id)
995 XtPointer cl;
996 XtIntervalId *id;
997 {
998 static int n = -1;
999 static int f = 0;
1000 char save;
1001 SFDir *dir;
1002
1003 if ((!SFtwiddle) && (SFdirPtr < SFdirEnd))
1004 {
1005 n++;
1006 if ((n > 2) || (SFdirPtr + n >= SFdirEnd))
1007 {
1008 n = 0;
1009 f++;
1010 if ((f > 2) || (SFdirPtr + f >= SFdirEnd))
1011 f = 0;
1012 }
1013 dir = &(SFdirs[SFdirPtr + n]);
1014 save = *(dir->path);
1015 *(dir->path) = 0;
1016 if (SFchdir(SFcurrentPath))
1017 {
1018 *(dir->path) = save;
1019
1020 /*
1021 * force a re-read
1022 */
1023 *(dir->dir) = 0;
1024
1025 SFupdatePath();
1026 }
1027 else
1028 {
1029 *(dir->path) = save;
1030 if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir)))
1031 SFdrawList(n, SF_DO_SCROLL);
1032 }
1033 }
1034
1035 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
1036 SFdirModTimer, (XtPointer) NULL);
1037 }
1038
1039 /* Return a single character describing what kind of file STATBUF is. */
1040
1041 static char
1042 SFstatChar(statBuf)
1043 struct stat *statBuf;
1044 {
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 ' ';
1054 }
1055
1056 /***************** Draw.c */
1057
1058 #ifdef FEAT_GUI_NEXTAW
1059 # include <X11/neXtaw/Cardinals.h>
1060 #else
1061 # include <X11/Xaw/Cardinals.h>
1062 #endif
1063
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
1069
1070 #ifdef ABS
1071 # undef ABS
1072 #endif
1073 #define ABS(x) (((x) < 0) ? (-(x)) : (x))
1074
1075 typedef struct
1076 {
1077 char *fontname;
1078 } TextData;
1079
1080 static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
1081
1082 static XtResource textResources[] =
1083 {
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
1091 };
1092
1093 #ifdef FEAT_XFONTSET
1094 static XFontSet SFfont;
1095 #else
1096 static XFontStruct *SFfont;
1097 #endif
1098
1099 static int SFcurrentListY;
1100
1101 static XtIntervalId SFscrollTimerId;
1102
1103 static void SFinitFont __ARGS((void));
1104
1105 static void
1106 SFinitFont()
1107 {
1108 TextData *data;
1109 #ifdef FEAT_XFONTSET
1110 XFontSetExtents *extents;
1111 char **missing, *def_str;
1112 int num_missing;
1113 #endif
1114
1115 data = XtNew(TextData);
1116
1117 XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
1118 XtNumber(textResources), (Arg *) NULL, ZERO);
1119
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)
1127 {
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)
1135 {
1136 EMSG2(_("E616: vim_SelFile: can't get font %s"), SF_DEFAULT_FONT);
1137 SFstatus = SEL_FILE_CANCEL;
1138 return;
1139 }
1140 }
1141
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
1152 }
1153
1154 static void SFcreateGC __ARGS((void));
1155
1156 static void
1157 SFcreateGC()
1158 {
1159 XGCValues gcValues;
1160 XRectangle rectangles[1];
1161
1162 gcValues.foreground = SFfore;
1163
1164 SFlineGC = XtGetGC(
1165 selFileLists[0],
1166 (XtGCMask)GCForeground,
1167 &gcValues);
1168
1169 SFscrollGC = XtGetGC(
1170 selFileLists[0],
1171 (XtGCMask)0,
1172 &gcValues);
1173
1174 gcValues.function = GXxor;
1175 gcValues.foreground = SFfore ^ SFback;
1176 gcValues.background = SFfore ^ SFback;
1177
1178 SFinvertGC = XtGetGC(
1179 selFileLists[0],
1180 (XtGCMask)GCFunction | GCForeground | GCBackground,
1181 &gcValues);
1182
1183 gcValues.foreground = SFfore;
1184 gcValues.background = SFback;
1185 #ifndef FEAT_XFONTSET
1186 gcValues.font = SFfont->fid;
1187 #endif
1188
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);
1198
1199 rectangles[0].x = SFlineToTextH + SFbesideText;
1200 rectangles[0].y = 0;
1201 rectangles[0].width = SFcharsPerEntry * SFcharWidth;
1202 rectangles[0].height = SFupperY + 1;
1203
1204 XSetClipRectangles(
1205 SFdisplay,
1206 SFtextGC,
1207 0,
1208 0,
1209 rectangles,
1210 1,
1211 Unsorted);
1212 }
1213
1214 static void
1215 SFclearList(n, doScroll)
1216 int n;
1217 int doScroll;
1218 {
1219 SFDir *dir;
1220
1221 SFcurrentInvert[n] = -1;
1222
1223 XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
1224
1225 XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2);
1226
1227 if (doScroll)
1228 {
1229 dir = &(SFdirs[SFdirPtr + n]);
1230
1231 if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars)
1232 {
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
1251
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
1268 }
1269 else
1270 {
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
1285 }
1286 }
1287 }
1288
1289 static void SFdeleteEntry __ARGS((SFDir *dir, SFEntry *entry));
1290
1291 static void
1292 SFdeleteEntry(dir, entry)
1293 SFDir *dir;
1294 SFEntry *entry;
1295 {
1296 SFEntry *e;
1297 SFEntry *end;
1298 int n;
1299 int idx;
1300
1301 idx = entry - dir->entries;
1302
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;
1309
1310 if (idx < dir->vOrigin)
1311 dir->vOrigin--;
1312
1313 XtFree(entry->real);
1314
1315 end = &(dir->entries[dir->nEntries - 1]);
1316
1317 for (e = entry; e < end; e++)
1318 *e = *(e + 1);
1319
1320 if (!(--dir->nEntries))
1321 return;
1322
1323 n = dir - &(SFdirs[SFdirPtr]);
1324 if ((n < 0) || (n > 2))
1325 return;
1326
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
1341 }
1342
1343 static void SFwriteStatChar __ARGS((char *name, int last, struct stat *statBuf));
1344
1345 static void
1346 SFwriteStatChar(name, last, statBuf)
1347 char *name;
1348 int last;
1349 struct stat *statBuf;
1350 {
1351 name[last] = SFstatChar(statBuf);
1352 }
1353
1354 static int SFstatAndCheck __ARGS((SFDir *dir, SFEntry *entry));
1355
1356 static int
1357 SFstatAndCheck(dir, entry)
1358 SFDir *dir;
1359 SFEntry *entry;
1360 {
1361 struct stat statBuf;
1362 char save;
1363 int last;
1364
1365 /*
1366 * must be restored before returning
1367 */
1368 save = *(dir->path);
1369 *(dir->path) = 0;
1370
1371 if (!SFchdir(SFcurrentPath))
1372 {
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
1380 )
1381 {
1382 if (SFfunc)
1383 {
1384 char *shown;
1385
1386 shown = NULL;
1387 if (SFfunc(entry->real, &shown, &statBuf))
1388 {
1389 if (shown)
1390 {
1391 int len;
1392
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;
1398 }
1399 }
1400 else
1401 {
1402 SFdeleteEntry(dir, entry);
1403
1404 *(dir->path) = save;
1405 return 1;
1406 }
1407 }
1408 SFwriteStatChar(entry->real, last, &statBuf);
1409 }
1410 else
1411 entry->real[last] = ' ';
1412 }
1413
1414 *(dir->path) = save;
1415 return 0;
1416 }
1417
1418
1419 static void
1420 SFdrawStrings(w, dir, from, to)
1421 Window w;
1422 SFDir *dir;
1423 int from;
1424 int to;
1425 {
1426 int i;
1427 SFEntry *entry;
1428 int x;
1429
1430 x = SFtextX - dir->hOrigin * SFcharWidth;
1431
1432 if (dir->vOrigin + to >= dir->nEntries)
1433 to = dir->nEntries - dir->vOrigin - 1;
1434 for (i = from; i <= to; i++)
1435 {
1436 entry = &(dir->entries[dir->vOrigin + i]);
1437 if (!(entry->statDone))
1438 {
1439 if (SFstatAndCheck(dir, entry))
1440 {
1441 if (dir->vOrigin + to >= dir->nEntries)
1442 to = dir->nEntries - dir->vOrigin - 1;
1443 i--;
1444 continue;
1445 }
1446 }
1447 #ifdef FEAT_XFONTSET
1448 XmbDrawImageString(
1449 SFdisplay,
1450 w,
1451 SFfont,
1452 SFtextGC,
1453 x,
1454 SFtextYoffset + i * SFentryHeight,
1455 entry->shown,
1456 strlen(entry->shown));
1457 #else
1458 XDrawImageString(
1459 SFdisplay,
1460 w,
1461 SFtextGC,
1462 x,
1463 SFtextYoffset + i * SFentryHeight,
1464 entry->shown,
1465 strlen(entry->shown));
1466 #endif
1467 if (dir->vOrigin + i == dir->beginSelection)
1468 {
1469 XDrawLine(
1470 SFdisplay,
1471 w,
1472 SFlineGC,
1473 SFlineToTextH + 1,
1474 SFlowerY + i * SFentryHeight,
1475 SFlineToTextH + SFentryWidth - 2,
1476 SFlowerY + i * SFentryHeight);
1477 }
1478 if ((dir->vOrigin + i >= dir->beginSelection) &&
1479 (dir->vOrigin + i <= dir->endSelection))
1480 {
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,
1487 w,
1488 SFlineGC,
1489 SFcompletionSegs,
1490 2);
1491 }
1492 if (dir->vOrigin + i == dir->endSelection)
1493 {
1494 XDrawLine(
1495 SFdisplay,
1496 w,
1497 SFlineGC,
1498 SFlineToTextH + 1,
1499 SFlowerY + (i + 1) * SFentryHeight - 1,
1500 SFlineToTextH + SFentryWidth - 2,
1501 SFlowerY + (i + 1) * SFentryHeight - 1);
1502 }
1503 }
1504 }
1505
1506 static void
1507 SFdrawList(n, doScroll)
1508 int n;
1509 int doScroll;
1510 {
1511 SFDir *dir;
1512 Window w;
1513
1514 SFclearList(n, doScroll);
1515
1516 if (SFdirPtr + n < SFdirEnd)
1517 {
1518 dir = &(SFdirs[SFdirPtr + n]);
1519 w = XtWindow(selFileLists[n]);
1520 #ifdef FEAT_XFONTSET
1521 XmbDrawImageString(
1522 SFdisplay,
1523 w,
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,
1533 w,
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);
1541 }
1542 }
1543
1544 static void
1545 SFdrawLists(doScroll)
1546 int doScroll;
1547 {
1548 int i;
1549
1550 for (i = 0; i < 3; i++)
1551 SFdrawList(i, doScroll);
1552 }
1553
1554 static void
1555 SFinvertEntry(n)
1556 int n;
1557 {
1558 XFillRectangle(
1559 SFdisplay,
1560 XtWindow(selFileLists[n]),
1561 SFinvertGC,
1562 SFlineToTextH,
1563 SFcurrentInvert[n] * SFentryHeight + SFlowerY,
1564 SFentryWidth,
1565 SFentryHeight);
1566 }
1567
1568 static unsigned long SFscrollTimerInterval __ARGS((void));
1569
1570 static unsigned long
1571 SFscrollTimerInterval()
1572 {
1573 static int maxVal = 200;
1574 static int varyDist = 50;
1575 static int minDist = 50;
1576 int t;
1577 int dist;
1578
1579 if (SFcurrentListY < SFlowerY)
1580 dist = SFlowerY - SFcurrentListY;
1581 else if (SFcurrentListY > SFupperY)
1582 dist = SFcurrentListY - SFupperY;
1583 else
1584 return (unsigned long) 1;
1585
1586 t = maxVal - ((maxVal / varyDist) * (dist - minDist));
1587
1588 if (t < 1)
1589 t = 1;
1590
1591 if (t > maxVal)
1592 t = maxVal;
1593
1594 return (unsigned long)t;
1595 }
1596
1597 static void SFscrollTimer __ARGS((XtPointer p, XtIntervalId *id));
1598
1599 /* ARGSUSED */
1600 static void
1601 SFscrollTimer(p, id)
1602 XtPointer p;
1603 XtIntervalId *id;
1604 {
1605 SFDir *dir;
1606 int save;
1607 int n;
1608
1609 n = (long)p;
1610
1611 dir = &(SFdirs[SFdirPtr + n]);
1612 save = dir->vOrigin;
1613
1614 if (SFcurrentListY < SFlowerY)
1615 {
1616 if (dir->vOrigin > 0)
1617 SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1);
1618 }
1619 else if (SFcurrentListY > SFupperY)
1620 {
1621 if (dir->vOrigin < dir->nEntries - SFlistSize)
1622 SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1);
1623 }
1624
1625 if (dir->vOrigin != save)
1626 {
1627 if (dir->nEntries)
1628 {
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
1643 }
1644 }
1645
1646 if (SFbuttonPressed)
1647 SFscrollTimerId = XtAppAddTimeOut(SFapp,
1648 SFscrollTimerInterval(), SFscrollTimer, (XtPointer) n);
1649 }
1650
1651 static int
1652 SFnewInvertEntry(n, event)
1653 int n;
1654 XMotionEvent *event;
1655 {
1656 int x, y;
1657 int nw;
1658 static int SFscrollTimerAdded = 0;
1659
1660 x = event->x;
1661 y = event->y;
1662
1663 if (SFdirPtr + n >= SFdirEnd)
1664 return -1;
1665
1666 if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY))
1667 {
1668 SFDir *dir = &(SFdirs[SFdirPtr + n]);
1669
1670 if (SFscrollTimerAdded)
1671 {
1672 SFscrollTimerAdded = 0;
1673 XtRemoveTimeOut(SFscrollTimerId);
1674 }
1675
1676 nw = (y - SFlowerY) / SFentryHeight;
1677 if (dir->vOrigin + nw >= dir->nEntries)
1678 return -1;
1679 return nw;
1680 }
1681 else
1682 {
1683 if (SFbuttonPressed)
1684 {
1685 SFcurrentListY = y;
1686 if (!SFscrollTimerAdded)
1687 {
1688 SFscrollTimerAdded = 1;
1689 SFscrollTimerId = XtAppAddTimeOut(SFapp,
1690 SFscrollTimerInterval(), SFscrollTimer,
1691 (XtPointer) n);
1692 }
1693 }
1694 return -1;
1695 }
1696 }
1697
1698 /* ARGSUSED */
1699 static void
1700 SFenterList(w, n, event)
1701 Widget w;
1702 int n;
1703 XEnterWindowEvent *event;
1704 {
1705 int nw;
1706
1707 /* sanity */
1708 if (SFcurrentInvert[n] != -1)
1709 {
1710 SFinvertEntry(n);
1711 SFcurrentInvert[n] = -1;
1712 }
1713
1714 nw = SFnewInvertEntry(n, (XMotionEvent *) event);
1715 if (nw != -1)
1716 {
1717 SFcurrentInvert[n] = nw;
1718 SFinvertEntry(n);
1719 }
1720 }
1721
1722 /* ARGSUSED */
1723 static void
1724 SFleaveList(w, n, event)
1725 Widget w;
1726 int n;
1727 XEvent *event;
1728 {
1729 if (SFcurrentInvert[n] != -1)
1730 {
1731 SFinvertEntry(n);
1732 SFcurrentInvert[n] = -1;
1733 }
1734 }
1735
1736 /* ARGSUSED */
1737 static void
1738 SFmotionList(w, n, event)
1739 Widget w;
1740 int n;
1741 XMotionEvent *event;
1742 {
1743 int nw;
1744
1745 nw = SFnewInvertEntry(n, event);
1746
1747 if (nw != SFcurrentInvert[n])
1748 {
1749 if (SFcurrentInvert[n] != -1)
1750 SFinvertEntry(n);
1751 SFcurrentInvert[n] = nw;
1752 if (nw != -1)
1753 SFinvertEntry(n);
1754 }
1755 }
1756
1757 /* ARGSUSED */
1758 static void
1759 SFvFloatSliderMovedCallback(w, n, fnew)
1760 Widget w;
1761 XtPointer n;
1762 XtPointer fnew;
1763 {
1764 int nw;
1765
1766 nw = (*(float *)fnew) * SFdirs[SFdirPtr + (int)(long)n].nEntries;
1767 SFvSliderMovedCallback(w, (int)(long)n, nw);
1768 }
1769
1770 /* ARGSUSED */
1771 static void
1772 SFvSliderMovedCallback(w, n, nw)
1773 Widget w;
1774 int n;
1775 int nw;
1776 {
1777 int old;
1778 Window win;
1779 SFDir *dir;
1780
1781 dir = &(SFdirs[SFdirPtr + n]);
1782
1783 old = dir->vOrigin;
1784 dir->vOrigin = nw;
1785
1786 if (old == nw)
1787 return;
1788
1789 win = XtWindow(selFileLists[n]);
1790
1791 if (ABS(nw - old) < SFlistSize)
1792 {
1793 if (nw > old)
1794 {
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);
1817 }
1818 else
1819 {
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);
1840 }
1841 }
1842 else
1843 {
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);
1853 }
1854 }
1855
1856 /* ARGSUSED */
1857 static void
1858 SFvAreaSelectedCallback(w, n, pnew)
1859 Widget w;
1860 XtPointer n;
1861 XtPointer pnew;
1862 {
1863 SFDir *dir;
1864 int nw;
1865
1866 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1867
1868 #ifdef FEAT_GUI_NEXTAW
1869 if ((int)(long)pnew < 0)
1870 {
1871 if ((int)(long)pnew > -SFvScrollHeight)
1872 (int)(long)pnew = -1;
1873 else
1874 (int)(long)pnew = -SFlistSize;
1875 }
1876 else if ((int)(long)pnew > 0)
1877 {
1878 if ((int)(long)pnew < SFvScrollHeight)
1879 (int)(long)pnew = 1;
1880 else
1881 (int)(long)pnew = SFlistSize;
1882 }
1883 #endif
1884 nw = dir->vOrigin + (int)(long)pnew;
1885
1886 if (nw > dir->nEntries - SFlistSize)
1887 nw = dir->nEntries - SFlistSize;
1888
1889 if (nw < 0)
1890 nw = 0;
1891
1892 if (dir->nEntries)
1893 {
1894 float f;
1895
1896 f = ((double) nw) / dir->nEntries;
1897
1898 #ifdef FEAT_GUI_NEXTAW
1899 XawScrollbarSetThumb(
1900 w,
1901 f,
1902 (float) (((double) ((dir->nEntries < SFlistSize) ?
1903 dir->nEntries : SFlistSize)) / dir->nEntries));
1904 #else
1905 vim_XawScrollbarSetThumb(
1906 w,
1907 f,
1908 (float) (((double) ((dir->nEntries < SFlistSize) ?
1909 dir->nEntries : SFlistSize)) / dir->nEntries),
1910 (double)dir->nEntries);
1911 #endif
1912 }
1913
1914 SFvSliderMovedCallback(w, (int)(long)n, nw);
1915 }
1916
1917 /* ARGSUSED */
1918 static void
1919 SFhSliderMovedCallback(w, n, nw)
1920 Widget w;
1921 XtPointer n;
1922 XtPointer nw;
1923 {
1924 SFDir *dir;
1925 int save;
1926
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;
1932
1933 SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
1934 }
1935
1936 /* ARGSUSED */
1937 static void
1938 SFhAreaSelectedCallback(w, n, pnew)
1939 Widget w;
1940 XtPointer n;
1941 XtPointer pnew;
1942 {
1943 SFDir *dir;
1944 int nw;
1945
1946 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1947
1948 #ifdef FEAT_GUI_NEXTAW
1949 if ((int)(long)pnew < 0)
1950 {
1951 if ((int)(long)pnew > -SFhScrollWidth)
1952 (int)(long)pnew = -1;
1953 else
1954 (int)(long)pnew = -SFcharsPerEntry;
1955 }
1956 else if ((int)(long)pnew > 0)
1957 {
1958 if ((int)(long)pnew < SFhScrollWidth)
1959 (int)(long)pnew = 1;
1960 else
1961 (int)(long)pnew = SFcharsPerEntry;
1962 }
1963 #endif
1964 nw = dir->hOrigin + (int)(long)pnew;
1965
1966 if (nw > dir->nChars - SFcharsPerEntry)
1967 nw = dir->nChars - SFcharsPerEntry;
1968
1969 if (nw < 0)
1970 nw = 0;
1971
1972 if (dir->nChars)
1973 {
1974 float f;
1975
1976 f = ((double) nw) / dir->nChars;
1977
1978 #ifdef FEAT_GUI_NEXTAW
1979 XawScrollbarSetThumb(
1980 w,
1981 f,
1982 (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
1983 dir->nChars : SFcharsPerEntry)) / dir->nChars));
1984 #else
1985 vim_XawScrollbarSetThumb(
1986 w,
1987 f,
1988 (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
1989 dir->nChars : SFcharsPerEntry)) / dir->nChars),
1990 (double)dir->nChars);
1991 #endif
1992
1993 SFhSliderMovedCallback(w, n, (XtPointer)&f);
1994 }
1995 }
1996
1997 /* ARGSUSED */
1998 static void
1999 SFpathSliderMovedCallback(w, client_data, nw)
2000 Widget w;
2001 XtPointer client_data;
2002 XtPointer nw;
2003 {
2004 SFDir *dir;
2005 int n;
2006 XawTextPosition pos;
2007 int SFdirPtrSave;
2008
2009 SFdirPtrSave = SFdirPtr;
2010 SFdirPtr = (*(float *)nw) * SFdirEnd;
2011 if (SFdirPtr == SFdirPtrSave)
2012 return;
2013
2014 SFdrawLists(SF_DO_SCROLL);
2015
2016 n = 2;
2017 while (SFdirPtr + n >= SFdirEnd)
2018 n--;
2019
2020 dir = &(SFdirs[SFdirPtr + n]);
2021
2022 pos = dir->path - SFcurrentPath;
2023
2024 if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
2025 {
2026 pos -= strlen(SFstartDir);
2027 if (pos < 0)
2028 pos = 0;
2029 }
2030
2031 XawTextSetInsertionPoint(selFileField, pos);
2032 }
2033
2034 /* ARGSUSED */
2035 static void
2036 SFpathAreaSelectedCallback(w, client_data, pnew)
2037 Widget w;
2038 XtPointer client_data;
2039 XtPointer pnew;
2040 {
2041 int nw;
2042 float f;
2043
2044 #ifdef FEAT_GUI_NEXTAW
2045 if ((int)(long)pnew < 0)
2046 {
2047 if ((int)(long)pnew > -SFpathScrollWidth)
2048 (int)(long)pnew = -1;
2049 else
2050 (int)(long)pnew = -3;
2051 }
2052 else if ((int)(long)pnew > 0)
2053 {
2054 if ((int)(long)pnew < SFpathScrollWidth)
2055 (int)(long)pnew = 1;
2056 else
2057 (int)(long)pnew = 3;
2058 }
2059 #endif
2060 nw = SFdirPtr + (int)(long)pnew;
2061
2062 if (nw > SFdirEnd - 3)
2063 nw = SFdirEnd - 3;
2064
2065 if (nw < 0)
2066 nw = 0;
2067
2068 f = ((double) nw) / SFdirEnd;
2069
2070 #ifdef FEAT_GUI_NEXTAW
2071 XawScrollbarSetThumb(
2072 w,
2073 f,
2074 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd));
2075 #else
2076 vim_XawScrollbarSetThumb(
2077 w,
2078 f,
2079 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd),
2080 (double)SFdirEnd);
2081 #endif
2082
2083 SFpathSliderMovedCallback(w, (XtPointer) NULL, (XtPointer)&f);
2084 }
2085
2086 static Boolean
2087 SFworkProc()
2088 {
2089 SFDir *dir;
2090 SFEntry *entry;
2091
2092 for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
2093 {
2094 if (!(dir->nEntries))
2095 continue;
2096 for (entry = &(dir->entries[dir->nEntries - 1]);
2097 entry >= dir->entries;
2098 entry--)
2099 {
2100 if (!(entry->statDone))
2101 {
2102 (void)SFstatAndCheck(dir, entry);
2103 return False;
2104 }
2105 }
2106 }
2107
2108 SFworkProcAdded = 0;
2109
2110 return True;
2111 }
2112
2113 /***************** Dir.c */
2114
2115 static int
2116 SFcompareEntries(p, q)
2117 const void *p;
2118 const void *q;
2119 {
2120 return strcmp(((SFEntry *)p)->real, ((SFEntry *)q)->real);
2121 }
2122
2123 static int
2124 SFgetDir(dir)
2125 SFDir *dir;
2126 {
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;
2136
2137 maxChars = strlen(dir->dir) - 1;
2138
2139 dir->entries = NULL;
2140 dir->nEntries = 0;
2141 dir->nChars = 0;
2142
2143 result = NULL;
2144 i = 0;
2145
2146 dirp = opendir(".");
2147 if (!dirp)
2148 return 1;
2149
2150 (void)mch_stat(".", &statBuf);
2151 dir->mtime = statBuf.st_mtime;
2152
2153 while ((dp = readdir(dirp)))
2154 {
2155 /* Ignore "." and ".." */
2156 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
2157 continue;
2158 if (i >= Alloc)
2159 {
2160 Alloc = 2 * (Alloc + 1);
2161 result = (SFEntry *) XtRealloc((char *) result,
2162 (unsigned) (Alloc * sizeof(SFEntry)));
2163 }
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++;
2173 }
2174
2175 qsort((char *) result, (size_t) i, sizeof(SFEntry), SFcompareEntries);
2176
2177 dir->entries = result;
2178 dir->nEntries = i;
2179 dir->nChars = maxChars + 1;
2180
2181 closedir(dirp);
2182
2183 return 0;
2184 }
2185
2186 /***************** SFinternal.h */
2187
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
2201
2202 static char *oneLineTextEditTranslations = "\
2203 <Key>Return: redraw-display()\n\
2204 Ctrl<Key>M: redraw-display()\n\
2205 ";
2206
2207 static void SFexposeList __ARGS((Widget w, XtPointer n, XEvent *event, Boolean *cont));
2208
2209 /* ARGSUSED */
2210 static void
2211 SFexposeList(w, n, event, cont)
2212 Widget w;
2213 XtPointer n;
2214 XEvent *event;
2215 Boolean *cont;
2216 {
2217 if ((event->type == NoExpose) || event->xexpose.count)
2218 return;
2219
2220 SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
2221 }
2222
2223 static void SFmodVerifyCallback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont));
2224
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;
2232 {
2233 char buf[2];
2234
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;
2240 }
2241
2242 static void SFokCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
2243
2244 /* ARGSUSED */
2245 static void
2246 SFokCallback(w, cl, cd)
2247 Widget w;
2248 XtPointer cl, cd;
2249 {
2250 SFstatus = SEL_FILE_OK;
2251 }
2252
2253 static XtCallbackRec SFokSelect[] =
2254 {
2255 { SFokCallback, (XtPointer) NULL },
2256 { NULL, (XtPointer) NULL },
2257 };
2258
2259 static void SFcancelCallback __ARGS((Widget w, XtPointer cl, XtPointer cd));
2260
2261 /* ARGSUSED */
2262 static void
2263 SFcancelCallback(w, cl, cd)
2264 Widget w;
2265 XtPointer cl, cd;
2266 {
2267 SFstatus = SEL_FILE_CANCEL;
2268 }
2269
2270 static XtCallbackRec SFcancelSelect[] =
2271 {
2272 { SFcancelCallback, (XtPointer) NULL },
2273 { NULL, (XtPointer) NULL },
2274 };
2275
2276 static void SFdismissAction __ARGS((Widget w, XEvent *event, String *params, Cardinal *num_params));
2277
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;
2285 {
2286 if (event->type == ClientMessage &&
2287 event->xclient.data.l[0] != SFwmDeleteWindow)
2288 return;
2289
2290 SFstatus = SEL_FILE_CANCEL;
2291 }
2292
2293 static char *wmDeleteWindowTranslation = "\
2294 <Message>WM_PROTOCOLS: SelFileDismiss()\n\
2295 ";
2296
2297 static XtActionsRec actions[] =
2298 {
2299 {"SelFileDismiss", SFdismissAction},
2300 };
2301
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;
2308 {
2309 if (selFileForm)
2310 {
2311 XtVaSetValues(selFileForm, XtNbackground, bg,
2312 XtNforeground, fg,
2313 XtNborderColor, bg,
2314 NULL);
2315 }
2316 {
2317 int i;
2318
2319 for (i = 0; i < 3; ++i)
2320 {
2321 if (selFileLists[i])
2322 {
2323 XtVaSetValues(selFileLists[i], XtNbackground, bg,
2324 XtNforeground, fg,
2325 XtNborderColor, fg,
2326 NULL);
2327 }
2328 }
2329 }
2330 if (selFileOK)
2331 {
2332 XtVaSetValues(selFileOK, XtNbackground, bg,
2333 XtNforeground, fg,
2334 XtNborderColor, fg,
2335 NULL);
2336 }
2337 if (selFileCancel)
2338 {
2339 XtVaSetValues(selFileCancel, XtNbackground, bg,
2340 XtNforeground, fg,
2341 XtNborderColor, fg,
2342 NULL);
2343 }
2344 if (selFilePrompt)
2345 {
2346 XtVaSetValues(selFilePrompt, XtNbackground, bg,
2347 XtNforeground, fg,
2348 NULL);
2349 }
2350 if (gui.dpy)
2351 {
2352 XSetBackground(gui.dpy, SFtextGC, bg);
2353 XSetForeground(gui.dpy, SFtextGC, fg);
2354 XSetForeground(gui.dpy, SFlineGC, fg);
2355
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);
2359 }
2360 if (selFileHScroll)
2361 {
2362 XtVaSetValues(selFileHScroll, XtNbackground, scroll_bg,
2363 XtNforeground, scroll_fg,
2364 XtNborderColor, fg,
2365 NULL);
2366 }
2367 {
2368 int i;
2369
2370 for (i = 0; i < 3; i++)
2371 {
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);
2380 }
2381 }
2382 }
2383
2384 static void
2385 SFcreateWidgets(toplevel, prompt, ok, cancel)
2386 Widget toplevel;
2387 char *prompt;
2388 char *ok;
2389 char *cancel;
2390 {
2391 Cardinal n;
2392 int listWidth, listHeight;
2393 int listSpacing = 10;
2394 int scrollThickness = 15;
2395 int hScrollX, hScrollY;
2396 int vScrollX, vScrollY;
2397
2398 selFile = XtVaAppCreateShell("selFile", "SelFile",
2399 transientShellWidgetClass, SFdisplay,
2400 XtNtransientFor, toplevel,
2401 XtNtitle, prompt,
2402 NULL);
2403
2404 /* Add WM_DELETE_WINDOW protocol */
2405 XtAppAddActions(XtWidgetToApplicationContext(selFile),
2406 actions, XtNumber(actions));
2407 XtOverrideTranslations(selFile,
2408 XtParseTranslationTable(wmDeleteWindowTranslation));
2409
2410 selFileForm = XtVaCreateManagedWidget("selFileForm",
2411 formWidgetClass, selFile,
2412 XtNdefaultDistance, 30,
2413 XtNforeground, SFfore,
2414 XtNbackground, SFback,
2415 XtNborderColor, SFback,
2416 NULL);
2417
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);
2430
2431 /*
2432 XtVaGetValues(selFilePrompt,
2433 XtNforeground, &SFfore,
2434 XtNbackground, &SFback,
2435 NULL);
2436 */
2437
2438 SFinitFont();
2439
2440 SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth +
2441 SFbesideText;
2442 SFentryHeight = SFaboveAndBelowText + SFcharHeight +
2443 SFaboveAndBelowText;
2444
2445 listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
2446 scrollThickness;
2447 listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2448 SFlineToTextV + SFlistSize * SFentryHeight +
2449 SFlineToTextV + 1 + scrollThickness;
2450
2451 SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;
2452
2453 hScrollX = -1;
2454 hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2455 SFlineToTextV + SFlistSize * SFentryHeight +
2456 SFlineToTextV;
2457 SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
2458
2459 vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
2460 vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
2461 SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
2462 SFlineToTextV;
2463
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;
2469
2470 SFtextX = SFlineToTextH + SFbesideText;
2471 SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
2472
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;
2481
2482 SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
2483 SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
2484 SFlineToTextH + SFentryWidth - 1;
2485
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);
2504
2505 XtOverrideTranslations(selFileField,
2506 XtParseTranslationTable(oneLineTextEditTranslations));
2507 XtSetKeyboardFocus(selFileForm, selFileField);
2508
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);
2531
2532 XtAddCallback(selFileHScroll, XtNjumpProc,
2533 (XtCallbackProc) SFpathSliderMovedCallback, (XtPointer)NULL);
2534 XtAddCallback(selFileHScroll, XtNscrollProc,
2535 (XtCallbackProc) SFpathAreaSelectedCallback, (XtPointer)NULL);
2536
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);
2551
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);
2568
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);
2585
2586 for (n = 0; n < 3; n++)
2587 {
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);
2605
2606 XtAddCallback(selFileVScrolls[n], XtNjumpProc,
2607 (XtCallbackProc)SFvFloatSliderMovedCallback, (XtPointer)n);
2608 XtAddCallback(selFileVScrolls[n], XtNscrollProc,
2609 (XtCallbackProc)SFvAreaSelectedCallback, (XtPointer)n);
2610
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);
2629
2630 XtAddCallback(selFileHScrolls[n], XtNjumpProc,
2631 (XtCallbackProc)SFhSliderMovedCallback, (XtPointer)n);
2632 XtAddCallback(selFileHScrolls[n], XtNscrollProc,
2633 (XtCallbackProc)SFhAreaSelectedCallback, (XtPointer)n);
2634 }
2635
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);
2652
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);
2670
2671 XtSetMappedWhenManaged(selFile, False);
2672 XtRealizeWidget(selFile);
2673
2674 /* Add WM_DELETE_WINDOW protocol */
2675 SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
2676 XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
2677
2678 SFcreateGC();
2679
2680 for (n = 0; n < 3; n++)
2681 {
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);
2694 }
2695
2696 XtAddEventHandler(selFileField, KeyPressMask, False,
2697 SFmodVerifyCallback, (XtPointer)NULL);
2698
2699 SFapp = XtWidgetToApplicationContext(selFile);
2700 }
2701
2702 static void
2703 SFtextChanged()
2704 {
2705 #if defined(FEAT_XFONTSET) && defined(XtNinternational)
2706 if (_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
2707 {
2708 wchar_t *wcbuf=(wchar_t *)SFtextBuffer;
2709
2710 if ((wcbuf[0] == L'/') || (wcbuf[0] == L'~'))
2711 {
2712 (void) wcstombs(SFcurrentPath, wcbuf, MAXPATHL);
2713 SFtextPos = XawTextGetInsertionPoint(selFileField);
2714 }
2715 else
2716 {
2717 strcpy(SFcurrentPath, SFstartDir);
2718 (void) wcstombs(SFcurrentPath + strlen(SFcurrentPath), wcbuf, MAXPATHL);
2719
2720 SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
2721 }
2722 }
2723 else
2724 #endif
2725 if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~'))
2726 {
2727 (void) strcpy(SFcurrentPath, SFtextBuffer);
2728 SFtextPos = XawTextGetInsertionPoint(selFileField);
2729 }
2730 else
2731 {
2732 (void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
2733
2734 SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
2735 }
2736
2737 if (!SFworkProcAdded)
2738 {
2739 (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
2740 SFworkProcAdded = 1;
2741 }
2742
2743 SFupdatePath();
2744 }
2745
2746 static char *
2747 SFgetText()
2748 {
2749 #if defined(FEAT_XFONTSET) && defined(XtNinternational)
2750 char *buf;
2751
2752 if (_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
2753 {
2754 wchar_t *wcbuf;
2755 int mbslength;
2756
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;
2767 }
2768 #endif
2769 return (char *)vim_strsave((char_u *)SFtextBuffer);
2770 }
2771
2772 static void
2773 SFprepareToReturn()
2774 {
2775 SFstatus = SEL_FILE_NULL;
2776 XtRemoveGrab(selFile);
2777 XtUnmapWidget(selFile);
2778 XtRemoveTimeOut(SFdirModTimerId);
2779 if (SFchdir(SFstartDir))
2780 {
2781 EMSG(_("E614: vim_SelFile: can't return to current directory"));
2782 SFstatus = SEL_FILE_CANCEL;
2783 }
2784 }
2785
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 */
2795 {
2796 static int firstTime = 1;
2797 XEvent event;
2798 char *name_return;
2799
2800 if (prompt == NULL)
2801 prompt = _("Pathname:");
2802 SFfore = fg;
2803 SFback = bg;
2804
2805 if (mch_dirname((char_u *)SFstartDir, MAXPATHL) == FAIL)
2806 {
2807 EMSG(_("E615: vim_SelFile: can't get current directory"));
2808 return NULL;
2809 }
2810
2811 if (firstTime)
2812 {
2813 firstTime = 0;
2814 SFdisplay = XtDisplay(toplevel);
2815 SFcreateWidgets(toplevel, prompt, _("OK"), _("Cancel"));
2816 }
2817 else
2818 {
2819 XtVaSetValues(selFilePrompt, XtNlabel, prompt, NULL);
2820 XtVaSetValues(selFile, XtNtitle, prompt, NULL);
2821 SFsetColors(bg, fg, scroll_bg, scroll_fg);
2822 }
2823
2824 XtVaSetValues(selFile, XtNx, x, XtNy, y, NULL);
2825 XtMapWidget(selFile);
2826
2827 (void)strcat(SFstartDir, "/");
2828 (void)strcpy(SFcurrentDir, SFstartDir);
2829
2830 if (init_path)
2831 {
2832 if (init_path[0] == '/')
2833 {
2834 (void)strcpy(SFcurrentPath, init_path);
2835 if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
2836 SFsetText(SFcurrentPath);
2837 else
2838 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
2839 }
2840 else
2841 {
2842 (void)strcat(strcpy(SFcurrentPath, SFstartDir), init_path);
2843 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
2844 }
2845 }
2846 else
2847 (void)strcpy(SFcurrentPath, SFstartDir);
2848
2849 SFfunc = show_entry;
2850
2851 SFtextChanged();
2852
2853 XtAddGrab(selFile, True, True);
2854
2855 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
2856 SFdirModTimer, (XtPointer) NULL);
2857
2858 while (1)
2859 {
2860 XtAppNextEvent(SFapp, &event);
2861 XtDispatchEvent(&event);
2862 switch (SFstatus)
2863 {
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;
2877 }
2878 }
2879 }
2880 #endif /* FEAT_BROWSE */