blob: 739d309b81897d038806c43571f3677cdb5a6368 [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
Bram Moolenaar30613902019-12-01 22:11:18 +010046// Only include this when using the file browser
Bram Moolenaar071d4272004-06-13 20:20:40 +000047
48#ifdef FEAT_BROWSE
49
Bram Moolenaar30613902019-12-01 22:11:18 +010050// Weird complication: for "make lint" Text.h doesn't combine with Xm.h
Bram Moolenaar071d4272004-06-13 20:20:40 +000051#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
Bram Moolenaar30613902019-12-01 22:11:18 +010059////////////////// SFinternal.h
Bram Moolenaar071d4272004-06-13 20:20:40 +000060
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 Moolenaar30613902019-12-01 22:11:18 +0100173///////////////// 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 Moolenaar963734e2020-11-01 13:33:49 +0100182static void SFmotionList(Widget w, XtPointer np, XMotionEvent *event, Boolean *cont);
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100183static void SFvSliderMovedCallback(Widget w, int n, int nw);
Bram Moolenaar963734e2020-11-01 13:33:49 +0100184static Boolean SFworkProc(void *);
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100185static int SFcompareEntries(const void *p, const void *q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000186
Bram Moolenaar30613902019-12-01 22:11:18 +0100187////////////////// xstat.h
Bram Moolenaar071d4272004-06-13 20:20:40 +0000188
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
Bram Moolenaar30613902019-12-01 22:11:18 +0100201////////////////// Path.c
Bram Moolenaar071d4272004-06-13 20:20:40 +0000202
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);
Bram Moolenaar964b3742019-05-24 18:54:09 +0200502 entries[i].real = XtMalloc((unsigned)(len + 3));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503 (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;
Bram Moolenaar30613902019-12-01 22:11:18 +0100518 SFhomeDir.vOrigin = 0; // :-)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519 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(
Bram Moolenaar963734e2020-11-01 13:33:49 +0100801 Widget w UNUSED,
802 XtPointer np UNUSED,
803 XEvent *event UNUSED,
804 Boolean *cont UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000805{
806 SFbuttonPressed = 1;
807}
808
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100810SFbuttonReleaseList(
Bram Moolenaar963734e2020-11-01 13:33:49 +0100811 Widget w UNUSED,
812 XtPointer np,
813 XEvent *event UNUSED,
814 Boolean *cont UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815{
Bram Moolenaar963734e2020-11-01 13:33:49 +0100816 long n = (long)np;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817 SFDir *dir;
818
819 SFbuttonPressed = 0;
820
821 if (SFcurrentInvert[n] != -1)
822 {
823 if (n < 2)
824 SFdoNotTouchDirPtr = 1;
825 SFdoNotTouchVorigin = 1;
826 dir = &(SFdirs[SFdirPtr + n]);
827 SFreplaceText(dir,
828 dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown);
Bram Moolenaar963734e2020-11-01 13:33:49 +0100829 SFmotionList(w, (XtPointer)(long)n, (XMotionEvent *)event, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 }
831}
832
Bram Moolenaar071d4272004-06-13 20:20:40 +0000833 static int
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100834SFcheckDir(int n, SFDir *dir)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835{
Bram Moolenaar8767f522016-07-01 17:17:39 +0200836 stat_T statBuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 int i;
838
839 if ((!mch_stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime))
840 {
841 /*
842 * If the pointer is currently in the window that we are about
843 * to update, we must warp it to prevent the user from
844 * accidentally selecting the wrong file.
845 */
846 if (SFcurrentInvert[n] != -1)
847 {
848 XWarpPointer(
849 SFdisplay,
850 None,
851 XtWindow(selFileLists[n]),
852 0,
853 0,
854 0,
855 0,
856 0,
857 0);
858 }
859
860 for (i = dir->nEntries - 1; i >= 0; i--)
861 {
862 if (dir->entries[i].shown != dir->entries[i].real)
863 XtFree(dir->entries[i].shown);
864 XtFree(dir->entries[i].real);
865 }
866 XtFree((char *) dir->entries);
867 if (SFgetDir(dir))
868 SFunreadableDir(dir);
869 if (dir->vOrigin > dir->nEntries - SFlistSize)
870 dir->vOrigin = dir->nEntries - SFlistSize;
871 if (dir->vOrigin < 0)
872 dir->vOrigin = 0;
873 if (dir->hOrigin > dir->nChars - SFcharsPerEntry)
874 dir->hOrigin = dir->nChars - SFcharsPerEntry;
875 if (dir->hOrigin < 0)
876 dir->hOrigin = 0;
877 dir->beginSelection = -1;
878 dir->endSelection = -1;
879 SFdoNotTouchVorigin = 1;
880 if ((dir + 1)->dir)
881 (void) SFfindFile(dir, (dir + 1)->dir);
882 else
883 (void) SFfindFile(dir, dir->path);
884
885 if (!SFworkProcAdded)
886 {
887 (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
888 SFworkProcAdded = 1;
889 }
890 return 1;
891 }
892 return 0;
893}
894
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 static int
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100896SFcheckFiles(SFDir *dir)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897{
898 int from, to;
899 int result;
900 char oldc, newc;
901 int i;
902 char *str;
903 int last;
Bram Moolenaar8767f522016-07-01 17:17:39 +0200904 stat_T statBuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905
906 result = 0;
907
908 from = dir->vOrigin;
909 to = dir->vOrigin + SFlistSize;
910 if (to > dir->nEntries)
911 to = dir->nEntries;
912
913 for (i = from; i < to; i++)
914 {
915 str = dir->entries[i].real;
916 last = strlen(str) - 1;
917 oldc = str[last];
918 str[last] = 0;
919 if (mch_stat(str, &statBuf))
920 newc = ' ';
921 else
922 newc = SFstatChar(&statBuf);
923 str[last] = newc;
924 if (newc != oldc)
925 result = 1;
926 }
927
928 return result;
929}
930
Bram Moolenaar071d4272004-06-13 20:20:40 +0000931 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100932SFdirModTimer(XtPointer cl UNUSED, XtIntervalId *id UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933{
934 static int n = -1;
935 static int f = 0;
936 char save;
937 SFDir *dir;
938
939 if ((!SFtwiddle) && (SFdirPtr < SFdirEnd))
940 {
941 n++;
942 if ((n > 2) || (SFdirPtr + n >= SFdirEnd))
943 {
944 n = 0;
945 f++;
946 if ((f > 2) || (SFdirPtr + f >= SFdirEnd))
947 f = 0;
948 }
949 dir = &(SFdirs[SFdirPtr + n]);
950 save = *(dir->path);
951 *(dir->path) = 0;
952 if (SFchdir(SFcurrentPath))
953 {
954 *(dir->path) = save;
955
956 /*
957 * force a re-read
958 */
959 *(dir->dir) = 0;
960
961 SFupdatePath();
962 }
963 else
964 {
965 *(dir->path) = save;
966 if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir)))
967 SFdrawList(n, SF_DO_SCROLL);
968 }
969 }
970
971 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
972 SFdirModTimer, (XtPointer) NULL);
973}
974
Bram Moolenaar30613902019-12-01 22:11:18 +0100975// Return a single character describing what kind of file STATBUF is.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000976
977 static char
Bram Moolenaar8767f522016-07-01 17:17:39 +0200978SFstatChar(stat_T *statBuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979{
980 if (S_ISDIR (statBuf->st_mode))
981 return '/';
982 if (S_ISREG (statBuf->st_mode))
983 return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
984#ifdef S_ISSOCK
985 if (S_ISSOCK (statBuf->st_mode))
986 return '=';
Bram Moolenaar30613902019-12-01 22:11:18 +0100987#endif // S_ISSOCK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988 return ' ';
989}
990
Bram Moolenaar30613902019-12-01 22:11:18 +0100991////////////////// Draw.c
Bram Moolenaar071d4272004-06-13 20:20:40 +0000992
993#ifdef FEAT_GUI_NEXTAW
994# include <X11/neXtaw/Cardinals.h>
995#else
996# include <X11/Xaw/Cardinals.h>
997#endif
998
999#ifdef FEAT_XFONTSET
1000# define SF_DEFAULT_FONT "-misc-fixed-medium-r-normal--14-*"
1001#else
1002# define SF_DEFAULT_FONT "9x15"
1003#endif
1004
1005#ifdef ABS
1006# undef ABS
1007#endif
1008#define ABS(x) (((x) < 0) ? (-(x)) : (x))
1009
1010typedef struct
1011{
1012 char *fontname;
1013} TextData;
1014
1015static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
1016
1017static XtResource textResources[] =
1018{
1019#ifdef FEAT_XFONTSET
1020 {XtNfontSet, XtCFontSet, XtRString, sizeof (char *),
1021 XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT},
1022#else
1023 {XtNfont, XtCFont, XtRString, sizeof (char *),
1024 XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT},
1025#endif
1026};
1027
1028#ifdef FEAT_XFONTSET
1029static XFontSet SFfont;
1030#else
1031static XFontStruct *SFfont;
1032#endif
1033
1034static int SFcurrentListY;
1035
1036static XtIntervalId SFscrollTimerId;
1037
Bram Moolenaar071d4272004-06-13 20:20:40 +00001038 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001039SFinitFont(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040{
1041 TextData *data;
1042#ifdef FEAT_XFONTSET
1043 XFontSetExtents *extents;
1044 char **missing, *def_str;
1045 int num_missing;
1046#endif
1047
1048 data = XtNew(TextData);
1049
1050 XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
1051 XtNumber(textResources), (Arg *) NULL, ZERO);
1052
1053#ifdef FEAT_XFONTSET
1054 SFfont = XCreateFontSet(SFdisplay, data->fontname,
1055 &missing, &num_missing, &def_str);
1056#else
1057 SFfont = XLoadQueryFont(SFdisplay, data->fontname);
1058#endif
1059 if (!SFfont)
1060 {
1061#ifdef FEAT_XFONTSET
1062 SFfont = XCreateFontSet(SFdisplay, SF_DEFAULT_FONT,
1063 &missing, &num_missing, &def_str);
1064#else
1065 SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);
1066#endif
1067 if (!SFfont)
1068 {
Bram Moolenaard88be5b2022-01-04 19:57:55 +00001069 semsg(_(e_vim_selfile_cant_get_font_str), SF_DEFAULT_FONT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070 SFstatus = SEL_FILE_CANCEL;
1071 return;
1072 }
1073 }
1074
1075#ifdef FEAT_XFONTSET
1076 extents = XExtentsOfFontSet(SFfont);
1077 SFcharWidth = extents->max_logical_extent.width;
1078 SFcharAscent = -extents->max_logical_extent.y;
1079 SFcharHeight = extents->max_logical_extent.height;
1080#else
1081 SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;
1082 SFcharAscent = SFfont->max_bounds.ascent;
1083 SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;
1084#endif
1085}
1086
Bram Moolenaar071d4272004-06-13 20:20:40 +00001087 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001088SFcreateGC(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001089{
1090 XGCValues gcValues;
1091 XRectangle rectangles[1];
1092
1093 gcValues.foreground = SFfore;
1094
1095 SFlineGC = XtGetGC(
1096 selFileLists[0],
1097 (XtGCMask)GCForeground,
1098 &gcValues);
1099
1100 SFscrollGC = XtGetGC(
1101 selFileLists[0],
1102 (XtGCMask)0,
1103 &gcValues);
1104
1105 gcValues.function = GXxor;
1106 gcValues.foreground = SFfore ^ SFback;
1107 gcValues.background = SFfore ^ SFback;
1108
1109 SFinvertGC = XtGetGC(
1110 selFileLists[0],
1111 (XtGCMask)GCFunction | GCForeground | GCBackground,
1112 &gcValues);
1113
1114 gcValues.foreground = SFfore;
1115 gcValues.background = SFback;
1116#ifndef FEAT_XFONTSET
1117 gcValues.font = SFfont->fid;
1118#endif
1119
1120 SFtextGC = XCreateGC(
1121 SFdisplay,
1122 XtWindow(selFileLists[0]),
1123#ifdef FEAT_XFONTSET
1124 (unsigned long)GCForeground | GCBackground,
1125#else
1126 (unsigned long)GCForeground | GCBackground | GCFont,
1127#endif
1128 &gcValues);
1129
1130 rectangles[0].x = SFlineToTextH + SFbesideText;
1131 rectangles[0].y = 0;
1132 rectangles[0].width = SFcharsPerEntry * SFcharWidth;
1133 rectangles[0].height = SFupperY + 1;
1134
1135 XSetClipRectangles(
1136 SFdisplay,
1137 SFtextGC,
1138 0,
1139 0,
1140 rectangles,
1141 1,
1142 Unsorted);
1143}
1144
1145 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001146SFclearList(int n, int doScroll)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001147{
1148 SFDir *dir;
1149
1150 SFcurrentInvert[n] = -1;
1151
1152 XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
1153
1154 XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2);
1155
1156 if (doScroll)
1157 {
1158 dir = &(SFdirs[SFdirPtr + n]);
1159
1160 if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars)
1161 {
1162#ifdef FEAT_GUI_NEXTAW
1163 XawScrollbarSetThumb(
1164 selFileVScrolls[n],
1165 (float) (((double) dir->vOrigin) /
1166 dir->nEntries),
1167 (float) (((double) ((dir->nEntries < SFlistSize)
1168 ? dir->nEntries : SFlistSize)) /
1169 dir->nEntries));
1170#else
1171 vim_XawScrollbarSetThumb(
1172 selFileVScrolls[n],
1173 (float) (((double) dir->vOrigin) /
1174 dir->nEntries),
1175 (float) (((double) ((dir->nEntries < SFlistSize)
1176 ? dir->nEntries : SFlistSize)) /
1177 dir->nEntries),
1178 (double)dir->nEntries);
1179#endif
1180
1181#ifdef FEAT_GUI_NEXTAW
1182 XawScrollbarSetThumb(
1183 selFileHScrolls[n],
1184 (float) (((double) dir->hOrigin) / dir->nChars),
1185 (float) (((double) ((dir->nChars <
1186 SFcharsPerEntry) ? dir->nChars :
1187 SFcharsPerEntry)) / dir->nChars));
1188#else
1189 vim_XawScrollbarSetThumb(
1190 selFileHScrolls[n],
1191 (float) (((double) dir->hOrigin) / dir->nChars),
1192 (float) (((double) ((dir->nChars <
1193 SFcharsPerEntry) ? dir->nChars :
1194 SFcharsPerEntry)) / dir->nChars),
1195 (double)dir->nChars);
1196#endif
1197 }
1198 else
1199 {
1200#ifdef FEAT_GUI_NEXTAW
1201 XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
1202 (float) 1.0);
1203#else
1204 vim_XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
1205 (float) 1.0, 1.0);
1206#endif
1207#ifdef FEAT_GUI_NEXTAW
1208 XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
1209 (float) 1.0);
1210#else
1211 vim_XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
1212 (float) 1.0, 1.0);
1213#endif
1214 }
1215 }
1216}
1217
Bram Moolenaar071d4272004-06-13 20:20:40 +00001218 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001219SFdeleteEntry(SFDir *dir, SFEntry *entry)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220{
1221 SFEntry *e;
1222 SFEntry *end;
1223 int n;
1224 int idx;
1225
1226 idx = entry - dir->entries;
1227
1228 if (idx < dir->beginSelection)
1229 dir->beginSelection--;
1230 if (idx <= dir->endSelection)
1231 dir->endSelection--;
1232 if (dir->beginSelection > dir->endSelection)
1233 dir->beginSelection = dir->endSelection = -1;
1234
1235 if (idx < dir->vOrigin)
1236 dir->vOrigin--;
1237
1238 XtFree(entry->real);
1239
1240 end = &(dir->entries[dir->nEntries - 1]);
1241
1242 for (e = entry; e < end; e++)
1243 *e = *(e + 1);
1244
1245 if (!(--dir->nEntries))
1246 return;
1247
1248 n = dir - &(SFdirs[SFdirPtr]);
1249 if ((n < 0) || (n > 2))
1250 return;
1251
1252#ifdef FEAT_GUI_NEXTAW
1253 XawScrollbarSetThumb(
1254 selFileVScrolls[n],
1255 (float) (((double) dir->vOrigin) / dir->nEntries),
1256 (float) (((double) ((dir->nEntries < SFlistSize) ?
1257 dir->nEntries : SFlistSize)) / dir->nEntries));
1258#else
1259 vim_XawScrollbarSetThumb(
1260 selFileVScrolls[n],
1261 (float) (((double) dir->vOrigin) / dir->nEntries),
1262 (float) (((double) ((dir->nEntries < SFlistSize) ?
1263 dir->nEntries : SFlistSize)) / dir->nEntries),
1264 (double)dir->nEntries);
1265#endif
1266}
1267
Bram Moolenaar071d4272004-06-13 20:20:40 +00001268 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001269SFwriteStatChar(
1270 char *name,
1271 int last,
Bram Moolenaar8767f522016-07-01 17:17:39 +02001272 stat_T *statBuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001273{
1274 name[last] = SFstatChar(statBuf);
1275}
1276
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277 static int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001278SFstatAndCheck(SFDir *dir, SFEntry *entry)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001279{
Bram Moolenaar8767f522016-07-01 17:17:39 +02001280 stat_T statBuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281 char save;
1282 int last;
1283
1284 /*
1285 * must be restored before returning
1286 */
1287 save = *(dir->path);
1288 *(dir->path) = 0;
1289
1290 if (!SFchdir(SFcurrentPath))
1291 {
1292 last = strlen(entry->real) - 1;
1293 entry->real[last] = 0;
1294 entry->statDone = 1;
1295 if ((!mch_stat(entry->real, &statBuf))
1296#ifdef S_IFLNK
1297 || (!mch_lstat(entry->real, &statBuf))
1298#endif
1299 )
1300 {
1301 if (SFfunc)
1302 {
1303 char *shown;
1304
1305 shown = NULL;
1306 if (SFfunc(entry->real, &shown, &statBuf))
1307 {
1308 if (shown)
1309 {
1310 int len;
1311
1312 len = strlen(shown);
Bram Moolenaar964b3742019-05-24 18:54:09 +02001313 entry->shown = XtMalloc((unsigned)(len + 2));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001314 (void) strcpy(entry->shown, shown);
1315 SFwriteStatChar(entry->shown, len, &statBuf);
1316 entry->shown[len + 1] = 0;
1317 }
1318 }
1319 else
1320 {
1321 SFdeleteEntry(dir, entry);
1322
1323 *(dir->path) = save;
1324 return 1;
1325 }
1326 }
1327 SFwriteStatChar(entry->real, last, &statBuf);
1328 }
1329 else
1330 entry->real[last] = ' ';
1331 }
1332
1333 *(dir->path) = save;
1334 return 0;
1335}
1336
1337
1338 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001339SFdrawStrings(
1340 Window w,
1341 SFDir *dir,
1342 int from,
1343 int to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001344{
1345 int i;
1346 SFEntry *entry;
1347 int x;
1348
1349 x = SFtextX - dir->hOrigin * SFcharWidth;
1350
1351 if (dir->vOrigin + to >= dir->nEntries)
1352 to = dir->nEntries - dir->vOrigin - 1;
1353 for (i = from; i <= to; i++)
1354 {
1355 entry = &(dir->entries[dir->vOrigin + i]);
1356 if (!(entry->statDone))
1357 {
1358 if (SFstatAndCheck(dir, entry))
1359 {
1360 if (dir->vOrigin + to >= dir->nEntries)
1361 to = dir->nEntries - dir->vOrigin - 1;
1362 i--;
1363 continue;
1364 }
1365 }
1366#ifdef FEAT_XFONTSET
1367 XmbDrawImageString(
1368 SFdisplay,
1369 w,
1370 SFfont,
1371 SFtextGC,
1372 x,
1373 SFtextYoffset + i * SFentryHeight,
1374 entry->shown,
1375 strlen(entry->shown));
1376#else
1377 XDrawImageString(
1378 SFdisplay,
1379 w,
1380 SFtextGC,
1381 x,
1382 SFtextYoffset + i * SFentryHeight,
1383 entry->shown,
1384 strlen(entry->shown));
1385#endif
1386 if (dir->vOrigin + i == dir->beginSelection)
1387 {
1388 XDrawLine(
1389 SFdisplay,
1390 w,
1391 SFlineGC,
1392 SFlineToTextH + 1,
1393 SFlowerY + i * SFentryHeight,
1394 SFlineToTextH + SFentryWidth - 2,
1395 SFlowerY + i * SFentryHeight);
1396 }
1397 if ((dir->vOrigin + i >= dir->beginSelection) &&
1398 (dir->vOrigin + i <= dir->endSelection))
1399 {
1400 SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
1401 SFlowerY + i * SFentryHeight;
1402 SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
1403 SFlowerY + (i + 1) * SFentryHeight - 1;
1404 XDrawSegments(
1405 SFdisplay,
1406 w,
1407 SFlineGC,
1408 SFcompletionSegs,
1409 2);
1410 }
1411 if (dir->vOrigin + i == dir->endSelection)
1412 {
1413 XDrawLine(
1414 SFdisplay,
1415 w,
1416 SFlineGC,
1417 SFlineToTextH + 1,
1418 SFlowerY + (i + 1) * SFentryHeight - 1,
1419 SFlineToTextH + SFentryWidth - 2,
1420 SFlowerY + (i + 1) * SFentryHeight - 1);
1421 }
1422 }
1423}
1424
1425 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001426SFdrawList(int n, int doScroll)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001427{
1428 SFDir *dir;
1429 Window w;
1430
1431 SFclearList(n, doScroll);
1432
1433 if (SFdirPtr + n < SFdirEnd)
1434 {
1435 dir = &(SFdirs[SFdirPtr + n]);
1436 w = XtWindow(selFileLists[n]);
1437#ifdef FEAT_XFONTSET
1438 XmbDrawImageString(
1439 SFdisplay,
1440 w,
1441 SFfont,
1442 SFtextGC,
1443 SFtextX - dir->hOrigin * SFcharWidth,
1444 SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
1445 dir->dir,
1446 strlen(dir->dir));
1447#else
1448 XDrawImageString(
1449 SFdisplay,
1450 w,
1451 SFtextGC,
1452 SFtextX - dir->hOrigin * SFcharWidth,
1453 SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
1454 dir->dir,
1455 strlen(dir->dir));
1456#endif
1457 SFdrawStrings(w, dir, 0, SFlistSize - 1);
1458 }
1459}
1460
1461 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001462SFdrawLists(int doScroll)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001463{
1464 int i;
1465
1466 for (i = 0; i < 3; i++)
1467 SFdrawList(i, doScroll);
1468}
1469
1470 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001471SFinvertEntry(int n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001472{
1473 XFillRectangle(
1474 SFdisplay,
1475 XtWindow(selFileLists[n]),
1476 SFinvertGC,
1477 SFlineToTextH,
1478 SFcurrentInvert[n] * SFentryHeight + SFlowerY,
1479 SFentryWidth,
1480 SFentryHeight);
1481}
1482
Bram Moolenaar071d4272004-06-13 20:20:40 +00001483 static unsigned long
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001484SFscrollTimerInterval(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001485{
1486 static int maxVal = 200;
1487 static int varyDist = 50;
1488 static int minDist = 50;
1489 int t;
1490 int dist;
1491
1492 if (SFcurrentListY < SFlowerY)
1493 dist = SFlowerY - SFcurrentListY;
1494 else if (SFcurrentListY > SFupperY)
1495 dist = SFcurrentListY - SFupperY;
1496 else
1497 return (unsigned long) 1;
1498
1499 t = maxVal - ((maxVal / varyDist) * (dist - minDist));
1500
1501 if (t < 1)
1502 t = 1;
1503
1504 if (t > maxVal)
1505 t = maxVal;
1506
1507 return (unsigned long)t;
1508}
1509
Bram Moolenaar071d4272004-06-13 20:20:40 +00001510 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001511SFscrollTimer(XtPointer p, XtIntervalId *id UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001512{
1513 SFDir *dir;
1514 int save;
1515 int n;
1516
1517 n = (long)p;
1518
1519 dir = &(SFdirs[SFdirPtr + n]);
1520 save = dir->vOrigin;
1521
1522 if (SFcurrentListY < SFlowerY)
1523 {
1524 if (dir->vOrigin > 0)
1525 SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1);
1526 }
1527 else if (SFcurrentListY > SFupperY)
1528 {
1529 if (dir->vOrigin < dir->nEntries - SFlistSize)
1530 SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1);
1531 }
1532
1533 if (dir->vOrigin != save)
1534 {
1535 if (dir->nEntries)
1536 {
1537#ifdef FEAT_GUI_NEXTAW
1538 XawScrollbarSetThumb(
1539 selFileVScrolls[n],
1540 (float) (((double) dir->vOrigin) / dir->nEntries),
1541 (float) (((double) ((dir->nEntries < SFlistSize) ?
1542 dir->nEntries : SFlistSize)) / dir->nEntries));
1543#else
1544 vim_XawScrollbarSetThumb(
1545 selFileVScrolls[n],
1546 (float) (((double) dir->vOrigin) / dir->nEntries),
1547 (float) (((double) ((dir->nEntries < SFlistSize) ?
1548 dir->nEntries : SFlistSize)) / dir->nEntries),
1549 (double)dir->nEntries);
1550#endif
1551 }
1552 }
1553
1554 if (SFbuttonPressed)
1555 SFscrollTimerId = XtAppAddTimeOut(SFapp,
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02001556 SFscrollTimerInterval(), SFscrollTimer,
1557 (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558}
1559
1560 static int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001561SFnewInvertEntry(int n, XMotionEvent *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001562{
1563 int x, y;
1564 int nw;
1565 static int SFscrollTimerAdded = 0;
1566
1567 x = event->x;
1568 y = event->y;
1569
1570 if (SFdirPtr + n >= SFdirEnd)
1571 return -1;
1572
1573 if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY))
1574 {
1575 SFDir *dir = &(SFdirs[SFdirPtr + n]);
1576
1577 if (SFscrollTimerAdded)
1578 {
1579 SFscrollTimerAdded = 0;
1580 XtRemoveTimeOut(SFscrollTimerId);
1581 }
1582
1583 nw = (y - SFlowerY) / SFentryHeight;
1584 if (dir->vOrigin + nw >= dir->nEntries)
1585 return -1;
1586 return nw;
1587 }
1588 else
1589 {
1590 if (SFbuttonPressed)
1591 {
1592 SFcurrentListY = y;
1593 if (!SFscrollTimerAdded)
1594 {
1595 SFscrollTimerAdded = 1;
1596 SFscrollTimerId = XtAppAddTimeOut(SFapp,
1597 SFscrollTimerInterval(), SFscrollTimer,
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02001598 (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001599 }
1600 }
1601 return -1;
1602 }
1603}
1604
Bram Moolenaar071d4272004-06-13 20:20:40 +00001605 static void
Bram Moolenaar963734e2020-11-01 13:33:49 +01001606SFenterList(
1607 Widget w UNUSED,
1608 XtPointer np,
1609 XEvent *event,
1610 Boolean *cont UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001611{
Bram Moolenaar963734e2020-11-01 13:33:49 +01001612 long n = (long)np;
1613 int nw;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614
Bram Moolenaar30613902019-12-01 22:11:18 +01001615 // sanity
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 if (SFcurrentInvert[n] != -1)
1617 {
1618 SFinvertEntry(n);
1619 SFcurrentInvert[n] = -1;
1620 }
1621
1622 nw = SFnewInvertEntry(n, (XMotionEvent *) event);
1623 if (nw != -1)
1624 {
1625 SFcurrentInvert[n] = nw;
1626 SFinvertEntry(n);
1627 }
1628}
1629
Bram Moolenaar071d4272004-06-13 20:20:40 +00001630 static void
Bram Moolenaar963734e2020-11-01 13:33:49 +01001631SFleaveList(
1632 Widget w UNUSED,
1633 XtPointer np,
1634 XEvent *event UNUSED,
1635 Boolean *cont UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636{
Bram Moolenaar963734e2020-11-01 13:33:49 +01001637 long n = (long)np;
1638
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639 if (SFcurrentInvert[n] != -1)
1640 {
1641 SFinvertEntry(n);
1642 SFcurrentInvert[n] = -1;
1643 }
1644}
1645
Bram Moolenaar071d4272004-06-13 20:20:40 +00001646 static void
Bram Moolenaar963734e2020-11-01 13:33:49 +01001647SFmotionList(
1648 Widget w UNUSED,
1649 XtPointer np,
1650 XMotionEvent *event UNUSED,
1651 Boolean *cont UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001652{
Bram Moolenaar963734e2020-11-01 13:33:49 +01001653 long n = (long)np;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654 int nw;
1655
1656 nw = SFnewInvertEntry(n, event);
1657
1658 if (nw != SFcurrentInvert[n])
1659 {
1660 if (SFcurrentInvert[n] != -1)
1661 SFinvertEntry(n);
1662 SFcurrentInvert[n] = nw;
1663 if (nw != -1)
1664 SFinvertEntry(n);
1665 }
1666}
1667
Bram Moolenaar071d4272004-06-13 20:20:40 +00001668 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001669SFvFloatSliderMovedCallback(Widget w, XtPointer n, XtPointer fnew)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001670{
1671 int nw;
1672
1673 nw = (*(float *)fnew) * SFdirs[SFdirPtr + (int)(long)n].nEntries;
1674 SFvSliderMovedCallback(w, (int)(long)n, nw);
1675}
1676
Bram Moolenaar071d4272004-06-13 20:20:40 +00001677 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001678SFvSliderMovedCallback(Widget w UNUSED, int n, int nw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001679{
1680 int old;
1681 Window win;
1682 SFDir *dir;
1683
1684 dir = &(SFdirs[SFdirPtr + n]);
1685
1686 old = dir->vOrigin;
1687 dir->vOrigin = nw;
1688
1689 if (old == nw)
1690 return;
1691
1692 win = XtWindow(selFileLists[n]);
1693
1694 if (ABS(nw - old) < SFlistSize)
1695 {
1696 if (nw > old)
1697 {
1698 XCopyArea(
1699 SFdisplay,
1700 win,
1701 win,
1702 SFscrollGC,
1703 SFlineToTextH,
1704 SFlowerY + (nw - old) * SFentryHeight,
1705 SFentryWidth + SFlineToTextH,
1706 (SFlistSize - (nw - old)) * SFentryHeight,
1707 SFlineToTextH,
1708 SFlowerY);
1709 XClearArea(
1710 SFdisplay,
1711 win,
1712 SFlineToTextH,
1713 SFlowerY + (SFlistSize - (nw - old)) *
1714 SFentryHeight,
1715 SFentryWidth + SFlineToTextH,
1716 (nw - old) * SFentryHeight,
1717 False);
1718 SFdrawStrings(win, dir, SFlistSize - (nw - old),
1719 SFlistSize - 1);
1720 }
1721 else
1722 {
1723 XCopyArea(
1724 SFdisplay,
1725 win,
1726 win,
1727 SFscrollGC,
1728 SFlineToTextH,
1729 SFlowerY,
1730 SFentryWidth + SFlineToTextH,
1731 (SFlistSize - (old - nw)) * SFentryHeight,
1732 SFlineToTextH,
1733 SFlowerY + (old - nw) * SFentryHeight);
1734 XClearArea(
1735 SFdisplay,
1736 win,
1737 SFlineToTextH,
1738 SFlowerY,
1739 SFentryWidth + SFlineToTextH,
1740 (old - nw) * SFentryHeight,
1741 False);
1742 SFdrawStrings(win, dir, 0, old - nw);
1743 }
1744 }
1745 else
1746 {
1747 XClearArea(
1748 SFdisplay,
1749 win,
1750 SFlineToTextH,
1751 SFlowerY,
1752 SFentryWidth + SFlineToTextH,
1753 SFlistSize * SFentryHeight,
1754 False);
1755 SFdrawStrings(win, dir, 0, SFlistSize - 1);
1756 }
1757}
1758
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001760SFvAreaSelectedCallback(Widget w, XtPointer n, XtPointer pnew)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761{
1762 SFDir *dir;
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001763 int nw = (int)(long)pnew;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764
1765 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1766
1767#ifdef FEAT_GUI_NEXTAW
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001768 if (nw < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001769 {
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001770 if (nw > -SFvScrollHeight)
1771 nw = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772 else
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001773 nw = -SFlistSize;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001774 }
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001775 else if (nw > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001776 {
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001777 if (nw < SFvScrollHeight)
1778 nw = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779 else
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001780 nw = SFlistSize;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781 }
1782#endif
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001783 nw += dir->vOrigin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001784
1785 if (nw > dir->nEntries - SFlistSize)
1786 nw = dir->nEntries - SFlistSize;
1787
1788 if (nw < 0)
1789 nw = 0;
1790
1791 if (dir->nEntries)
1792 {
1793 float f;
1794
1795 f = ((double) nw) / dir->nEntries;
1796
1797#ifdef FEAT_GUI_NEXTAW
1798 XawScrollbarSetThumb(
1799 w,
1800 f,
1801 (float) (((double) ((dir->nEntries < SFlistSize) ?
1802 dir->nEntries : SFlistSize)) / dir->nEntries));
1803#else
1804 vim_XawScrollbarSetThumb(
1805 w,
1806 f,
1807 (float) (((double) ((dir->nEntries < SFlistSize) ?
1808 dir->nEntries : SFlistSize)) / dir->nEntries),
1809 (double)dir->nEntries);
1810#endif
1811 }
1812
1813 SFvSliderMovedCallback(w, (int)(long)n, nw);
1814}
1815
Bram Moolenaar071d4272004-06-13 20:20:40 +00001816 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001817SFhSliderMovedCallback(Widget w UNUSED, XtPointer n, XtPointer nw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818{
1819 SFDir *dir;
1820 int save;
1821
1822 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1823 save = dir->hOrigin;
1824 dir->hOrigin = (*(float *)nw) * dir->nChars;
1825 if (dir->hOrigin == save)
1826 return;
1827
1828 SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
1829}
1830
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001832SFhAreaSelectedCallback(Widget w, XtPointer n, XtPointer pnew)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833{
1834 SFDir *dir;
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001835 int nw = (int)(long)pnew;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001836
1837 dir = &(SFdirs[SFdirPtr + (int)(long)n]);
1838
1839#ifdef FEAT_GUI_NEXTAW
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001840 if (nw < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001841 {
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001842 if (nw > -SFhScrollWidth)
1843 nw = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 else
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001845 nw = -SFcharsPerEntry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846 }
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001847 else if (nw > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848 {
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001849 if (nw < SFhScrollWidth)
1850 nw = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851 else
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001852 nw = SFcharsPerEntry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853 }
1854#endif
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001855 nw += dir->hOrigin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001856
1857 if (nw > dir->nChars - SFcharsPerEntry)
1858 nw = dir->nChars - SFcharsPerEntry;
1859
1860 if (nw < 0)
1861 nw = 0;
1862
1863 if (dir->nChars)
1864 {
1865 float f;
1866
1867 f = ((double) nw) / dir->nChars;
1868
1869#ifdef FEAT_GUI_NEXTAW
1870 XawScrollbarSetThumb(
1871 w,
1872 f,
1873 (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
1874 dir->nChars : SFcharsPerEntry)) / dir->nChars));
1875#else
1876 vim_XawScrollbarSetThumb(
1877 w,
1878 f,
1879 (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
1880 dir->nChars : SFcharsPerEntry)) / dir->nChars),
1881 (double)dir->nChars);
1882#endif
1883
1884 SFhSliderMovedCallback(w, n, (XtPointer)&f);
1885 }
1886}
1887
Bram Moolenaar071d4272004-06-13 20:20:40 +00001888 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001889SFpathSliderMovedCallback(
1890 Widget w UNUSED,
1891 XtPointer client_data UNUSED,
1892 XtPointer nw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893{
1894 SFDir *dir;
1895 int n;
1896 XawTextPosition pos;
1897 int SFdirPtrSave;
1898
1899 SFdirPtrSave = SFdirPtr;
1900 SFdirPtr = (*(float *)nw) * SFdirEnd;
1901 if (SFdirPtr == SFdirPtrSave)
1902 return;
1903
1904 SFdrawLists(SF_DO_SCROLL);
1905
1906 n = 2;
1907 while (SFdirPtr + n >= SFdirEnd)
1908 n--;
1909
1910 dir = &(SFdirs[SFdirPtr + n]);
1911
1912 pos = dir->path - SFcurrentPath;
1913
1914 if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
1915 {
1916 pos -= strlen(SFstartDir);
1917 if (pos < 0)
1918 pos = 0;
1919 }
1920
1921 XawTextSetInsertionPoint(selFileField, pos);
1922}
1923
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001925SFpathAreaSelectedCallback(
1926 Widget w,
1927 XtPointer client_data UNUSED,
1928 XtPointer pnew)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929{
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001930 int nw = (int)(long)pnew;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 float f;
1932
1933#ifdef FEAT_GUI_NEXTAW
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001934 if (nw < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935 {
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001936 if (nw > -SFpathScrollWidth)
1937 nw = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938 else
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001939 nw = -3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 }
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001941 else if (nw > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942 {
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001943 if (nw < SFpathScrollWidth)
1944 nw = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945 else
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001946 nw = 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001947 }
1948#endif
Bram Moolenaar9fb0e132006-05-13 13:51:38 +00001949 nw += SFdirPtr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001950
1951 if (nw > SFdirEnd - 3)
1952 nw = SFdirEnd - 3;
1953
1954 if (nw < 0)
1955 nw = 0;
1956
1957 f = ((double) nw) / SFdirEnd;
1958
1959#ifdef FEAT_GUI_NEXTAW
1960 XawScrollbarSetThumb(
1961 w,
1962 f,
1963 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd));
1964#else
1965 vim_XawScrollbarSetThumb(
1966 w,
1967 f,
1968 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd),
1969 (double)SFdirEnd);
1970#endif
1971
1972 SFpathSliderMovedCallback(w, (XtPointer) NULL, (XtPointer)&f);
1973}
1974
1975 static Boolean
Bram Moolenaar963734e2020-11-01 13:33:49 +01001976SFworkProc(void *arg UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001977{
1978 SFDir *dir;
1979 SFEntry *entry;
1980
1981 for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
1982 {
1983 if (!(dir->nEntries))
1984 continue;
1985 for (entry = &(dir->entries[dir->nEntries - 1]);
1986 entry >= dir->entries;
1987 entry--)
1988 {
1989 if (!(entry->statDone))
1990 {
1991 (void)SFstatAndCheck(dir, entry);
1992 return False;
1993 }
1994 }
1995 }
1996
1997 SFworkProcAdded = 0;
1998
1999 return True;
2000}
2001
Bram Moolenaar30613902019-12-01 22:11:18 +01002002////////////////// Dir.c
Bram Moolenaar071d4272004-06-13 20:20:40 +00002003
2004 static int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002005SFcompareEntries(const void *p, const void *q)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002006{
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002007 return strcmp(((SFEntry *)p)->real, ((SFEntry *)q)->real);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002008}
2009
2010 static int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002011SFgetDir(
2012 SFDir *dir)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013{
2014 SFEntry *result = NULL;
2015 int Alloc = 0;
2016 int i;
2017 DIR *dirp;
2018 struct dirent *dp;
2019 char *str;
2020 int len;
2021 int maxChars;
Bram Moolenaar8767f522016-07-01 17:17:39 +02002022 stat_T statBuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023
2024 maxChars = strlen(dir->dir) - 1;
2025
2026 dir->entries = NULL;
2027 dir->nEntries = 0;
2028 dir->nChars = 0;
2029
2030 result = NULL;
2031 i = 0;
2032
2033 dirp = opendir(".");
2034 if (!dirp)
2035 return 1;
2036
2037 (void)mch_stat(".", &statBuf);
2038 dir->mtime = statBuf.st_mtime;
2039
2040 while ((dp = readdir(dirp)))
2041 {
Bram Moolenaar30613902019-12-01 22:11:18 +01002042 // Ignore "." and ".."
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
2044 continue;
2045 if (i >= Alloc)
2046 {
2047 Alloc = 2 * (Alloc + 1);
2048 result = (SFEntry *) XtRealloc((char *) result,
2049 (unsigned) (Alloc * sizeof(SFEntry)));
2050 }
2051 result[i].statDone = 0;
2052 str = dp->d_name;
2053 len = strlen(str);
Bram Moolenaar964b3742019-05-24 18:54:09 +02002054 result[i].real = XtMalloc((unsigned)(len + 2));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002055 (void) strcat(strcpy(result[i].real, str), " ");
2056 if (len > maxChars)
2057 maxChars = len;
2058 result[i].shown = result[i].real;
2059 i++;
2060 }
2061
2062 qsort((char *) result, (size_t) i, sizeof(SFEntry), SFcompareEntries);
2063
2064 dir->entries = result;
2065 dir->nEntries = i;
2066 dir->nChars = maxChars + 1;
2067
2068 closedir(dirp);
2069
2070 return 0;
2071}
2072
Bram Moolenaar30613902019-12-01 22:11:18 +01002073////////////////// SFinternal.h
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074
2075#include <sys/param.h>
2076#include <X11/cursorfont.h>
2077#include <X11/Composite.h>
2078#include <X11/Shell.h>
2079#ifdef FEAT_GUI_NEXTAW
2080# include <X11/neXtaw/Form.h>
2081# include <X11/neXtaw/Command.h>
2082# include <X11/neXtaw/Label.h>
2083#else
2084#include <X11/Xaw/Form.h>
2085#include <X11/Xaw/Command.h>
2086#include <X11/Xaw/Label.h>
2087#endif
2088
2089static char *oneLineTextEditTranslations = "\
2090 <Key>Return: redraw-display()\n\
2091 Ctrl<Key>M: redraw-display()\n\
2092";
2093
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002095SFexposeList(
2096 Widget w UNUSED,
2097 XtPointer n,
2098 XEvent *event,
2099 Boolean *cont UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002100{
2101 if ((event->type == NoExpose) || event->xexpose.count)
2102 return;
2103
2104 SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
2105}
2106
Bram Moolenaar071d4272004-06-13 20:20:40 +00002107 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002108SFmodVerifyCallback(
2109 Widget w UNUSED,
2110 XtPointer client_data UNUSED,
2111 XEvent *event,
2112 Boolean *cont UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002113{
2114 char buf[2];
2115
2116 if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
2117 ((*buf) == '\r'))
2118 SFstatus = SEL_FILE_OK;
2119 else
2120 SFstatus = SEL_FILE_TEXT;
2121}
2122
Bram Moolenaar071d4272004-06-13 20:20:40 +00002123 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002124SFokCallback(Widget w UNUSED, XtPointer cl UNUSED, XtPointer cd UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002125{
2126 SFstatus = SEL_FILE_OK;
2127}
2128
2129static XtCallbackRec SFokSelect[] =
2130{
2131 { SFokCallback, (XtPointer) NULL },
2132 { NULL, (XtPointer) NULL },
2133};
2134
Bram Moolenaar071d4272004-06-13 20:20:40 +00002135 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002136SFcancelCallback(Widget w UNUSED, XtPointer cl UNUSED, XtPointer cd UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137{
2138 SFstatus = SEL_FILE_CANCEL;
2139}
2140
2141static XtCallbackRec SFcancelSelect[] =
2142{
2143 { SFcancelCallback, (XtPointer) NULL },
2144 { NULL, (XtPointer) NULL },
2145};
2146
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002148SFdismissAction(
2149 Widget w UNUSED,
2150 XEvent *event,
2151 String *params UNUSED,
2152 Cardinal *num_params UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002153{
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00002154 if (event->type == ClientMessage
2155 && (Atom)event->xclient.data.l[0] != SFwmDeleteWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002156 return;
2157
2158 SFstatus = SEL_FILE_CANCEL;
2159}
2160
2161static char *wmDeleteWindowTranslation = "\
2162 <Message>WM_PROTOCOLS: SelFileDismiss()\n\
2163";
2164
2165static XtActionsRec actions[] =
2166{
2167 {"SelFileDismiss", SFdismissAction},
2168};
2169
2170 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002171SFsetColors(
2172 guicolor_T bg,
2173 guicolor_T fg,
2174 guicolor_T scroll_bg,
2175 guicolor_T scroll_fg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002176{
2177 if (selFileForm)
2178 {
2179 XtVaSetValues(selFileForm, XtNbackground, bg,
2180 XtNforeground, fg,
2181 XtNborderColor, bg,
2182 NULL);
2183 }
2184 {
2185 int i;
2186
2187 for (i = 0; i < 3; ++i)
2188 {
2189 if (selFileLists[i])
2190 {
2191 XtVaSetValues(selFileLists[i], XtNbackground, bg,
2192 XtNforeground, fg,
2193 XtNborderColor, fg,
2194 NULL);
2195 }
2196 }
2197 }
2198 if (selFileOK)
2199 {
2200 XtVaSetValues(selFileOK, XtNbackground, bg,
2201 XtNforeground, fg,
2202 XtNborderColor, fg,
2203 NULL);
2204 }
2205 if (selFileCancel)
2206 {
2207 XtVaSetValues(selFileCancel, XtNbackground, bg,
2208 XtNforeground, fg,
2209 XtNborderColor, fg,
2210 NULL);
2211 }
2212 if (selFilePrompt)
2213 {
2214 XtVaSetValues(selFilePrompt, XtNbackground, bg,
2215 XtNforeground, fg,
2216 NULL);
2217 }
2218 if (gui.dpy)
2219 {
2220 XSetBackground(gui.dpy, SFtextGC, bg);
2221 XSetForeground(gui.dpy, SFtextGC, fg);
2222 XSetForeground(gui.dpy, SFlineGC, fg);
2223
Bram Moolenaar30613902019-12-01 22:11:18 +01002224 // This is an xor GC, so combine the fg and background
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225 XSetBackground(gui.dpy, SFinvertGC, fg ^ bg);
2226 XSetForeground(gui.dpy, SFinvertGC, fg ^ bg);
2227 }
2228 if (selFileHScroll)
2229 {
2230 XtVaSetValues(selFileHScroll, XtNbackground, scroll_bg,
2231 XtNforeground, scroll_fg,
2232 XtNborderColor, fg,
2233 NULL);
2234 }
2235 {
2236 int i;
2237
2238 for (i = 0; i < 3; i++)
2239 {
2240 XtVaSetValues(selFileVScrolls[i], XtNbackground, scroll_bg,
2241 XtNforeground, scroll_fg,
2242 XtNborderColor, fg,
2243 NULL);
2244 XtVaSetValues(selFileHScrolls[i], XtNbackground, scroll_bg,
2245 XtNforeground, scroll_fg,
2246 XtNborderColor, fg,
2247 NULL);
2248 }
2249 }
2250}
2251
2252 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002253SFcreateWidgets(
2254 Widget toplevel,
2255 char *prompt,
2256 char *ok,
2257 char *cancel)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258{
2259 Cardinal n;
2260 int listWidth, listHeight;
2261 int listSpacing = 10;
2262 int scrollThickness = 15;
2263 int hScrollX, hScrollY;
2264 int vScrollX, vScrollY;
2265
2266 selFile = XtVaAppCreateShell("selFile", "SelFile",
2267 transientShellWidgetClass, SFdisplay,
2268 XtNtransientFor, toplevel,
2269 XtNtitle, prompt,
2270 NULL);
2271
Bram Moolenaar30613902019-12-01 22:11:18 +01002272 // Add WM_DELETE_WINDOW protocol
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273 XtAppAddActions(XtWidgetToApplicationContext(selFile),
2274 actions, XtNumber(actions));
2275 XtOverrideTranslations(selFile,
2276 XtParseTranslationTable(wmDeleteWindowTranslation));
2277
2278 selFileForm = XtVaCreateManagedWidget("selFileForm",
2279 formWidgetClass, selFile,
2280 XtNdefaultDistance, 30,
2281 XtNforeground, SFfore,
2282 XtNbackground, SFback,
2283 XtNborderColor, SFback,
2284 NULL);
2285
2286 selFilePrompt = XtVaCreateManagedWidget("selFilePrompt",
2287 labelWidgetClass, selFileForm,
2288 XtNlabel, prompt,
2289 XtNresizable, True,
2290 XtNtop, XtChainTop,
2291 XtNbottom, XtChainTop,
2292 XtNleft, XtChainLeft,
2293 XtNright, XtChainLeft,
2294 XtNborderWidth, 0,
2295 XtNforeground, SFfore,
2296 XtNbackground, SFback,
2297 NULL);
2298
2299 /*
2300 XtVaGetValues(selFilePrompt,
2301 XtNforeground, &SFfore,
2302 XtNbackground, &SFback,
2303 NULL);
2304 */
2305
2306 SFinitFont();
2307
2308 SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth +
2309 SFbesideText;
2310 SFentryHeight = SFaboveAndBelowText + SFcharHeight +
2311 SFaboveAndBelowText;
2312
2313 listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
2314 scrollThickness;
2315 listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2316 SFlineToTextV + SFlistSize * SFentryHeight +
2317 SFlineToTextV + 1 + scrollThickness;
2318
2319 SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;
2320
2321 hScrollX = -1;
2322 hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2323 SFlineToTextV + SFlistSize * SFentryHeight +
2324 SFlineToTextV;
2325 SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
2326
2327 vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
2328 vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
2329 SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
2330 SFlineToTextV;
2331
2332 SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
2333 SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2334 SFlineToTextV;
2335 SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
2336 SFlineToTextV + SFlistSize * SFentryHeight - 1;
2337
2338 SFtextX = SFlineToTextH + SFbesideText;
2339 SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
2340
2341 SFsegs[0].x1 = 0;
2342 SFsegs[0].y1 = vScrollY;
2343 SFsegs[0].x2 = vScrollX - 1;
2344 SFsegs[0].y2 = vScrollY;
2345 SFsegs[1].x1 = vScrollX;
2346 SFsegs[1].y1 = 0;
2347 SFsegs[1].x2 = vScrollX;
2348 SFsegs[1].y2 = vScrollY - 1;
2349
2350 SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
2351 SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
2352 SFlineToTextH + SFentryWidth - 1;
2353
2354 selFileField = XtVaCreateManagedWidget("selFileField",
2355 asciiTextWidgetClass, selFileForm,
2356 XtNwidth, 3 * listWidth + 2 * listSpacing + 4,
2357 XtNborderColor, SFfore,
2358 XtNfromVert, selFilePrompt,
2359 XtNvertDistance, 10,
2360 XtNresizable, True,
2361 XtNtop, XtChainTop,
2362 XtNbottom, XtChainTop,
2363 XtNleft, XtChainLeft,
2364 XtNright, XtChainLeft,
2365 XtNstring, SFtextBuffer,
2366 XtNlength, MAXPATHL,
2367 XtNeditType, XawtextEdit,
2368 XtNwrap, XawtextWrapWord,
2369 XtNresize, XawtextResizeHeight,
2370 XtNuseStringInPlace, True,
2371 NULL);
2372
2373 XtOverrideTranslations(selFileField,
2374 XtParseTranslationTable(oneLineTextEditTranslations));
2375 XtSetKeyboardFocus(selFileForm, selFileField);
2376
2377 selFileHScroll = XtVaCreateManagedWidget("selFileHScroll",
2378#ifdef FEAT_GUI_NEXTAW
2379 scrollbarWidgetClass, selFileForm,
2380#else
2381 vim_scrollbarWidgetClass, selFileForm,
2382#endif
2383 XtNorientation, XtorientHorizontal,
2384 XtNwidth, SFpathScrollWidth,
2385 XtNheight, scrollThickness,
2386 XtNborderColor, SFfore,
2387 XtNfromVert, selFileField,
2388 XtNvertDistance, 30,
2389 XtNtop, XtChainTop,
2390 XtNbottom, XtChainTop,
2391 XtNleft, XtChainLeft,
2392 XtNright, XtChainLeft,
2393 XtNforeground, gui.scroll_fg_pixel,
2394 XtNbackground, gui.scroll_bg_pixel,
2395#ifndef FEAT_GUI_NEXTAW
2396 XtNlimitThumb, 1,
2397#endif
2398 NULL);
2399
2400 XtAddCallback(selFileHScroll, XtNjumpProc,
2401 (XtCallbackProc) SFpathSliderMovedCallback, (XtPointer)NULL);
2402 XtAddCallback(selFileHScroll, XtNscrollProc,
2403 (XtCallbackProc) SFpathAreaSelectedCallback, (XtPointer)NULL);
2404
2405 selFileLists[0] = XtVaCreateManagedWidget("selFileList1",
2406 compositeWidgetClass, selFileForm,
2407 XtNwidth, listWidth,
2408 XtNheight, listHeight,
2409 XtNforeground, SFfore,
2410 XtNbackground, SFback,
2411 XtNborderColor, SFfore,
2412 XtNfromVert, selFileHScroll,
2413 XtNvertDistance, 10,
2414 XtNtop, XtChainTop,
2415 XtNbottom, XtChainTop,
2416 XtNleft, XtChainLeft,
2417 XtNright, XtChainLeft,
2418 NULL);
2419
2420 selFileLists[1] = XtVaCreateManagedWidget("selFileList2",
2421 compositeWidgetClass, selFileForm,
2422 XtNwidth, listWidth,
2423 XtNheight, listHeight,
2424 XtNforeground, SFfore,
2425 XtNbackground, SFback,
2426 XtNborderColor, SFfore,
2427 XtNfromHoriz, selFileLists[0],
2428 XtNfromVert, selFileHScroll,
2429 XtNhorizDistance, listSpacing,
2430 XtNvertDistance, 10,
2431 XtNtop, XtChainTop,
2432 XtNbottom, XtChainTop,
2433 XtNleft, XtChainLeft,
2434 XtNright, XtChainLeft,
2435 NULL);
2436
2437 selFileLists[2] = XtVaCreateManagedWidget("selFileList3",
2438 compositeWidgetClass, selFileForm,
2439 XtNwidth, listWidth,
2440 XtNheight, listHeight,
2441 XtNforeground, SFfore,
2442 XtNbackground, SFback,
2443 XtNborderColor, SFfore,
2444 XtNfromHoriz, selFileLists[1],
2445 XtNfromVert, selFileHScroll,
2446 XtNhorizDistance, listSpacing,
2447 XtNvertDistance, 10,
2448 XtNtop, XtChainTop,
2449 XtNbottom, XtChainTop,
2450 XtNleft, XtChainLeft,
2451 XtNright, XtChainLeft,
2452 NULL);
2453
2454 for (n = 0; n < 3; n++)
2455 {
2456 selFileVScrolls[n] = XtVaCreateManagedWidget("selFileVScroll",
2457#ifdef FEAT_GUI_NEXTAW
2458 scrollbarWidgetClass, selFileLists[n],
2459#else
2460 vim_scrollbarWidgetClass, selFileLists[n],
2461#endif
2462 XtNx, vScrollX,
2463 XtNy, vScrollY,
2464 XtNwidth, scrollThickness,
2465 XtNheight, SFvScrollHeight,
2466 XtNborderColor, SFfore,
2467 XtNforeground, gui.scroll_fg_pixel,
2468 XtNbackground, gui.scroll_bg_pixel,
2469#ifndef FEAT_GUI_NEXTAW
2470 XtNlimitThumb, 1,
2471#endif
2472 NULL);
2473
2474 XtAddCallback(selFileVScrolls[n], XtNjumpProc,
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02002475 (XtCallbackProc)SFvFloatSliderMovedCallback,
2476 (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 XtAddCallback(selFileVScrolls[n], XtNscrollProc,
Bram Moolenaar6470de82013-06-27 22:36:03 +02002478 (XtCallbackProc)SFvAreaSelectedCallback, (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479
2480 selFileHScrolls[n] = XtVaCreateManagedWidget("selFileHScroll",
2481#ifdef FEAT_GUI_NEXTAW
2482 scrollbarWidgetClass, selFileLists[n],
2483#else
2484 vim_scrollbarWidgetClass, selFileLists[n],
2485#endif
2486 XtNorientation, XtorientHorizontal,
2487 XtNx, hScrollX,
2488 XtNy, hScrollY,
2489 XtNwidth, SFhScrollWidth,
2490 XtNheight, scrollThickness,
2491 XtNborderColor, SFfore,
2492 XtNforeground, gui.scroll_fg_pixel,
2493 XtNbackground, gui.scroll_bg_pixel,
2494#ifndef FEAT_GUI_NEXTAW
2495 XtNlimitThumb, 1,
2496#endif
2497 NULL);
2498
2499 XtAddCallback(selFileHScrolls[n], XtNjumpProc,
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02002500 (XtCallbackProc)SFhSliderMovedCallback,
2501 (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 XtAddCallback(selFileHScrolls[n], XtNscrollProc,
Bram Moolenaar6470de82013-06-27 22:36:03 +02002503 (XtCallbackProc)SFhAreaSelectedCallback, (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 }
2505
2506 selFileOK = XtVaCreateManagedWidget("selFileOK",
2507 commandWidgetClass, selFileForm,
2508 XtNlabel, ok,
2509 XtNresizable, True,
2510 XtNcallback, SFokSelect,
2511 XtNforeground, SFfore,
2512 XtNbackground, SFback,
2513 XtNborderColor, SFfore,
2514 XtNfromHoriz, selFileLists[0],
2515 XtNfromVert, selFileLists[0],
2516 XtNvertDistance, 30,
2517 XtNtop, XtChainTop,
2518 XtNbottom, XtChainTop,
2519 XtNleft, XtChainLeft,
2520 XtNright, XtChainLeft,
2521 NULL);
2522
2523 selFileCancel = XtVaCreateManagedWidget("selFileCancel",
2524 commandWidgetClass, selFileForm,
2525 XtNlabel, cancel,
2526 XtNresizable, True,
2527 XtNcallback, SFcancelSelect,
2528 XtNforeground, SFfore,
2529 XtNbackground, SFback,
2530 XtNborderColor, SFfore,
2531 XtNfromHoriz, selFileOK,
2532 XtNfromVert, selFileLists[0],
2533 XtNhorizDistance, 30,
2534 XtNvertDistance, 30,
2535 XtNtop, XtChainTop,
2536 XtNbottom, XtChainTop,
2537 XtNleft, XtChainLeft,
2538 XtNright, XtChainLeft,
2539 NULL);
2540
2541 XtSetMappedWhenManaged(selFile, False);
2542 XtRealizeWidget(selFile);
2543
Bram Moolenaar30613902019-12-01 22:11:18 +01002544 // Add WM_DELETE_WINDOW protocol
Bram Moolenaar071d4272004-06-13 20:20:40 +00002545 SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
2546 XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
2547
2548 SFcreateGC();
2549
2550 for (n = 0; n < 3; n++)
2551 {
2552 XtAddEventHandler(selFileLists[n], ExposureMask, True,
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02002553 (XtEventHandler)SFexposeList, (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554 XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02002555 (XtEventHandler)SFenterList, (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556 XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02002557 (XtEventHandler)SFleaveList, (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558 XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02002559 (XtEventHandler)SFmotionList, (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02002561 (XtEventHandler)SFbuttonPressList, (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562 XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02002563 (XtEventHandler)SFbuttonReleaseList, (XtPointer)(long_u)n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 }
2565
2566 XtAddEventHandler(selFileField, KeyPressMask, False,
2567 SFmodVerifyCallback, (XtPointer)NULL);
2568
2569 SFapp = XtWidgetToApplicationContext(selFile);
2570}
2571
2572 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002573SFtextChanged(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574{
2575#if defined(FEAT_XFONTSET) && defined(XtNinternational)
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00002576 if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577 {
2578 wchar_t *wcbuf=(wchar_t *)SFtextBuffer;
2579
2580 if ((wcbuf[0] == L'/') || (wcbuf[0] == L'~'))
2581 {
2582 (void) wcstombs(SFcurrentPath, wcbuf, MAXPATHL);
2583 SFtextPos = XawTextGetInsertionPoint(selFileField);
2584 }
2585 else
2586 {
2587 strcpy(SFcurrentPath, SFstartDir);
2588 (void) wcstombs(SFcurrentPath + strlen(SFcurrentPath), wcbuf, MAXPATHL);
2589
2590 SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
2591 }
2592 }
2593 else
2594#endif
2595 if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~'))
2596 {
2597 (void) strcpy(SFcurrentPath, SFtextBuffer);
2598 SFtextPos = XawTextGetInsertionPoint(selFileField);
2599 }
2600 else
2601 {
2602 (void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
2603
2604 SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
2605 }
2606
2607 if (!SFworkProcAdded)
2608 {
2609 (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
2610 SFworkProcAdded = 1;
2611 }
2612
2613 SFupdatePath();
2614}
2615
2616 static char *
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002617SFgetText(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618{
2619#if defined(FEAT_XFONTSET) && defined(XtNinternational)
2620 char *buf;
2621
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00002622 if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623 {
2624 wchar_t *wcbuf;
2625 int mbslength;
2626
2627 XtVaGetValues(selFileField,
2628 XtNstring, &wcbuf,
2629 NULL);
2630 mbslength = wcstombs(NULL, wcbuf, 0);
Bram Moolenaar30613902019-12-01 22:11:18 +01002631 // Hack: some broken wcstombs() returns zero, just get a large buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632 if (mbslength == 0 && wcbuf != NULL && wcbuf[0] != 0)
2633 mbslength = MAXPATHL;
2634 buf=(char *)XtMalloc(mbslength + 1);
2635 wcstombs(buf, wcbuf, mbslength +1);
2636 return buf;
2637 }
2638#endif
2639 return (char *)vim_strsave((char_u *)SFtextBuffer);
2640}
2641
2642 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002643SFprepareToReturn(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644{
2645 SFstatus = SEL_FILE_NULL;
2646 XtRemoveGrab(selFile);
2647 XtUnmapWidget(selFile);
2648 XtRemoveTimeOut(SFdirModTimerId);
2649 if (SFchdir(SFstartDir))
2650 {
Bram Moolenaard88be5b2022-01-04 19:57:55 +00002651 emsg(_(e_vim_selfile_cant_return_to_current_directory));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652 SFstatus = SEL_FILE_CANCEL;
2653 }
2654}
2655
2656 char *
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002657vim_SelFile(
2658 Widget toplevel,
2659 char *prompt,
2660 char *init_path,
2661 int (*show_entry)(),
Bram Moolenaar02fdaea2016-01-30 18:13:55 +01002662 int x,
2663 int y,
2664 guicolor_T fg,
2665 guicolor_T bg,
2666 guicolor_T scroll_fg,
Bram Moolenaar30613902019-12-01 22:11:18 +01002667 guicolor_T scroll_bg) // The "Scrollbar" group colors
Bram Moolenaar071d4272004-06-13 20:20:40 +00002668{
2669 static int firstTime = 1;
2670 XEvent event;
2671 char *name_return;
2672
2673 if (prompt == NULL)
2674 prompt = _("Pathname:");
2675 SFfore = fg;
2676 SFback = bg;
2677
2678 if (mch_dirname((char_u *)SFstartDir, MAXPATHL) == FAIL)
2679 {
Bram Moolenaard88be5b2022-01-04 19:57:55 +00002680 emsg(_(e_vim_selfile_cant_get_current_directory));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 return NULL;
2682 }
2683
2684 if (firstTime)
2685 {
2686 firstTime = 0;
2687 SFdisplay = XtDisplay(toplevel);
2688 SFcreateWidgets(toplevel, prompt, _("OK"), _("Cancel"));
2689 }
2690 else
2691 {
2692 XtVaSetValues(selFilePrompt, XtNlabel, prompt, NULL);
2693 XtVaSetValues(selFile, XtNtitle, prompt, NULL);
2694 SFsetColors(bg, fg, scroll_bg, scroll_fg);
2695 }
2696
2697 XtVaSetValues(selFile, XtNx, x, XtNy, y, NULL);
2698 XtMapWidget(selFile);
2699
2700 (void)strcat(SFstartDir, "/");
2701 (void)strcpy(SFcurrentDir, SFstartDir);
2702
2703 if (init_path)
2704 {
2705 if (init_path[0] == '/')
2706 {
2707 (void)strcpy(SFcurrentPath, init_path);
2708 if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
2709 SFsetText(SFcurrentPath);
2710 else
2711 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
2712 }
2713 else
2714 {
2715 (void)strcat(strcpy(SFcurrentPath, SFstartDir), init_path);
2716 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
2717 }
2718 }
2719 else
2720 (void)strcpy(SFcurrentPath, SFstartDir);
2721
2722 SFfunc = show_entry;
2723
2724 SFtextChanged();
2725
2726 XtAddGrab(selFile, True, True);
2727
2728 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
2729 SFdirModTimer, (XtPointer) NULL);
2730
Bram Moolenaara466c992005-07-09 21:03:22 +00002731 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002732 {
2733 XtAppNextEvent(SFapp, &event);
2734 XtDispatchEvent(&event);
2735 switch (SFstatus)
2736 {
2737 case SEL_FILE_TEXT:
2738 SFstatus = SEL_FILE_NULL;
2739 SFtextChanged();
2740 break;
2741 case SEL_FILE_OK:
2742 name_return = SFgetText();
2743 SFprepareToReturn();
2744 return name_return;
2745 case SEL_FILE_CANCEL:
2746 SFprepareToReturn();
2747 return NULL;
2748 case SEL_FILE_NULL:
2749 break;
2750 }
2751 }
2752}
Bram Moolenaar30613902019-12-01 22:11:18 +01002753#endif // FEAT_BROWSE