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