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