/src/gui_at_fs.c

https://bitbucket.org/ultra_iter/vim-qt · C · 2866 lines · 2398 code · 392 blank · 76 comment · 310 complexity · cab4c1d97148f661f4d636ac9963a3b8 MD5 · raw file

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