1 /* vi:set ts=8 sts=4 sw=4 noet: */ 2 3 /* 4 * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan 5 * 6 * Permission to use, copy, modify, and distribute this software and its 7 * documentation for any purpose and without fee is hereby granted, provided 8 * that the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of Software Research Associates not be used 11 * in advertising or publicity pertaining to distribution of the software 12 * without specific, written prior permission. Software Research Associates 13 * makes no representations about the suitability of this software for any 14 * purpose. It is provided "as is" without express or implied warranty. 15 * 16 * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 18 * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL, 19 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 20 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 21 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 * 24 * Author: Erik M. van der Poel 25 * Software Research Associates, Inc., Tokyo, Japan 26 * [email protected] 27 */ 28 /* 29 * Author's addresses: 30 * [email protected] 31 * erik%[email protected] 32 * erik%[email protected] 33 * try junet instead of co.jp 34 * Erik M. van der Poel 35 * Software Research Associates, Inc. 36 * 1-1-1 Hirakawa-cho, Chiyoda-ku 37 * Tokyo 102 Japan. TEL +81-3-234-2692 38 */ 39 40 /* 41 * Heavely modified for Vim by Bram Moolenaar 42 */ 43 44 #include "vim.h" 45 46 /* Only include this when using the file browser */ 47 48 #ifdef FEAT_BROWSE 49 50 /* Weird complication: for "make lint" Text.h doesn't combine with Xm.h */ 51 #if defined(FEAT_GUI_MOTIF) && defined(FMT8BIT) 52 # undef FMT8BIT 53 #endif 54 55 #ifndef FEAT_GUI_NEXTAW 56 # include "gui_at_sb.h" 57 #endif 58 59 /***************** SFinternal.h */ 60 61 #include <X11/Intrinsic.h> 62 #include <X11/StringDefs.h> 63 #include <X11/Xos.h> 64 #ifdef FEAT_GUI_NEXTAW 65 # include <X11/neXtaw/Text.h> 66 # include <X11/neXtaw/AsciiText.h> 67 # include <X11/neXtaw/Scrollbar.h> 68 #else 69 # include <X11/Xaw/Text.h> 70 # include <X11/Xaw/AsciiText.h> 71 #endif 72 73 #define SEL_FILE_CANCEL -1 74 #define SEL_FILE_OK 0 75 #define SEL_FILE_NULL 1 76 #define SEL_FILE_TEXT 2 77 78 #define SF_DO_SCROLL 1 79 #define SF_DO_NOT_SCROLL 0 80 81 typedef struct 82 { 83 int statDone; 84 char *real; 85 char *shown; 86 } SFEntry; 87 88 typedef struct 89 { 90 char *dir; 91 char *path; 92 SFEntry *entries; 93 int nEntries; 94 int vOrigin; 95 int nChars; 96 int hOrigin; 97 int changed; 98 int beginSelection; 99 int endSelection; 100 time_t mtime; 101 } SFDir; 102 103 static char SFstartDir[MAXPATHL], 104 SFcurrentPath[MAXPATHL], 105 SFcurrentDir[MAXPATHL]; 106 107 static Widget selFile, 108 selFileField, 109 selFileForm, 110 selFileHScroll, 111 selFileHScrolls[3], 112 selFileLists[3], 113 selFileOK, 114 selFileCancel, 115 selFilePrompt, 116 selFileVScrolls[3]; 117 118 static Display *SFdisplay; 119 120 static int SFcharWidth, SFcharAscent, SFcharHeight; 121 122 static SFDir *SFdirs = NULL; 123 124 static int SFdirEnd; 125 static int SFdirPtr; 126 127 static Pixel SFfore, SFback; 128 129 static Atom SFwmDeleteWindow; 130 131 static XSegment SFsegs[2], SFcompletionSegs[2]; 132 133 static XawTextPosition SFtextPos; 134 135 static int SFupperX, SFlowerY, SFupperY; 136 137 static int SFtextX, SFtextYoffset; 138 139 static int SFentryWidth, SFentryHeight; 140 141 static int SFlineToTextH = 3; 142 static int SFlineToTextV = 3; 143 144 static int SFbesideText = 3; 145 static int SFaboveAndBelowText = 2; 146 147 static int SFcharsPerEntry = 15; 148 149 static int SFlistSize = 10; 150 151 static int SFcurrentInvert[3] = { -1, -1, -1 }; 152 153 static int SFworkProcAdded = 0; 154 155 static XtAppContext SFapp; 156 157 static int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth; 158 159 #ifdef FEAT_XFONTSET 160 static char SFtextBuffer[MAXPATHL*sizeof(wchar_t)]; 161 #else 162 static char SFtextBuffer[MAXPATHL]; 163 #endif 164 165 static int SFbuttonPressed = 0; 166 167 static XtIntervalId SFdirModTimerId; 168 169 static int (*SFfunc)(); 170 171 static int SFstatus = SEL_FILE_NULL; 172 173 /***************** forward declare static functions */ 174 175 static void SFsetText(char *path); 176 static void SFtextChanged(void); 177 static int SFgetDir(SFDir *dir); 178 static void SFdrawLists(int doScroll); 179 static void SFdrawList(int n, int doScroll); 180 static void SFclearList(int n, int doScroll); 181 static char SFstatChar(stat_T *statBuf); 182 static void SFmotionList(Widget w, int n, XMotionEvent *event); 183 static void SFvSliderMovedCallback(Widget w, int n, int nw); 184 static Boolean SFworkProc(void); 185 static int SFcompareEntries(const void *p, const void *q); 186 187 /***************** xstat.h */ 188 189 #ifndef S_IXUSR 190 # define S_IXUSR 0100 191 #endif 192 #ifndef S_IXGRP 193 # define S_IXGRP 0010 194 #endif 195 #ifndef S_IXOTH 196 # define S_IXOTH 0001 197 #endif 198 199 #define S_ISXXX(m) ((m) & (S_IXUSR | S_IXGRP | S_IXOTH)) 200 201 /***************** Path.c */ 202 203 #include <pwd.h> 204 205 typedef struct 206 { 207 char *name; 208 char *dir; 209 } SFLogin; 210 211 static int SFdoNotTouchDirPtr = 0; 212 213 static int SFdoNotTouchVorigin = 0; 214 215 static SFDir SFrootDir, SFhomeDir; 216 217 static SFLogin *SFlogins; 218 219 static int SFtwiddle = 0; 220 221 static int 222 SFchdir(char *path) 223 { 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 238 static void 239 SFfree(int i) 240 { 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 259 static void 260 SFstrdup(char **s1, char *s2) 261 { 262 *s1 = strcpy(XtMalloc((unsigned)(strlen(s2) + 1)), s2); 263 } 264 265 static void 266 SFunreadableDir(SFDir *dir) 267 { 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 278 static void 279 SFreplaceText(SFDir *dir, char *str) 280 { 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 297 static void 298 SFexpand(char *str) 299 { 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 351 static int 352 SFfindFile(SFDir *dir, char *str) 353 { 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 448 static void 449 SFunselect(void) 450 { 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 460 static int 461 SFcompareLogins(const void *p, const void *q) 462 { 463 return strcmp(((SFLogin *)p)->name, ((SFLogin *)q)->name); 464 } 465 466 static void 467 SFgetHomeDirs(void) 468 { 469 struct passwd *pw; 470 int Alloc; 471 int i; 472 SFEntry *entries = NULL; 473 int len; 474 int maxChars; 475 476 Alloc = 1; 477 i = 1; 478 entries = (SFEntry *)XtMalloc(sizeof(SFEntry)); 479 SFlogins = (SFLogin *)XtMalloc(sizeof(SFLogin)); 480 entries[0].real = XtMalloc(3); 481 (void) strcpy(entries[0].real, "~"); 482 entries[0].shown = entries[0].real; 483 entries[0].statDone = 1; 484 SFlogins[0].name = ""; 485 pw = getpwuid((int) getuid()); 486 SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/"); 487 maxChars = 0; 488 489 (void) setpwent(); 490 491 while ((pw = getpwent()) && (*(pw->pw_name))) 492 { 493 if (i >= Alloc) 494 { 495 Alloc *= 2; 496 entries = (SFEntry *) XtRealloc((char *)entries, 497 (unsigned)(Alloc * sizeof(SFEntry))); 498 SFlogins = (SFLogin *) XtRealloc((char *)SFlogins, 499 (unsigned)(Alloc * sizeof(SFLogin))); 500 } 501 len = strlen(pw->pw_name); 502 entries[i].real = XtMalloc((unsigned)(len + 3)); 503 (void) strcat(strcpy(entries[i].real, "~"), pw->pw_name); 504 entries[i].shown = entries[i].real; 505 entries[i].statDone = 1; 506 if (len > maxChars) 507 maxChars = len; 508 SFstrdup(&SFlogins[i].name, pw->pw_name); 509 SFstrdup(&SFlogins[i].dir, pw->pw_dir); 510 i++; 511 } 512 513 SFhomeDir.dir = XtMalloc(1); 514 SFhomeDir.dir[0] = 0; 515 SFhomeDir.path = SFcurrentPath; 516 SFhomeDir.entries = entries; 517 SFhomeDir.nEntries = i; 518 SFhomeDir.vOrigin = 0; /* :-) */ 519 SFhomeDir.nChars = maxChars + 2; 520 SFhomeDir.hOrigin = 0; 521 SFhomeDir.changed = 1; 522 SFhomeDir.beginSelection = -1; 523 SFhomeDir.endSelection = -1; 524 525 qsort((char *)entries, (size_t)i, sizeof(SFEntry), SFcompareEntries); 526 qsort((char *)SFlogins, (size_t)i, sizeof(SFLogin), SFcompareLogins); 527 528 for (i--; i >= 0; i--) 529 (void)strcat(entries[i].real, "/"); 530 } 531 532 static int 533 SFfindHomeDir(char *begin, char *end) 534 { 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 563 SFupdatePath(void) 564 { 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 757 WcsLen(wchar_t *p) 758 { 759 int i = 0; 760 while (*p++ != 0) 761 i++; 762 return i; 763 } 764 #endif 765 766 static void 767 SFsetText(char *path) 768 { 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 777 if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide) 778 { 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 799 static void 800 SFbuttonPressList( 801 Widget w UNUSED, 802 int n UNUSED, 803 XButtonPressedEvent *event UNUSED) 804 { 805 SFbuttonPressed = 1; 806 } 807 808 static void 809 SFbuttonReleaseList( 810 Widget w, 811 int n, 812 XButtonReleasedEvent *event) 813 { 814 SFDir *dir; 815 816 SFbuttonPressed = 0; 817 818 if (SFcurrentInvert[n] != -1) 819 { 820 if (n < 2) 821 SFdoNotTouchDirPtr = 1; 822 SFdoNotTouchVorigin = 1; 823 dir = &(SFdirs[SFdirPtr + n]); 824 SFreplaceText(dir, 825 dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown); 826 SFmotionList(w, n, (XMotionEvent *) event); 827 } 828 } 829 830 static int 831 SFcheckDir(int n, SFDir *dir) 832 { 833 stat_T statBuf; 834 int i; 835 836 if ((!mch_stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime)) 837 { 838 /* 839 * If the pointer is currently in the window that we are about 840 * to update, we must warp it to prevent the user from 841 * accidentally selecting the wrong file. 842 */ 843 if (SFcurrentInvert[n] != -1) 844 { 845 XWarpPointer( 846 SFdisplay, 847 None, 848 XtWindow(selFileLists[n]), 849 0, 850 0, 851 0, 852 0, 853 0, 854 0); 855 } 856 857 for (i = dir->nEntries - 1; i >= 0; i--) 858 { 859 if (dir->entries[i].shown != dir->entries[i].real) 860 XtFree(dir->entries[i].shown); 861 XtFree(dir->entries[i].real); 862 } 863 XtFree((char *) dir->entries); 864 if (SFgetDir(dir)) 865 SFunreadableDir(dir); 866 if (dir->vOrigin > dir->nEntries - SFlistSize) 867 dir->vOrigin = dir->nEntries - SFlistSize; 868 if (dir->vOrigin < 0) 869 dir->vOrigin = 0; 870 if (dir->hOrigin > dir->nChars - SFcharsPerEntry) 871 dir->hOrigin = dir->nChars - SFcharsPerEntry; 872 if (dir->hOrigin < 0) 873 dir->hOrigin = 0; 874 dir->beginSelection = -1; 875 dir->endSelection = -1; 876 SFdoNotTouchVorigin = 1; 877 if ((dir + 1)->dir) 878 (void) SFfindFile(dir, (dir + 1)->dir); 879 else 880 (void) SFfindFile(dir, dir->path); 881 882 if (!SFworkProcAdded) 883 { 884 (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL); 885 SFworkProcAdded = 1; 886 } 887 return 1; 888 } 889 return 0; 890 } 891 892 static int 893 SFcheckFiles(SFDir *dir) 894 { 895 int from, to; 896 int result; 897 char oldc, newc; 898 int i; 899 char *str; 900 int last; 901 stat_T statBuf; 902 903 result = 0; 904 905 from = dir->vOrigin; 906 to = dir->vOrigin + SFlistSize; 907 if (to > dir->nEntries) 908 to = dir->nEntries; 909 910 for (i = from; i < to; i++) 911 { 912 str = dir->entries[i].real; 913 last = strlen(str) - 1; 914 oldc = str[last]; 915 str[last] = 0; 916 if (mch_stat(str, &statBuf)) 917 newc = ' '; 918 else 919 newc = SFstatChar(&statBuf); 920 str[last] = newc; 921 if (newc != oldc) 922 result = 1; 923 } 924 925 return result; 926 } 927 928 static void 929 SFdirModTimer(XtPointer cl UNUSED, XtIntervalId *id UNUSED) 930 { 931 static int n = -1; 932 static int f = 0; 933 char save; 934 SFDir *dir; 935 936 if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) 937 { 938 n++; 939 if ((n > 2) || (SFdirPtr + n >= SFdirEnd)) 940 { 941 n = 0; 942 f++; 943 if ((f > 2) || (SFdirPtr + f >= SFdirEnd)) 944 f = 0; 945 } 946 dir = &(SFdirs[SFdirPtr + n]); 947 save = *(dir->path); 948 *(dir->path) = 0; 949 if (SFchdir(SFcurrentPath)) 950 { 951 *(dir->path) = save; 952 953 /* 954 * force a re-read 955 */ 956 *(dir->dir) = 0; 957 958 SFupdatePath(); 959 } 960 else 961 { 962 *(dir->path) = save; 963 if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir))) 964 SFdrawList(n, SF_DO_SCROLL); 965 } 966 } 967 968 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000, 969 SFdirModTimer, (XtPointer) NULL); 970 } 971 972 /* Return a single character describing what kind of file STATBUF is. */ 973 974 static char 975 SFstatChar(stat_T *statBuf) 976 { 977 if (S_ISDIR (statBuf->st_mode)) 978 return '/'; 979 if (S_ISREG (statBuf->st_mode)) 980 return S_ISXXX (statBuf->st_mode) ? '*' : ' '; 981 #ifdef S_ISSOCK 982 if (S_ISSOCK (statBuf->st_mode)) 983 return '='; 984 #endif /* S_ISSOCK */ 985 return ' '; 986 } 987 988 /***************** Draw.c */ 989 990 #ifdef FEAT_GUI_NEXTAW 991 # include <X11/neXtaw/Cardinals.h> 992 #else 993 # include <X11/Xaw/Cardinals.h> 994 #endif 995 996 #ifdef FEAT_XFONTSET 997 # define SF_DEFAULT_FONT "-misc-fixed-medium-r-normal--14-*" 998 #else 999 # define SF_DEFAULT_FONT "9x15" 1000 #endif 1001 1002 #ifdef ABS 1003 # undef ABS 1004 #endif 1005 #define ABS(x) (((x) < 0) ? (-(x)) : (x)) 1006 1007 typedef struct 1008 { 1009 char *fontname; 1010 } TextData; 1011 1012 static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC; 1013 1014 static XtResource textResources[] = 1015 { 1016 #ifdef FEAT_XFONTSET 1017 {XtNfontSet, XtCFontSet, XtRString, sizeof (char *), 1018 XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT}, 1019 #else 1020 {XtNfont, XtCFont, XtRString, sizeof (char *), 1021 XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT}, 1022 #endif 1023 }; 1024 1025 #ifdef FEAT_XFONTSET 1026 static XFontSet SFfont; 1027 #else 1028 static XFontStruct *SFfont; 1029 #endif 1030 1031 static int SFcurrentListY; 1032 1033 static XtIntervalId SFscrollTimerId; 1034 1035 static void 1036 SFinitFont(void) 1037 { 1038 TextData *data; 1039 #ifdef FEAT_XFONTSET 1040 XFontSetExtents *extents; 1041 char **missing, *def_str; 1042 int num_missing; 1043 #endif 1044 1045 data = XtNew(TextData); 1046 1047 XtGetApplicationResources(selFileForm, (XtPointer) data, textResources, 1048 XtNumber(textResources), (Arg *) NULL, ZERO); 1049 1050 #ifdef FEAT_XFONTSET 1051 SFfont = XCreateFontSet(SFdisplay, data->fontname, 1052 &missing, &num_missing, &def_str); 1053 #else 1054 SFfont = XLoadQueryFont(SFdisplay, data->fontname); 1055 #endif 1056 if (!SFfont) 1057 { 1058 #ifdef FEAT_XFONTSET 1059 SFfont = XCreateFontSet(SFdisplay, SF_DEFAULT_FONT, 1060 &missing, &num_missing, &def_str); 1061 #else 1062 SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT); 1063 #endif 1064 if (!SFfont) 1065 { 1066 semsg(_("E616: vim_SelFile: can't get font %s"), SF_DEFAULT_FONT); 1067 SFstatus = SEL_FILE_CANCEL; 1068 return; 1069 } 1070 } 1071 1072 #ifdef FEAT_XFONTSET 1073 extents = XExtentsOfFontSet(SFfont); 1074 SFcharWidth = extents->max_logical_extent.width; 1075 SFcharAscent = -extents->max_logical_extent.y; 1076 SFcharHeight = extents->max_logical_extent.height; 1077 #else 1078 SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2; 1079 SFcharAscent = SFfont->max_bounds.ascent; 1080 SFcharHeight = SFcharAscent + SFfont->max_bounds.descent; 1081 #endif 1082 } 1083 1084 static void 1085 SFcreateGC(void) 1086 { 1087 XGCValues gcValues; 1088 XRectangle rectangles[1]; 1089 1090 gcValues.foreground = SFfore; 1091 1092 SFlineGC = XtGetGC( 1093 selFileLists[0], 1094 (XtGCMask)GCForeground, 1095 &gcValues); 1096 1097 SFscrollGC = XtGetGC( 1098 selFileLists[0], 1099 (XtGCMask)0, 1100 &gcValues); 1101 1102 gcValues.function = GXxor; 1103 gcValues.foreground = SFfore ^ SFback; 1104 gcValues.background = SFfore ^ SFback; 1105 1106 SFinvertGC = XtGetGC( 1107 selFileLists[0], 1108 (XtGCMask)GCFunction | GCForeground | GCBackground, 1109 &gcValues); 1110 1111 gcValues.foreground = SFfore; 1112 gcValues.background = SFback; 1113 #ifndef FEAT_XFONTSET 1114 gcValues.font = SFfont->fid; 1115 #endif 1116 1117 SFtextGC = XCreateGC( 1118 SFdisplay, 1119 XtWindow(selFileLists[0]), 1120 #ifdef FEAT_XFONTSET 1121 (unsigned long)GCForeground | GCBackground, 1122 #else 1123 (unsigned long)GCForeground | GCBackground | GCFont, 1124 #endif 1125 &gcValues); 1126 1127 rectangles[0].x = SFlineToTextH + SFbesideText; 1128 rectangles[0].y = 0; 1129 rectangles[0].width = SFcharsPerEntry * SFcharWidth; 1130 rectangles[0].height = SFupperY + 1; 1131 1132 XSetClipRectangles( 1133 SFdisplay, 1134 SFtextGC, 1135 0, 1136 0, 1137 rectangles, 1138 1, 1139 Unsorted); 1140 } 1141 1142 static void 1143 SFclearList(int n, int doScroll) 1144 { 1145 SFDir *dir; 1146 1147 SFcurrentInvert[n] = -1; 1148 1149 XClearWindow(SFdisplay, XtWindow(selFileLists[n])); 1150 1151 XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2); 1152 1153 if (doScroll) 1154 { 1155 dir = &(SFdirs[SFdirPtr + n]); 1156 1157 if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars) 1158 { 1159 #ifdef FEAT_GUI_NEXTAW 1160 XawScrollbarSetThumb( 1161 selFileVScrolls[n], 1162 (float) (((double) dir->vOrigin) / 1163 dir->nEntries), 1164 (float) (((double) ((dir->nEntries < SFlistSize) 1165 ? dir->nEntries : SFlistSize)) / 1166 dir->nEntries)); 1167 #else 1168 vim_XawScrollbarSetThumb( 1169 selFileVScrolls[n], 1170 (float) (((double) dir->vOrigin) / 1171 dir->nEntries), 1172 (float) (((double) ((dir->nEntries < SFlistSize) 1173 ? dir->nEntries : SFlistSize)) / 1174 dir->nEntries), 1175 (double)dir->nEntries); 1176 #endif 1177 1178 #ifdef FEAT_GUI_NEXTAW 1179 XawScrollbarSetThumb( 1180 selFileHScrolls[n], 1181 (float) (((double) dir->hOrigin) / dir->nChars), 1182 (float) (((double) ((dir->nChars < 1183 SFcharsPerEntry) ? dir->nChars : 1184 SFcharsPerEntry)) / dir->nChars)); 1185 #else 1186 vim_XawScrollbarSetThumb( 1187 selFileHScrolls[n], 1188 (float) (((double) dir->hOrigin) / dir->nChars), 1189 (float) (((double) ((dir->nChars < 1190 SFcharsPerEntry) ? dir->nChars : 1191 SFcharsPerEntry)) / dir->nChars), 1192 (double)dir->nChars); 1193 #endif 1194 } 1195 else 1196 { 1197 #ifdef FEAT_GUI_NEXTAW 1198 XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0, 1199 (float) 1.0); 1200 #else 1201 vim_XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0, 1202 (float) 1.0, 1.0); 1203 #endif 1204 #ifdef FEAT_GUI_NEXTAW 1205 XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0, 1206 (float) 1.0); 1207 #else 1208 vim_XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0, 1209 (float) 1.0, 1.0); 1210 #endif 1211 } 1212 } 1213 } 1214 1215 static void 1216 SFdeleteEntry(SFDir *dir, SFEntry *entry) 1217 { 1218 SFEntry *e; 1219 SFEntry *end; 1220 int n; 1221 int idx; 1222 1223 idx = entry - dir->entries; 1224 1225 if (idx < dir->beginSelection) 1226 dir->beginSelection--; 1227 if (idx <= dir->endSelection) 1228 dir->endSelection--; 1229 if (dir->beginSelection > dir->endSelection) 1230 dir->beginSelection = dir->endSelection = -1; 1231 1232 if (idx < dir->vOrigin) 1233 dir->vOrigin--; 1234 1235 XtFree(entry->real); 1236 1237 end = &(dir->entries[dir->nEntries - 1]); 1238 1239 for (e = entry; e < end; e++) 1240 *e = *(e + 1); 1241 1242 if (!(--dir->nEntries)) 1243 return; 1244 1245 n = dir - &(SFdirs[SFdirPtr]); 1246 if ((n < 0) || (n > 2)) 1247 return; 1248 1249 #ifdef FEAT_GUI_NEXTAW 1250 XawScrollbarSetThumb( 1251 selFileVScrolls[n], 1252 (float) (((double) dir->vOrigin) / dir->nEntries), 1253 (float) (((double) ((dir->nEntries < SFlistSize) ? 1254 dir->nEntries : SFlistSize)) / dir->nEntries)); 1255 #else 1256 vim_XawScrollbarSetThumb( 1257 selFileVScrolls[n], 1258 (float) (((double) dir->vOrigin) / dir->nEntries), 1259 (float) (((double) ((dir->nEntries < SFlistSize) ? 1260 dir->nEntries : SFlistSize)) / dir->nEntries), 1261 (double)dir->nEntries); 1262 #endif 1263 } 1264 1265 static void 1266 SFwriteStatChar( 1267 char *name, 1268 int last, 1269 stat_T *statBuf) 1270 { 1271 name[last] = SFstatChar(statBuf); 1272 } 1273 1274 static int 1275 SFstatAndCheck(SFDir *dir, SFEntry *entry) 1276 { 1277 stat_T statBuf; 1278 char save; 1279 int last; 1280 1281 /* 1282 * must be restored before returning 1283 */ 1284 save = *(dir->path); 1285 *(dir->path) = 0; 1286 1287 if (!SFchdir(SFcurrentPath)) 1288 { 1289 last = strlen(entry->real) - 1; 1290 entry->real[last] = 0; 1291 entry->statDone = 1; 1292 if ((!mch_stat(entry->real, &statBuf)) 1293 #ifdef S_IFLNK 1294 || (!mch_lstat(entry->real, &statBuf)) 1295 #endif 1296 ) 1297 { 1298 if (SFfunc) 1299 { 1300 char *shown; 1301 1302 shown = NULL; 1303 if (SFfunc(entry->real, &shown, &statBuf)) 1304 { 1305 if (shown) 1306 { 1307 int len; 1308 1309 len = strlen(shown); 1310 entry->shown = XtMalloc((unsigned)(len + 2)); 1311 (void) strcpy(entry->shown, shown); 1312 SFwriteStatChar(entry->shown, len, &statBuf); 1313 entry->shown[len + 1] = 0; 1314 } 1315 } 1316 else 1317 { 1318 SFdeleteEntry(dir, entry); 1319 1320 *(dir->path) = save; 1321 return 1; 1322 } 1323 } 1324 SFwriteStatChar(entry->real, last, &statBuf); 1325 } 1326 else 1327 entry->real[last] = ' '; 1328 } 1329 1330 *(dir->path) = save; 1331 return 0; 1332 } 1333 1334 1335 static void 1336 SFdrawStrings( 1337 Window w, 1338 SFDir *dir, 1339 int from, 1340 int to) 1341 { 1342 int i; 1343 SFEntry *entry; 1344 int x; 1345 1346 x = SFtextX - dir->hOrigin * SFcharWidth; 1347 1348 if (dir->vOrigin + to >= dir->nEntries) 1349 to = dir->nEntries - dir->vOrigin - 1; 1350 for (i = from; i <= to; i++) 1351 { 1352 entry = &(dir->entries[dir->vOrigin + i]); 1353 if (!(entry->statDone)) 1354 { 1355 if (SFstatAndCheck(dir, entry)) 1356 { 1357 if (dir->vOrigin + to >= dir->nEntries) 1358 to = dir->nEntries - dir->vOrigin - 1; 1359 i--; 1360 continue; 1361 } 1362 } 1363 #ifdef FEAT_XFONTSET 1364 XmbDrawImageString( 1365 SFdisplay, 1366 w, 1367 SFfont, 1368 SFtextGC, 1369 x, 1370 SFtextYoffset + i * SFentryHeight, 1371 entry->shown, 1372 strlen(entry->shown)); 1373 #else 1374 XDrawImageString( 1375 SFdisplay, 1376 w, 1377 SFtextGC, 1378 x, 1379 SFtextYoffset + i * SFentryHeight, 1380 entry->shown, 1381 strlen(entry->shown)); 1382 #endif 1383 if (dir->vOrigin + i == dir->beginSelection) 1384 { 1385 XDrawLine( 1386 SFdisplay, 1387 w, 1388 SFlineGC, 1389 SFlineToTextH + 1, 1390 SFlowerY + i * SFentryHeight, 1391 SFlineToTextH + SFentryWidth - 2, 1392 SFlowerY + i * SFentryHeight); 1393 } 1394 if ((dir->vOrigin + i >= dir->beginSelection) && 1395 (dir->vOrigin + i <= dir->endSelection)) 1396 { 1397 SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 = 1398 SFlowerY + i * SFentryHeight; 1399 SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 = 1400 SFlowerY + (i + 1) * SFentryHeight - 1; 1401 XDrawSegments( 1402 SFdisplay, 1403 w, 1404 SFlineGC, 1405 SFcompletionSegs, 1406 2); 1407 } 1408 if (dir->vOrigin + i == dir->endSelection) 1409 { 1410 XDrawLine( 1411 SFdisplay, 1412 w, 1413 SFlineGC, 1414 SFlineToTextH + 1, 1415 SFlowerY + (i + 1) * SFentryHeight - 1, 1416 SFlineToTextH + SFentryWidth - 2, 1417 SFlowerY + (i + 1) * SFentryHeight - 1); 1418 } 1419 } 1420 } 1421 1422 static void 1423 SFdrawList(int n, int doScroll) 1424 { 1425 SFDir *dir; 1426 Window w; 1427 1428 SFclearList(n, doScroll); 1429 1430 if (SFdirPtr + n < SFdirEnd) 1431 { 1432 dir = &(SFdirs[SFdirPtr + n]); 1433 w = XtWindow(selFileLists[n]); 1434 #ifdef FEAT_XFONTSET 1435 XmbDrawImageString( 1436 SFdisplay, 1437 w, 1438 SFfont, 1439 SFtextGC, 1440 SFtextX - dir->hOrigin * SFcharWidth, 1441 SFlineToTextV + SFaboveAndBelowText + SFcharAscent, 1442 dir->dir, 1443 strlen(dir->dir)); 1444 #else 1445 XDrawImageString( 1446 SFdisplay, 1447 w, 1448 SFtextGC, 1449 SFtextX - dir->hOrigin * SFcharWidth, 1450 SFlineToTextV + SFaboveAndBelowText + SFcharAscent, 1451 dir->dir, 1452 strlen(dir->dir)); 1453 #endif 1454 SFdrawStrings(w, dir, 0, SFlistSize - 1); 1455 } 1456 } 1457 1458 static void 1459 SFdrawLists(int doScroll) 1460 { 1461 int i; 1462 1463 for (i = 0; i < 3; i++) 1464 SFdrawList(i, doScroll); 1465 } 1466 1467 static void 1468 SFinvertEntry(int n) 1469 { 1470 XFillRectangle( 1471 SFdisplay, 1472 XtWindow(selFileLists[n]), 1473 SFinvertGC, 1474 SFlineToTextH, 1475 SFcurrentInvert[n] * SFentryHeight + SFlowerY, 1476 SFentryWidth, 1477 SFentryHeight); 1478 } 1479 1480 static unsigned long 1481 SFscrollTimerInterval(void) 1482 { 1483 static int maxVal = 200; 1484 static int varyDist = 50; 1485 static int minDist = 50; 1486 int t; 1487 int dist; 1488 1489 if (SFcurrentListY < SFlowerY) 1490 dist = SFlowerY - SFcurrentListY; 1491 else if (SFcurrentListY > SFupperY) 1492 dist = SFcurrentListY - SFupperY; 1493 else 1494 return (unsigned long) 1; 1495 1496 t = maxVal - ((maxVal / varyDist) * (dist - minDist)); 1497 1498 if (t < 1) 1499 t = 1; 1500 1501 if (t > maxVal) 1502 t = maxVal; 1503 1504 return (unsigned long)t; 1505 } 1506 1507 static void 1508 SFscrollTimer(XtPointer p, XtIntervalId *id UNUSED) 1509 { 1510 SFDir *dir; 1511 int save; 1512 int n; 1513 1514 n = (long)p; 1515 1516 dir = &(SFdirs[SFdirPtr + n]); 1517 save = dir->vOrigin; 1518 1519 if (SFcurrentListY < SFlowerY) 1520 { 1521 if (dir->vOrigin > 0) 1522 SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1); 1523 } 1524 else if (SFcurrentListY > SFupperY) 1525 { 1526 if (dir->vOrigin < dir->nEntries - SFlistSize) 1527 SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1); 1528 } 1529 1530 if (dir->vOrigin != save) 1531 { 1532 if (dir->nEntries) 1533 { 1534 #ifdef FEAT_GUI_NEXTAW 1535 XawScrollbarSetThumb( 1536 selFileVScrolls[n], 1537 (float) (((double) dir->vOrigin) / dir->nEntries), 1538 (float) (((double) ((dir->nEntries < SFlistSize) ? 1539 dir->nEntries : SFlistSize)) / dir->nEntries)); 1540 #else 1541 vim_XawScrollbarSetThumb( 1542 selFileVScrolls[n], 1543 (float) (((double) dir->vOrigin) / dir->nEntries), 1544 (float) (((double) ((dir->nEntries < SFlistSize) ? 1545 dir->nEntries : SFlistSize)) / dir->nEntries), 1546 (double)dir->nEntries); 1547 #endif 1548 } 1549 } 1550 1551 if (SFbuttonPressed) 1552 SFscrollTimerId = XtAppAddTimeOut(SFapp, 1553 SFscrollTimerInterval(), SFscrollTimer, 1554 (XtPointer)(long_u)n); 1555 } 1556 1557 static int 1558 SFnewInvertEntry(int n, XMotionEvent *event) 1559 { 1560 int x, y; 1561 int nw; 1562 static int SFscrollTimerAdded = 0; 1563 1564 x = event->x; 1565 y = event->y; 1566 1567 if (SFdirPtr + n >= SFdirEnd) 1568 return -1; 1569 1570 if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY)) 1571 { 1572 SFDir *dir = &(SFdirs[SFdirPtr + n]); 1573 1574 if (SFscrollTimerAdded) 1575 { 1576 SFscrollTimerAdded = 0; 1577 XtRemoveTimeOut(SFscrollTimerId); 1578 } 1579 1580 nw = (y - SFlowerY) / SFentryHeight; 1581 if (dir->vOrigin + nw >= dir->nEntries) 1582 return -1; 1583 return nw; 1584 } 1585 else 1586 { 1587 if (SFbuttonPressed) 1588 { 1589 SFcurrentListY = y; 1590 if (!SFscrollTimerAdded) 1591 { 1592 SFscrollTimerAdded = 1; 1593 SFscrollTimerId = XtAppAddTimeOut(SFapp, 1594 SFscrollTimerInterval(), SFscrollTimer, 1595 (XtPointer)(long_u)n); 1596 } 1597 } 1598 return -1; 1599 } 1600 } 1601 1602 static void 1603 SFenterList(Widget w UNUSED, int n, XEnterWindowEvent *event) 1604 { 1605 int nw; 1606 1607 /* sanity */ 1608 if (SFcurrentInvert[n] != -1) 1609 { 1610 SFinvertEntry(n); 1611 SFcurrentInvert[n] = -1; 1612 } 1613 1614 nw = SFnewInvertEntry(n, (XMotionEvent *) event); 1615 if (nw != -1) 1616 { 1617 SFcurrentInvert[n] = nw; 1618 SFinvertEntry(n); 1619 } 1620 } 1621 1622 static void 1623 SFleaveList(Widget w UNUSED, int n, XEvent *event UNUSED) 1624 { 1625 if (SFcurrentInvert[n] != -1) 1626 { 1627 SFinvertEntry(n); 1628 SFcurrentInvert[n] = -1; 1629 } 1630 } 1631 1632 static void 1633 SFmotionList(Widget w UNUSED, int n, XMotionEvent *event) 1634 { 1635 int nw; 1636 1637 nw = SFnewInvertEntry(n, event); 1638 1639 if (nw != SFcurrentInvert[n]) 1640 { 1641 if (SFcurrentInvert[n] != -1) 1642 SFinvertEntry(n); 1643 SFcurrentInvert[n] = nw; 1644 if (nw != -1) 1645 SFinvertEntry(n); 1646 } 1647 } 1648 1649 static void 1650 SFvFloatSliderMovedCallback(Widget w, XtPointer n, XtPointer fnew) 1651 { 1652 int nw; 1653 1654 nw = (*(float *)fnew) * SFdirs[SFdirPtr + (int)(long)n].nEntries; 1655 SFvSliderMovedCallback(w, (int)(long)n, nw); 1656 } 1657 1658 static void 1659 SFvSliderMovedCallback(Widget w UNUSED, int n, int nw) 1660 { 1661 int old; 1662 Window win; 1663 SFDir *dir; 1664 1665 dir = &(SFdirs[SFdirPtr + n]); 1666 1667 old = dir->vOrigin; 1668 dir->vOrigin = nw; 1669 1670 if (old == nw) 1671 return; 1672 1673 win = XtWindow(selFileLists[n]); 1674 1675 if (ABS(nw - old) < SFlistSize) 1676 { 1677 if (nw > old) 1678 { 1679 XCopyArea( 1680 SFdisplay, 1681 win, 1682 win, 1683 SFscrollGC, 1684 SFlineToTextH, 1685 SFlowerY + (nw - old) * SFentryHeight, 1686 SFentryWidth + SFlineToTextH, 1687 (SFlistSize - (nw - old)) * SFentryHeight, 1688 SFlineToTextH, 1689 SFlowerY); 1690 XClearArea( 1691 SFdisplay, 1692 win, 1693 SFlineToTextH, 1694 SFlowerY + (SFlistSize - (nw - old)) * 1695 SFentryHeight, 1696 SFentryWidth + SFlineToTextH, 1697 (nw - old) * SFentryHeight, 1698 False); 1699 SFdrawStrings(win, dir, SFlistSize - (nw - old), 1700 SFlistSize - 1); 1701 } 1702 else 1703 { 1704 XCopyArea( 1705 SFdisplay, 1706 win, 1707 win, 1708 SFscrollGC, 1709 SFlineToTextH, 1710 SFlowerY, 1711 SFentryWidth + SFlineToTextH, 1712 (SFlistSize - (old - nw)) * SFentryHeight, 1713 SFlineToTextH, 1714 SFlowerY + (old - nw) * SFentryHeight); 1715 XClearArea( 1716 SFdisplay, 1717 win, 1718 SFlineToTextH, 1719 SFlowerY, 1720 SFentryWidth + SFlineToTextH, 1721 (old - nw) * SFentryHeight, 1722 False); 1723 SFdrawStrings(win, dir, 0, old - nw); 1724 } 1725 } 1726 else 1727 { 1728 XClearArea( 1729 SFdisplay, 1730 win, 1731 SFlineToTextH, 1732 SFlowerY, 1733 SFentryWidth + SFlineToTextH, 1734 SFlistSize * SFentryHeight, 1735 False); 1736 SFdrawStrings(win, dir, 0, SFlistSize - 1); 1737 } 1738 } 1739 1740 static void 1741 SFvAreaSelectedCallback(Widget w, XtPointer n, XtPointer pnew) 1742 { 1743 SFDir *dir; 1744 int nw = (int)(long)pnew; 1745 1746 dir = &(SFdirs[SFdirPtr + (int)(long)n]); 1747 1748 #ifdef FEAT_GUI_NEXTAW 1749 if (nw < 0) 1750 { 1751 if (nw > -SFvScrollHeight) 1752 nw = -1; 1753 else 1754 nw = -SFlistSize; 1755 } 1756 else if (nw > 0) 1757 { 1758 if (nw < SFvScrollHeight) 1759 nw = 1; 1760 else 1761 nw = SFlistSize; 1762 } 1763 #endif 1764 nw += dir->vOrigin; 1765 1766 if (nw > dir->nEntries - SFlistSize) 1767 nw = dir->nEntries - SFlistSize; 1768 1769 if (nw < 0) 1770 nw = 0; 1771 1772 if (dir->nEntries) 1773 { 1774 float f; 1775 1776 f = ((double) nw) / dir->nEntries; 1777 1778 #ifdef FEAT_GUI_NEXTAW 1779 XawScrollbarSetThumb( 1780 w, 1781 f, 1782 (float) (((double) ((dir->nEntries < SFlistSize) ? 1783 dir->nEntries : SFlistSize)) / dir->nEntries)); 1784 #else 1785 vim_XawScrollbarSetThumb( 1786 w, 1787 f, 1788 (float) (((double) ((dir->nEntries < SFlistSize) ? 1789 dir->nEntries : SFlistSize)) / dir->nEntries), 1790 (double)dir->nEntries); 1791 #endif 1792 } 1793 1794 SFvSliderMovedCallback(w, (int)(long)n, nw); 1795 } 1796 1797 static void 1798 SFhSliderMovedCallback(Widget w UNUSED, XtPointer n, XtPointer nw) 1799 { 1800 SFDir *dir; 1801 int save; 1802 1803 dir = &(SFdirs[SFdirPtr + (int)(long)n]); 1804 save = dir->hOrigin; 1805 dir->hOrigin = (*(float *)nw) * dir->nChars; 1806 if (dir->hOrigin == save) 1807 return; 1808 1809 SFdrawList((int)(long)n, SF_DO_NOT_SCROLL); 1810 } 1811 1812 static void 1813 SFhAreaSelectedCallback(Widget w, XtPointer n, XtPointer pnew) 1814 { 1815 SFDir *dir; 1816 int nw = (int)(long)pnew; 1817 1818 dir = &(SFdirs[SFdirPtr + (int)(long)n]); 1819 1820 #ifdef FEAT_GUI_NEXTAW 1821 if (nw < 0) 1822 { 1823 if (nw > -SFhScrollWidth) 1824 nw = -1; 1825 else 1826 nw = -SFcharsPerEntry; 1827 } 1828 else if (nw > 0) 1829 { 1830 if (nw < SFhScrollWidth) 1831 nw = 1; 1832 else 1833 nw = SFcharsPerEntry; 1834 } 1835 #endif 1836 nw += dir->hOrigin; 1837 1838 if (nw > dir->nChars - SFcharsPerEntry) 1839 nw = dir->nChars - SFcharsPerEntry; 1840 1841 if (nw < 0) 1842 nw = 0; 1843 1844 if (dir->nChars) 1845 { 1846 float f; 1847 1848 f = ((double) nw) / dir->nChars; 1849 1850 #ifdef FEAT_GUI_NEXTAW 1851 XawScrollbarSetThumb( 1852 w, 1853 f, 1854 (float) (((double) ((dir->nChars < SFcharsPerEntry) ? 1855 dir->nChars : SFcharsPerEntry)) / dir->nChars)); 1856 #else 1857 vim_XawScrollbarSetThumb( 1858 w, 1859 f, 1860 (float) (((double) ((dir->nChars < SFcharsPerEntry) ? 1861 dir->nChars : SFcharsPerEntry)) / dir->nChars), 1862 (double)dir->nChars); 1863 #endif 1864 1865 SFhSliderMovedCallback(w, n, (XtPointer)&f); 1866 } 1867 } 1868 1869 static void 1870 SFpathSliderMovedCallback( 1871 Widget w UNUSED, 1872 XtPointer client_data UNUSED, 1873 XtPointer nw) 1874 { 1875 SFDir *dir; 1876 int n; 1877 XawTextPosition pos; 1878 int SFdirPtrSave; 1879 1880 SFdirPtrSave = SFdirPtr; 1881 SFdirPtr = (*(float *)nw) * SFdirEnd; 1882 if (SFdirPtr == SFdirPtrSave) 1883 return; 1884 1885 SFdrawLists(SF_DO_SCROLL); 1886 1887 n = 2; 1888 while (SFdirPtr + n >= SFdirEnd) 1889 n--; 1890 1891 dir = &(SFdirs[SFdirPtr + n]); 1892 1893 pos = dir->path - SFcurrentPath; 1894 1895 if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) 1896 { 1897 pos -= strlen(SFstartDir); 1898 if (pos < 0) 1899 pos = 0; 1900 } 1901 1902 XawTextSetInsertionPoint(selFileField, pos); 1903 } 1904 1905 static void 1906 SFpathAreaSelectedCallback( 1907 Widget w, 1908 XtPointer client_data UNUSED, 1909 XtPointer pnew) 1910 { 1911 int nw = (int)(long)pnew; 1912 float f; 1913 1914 #ifdef FEAT_GUI_NEXTAW 1915 if (nw < 0) 1916 { 1917 if (nw > -SFpathScrollWidth) 1918 nw = -1; 1919 else 1920 nw = -3; 1921 } 1922 else if (nw > 0) 1923 { 1924 if (nw < SFpathScrollWidth) 1925 nw = 1; 1926 else 1927 nw = 3; 1928 } 1929 #endif 1930 nw += SFdirPtr; 1931 1932 if (nw > SFdirEnd - 3) 1933 nw = SFdirEnd - 3; 1934 1935 if (nw < 0) 1936 nw = 0; 1937 1938 f = ((double) nw) / SFdirEnd; 1939 1940 #ifdef FEAT_GUI_NEXTAW 1941 XawScrollbarSetThumb( 1942 w, 1943 f, 1944 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd)); 1945 #else 1946 vim_XawScrollbarSetThumb( 1947 w, 1948 f, 1949 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd), 1950 (double)SFdirEnd); 1951 #endif 1952 1953 SFpathSliderMovedCallback(w, (XtPointer) NULL, (XtPointer)&f); 1954 } 1955 1956 static Boolean 1957 SFworkProc(void) 1958 { 1959 SFDir *dir; 1960 SFEntry *entry; 1961 1962 for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) 1963 { 1964 if (!(dir->nEntries)) 1965 continue; 1966 for (entry = &(dir->entries[dir->nEntries - 1]); 1967 entry >= dir->entries; 1968 entry--) 1969 { 1970 if (!(entry->statDone)) 1971 { 1972 (void)SFstatAndCheck(dir, entry); 1973 return False; 1974 } 1975 } 1976 } 1977 1978 SFworkProcAdded = 0; 1979 1980 return True; 1981 } 1982 1983 /***************** Dir.c */ 1984 1985 static int 1986 SFcompareEntries(const void *p, const void *q) 1987 { 1988 return strcmp(((SFEntry *)p)->real, ((SFEntry *)q)->real); 1989 } 1990 1991 static int 1992 SFgetDir( 1993 SFDir *dir) 1994 { 1995 SFEntry *result = NULL; 1996 int Alloc = 0; 1997 int i; 1998 DIR *dirp; 1999 struct dirent *dp; 2000 char *str; 2001 int len; 2002 int maxChars; 2003 stat_T statBuf; 2004 2005 maxChars = strlen(dir->dir) - 1; 2006 2007 dir->entries = NULL; 2008 dir->nEntries = 0; 2009 dir->nChars = 0; 2010 2011 result = NULL; 2012 i = 0; 2013 2014 dirp = opendir("."); 2015 if (!dirp) 2016 return 1; 2017 2018 (void)mch_stat(".", &statBuf); 2019 dir->mtime = statBuf.st_mtime; 2020 2021 while ((dp = readdir(dirp))) 2022 { 2023 /* Ignore "." and ".." */ 2024 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) 2025 continue; 2026 if (i >= Alloc) 2027 { 2028 Alloc = 2 * (Alloc + 1); 2029 result = (SFEntry *) XtRealloc((char *) result, 2030 (unsigned) (Alloc * sizeof(SFEntry))); 2031 } 2032 result[i].statDone = 0; 2033 str = dp->d_name; 2034 len = strlen(str); 2035 result[i].real = XtMalloc((unsigned)(len + 2)); 2036 (void) strcat(strcpy(result[i].real, str), " "); 2037 if (len > maxChars) 2038 maxChars = len; 2039 result[i].shown = result[i].real; 2040 i++; 2041 } 2042 2043 qsort((char *) result, (size_t) i, sizeof(SFEntry), SFcompareEntries); 2044 2045 dir->entries = result; 2046 dir->nEntries = i; 2047 dir->nChars = maxChars + 1; 2048 2049 closedir(dirp); 2050 2051 return 0; 2052 } 2053 2054 /***************** SFinternal.h */ 2055 2056 #include <sys/param.h> 2057 #include <X11/cursorfont.h> 2058 #include <X11/Composite.h> 2059 #include <X11/Shell.h> 2060 #ifdef FEAT_GUI_NEXTAW 2061 # include <X11/neXtaw/Form.h> 2062 # include <X11/neXtaw/Command.h> 2063 # include <X11/neXtaw/Label.h> 2064 #else 2065 #include <X11/Xaw/Form.h> 2066 #include <X11/Xaw/Command.h> 2067 #include <X11/Xaw/Label.h> 2068 #endif 2069 2070 static char *oneLineTextEditTranslations = "\ 2071 <Key>Return: redraw-display()\n\ 2072 Ctrl<Key>M: redraw-display()\n\ 2073 "; 2074 2075 static void 2076 SFexposeList( 2077 Widget w UNUSED, 2078 XtPointer n, 2079 XEvent *event, 2080 Boolean *cont UNUSED) 2081 { 2082 if ((event->type == NoExpose) || event->xexpose.count) 2083 return; 2084 2085 SFdrawList((int)(long)n, SF_DO_NOT_SCROLL); 2086 } 2087 2088 static void 2089 SFmodVerifyCallback( 2090 Widget w UNUSED, 2091 XtPointer client_data UNUSED, 2092 XEvent *event, 2093 Boolean *cont UNUSED) 2094 { 2095 char buf[2]; 2096 2097 if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) && 2098 ((*buf) == '\r')) 2099 SFstatus = SEL_FILE_OK; 2100 else 2101 SFstatus = SEL_FILE_TEXT; 2102 } 2103 2104 static void 2105 SFokCallback(Widget w UNUSED, XtPointer cl UNUSED, XtPointer cd UNUSED) 2106 { 2107 SFstatus = SEL_FILE_OK; 2108 } 2109 2110 static XtCallbackRec SFokSelect[] = 2111 { 2112 { SFokCallback, (XtPointer) NULL }, 2113 { NULL, (XtPointer) NULL }, 2114 }; 2115 2116 static void 2117 SFcancelCallback(Widget w UNUSED, XtPointer cl UNUSED, XtPointer cd UNUSED) 2118 { 2119 SFstatus = SEL_FILE_CANCEL; 2120 } 2121 2122 static XtCallbackRec SFcancelSelect[] = 2123 { 2124 { SFcancelCallback, (XtPointer) NULL }, 2125 { NULL, (XtPointer) NULL }, 2126 }; 2127 2128 static void 2129 SFdismissAction( 2130 Widget w UNUSED, 2131 XEvent *event, 2132 String *params UNUSED, 2133 Cardinal *num_params UNUSED) 2134 { 2135 if (event->type == ClientMessage 2136 && (Atom)event->xclient.data.l[0] != SFwmDeleteWindow) 2137 return; 2138 2139 SFstatus = SEL_FILE_CANCEL; 2140 } 2141 2142 static char *wmDeleteWindowTranslation = "\ 2143 <Message>WM_PROTOCOLS: SelFileDismiss()\n\ 2144 "; 2145 2146 static XtActionsRec actions[] = 2147 { 2148 {"SelFileDismiss", SFdismissAction}, 2149 }; 2150 2151 static void 2152 SFsetColors( 2153 guicolor_T bg, 2154 guicolor_T fg, 2155 guicolor_T scroll_bg, 2156 guicolor_T scroll_fg) 2157 { 2158 if (selFileForm) 2159 { 2160 XtVaSetValues(selFileForm, XtNbackground, bg, 2161 XtNforeground, fg, 2162 XtNborderColor, bg, 2163 NULL); 2164 } 2165 { 2166 int i; 2167 2168 for (i = 0; i < 3; ++i) 2169 { 2170 if (selFileLists[i]) 2171 { 2172 XtVaSetValues(selFileLists[i], XtNbackground, bg, 2173 XtNforeground, fg, 2174 XtNborderColor, fg, 2175 NULL); 2176 } 2177 } 2178 } 2179 if (selFileOK) 2180 { 2181 XtVaSetValues(selFileOK, XtNbackground, bg, 2182 XtNforeground, fg, 2183 XtNborderColor, fg, 2184 NULL); 2185 } 2186 if (selFileCancel) 2187 { 2188 XtVaSetValues(selFileCancel, XtNbackground, bg, 2189 XtNforeground, fg, 2190 XtNborderColor, fg, 2191 NULL); 2192 } 2193 if (selFilePrompt) 2194 { 2195 XtVaSetValues(selFilePrompt, XtNbackground, bg, 2196 XtNforeground, fg, 2197 NULL); 2198 } 2199 if (gui.dpy) 2200 { 2201 XSetBackground(gui.dpy, SFtextGC, bg); 2202 XSetForeground(gui.dpy, SFtextGC, fg); 2203 XSetForeground(gui.dpy, SFlineGC, fg); 2204 2205 /* This is an xor GC, so combine the fg and background */ 2206 XSetBackground(gui.dpy, SFinvertGC, fg ^ bg); 2207 XSetForeground(gui.dpy, SFinvertGC, fg ^ bg); 2208 } 2209 if (selFileHScroll) 2210 { 2211 XtVaSetValues(selFileHScroll, XtNbackground, scroll_bg, 2212 XtNforeground, scroll_fg, 2213 XtNborderColor, fg, 2214 NULL); 2215 } 2216 { 2217 int i; 2218 2219 for (i = 0; i < 3; i++) 2220 { 2221 XtVaSetValues(selFileVScrolls[i], XtNbackground, scroll_bg, 2222 XtNforeground, scroll_fg, 2223 XtNborderColor, fg, 2224 NULL); 2225 XtVaSetValues(selFileHScrolls[i], XtNbackground, scroll_bg, 2226 XtNforeground, scroll_fg, 2227 XtNborderColor, fg, 2228 NULL); 2229 } 2230 } 2231 } 2232 2233 static void 2234 SFcreateWidgets( 2235 Widget toplevel, 2236 char *prompt, 2237 char *ok, 2238 char *cancel) 2239 { 2240 Cardinal n; 2241 int listWidth, listHeight; 2242 int listSpacing = 10; 2243 int scrollThickness = 15; 2244 int hScrollX, hScrollY; 2245 int vScrollX, vScrollY; 2246 2247 selFile = XtVaAppCreateShell("selFile", "SelFile", 2248 transientShellWidgetClass, SFdisplay, 2249 XtNtransientFor, toplevel, 2250 XtNtitle, prompt, 2251 NULL); 2252 2253 /* Add WM_DELETE_WINDOW protocol */ 2254 XtAppAddActions(XtWidgetToApplicationContext(selFile), 2255 actions, XtNumber(actions)); 2256 XtOverrideTranslations(selFile, 2257 XtParseTranslationTable(wmDeleteWindowTranslation)); 2258 2259 selFileForm = XtVaCreateManagedWidget("selFileForm", 2260 formWidgetClass, selFile, 2261 XtNdefaultDistance, 30, 2262 XtNforeground, SFfore, 2263 XtNbackground, SFback, 2264 XtNborderColor, SFback, 2265 NULL); 2266 2267 selFilePrompt = XtVaCreateManagedWidget("selFilePrompt", 2268 labelWidgetClass, selFileForm, 2269 XtNlabel, prompt, 2270 XtNresizable, True, 2271 XtNtop, XtChainTop, 2272 XtNbottom, XtChainTop, 2273 XtNleft, XtChainLeft, 2274 XtNright, XtChainLeft, 2275 XtNborderWidth, 0, 2276 XtNforeground, SFfore, 2277 XtNbackground, SFback, 2278 NULL); 2279 2280 /* 2281 XtVaGetValues(selFilePrompt, 2282 XtNforeground, &SFfore, 2283 XtNbackground, &SFback, 2284 NULL); 2285 */ 2286 2287 SFinitFont(); 2288 2289 SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth + 2290 SFbesideText; 2291 SFentryHeight = SFaboveAndBelowText + SFcharHeight + 2292 SFaboveAndBelowText; 2293 2294 listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 + 2295 scrollThickness; 2296 listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + 2297 SFlineToTextV + SFlistSize * SFentryHeight + 2298 SFlineToTextV + 1 + scrollThickness; 2299 2300 SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4; 2301 2302 hScrollX = -1; 2303 hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + 2304 SFlineToTextV + SFlistSize * SFentryHeight + 2305 SFlineToTextV; 2306 SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH; 2307 2308 vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH; 2309 vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV; 2310 SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight + 2311 SFlineToTextV; 2312 2313 SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1; 2314 SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + 2315 SFlineToTextV; 2316 SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + 2317 SFlineToTextV + SFlistSize * SFentryHeight - 1; 2318 2319 SFtextX = SFlineToTextH + SFbesideText; 2320 SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent; 2321 2322 SFsegs[0].x1 = 0; 2323 SFsegs[0].y1 = vScrollY; 2324 SFsegs[0].x2 = vScrollX - 1; 2325 SFsegs[0].y2 = vScrollY; 2326 SFsegs[1].x1 = vScrollX; 2327 SFsegs[1].y1 = 0; 2328 SFsegs[1].x2 = vScrollX; 2329 SFsegs[1].y2 = vScrollY - 1; 2330 2331 SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH; 2332 SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 = 2333 SFlineToTextH + SFentryWidth - 1; 2334 2335 selFileField = XtVaCreateManagedWidget("selFileField", 2336 asciiTextWidgetClass, selFileForm, 2337 XtNwidth, 3 * listWidth + 2 * listSpacing + 4, 2338 XtNborderColor, SFfore, 2339 XtNfromVert, selFilePrompt, 2340 XtNvertDistance, 10, 2341 XtNresizable, True, 2342 XtNtop, XtChainTop, 2343 XtNbottom, XtChainTop, 2344 XtNleft, XtChainLeft, 2345 XtNright, XtChainLeft, 2346 XtNstring, SFtextBuffer, 2347 XtNlength, MAXPATHL, 2348 XtNeditType, XawtextEdit, 2349 XtNwrap, XawtextWrapWord, 2350 XtNresize, XawtextResizeHeight, 2351 XtNuseStringInPlace, True, 2352 NULL); 2353 2354 XtOverrideTranslations(selFileField, 2355 XtParseTranslationTable(oneLineTextEditTranslations)); 2356 XtSetKeyboardFocus(selFileForm, selFileField); 2357 2358 selFileHScroll = XtVaCreateManagedWidget("selFileHScroll", 2359 #ifdef FEAT_GUI_NEXTAW 2360 scrollbarWidgetClass, selFileForm, 2361 #else 2362 vim_scrollbarWidgetClass, selFileForm, 2363 #endif 2364 XtNorientation, XtorientHorizontal, 2365 XtNwidth, SFpathScrollWidth, 2366 XtNheight, scrollThickness, 2367 XtNborderColor, SFfore, 2368 XtNfromVert, selFileField, 2369 XtNvertDistance, 30, 2370 XtNtop, XtChainTop, 2371 XtNbottom, XtChainTop, 2372 XtNleft, XtChainLeft, 2373 XtNright, XtChainLeft, 2374 XtNforeground, gui.scroll_fg_pixel, 2375 XtNbackground, gui.scroll_bg_pixel, 2376 #ifndef FEAT_GUI_NEXTAW 2377 XtNlimitThumb, 1, 2378 #endif 2379 NULL); 2380 2381 XtAddCallback(selFileHScroll, XtNjumpProc, 2382 (XtCallbackProc) SFpathSliderMovedCallback, (XtPointer)NULL); 2383 XtAddCallback(selFileHScroll, XtNscrollProc, 2384 (XtCallbackProc) SFpathAreaSelectedCallback, (XtPointer)NULL); 2385 2386 selFileLists[0] = XtVaCreateManagedWidget("selFileList1", 2387 compositeWidgetClass, selFileForm, 2388 XtNwidth, listWidth, 2389 XtNheight, listHeight, 2390 XtNforeground, SFfore, 2391 XtNbackground, SFback, 2392 XtNborderColor, SFfore, 2393 XtNfromVert, selFileHScroll, 2394 XtNvertDistance, 10, 2395 XtNtop, XtChainTop, 2396 XtNbottom, XtChainTop, 2397 XtNleft, XtChainLeft, 2398 XtNright, XtChainLeft, 2399 NULL); 2400 2401 selFileLists[1] = XtVaCreateManagedWidget("selFileList2", 2402 compositeWidgetClass, selFileForm, 2403 XtNwidth, listWidth, 2404 XtNheight, listHeight, 2405 XtNforeground, SFfore, 2406 XtNbackground, SFback, 2407 XtNborderColor, SFfore, 2408 XtNfromHoriz, selFileLists[0], 2409 XtNfromVert, selFileHScroll, 2410 XtNhorizDistance, listSpacing, 2411 XtNvertDistance, 10, 2412 XtNtop, XtChainTop, 2413 XtNbottom, XtChainTop, 2414 XtNleft, XtChainLeft, 2415 XtNright, XtChainLeft, 2416 NULL); 2417 2418 selFileLists[2] = XtVaCreateManagedWidget("selFileList3", 2419 compositeWidgetClass, selFileForm, 2420 XtNwidth, listWidth, 2421 XtNheight, listHeight, 2422 XtNforeground, SFfore, 2423 XtNbackground, SFback, 2424 XtNborderColor, SFfore, 2425 XtNfromHoriz, selFileLists[1], 2426 XtNfromVert, selFileHScroll, 2427 XtNhorizDistance, listSpacing, 2428 XtNvertDistance, 10, 2429 XtNtop, XtChainTop, 2430 XtNbottom, XtChainTop, 2431 XtNleft, XtChainLeft, 2432 XtNright, XtChainLeft, 2433 NULL); 2434 2435 for (n = 0; n < 3; n++) 2436 { 2437 selFileVScrolls[n] = XtVaCreateManagedWidget("selFileVScroll", 2438 #ifdef FEAT_GUI_NEXTAW 2439 scrollbarWidgetClass, selFileLists[n], 2440 #else 2441 vim_scrollbarWidgetClass, selFileLists[n], 2442 #endif 2443 XtNx, vScrollX, 2444 XtNy, vScrollY, 2445 XtNwidth, scrollThickness, 2446 XtNheight, SFvScrollHeight, 2447 XtNborderColor, SFfore, 2448 XtNforeground, gui.scroll_fg_pixel, 2449 XtNbackground, gui.scroll_bg_pixel, 2450 #ifndef FEAT_GUI_NEXTAW 2451 XtNlimitThumb, 1, 2452 #endif 2453 NULL); 2454 2455 XtAddCallback(selFileVScrolls[n], XtNjumpProc, 2456 (XtCallbackProc)SFvFloatSliderMovedCallback, 2457 (XtPointer)(long_u)n); 2458 XtAddCallback(selFileVScrolls[n], XtNscrollProc, 2459 (XtCallbackProc)SFvAreaSelectedCallback, (XtPointer)(long_u)n); 2460 2461 selFileHScrolls[n] = XtVaCreateManagedWidget("selFileHScroll", 2462 #ifdef FEAT_GUI_NEXTAW 2463 scrollbarWidgetClass, selFileLists[n], 2464 #else 2465 vim_scrollbarWidgetClass, selFileLists[n], 2466 #endif 2467 XtNorientation, XtorientHorizontal, 2468 XtNx, hScrollX, 2469 XtNy, hScrollY, 2470 XtNwidth, SFhScrollWidth, 2471 XtNheight, scrollThickness, 2472 XtNborderColor, SFfore, 2473 XtNforeground, gui.scroll_fg_pixel, 2474 XtNbackground, gui.scroll_bg_pixel, 2475 #ifndef FEAT_GUI_NEXTAW 2476 XtNlimitThumb, 1, 2477 #endif 2478 NULL); 2479 2480 XtAddCallback(selFileHScrolls[n], XtNjumpProc, 2481 (XtCallbackProc)SFhSliderMovedCallback, 2482 (XtPointer)(long_u)n); 2483 XtAddCallback(selFileHScrolls[n], XtNscrollProc, 2484 (XtCallbackProc)SFhAreaSelectedCallback, (XtPointer)(long_u)n); 2485 } 2486 2487 selFileOK = XtVaCreateManagedWidget("selFileOK", 2488 commandWidgetClass, selFileForm, 2489 XtNlabel, ok, 2490 XtNresizable, True, 2491 XtNcallback, SFokSelect, 2492 XtNforeground, SFfore, 2493 XtNbackground, SFback, 2494 XtNborderColor, SFfore, 2495 XtNfromHoriz, selFileLists[0], 2496 XtNfromVert, selFileLists[0], 2497 XtNvertDistance, 30, 2498 XtNtop, XtChainTop, 2499 XtNbottom, XtChainTop, 2500 XtNleft, XtChainLeft, 2501 XtNright, XtChainLeft, 2502 NULL); 2503 2504 selFileCancel = XtVaCreateManagedWidget("selFileCancel", 2505 commandWidgetClass, selFileForm, 2506 XtNlabel, cancel, 2507 XtNresizable, True, 2508 XtNcallback, SFcancelSelect, 2509 XtNforeground, SFfore, 2510 XtNbackground, SFback, 2511 XtNborderColor, SFfore, 2512 XtNfromHoriz, selFileOK, 2513 XtNfromVert, selFileLists[0], 2514 XtNhorizDistance, 30, 2515 XtNvertDistance, 30, 2516 XtNtop, XtChainTop, 2517 XtNbottom, XtChainTop, 2518 XtNleft, XtChainLeft, 2519 XtNright, XtChainLeft, 2520 NULL); 2521 2522 XtSetMappedWhenManaged(selFile, False); 2523 XtRealizeWidget(selFile); 2524 2525 /* Add WM_DELETE_WINDOW protocol */ 2526 SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False); 2527 XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1); 2528 2529 SFcreateGC(); 2530 2531 for (n = 0; n < 3; n++) 2532 { 2533 XtAddEventHandler(selFileLists[n], ExposureMask, True, 2534 (XtEventHandler)SFexposeList, (XtPointer)(long_u)n); 2535 XtAddEventHandler(selFileLists[n], EnterWindowMask, False, 2536 (XtEventHandler)SFenterList, (XtPointer)(long_u)n); 2537 XtAddEventHandler(selFileLists[n], LeaveWindowMask, False, 2538 (XtEventHandler)SFleaveList, (XtPointer)(long_u)n); 2539 XtAddEventHandler(selFileLists[n], PointerMotionMask, False, 2540 (XtEventHandler)SFmotionList, (XtPointer)(long_u)n); 2541 XtAddEventHandler(selFileLists[n], ButtonPressMask, False, 2542 (XtEventHandler)SFbuttonPressList, (XtPointer)(long_u)n); 2543 XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False, 2544 (XtEventHandler)SFbuttonReleaseList, (XtPointer)(long_u)n); 2545 } 2546 2547 XtAddEventHandler(selFileField, KeyPressMask, False, 2548 SFmodVerifyCallback, (XtPointer)NULL); 2549 2550 SFapp = XtWidgetToApplicationContext(selFile); 2551 } 2552 2553 static void 2554 SFtextChanged(void) 2555 { 2556 #if defined(FEAT_XFONTSET) && defined(XtNinternational) 2557 if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide) 2558 { 2559 wchar_t *wcbuf=(wchar_t *)SFtextBuffer; 2560 2561 if ((wcbuf[0] == L'/') || (wcbuf[0] == L'~')) 2562 { 2563 (void) wcstombs(SFcurrentPath, wcbuf, MAXPATHL); 2564 SFtextPos = XawTextGetInsertionPoint(selFileField); 2565 } 2566 else 2567 { 2568 strcpy(SFcurrentPath, SFstartDir); 2569 (void) wcstombs(SFcurrentPath + strlen(SFcurrentPath), wcbuf, MAXPATHL); 2570 2571 SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir); 2572 } 2573 } 2574 else 2575 #endif 2576 if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~')) 2577 { 2578 (void) strcpy(SFcurrentPath, SFtextBuffer); 2579 SFtextPos = XawTextGetInsertionPoint(selFileField); 2580 } 2581 else 2582 { 2583 (void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer); 2584 2585 SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir); 2586 } 2587 2588 if (!SFworkProcAdded) 2589 { 2590 (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL); 2591 SFworkProcAdded = 1; 2592 } 2593 2594 SFupdatePath(); 2595 } 2596 2597 static char * 2598 SFgetText(void) 2599 { 2600 #if defined(FEAT_XFONTSET) && defined(XtNinternational) 2601 char *buf; 2602 2603 if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide) 2604 { 2605 wchar_t *wcbuf; 2606 int mbslength; 2607 2608 XtVaGetValues(selFileField, 2609 XtNstring, &wcbuf, 2610 NULL); 2611 mbslength = wcstombs(NULL, wcbuf, 0); 2612 /* Hack: some broken wcstombs() returns zero, just get a large buffer */ 2613 if (mbslength == 0 && wcbuf != NULL && wcbuf[0] != 0) 2614 mbslength = MAXPATHL; 2615 buf=(char *)XtMalloc(mbslength + 1); 2616 wcstombs(buf, wcbuf, mbslength +1); 2617 return buf; 2618 } 2619 #endif 2620 return (char *)vim_strsave((char_u *)SFtextBuffer); 2621 } 2622 2623 static void 2624 SFprepareToReturn(void) 2625 { 2626 SFstatus = SEL_FILE_NULL; 2627 XtRemoveGrab(selFile); 2628 XtUnmapWidget(selFile); 2629 XtRemoveTimeOut(SFdirModTimerId); 2630 if (SFchdir(SFstartDir)) 2631 { 2632 emsg(_("E614: vim_SelFile: can't return to current directory")); 2633 SFstatus = SEL_FILE_CANCEL; 2634 } 2635 } 2636 2637 char * 2638 vim_SelFile( 2639 Widget toplevel, 2640 char *prompt, 2641 char *init_path, 2642 int (*show_entry)(), 2643 int x, 2644 int y, 2645 guicolor_T fg, 2646 guicolor_T bg, 2647 guicolor_T scroll_fg, 2648 guicolor_T scroll_bg) /* The "Scrollbar" group colors */ 2649 { 2650 static int firstTime = 1; 2651 XEvent event; 2652 char *name_return; 2653 2654 if (prompt == NULL) 2655 prompt = _("Pathname:"); 2656 SFfore = fg; 2657 SFback = bg; 2658 2659 if (mch_dirname((char_u *)SFstartDir, MAXPATHL) == FAIL) 2660 { 2661 emsg(_("E615: vim_SelFile: can't get current directory")); 2662 return NULL; 2663 } 2664 2665 if (firstTime) 2666 { 2667 firstTime = 0; 2668 SFdisplay = XtDisplay(toplevel); 2669 SFcreateWidgets(toplevel, prompt, _("OK"), _("Cancel")); 2670 } 2671 else 2672 { 2673 XtVaSetValues(selFilePrompt, XtNlabel, prompt, NULL); 2674 XtVaSetValues(selFile, XtNtitle, prompt, NULL); 2675 SFsetColors(bg, fg, scroll_bg, scroll_fg); 2676 } 2677 2678 XtVaSetValues(selFile, XtNx, x, XtNy, y, NULL); 2679 XtMapWidget(selFile); 2680 2681 (void)strcat(SFstartDir, "/"); 2682 (void)strcpy(SFcurrentDir, SFstartDir); 2683 2684 if (init_path) 2685 { 2686 if (init_path[0] == '/') 2687 { 2688 (void)strcpy(SFcurrentPath, init_path); 2689 if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) 2690 SFsetText(SFcurrentPath); 2691 else 2692 SFsetText(&(SFcurrentPath[strlen(SFstartDir)])); 2693 } 2694 else 2695 { 2696 (void)strcat(strcpy(SFcurrentPath, SFstartDir), init_path); 2697 SFsetText(&(SFcurrentPath[strlen(SFstartDir)])); 2698 } 2699 } 2700 else 2701 (void)strcpy(SFcurrentPath, SFstartDir); 2702 2703 SFfunc = show_entry; 2704 2705 SFtextChanged(); 2706 2707 XtAddGrab(selFile, True, True); 2708 2709 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000, 2710 SFdirModTimer, (XtPointer) NULL); 2711 2712 for (;;) 2713 { 2714 XtAppNextEvent(SFapp, &event); 2715 XtDispatchEvent(&event); 2716 switch (SFstatus) 2717 { 2718 case SEL_FILE_TEXT: 2719 SFstatus = SEL_FILE_NULL; 2720 SFtextChanged(); 2721 break; 2722 case SEL_FILE_OK: 2723 name_return = SFgetText(); 2724 SFprepareToReturn(); 2725 return name_return; 2726 case SEL_FILE_CANCEL: 2727 SFprepareToReturn(); 2728 return NULL; 2729 case SEL_FILE_NULL: 2730 break; 2731 } 2732 } 2733 } 2734 #endif /* FEAT_BROWSE */ 2735