Mercurial > vim
view src/gui_at_fs.c @ 3087:3ecf9e91d88a v7.3.315
updated for version 7.3.315
Problem: Opening a window before forking causes problems for GTK.
Solution: Fork first, create the window in the child and report back to the
parent process whether it worked. If successful the parent exits,
if unsuccessful the child exits and the parent continues in the
terminal. (Tim Starling)
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Wed, 14 Sep 2011 19:04:39 +0200 |
parents | e5265e4d4725 |
children | f8d307ebd74a |
line wrap: on
line source
/* vi:set ts=8 sts=4 sw=4: */ /* * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Software Research Associates not be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. Software Research Associates * makes no representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Author: Erik M. van der Poel * Software Research Associates, Inc., Tokyo, Japan * erik@sra.co.jp */ /* * Author's addresses: * erik@sra.co.jp * erik%sra.co.jp@uunet.uu.net * erik%sra.co.jp@mcvax.uucp * try junet instead of co.jp * Erik M. van der Poel * Software Research Associates, Inc. * 1-1-1 Hirakawa-cho, Chiyoda-ku * Tokyo 102 Japan. TEL +81-3-234-2692 */ /* * Heavely modified for Vim by Bram Moolenaar */ #include "vim.h" /* Only include this when using the file browser */ #ifdef FEAT_BROWSE /* Weird complication: for "make lint" Text.h doesn't combine with Xm.h */ #if defined(FEAT_GUI_MOTIF) && defined(FMT8BIT) # undef FMT8BIT #endif #ifndef FEAT_GUI_NEXTAW # include "gui_at_sb.h" #endif /***************** SFinternal.h */ #include <X11/Intrinsic.h> #include <X11/StringDefs.h> #include <X11/Xos.h> #ifdef FEAT_GUI_NEXTAW # include <X11/neXtaw/Text.h> # include <X11/neXtaw/AsciiText.h> # include <X11/neXtaw/Scrollbar.h> #else # include <X11/Xaw/Text.h> # include <X11/Xaw/AsciiText.h> #endif #define SEL_FILE_CANCEL -1 #define SEL_FILE_OK 0 #define SEL_FILE_NULL 1 #define SEL_FILE_TEXT 2 #define SF_DO_SCROLL 1 #define SF_DO_NOT_SCROLL 0 typedef struct { int statDone; char *real; char *shown; } SFEntry; typedef struct { char *dir; char *path; SFEntry *entries; int nEntries; int vOrigin; int nChars; int hOrigin; int changed; int beginSelection; int endSelection; time_t mtime; } SFDir; static char SFstartDir[MAXPATHL], SFcurrentPath[MAXPATHL], SFcurrentDir[MAXPATHL]; static Widget selFile, selFileField, selFileForm, selFileHScroll, selFileHScrolls[3], selFileLists[3], selFileOK, selFileCancel, selFilePrompt, selFileVScrolls[3]; static Display *SFdisplay; static int SFcharWidth, SFcharAscent, SFcharHeight; static SFDir *SFdirs = NULL; static int SFdirEnd; static int SFdirPtr; static Pixel SFfore, SFback; static Atom SFwmDeleteWindow; static XSegment SFsegs[2], SFcompletionSegs[2]; static XawTextPosition SFtextPos; static int SFupperX, SFlowerY, SFupperY; static int SFtextX, SFtextYoffset; static int SFentryWidth, SFentryHeight; static int SFlineToTextH = 3; static int SFlineToTextV = 3; static int SFbesideText = 3; static int SFaboveAndBelowText = 2; static int SFcharsPerEntry = 15; static int SFlistSize = 10; static int SFcurrentInvert[3] = { -1, -1, -1 }; static int SFworkProcAdded = 0; static XtAppContext SFapp; static int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth; #ifdef FEAT_XFONTSET static char SFtextBuffer[MAXPATHL*sizeof(wchar_t)]; #else static char SFtextBuffer[MAXPATHL]; #endif static int SFbuttonPressed = 0; static XtIntervalId SFdirModTimerId; static int (*SFfunc)(); static int SFstatus = SEL_FILE_NULL; /***************** static functions */ static void SFsetText __ARGS((char *path)); static void SFtextChanged __ARGS((void)); static char *SFgetText __ARGS((void)); static void SFupdatePath __ARGS((void)); static int SFgetDir __ARGS((SFDir *dir)); static void SFdrawLists __ARGS((int doScroll)); static void SFdrawList __ARGS((int n, int doScroll)); static void SFclearList __ARGS((int n, int doScroll)); static void SFbuttonPressList __ARGS((Widget w, int n, XButtonPressedEvent *event)); static void SFbuttonReleaseList __ARGS((Widget w, int n, XButtonReleasedEvent *event)); static void SFdirModTimer __ARGS((XtPointer cl, XtIntervalId *id)); static char SFstatChar __ARGS((struct stat *statBuf)); static void SFdrawStrings __ARGS((Window w, SFDir *dir, int from, int to)); static int SFnewInvertEntry __ARGS((int n, XMotionEvent *event)); static void SFinvertEntry __ARGS((int n)); static void SFenterList __ARGS((Widget w, int n, XEnterWindowEvent *event)); static void SFleaveList __ARGS((Widget w, int n, XEvent *event)); static void SFmotionList __ARGS((Widget w, int n, XMotionEvent *event)); static void SFvFloatSliderMovedCallback __ARGS((Widget w, XtPointer n, XtPointer fnew)); static void SFvSliderMovedCallback __ARGS((Widget w, int n, int nw)); static void SFvAreaSelectedCallback __ARGS((Widget w, XtPointer n, XtPointer pnew)); static void SFhSliderMovedCallback __ARGS((Widget w, XtPointer n, XtPointer nw)); static void SFhAreaSelectedCallback __ARGS((Widget w, XtPointer n, XtPointer pnew)); static void SFpathSliderMovedCallback __ARGS((Widget w, XtPointer client_data, XtPointer nw)); static void SFpathAreaSelectedCallback __ARGS((Widget w, XtPointer client_data, XtPointer pnew)); static Boolean SFworkProc __ARGS((void)); static int SFcompareEntries __ARGS((const void *p, const void *q)); static void SFprepareToReturn __ARGS((void)); static void SFcreateWidgets __ARGS((Widget toplevel, char *prompt, char *ok, char *cancel)); static void SFsetColors __ARGS((guicolor_T bg, guicolor_T fg, guicolor_T scroll_bg, guicolor_T scrollfg)); /***************** xstat.h */ #ifndef S_IXUSR # define S_IXUSR 0100 #endif #ifndef S_IXGRP # define S_IXGRP 0010 #endif #ifndef S_IXOTH # define S_IXOTH 0001 #endif #define S_ISXXX(m) ((m) & (S_IXUSR | S_IXGRP | S_IXOTH)) /***************** Path.c */ #include <pwd.h> typedef struct { char *name; char *dir; } SFLogin; static int SFdoNotTouchDirPtr = 0; static int SFdoNotTouchVorigin = 0; static SFDir SFrootDir, SFhomeDir; static SFLogin *SFlogins; static int SFtwiddle = 0; static int SFchdir __ARGS((char *path)); static int SFchdir(path) char *path; { int result; result = 0; if (strcmp(path, SFcurrentDir)) { result = mch_chdir(path); if (!result) (void) strcpy(SFcurrentDir, path); } return result; } static void SFfree __ARGS((int i)); static void SFfree(i) int i; { SFDir *dir; int j; dir = &(SFdirs[i]); for (j = dir->nEntries - 1; j >= 0; j--) { if (dir->entries[j].shown != dir->entries[j].real) XtFree(dir->entries[j].shown); XtFree(dir->entries[j].real); } XtFree((char *)dir->entries); XtFree(dir->dir); dir->dir = NULL; } static void SFstrdup __ARGS((char **s1, char *s2)); static void SFstrdup(s1, s2) char **s1; char *s2; { *s1 = strcpy(XtMalloc((unsigned)(strlen(s2) + 1)), s2); } static void SFunreadableDir __ARGS((SFDir *dir)); static void SFunreadableDir(dir) SFDir *dir; { char *cannotOpen = _("<cannot open> "); dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry)); dir->entries[0].statDone = 1; SFstrdup(&dir->entries[0].real, cannotOpen); dir->entries[0].shown = dir->entries[0].real; dir->nEntries = 1; dir->nChars = strlen(cannotOpen); } static void SFreplaceText __ARGS((SFDir *dir, char *str)); static void SFreplaceText(dir, str) SFDir *dir; char *str; { int len; *(dir->path) = 0; len = strlen(str); if (str[len - 1] == '/') (void) strcat(SFcurrentPath, str); else (void) strncat(SFcurrentPath, str, len - 1); if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) SFsetText(SFcurrentPath); else SFsetText(&(SFcurrentPath[strlen(SFstartDir)])); SFtextChanged(); } static void SFexpand __ARGS((char *str)); static void SFexpand(str) char *str; { int len; int cmp; char *name, *growing; SFDir *dir; SFEntry *entry, *max; len = strlen(str); dir = &(SFdirs[SFdirEnd - 1]); if (dir->beginSelection == -1) { SFstrdup(&str, str); SFreplaceText(dir, str); XtFree(str); return; } else if (dir->beginSelection == dir->endSelection) { SFreplaceText(dir, dir->entries[dir->beginSelection].shown); return; } max = &(dir->entries[dir->endSelection + 1]); name = dir->entries[dir->beginSelection].shown; SFstrdup(&growing, name); cmp = 0; while (!cmp) { entry = &(dir->entries[dir->beginSelection]); while (entry < max) { if ((cmp = strncmp(growing, entry->shown, len))) break; entry++; } len++; } /* * SFreplaceText() expects filename */ growing[len - 2] = ' '; growing[len - 1] = 0; SFreplaceText(dir, growing); XtFree(growing); } static int SFfindFile __ARGS((SFDir *dir, char *str)); static int SFfindFile(dir, str) SFDir *dir; char *str; { int i, last, max; char *name, save; SFEntry *entries; int len; int begin, end; int result; len = strlen(str); if (str[len - 1] == ' ') { SFexpand(str); return 1; } else if (str[len - 1] == '/') len--; max = dir->nEntries; entries = dir->entries; i = 0; while (i < max) { name = entries[i].shown; last = strlen(name) - 1; save = name[last]; name[last] = 0; result = strncmp(str, name, len); name[last] = save; if (result <= 0) break; i++; } begin = i; while (i < max) { name = entries[i].shown; last = strlen(name) - 1; save = name[last]; name[last] = 0; result = strncmp(str, name, len); name[last] = save; if (result) break; i++; } end = i; if (begin != end) { if ((dir->beginSelection != begin) || (dir->endSelection != end - 1)) { dir->changed = 1; dir->beginSelection = begin; if (str[strlen(str) - 1] == '/') dir->endSelection = begin; else dir->endSelection = end - 1; } } else if (dir->beginSelection != -1) { dir->changed = 1; dir->beginSelection = -1; dir->endSelection = -1; } if (SFdoNotTouchVorigin || ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))) { SFdoNotTouchVorigin = 0; return 0; } i = begin - 1; if (i > max - SFlistSize) i = max - SFlistSize; if (i < 0) i = 0; if (dir->vOrigin != i) { dir->vOrigin = i; dir->changed = 1; } return 0; } static void SFunselect __ARGS((void)); static void SFunselect() { SFDir *dir; dir = &(SFdirs[SFdirEnd - 1]); if (dir->beginSelection != -1) dir->changed = 1; dir->beginSelection = -1; dir->endSelection = -1; } static int SFcompareLogins __ARGS((const void *p, const void *q)); static int SFcompareLogins(p, q) const void *p, *q; { return strcmp(((SFLogin *)p)->name, ((SFLogin *)q)->name); } static void SFgetHomeDirs __ARGS((void)); static void SFgetHomeDirs() { struct passwd *pw; int Alloc; int i; SFEntry *entries = NULL; int len; int maxChars; Alloc = 1; i = 1; entries = (SFEntry *)XtMalloc(sizeof(SFEntry)); SFlogins = (SFLogin *)XtMalloc(sizeof(SFLogin)); entries[0].real = XtMalloc(3); (void) strcpy(entries[0].real, "~"); entries[0].shown = entries[0].real; entries[0].statDone = 1; SFlogins[0].name = ""; pw = getpwuid((int) getuid()); SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/"); maxChars = 0; (void) setpwent(); while ((pw = getpwent()) && (*(pw->pw_name))) { if (i >= Alloc) { Alloc *= 2; entries = (SFEntry *) XtRealloc((char *)entries, (unsigned)(Alloc * sizeof(SFEntry))); SFlogins = (SFLogin *) XtRealloc((char *)SFlogins, (unsigned)(Alloc * sizeof(SFLogin))); } len = strlen(pw->pw_name); entries[i].real = XtMalloc((unsigned) (len + 3)); (void) strcat(strcpy(entries[i].real, "~"), pw->pw_name); entries[i].shown = entries[i].real; entries[i].statDone = 1; if (len > maxChars) maxChars = len; SFstrdup(&SFlogins[i].name, pw->pw_name); SFstrdup(&SFlogins[i].dir, pw->pw_dir); i++; } SFhomeDir.dir = XtMalloc(1); SFhomeDir.dir[0] = 0; SFhomeDir.path = SFcurrentPath; SFhomeDir.entries = entries; SFhomeDir.nEntries = i; SFhomeDir.vOrigin = 0; /* :-) */ SFhomeDir.nChars = maxChars + 2; SFhomeDir.hOrigin = 0; SFhomeDir.changed = 1; SFhomeDir.beginSelection = -1; SFhomeDir.endSelection = -1; qsort((char *)entries, (size_t)i, sizeof(SFEntry), SFcompareEntries); qsort((char *)SFlogins, (size_t)i, sizeof(SFLogin), SFcompareLogins); for (i--; i >= 0; i--) (void)strcat(entries[i].real, "/"); } static int SFfindHomeDir __ARGS((char *begin, char *end)); static int SFfindHomeDir(begin, end) char *begin, *end; { char save; char *theRest; int i; save = *end; *end = 0; for (i = SFhomeDir.nEntries - 1; i >= 0; i--) { if (!strcmp(SFhomeDir.entries[i].real, begin)) { *end = save; SFstrdup(&theRest, end); (void) strcat(strcat(strcpy(SFcurrentPath, SFlogins[i].dir), "/"), theRest); XtFree(theRest); SFsetText(SFcurrentPath); SFtextChanged(); return 1; } } *end = save; return 0; } static void SFupdatePath() { static int Alloc; static int wasTwiddle = 0; char *begin, *end; int i, j; int prevChange; int SFdirPtrSave, SFdirEndSave; SFDir *dir; if (!SFdirs) { SFdirs = (SFDir *) XtMalloc((Alloc = 10) * sizeof(SFDir)); dir = &(SFdirs[0]); SFstrdup(&dir->dir, "/"); (void) SFchdir("/"); (void) SFgetDir(dir); for (j = 1; j < Alloc; j++) SFdirs[j].dir = NULL; dir->path = SFcurrentPath + 1; dir->vOrigin = 0; dir->hOrigin = 0; dir->changed = 1; dir->beginSelection = -1; dir->endSelection = -1; SFhomeDir.dir = NULL; } SFdirEndSave = SFdirEnd; SFdirEnd = 1; SFdirPtrSave = SFdirPtr; SFdirPtr = 0; begin = NULL; if (SFcurrentPath[0] == '~') { if (!SFtwiddle) { SFtwiddle = 1; dir = &(SFdirs[0]); SFrootDir = *dir; if (!SFhomeDir.dir) SFgetHomeDirs(); *dir = SFhomeDir; dir->changed = 1; } end = SFcurrentPath; SFdoNotTouchDirPtr = 1; wasTwiddle = 1; } else { if (SFtwiddle) { SFtwiddle = 0; dir = &(SFdirs[0]); *dir = SFrootDir; dir->changed = 1; } end = SFcurrentPath + 1; } i = 0; prevChange = 0; while (*end) { while (*end++ == '/') ; end--; begin = end; while ((*end) && (*end++ != '/')) ; if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) { SFdirPtr = i - 1; if (SFdirPtr < 0) SFdirPtr = 0; } if (*begin) { if (*(end - 1) == '/') { char save = *end; if (SFtwiddle) { if (SFfindHomeDir(begin, end)) return; } *end = 0; i++; SFdirEnd++; if (i >= Alloc) { SFdirs = (SFDir *) XtRealloc((char *) SFdirs, (unsigned)((Alloc *= 2) * sizeof(SFDir))); for (j = Alloc / 2; j < Alloc; j++) SFdirs[j].dir = NULL; } dir = &(SFdirs[i]); if ((!(dir->dir)) || prevChange || strcmp(dir->dir, begin)) { if (dir->dir) SFfree(i); prevChange = 1; SFstrdup(&dir->dir, begin); dir->path = end; dir->vOrigin = 0; dir->hOrigin = 0; dir->changed = 1; dir->beginSelection = -1; dir->endSelection = -1; (void)SFfindFile(dir - 1, begin); if (SFchdir(SFcurrentPath) || SFgetDir(dir)) { SFunreadableDir(dir); break; } } *end = save; if (!save) SFunselect(); } else { if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) return; } } else SFunselect(); } if ((end == SFcurrentPath + 1) && (!SFtwiddle)) SFunselect(); for (i = SFdirEnd; i < Alloc; i++) if (SFdirs[i].dir) SFfree(i); if (SFdoNotTouchDirPtr) { if (wasTwiddle) { wasTwiddle = 0; SFdirPtr = SFdirEnd - 2; if (SFdirPtr < 0) SFdirPtr = 0; } else SFdirPtr = SFdirPtrSave; SFdoNotTouchDirPtr = 0; } if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) { #ifdef FEAT_GUI_NEXTAW XawScrollbarSetThumb( selFileHScroll, (float) (((double) SFdirPtr) / SFdirEnd), (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd)); #else vim_XawScrollbarSetThumb( selFileHScroll, (float) (((double) SFdirPtr) / SFdirEnd), (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd), (double)SFdirEnd); #endif } if (SFdirPtr != SFdirPtrSave) SFdrawLists(SF_DO_SCROLL); else for (i = 0; i < 3; i++) { if (SFdirPtr + i < SFdirEnd) { if (SFdirs[SFdirPtr + i].changed) { SFdirs[SFdirPtr + i].changed = 0; SFdrawList(i, SF_DO_SCROLL); } } else SFclearList(i, SF_DO_SCROLL); } } #ifdef XtNinternational static int WcsLen(p) wchar_t *p; { int i = 0; while (*p++ != 0) i++; return i; } #endif static void SFsetText(path) char *path; { XawTextBlock text; text.firstPos = 0; text.length = strlen(path); text.ptr = path; text.format = FMT8BIT; #ifdef XtNinternational if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide) { XawTextReplace(selFileField, (XawTextPosition)0, (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0]), &text); XawTextSetInsertionPoint(selFileField, (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0])); } else { XawTextReplace(selFileField, (XawTextPosition)0, (XawTextPosition)strlen(SFtextBuffer), &text); XawTextSetInsertionPoint(selFileField, (XawTextPosition)strlen(SFtextBuffer)); } #else XawTextReplace(selFileField, (XawTextPosition)0, (XawTextPosition)strlen(SFtextBuffer), &text); XawTextSetInsertionPoint(selFileField, (XawTextPosition)strlen(SFtextBuffer)); #endif } static void SFbuttonPressList(w, n, event) Widget w UNUSED; int n UNUSED; XButtonPressedEvent *event UNUSED; { SFbuttonPressed = 1; } static void SFbuttonReleaseList(w, n, event) Widget w; int n; XButtonReleasedEvent *event; { SFDir *dir; SFbuttonPressed = 0; if (SFcurrentInvert[n] != -1) { if (n < 2) SFdoNotTouchDirPtr = 1; SFdoNotTouchVorigin = 1; dir = &(SFdirs[SFdirPtr + n]); SFreplaceText(dir, dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown); SFmotionList(w, n, (XMotionEvent *) event); } } static int SFcheckDir __ARGS((int n, SFDir *dir)); static int SFcheckDir(n, dir) int n; SFDir *dir; { struct stat statBuf; int i; if ((!mch_stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime)) { /* * If the pointer is currently in the window that we are about * to update, we must warp it to prevent the user from * accidentally selecting the wrong file. */ if (SFcurrentInvert[n] != -1) { XWarpPointer( SFdisplay, None, XtWindow(selFileLists[n]), 0, 0, 0, 0, 0, 0); } for (i = dir->nEntries - 1; i >= 0; i--) { if (dir->entries[i].shown != dir->entries[i].real) XtFree(dir->entries[i].shown); XtFree(dir->entries[i].real); } XtFree((char *) dir->entries); if (SFgetDir(dir)) SFunreadableDir(dir); if (dir->vOrigin > dir->nEntries - SFlistSize) dir->vOrigin = dir->nEntries - SFlistSize; if (dir->vOrigin < 0) dir->vOrigin = 0; if (dir->hOrigin > dir->nChars - SFcharsPerEntry) dir->hOrigin = dir->nChars - SFcharsPerEntry; if (dir->hOrigin < 0) dir->hOrigin = 0; dir->beginSelection = -1; dir->endSelection = -1; SFdoNotTouchVorigin = 1; if ((dir + 1)->dir) (void) SFfindFile(dir, (dir + 1)->dir); else (void) SFfindFile(dir, dir->path); if (!SFworkProcAdded) { (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL); SFworkProcAdded = 1; } return 1; } return 0; } static int SFcheckFiles __ARGS((SFDir *dir)); static int SFcheckFiles(dir) SFDir *dir; { int from, to; int result; char oldc, newc; int i; char *str; int last; struct stat statBuf; result = 0; from = dir->vOrigin; to = dir->vOrigin + SFlistSize; if (to > dir->nEntries) to = dir->nEntries; for (i = from; i < to; i++) { str = dir->entries[i].real; last = strlen(str) - 1; oldc = str[last]; str[last] = 0; if (mch_stat(str, &statBuf)) newc = ' '; else newc = SFstatChar(&statBuf); str[last] = newc; if (newc != oldc) result = 1; } return result; } static void SFdirModTimer(cl, id) XtPointer cl UNUSED; XtIntervalId *id UNUSED; { static int n = -1; static int f = 0; char save; SFDir *dir; if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) { n++; if ((n > 2) || (SFdirPtr + n >= SFdirEnd)) { n = 0; f++; if ((f > 2) || (SFdirPtr + f >= SFdirEnd)) f = 0; } dir = &(SFdirs[SFdirPtr + n]); save = *(dir->path); *(dir->path) = 0; if (SFchdir(SFcurrentPath)) { *(dir->path) = save; /* * force a re-read */ *(dir->dir) = 0; SFupdatePath(); } else { *(dir->path) = save; if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir))) SFdrawList(n, SF_DO_SCROLL); } } SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000, SFdirModTimer, (XtPointer) NULL); } /* Return a single character describing what kind of file STATBUF is. */ static char SFstatChar(statBuf) struct stat *statBuf; { if (S_ISDIR (statBuf->st_mode)) return '/'; if (S_ISREG (statBuf->st_mode)) return S_ISXXX (statBuf->st_mode) ? '*' : ' '; #ifdef S_ISSOCK if (S_ISSOCK (statBuf->st_mode)) return '='; #endif /* S_ISSOCK */ return ' '; } /***************** Draw.c */ #ifdef FEAT_GUI_NEXTAW # include <X11/neXtaw/Cardinals.h> #else # include <X11/Xaw/Cardinals.h> #endif #ifdef FEAT_XFONTSET # define SF_DEFAULT_FONT "-misc-fixed-medium-r-normal--14-*" #else # define SF_DEFAULT_FONT "9x15" #endif #ifdef ABS # undef ABS #endif #define ABS(x) (((x) < 0) ? (-(x)) : (x)) typedef struct { char *fontname; } TextData; static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC; static XtResource textResources[] = { #ifdef FEAT_XFONTSET {XtNfontSet, XtCFontSet, XtRString, sizeof (char *), XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT}, #else {XtNfont, XtCFont, XtRString, sizeof (char *), XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT}, #endif }; #ifdef FEAT_XFONTSET static XFontSet SFfont; #else static XFontStruct *SFfont; #endif static int SFcurrentListY; static XtIntervalId SFscrollTimerId; static void SFinitFont __ARGS((void)); static void SFinitFont() { TextData *data; #ifdef FEAT_XFONTSET XFontSetExtents *extents; char **missing, *def_str; int num_missing; #endif data = XtNew(TextData); XtGetApplicationResources(selFileForm, (XtPointer) data, textResources, XtNumber(textResources), (Arg *) NULL, ZERO); #ifdef FEAT_XFONTSET SFfont = XCreateFontSet(SFdisplay, data->fontname, &missing, &num_missing, &def_str); #else SFfont = XLoadQueryFont(SFdisplay, data->fontname); #endif if (!SFfont) { #ifdef FEAT_XFONTSET SFfont = XCreateFontSet(SFdisplay, SF_DEFAULT_FONT, &missing, &num_missing, &def_str); #else SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT); #endif if (!SFfont) { EMSG2(_("E616: vim_SelFile: can't get font %s"), SF_DEFAULT_FONT); SFstatus = SEL_FILE_CANCEL; return; } } #ifdef FEAT_XFONTSET extents = XExtentsOfFontSet(SFfont); SFcharWidth = extents->max_logical_extent.width; SFcharAscent = -extents->max_logical_extent.y; SFcharHeight = extents->max_logical_extent.height; #else SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2; SFcharAscent = SFfont->max_bounds.ascent; SFcharHeight = SFcharAscent + SFfont->max_bounds.descent; #endif } static void SFcreateGC __ARGS((void)); static void SFcreateGC() { XGCValues gcValues; XRectangle rectangles[1]; gcValues.foreground = SFfore; SFlineGC = XtGetGC( selFileLists[0], (XtGCMask)GCForeground, &gcValues); SFscrollGC = XtGetGC( selFileLists[0], (XtGCMask)0, &gcValues); gcValues.function = GXxor; gcValues.foreground = SFfore ^ SFback; gcValues.background = SFfore ^ SFback; SFinvertGC = XtGetGC( selFileLists[0], (XtGCMask)GCFunction | GCForeground | GCBackground, &gcValues); gcValues.foreground = SFfore; gcValues.background = SFback; #ifndef FEAT_XFONTSET gcValues.font = SFfont->fid; #endif SFtextGC = XCreateGC( SFdisplay, XtWindow(selFileLists[0]), #ifdef FEAT_XFONTSET (unsigned long)GCForeground | GCBackground, #else (unsigned long)GCForeground | GCBackground | GCFont, #endif &gcValues); rectangles[0].x = SFlineToTextH + SFbesideText; rectangles[0].y = 0; rectangles[0].width = SFcharsPerEntry * SFcharWidth; rectangles[0].height = SFupperY + 1; XSetClipRectangles( SFdisplay, SFtextGC, 0, 0, rectangles, 1, Unsorted); } static void SFclearList(n, doScroll) int n; int doScroll; { SFDir *dir; SFcurrentInvert[n] = -1; XClearWindow(SFdisplay, XtWindow(selFileLists[n])); XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2); if (doScroll) { dir = &(SFdirs[SFdirPtr + n]); if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars) { #ifdef FEAT_GUI_NEXTAW XawScrollbarSetThumb( selFileVScrolls[n], (float) (((double) dir->vOrigin) / dir->nEntries), (float) (((double) ((dir->nEntries < SFlistSize) ? dir->nEntries : SFlistSize)) / dir->nEntries)); #else vim_XawScrollbarSetThumb( selFileVScrolls[n], (float) (((double) dir->vOrigin) / dir->nEntries), (float) (((double) ((dir->nEntries < SFlistSize) ? dir->nEntries : SFlistSize)) / dir->nEntries), (double)dir->nEntries); #endif #ifdef FEAT_GUI_NEXTAW XawScrollbarSetThumb( selFileHScrolls[n], (float) (((double) dir->hOrigin) / dir->nChars), (float) (((double) ((dir->nChars < SFcharsPerEntry) ? dir->nChars : SFcharsPerEntry)) / dir->nChars)); #else vim_XawScrollbarSetThumb( selFileHScrolls[n], (float) (((double) dir->hOrigin) / dir->nChars), (float) (((double) ((dir->nChars < SFcharsPerEntry) ? dir->nChars : SFcharsPerEntry)) / dir->nChars), (double)dir->nChars); #endif } else { #ifdef FEAT_GUI_NEXTAW XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0, (float) 1.0); #else vim_XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0, (float) 1.0, 1.0); #endif #ifdef FEAT_GUI_NEXTAW XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0, (float) 1.0); #else vim_XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0, (float) 1.0, 1.0); #endif } } } static void SFdeleteEntry __ARGS((SFDir *dir, SFEntry *entry)); static void SFdeleteEntry(dir, entry) SFDir *dir; SFEntry *entry; { SFEntry *e; SFEntry *end; int n; int idx; idx = entry - dir->entries; if (idx < dir->beginSelection) dir->beginSelection--; if (idx <= dir->endSelection) dir->endSelection--; if (dir->beginSelection > dir->endSelection) dir->beginSelection = dir->endSelection = -1; if (idx < dir->vOrigin) dir->vOrigin--; XtFree(entry->real); end = &(dir->entries[dir->nEntries - 1]); for (e = entry; e < end; e++) *e = *(e + 1); if (!(--dir->nEntries)) return; n = dir - &(SFdirs[SFdirPtr]); if ((n < 0) || (n > 2)) return; #ifdef FEAT_GUI_NEXTAW XawScrollbarSetThumb( selFileVScrolls[n], (float) (((double) dir->vOrigin) / dir->nEntries), (float) (((double) ((dir->nEntries < SFlistSize) ? dir->nEntries : SFlistSize)) / dir->nEntries)); #else vim_XawScrollbarSetThumb( selFileVScrolls[n], (float) (((double) dir->vOrigin) / dir->nEntries), (float) (((double) ((dir->nEntries < SFlistSize) ? dir->nEntries : SFlistSize)) / dir->nEntries), (double)dir->nEntries); #endif } static void SFwriteStatChar __ARGS((char *name, int last, struct stat *statBuf)); static void SFwriteStatChar(name, last, statBuf) char *name; int last; struct stat *statBuf; { name[last] = SFstatChar(statBuf); } static int SFstatAndCheck __ARGS((SFDir *dir, SFEntry *entry)); static int SFstatAndCheck(dir, entry) SFDir *dir; SFEntry *entry; { struct stat statBuf; char save; int last; /* * must be restored before returning */ save = *(dir->path); *(dir->path) = 0; if (!SFchdir(SFcurrentPath)) { last = strlen(entry->real) - 1; entry->real[last] = 0; entry->statDone = 1; if ((!mch_stat(entry->real, &statBuf)) #ifdef S_IFLNK || (!mch_lstat(entry->real, &statBuf)) #endif ) { if (SFfunc) { char *shown; shown = NULL; if (SFfunc(entry->real, &shown, &statBuf)) { if (shown) { int len; len = strlen(shown); entry->shown = XtMalloc((unsigned) (len + 2)); (void) strcpy(entry->shown, shown); SFwriteStatChar(entry->shown, len, &statBuf); entry->shown[len + 1] = 0; } } else { SFdeleteEntry(dir, entry); *(dir->path) = save; return 1; } } SFwriteStatChar(entry->real, last, &statBuf); } else entry->real[last] = ' '; } *(dir->path) = save; return 0; } static void SFdrawStrings(w, dir, from, to) Window w; SFDir *dir; int from; int to; { int i; SFEntry *entry; int x; x = SFtextX - dir->hOrigin * SFcharWidth; if (dir->vOrigin + to >= dir->nEntries) to = dir->nEntries - dir->vOrigin - 1; for (i = from; i <= to; i++) { entry = &(dir->entries[dir->vOrigin + i]); if (!(entry->statDone)) { if (SFstatAndCheck(dir, entry)) { if (dir->vOrigin + to >= dir->nEntries) to = dir->nEntries - dir->vOrigin - 1; i--; continue; } } #ifdef FEAT_XFONTSET XmbDrawImageString( SFdisplay, w, SFfont, SFtextGC, x, SFtextYoffset + i * SFentryHeight, entry->shown, strlen(entry->shown)); #else XDrawImageString( SFdisplay, w, SFtextGC, x, SFtextYoffset + i * SFentryHeight, entry->shown, strlen(entry->shown)); #endif if (dir->vOrigin + i == dir->beginSelection) { XDrawLine( SFdisplay, w, SFlineGC, SFlineToTextH + 1, SFlowerY + i * SFentryHeight, SFlineToTextH + SFentryWidth - 2, SFlowerY + i * SFentryHeight); } if ((dir->vOrigin + i >= dir->beginSelection) && (dir->vOrigin + i <= dir->endSelection)) { SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 = SFlowerY + i * SFentryHeight; SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 = SFlowerY + (i + 1) * SFentryHeight - 1; XDrawSegments( SFdisplay, w, SFlineGC, SFcompletionSegs, 2); } if (dir->vOrigin + i == dir->endSelection) { XDrawLine( SFdisplay, w, SFlineGC, SFlineToTextH + 1, SFlowerY + (i + 1) * SFentryHeight - 1, SFlineToTextH + SFentryWidth - 2, SFlowerY + (i + 1) * SFentryHeight - 1); } } } static void SFdrawList(n, doScroll) int n; int doScroll; { SFDir *dir; Window w; SFclearList(n, doScroll); if (SFdirPtr + n < SFdirEnd) { dir = &(SFdirs[SFdirPtr + n]); w = XtWindow(selFileLists[n]); #ifdef FEAT_XFONTSET XmbDrawImageString( SFdisplay, w, SFfont, SFtextGC, SFtextX - dir->hOrigin * SFcharWidth, SFlineToTextV + SFaboveAndBelowText + SFcharAscent, dir->dir, strlen(dir->dir)); #else XDrawImageString( SFdisplay, w, SFtextGC, SFtextX - dir->hOrigin * SFcharWidth, SFlineToTextV + SFaboveAndBelowText + SFcharAscent, dir->dir, strlen(dir->dir)); #endif SFdrawStrings(w, dir, 0, SFlistSize - 1); } } static void SFdrawLists(doScroll) int doScroll; { int i; for (i = 0; i < 3; i++) SFdrawList(i, doScroll); } static void SFinvertEntry(n) int n; { XFillRectangle( SFdisplay, XtWindow(selFileLists[n]), SFinvertGC, SFlineToTextH, SFcurrentInvert[n] * SFentryHeight + SFlowerY, SFentryWidth, SFentryHeight); } static unsigned long SFscrollTimerInterval __ARGS((void)); static unsigned long SFscrollTimerInterval() { static int maxVal = 200; static int varyDist = 50; static int minDist = 50; int t; int dist; if (SFcurrentListY < SFlowerY) dist = SFlowerY - SFcurrentListY; else if (SFcurrentListY > SFupperY) dist = SFcurrentListY - SFupperY; else return (unsigned long) 1; t = maxVal - ((maxVal / varyDist) * (dist - minDist)); if (t < 1) t = 1; if (t > maxVal) t = maxVal; return (unsigned long)t; } static void SFscrollTimer __ARGS((XtPointer p, XtIntervalId *id)); static void SFscrollTimer(p, id) XtPointer p; XtIntervalId *id UNUSED; { SFDir *dir; int save; int n; n = (long)p; dir = &(SFdirs[SFdirPtr + n]); save = dir->vOrigin; if (SFcurrentListY < SFlowerY) { if (dir->vOrigin > 0) SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1); } else if (SFcurrentListY > SFupperY) { if (dir->vOrigin < dir->nEntries - SFlistSize) SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1); } if (dir->vOrigin != save) { if (dir->nEntries) { #ifdef FEAT_GUI_NEXTAW XawScrollbarSetThumb( selFileVScrolls[n], (float) (((double) dir->vOrigin) / dir->nEntries), (float) (((double) ((dir->nEntries < SFlistSize) ? dir->nEntries : SFlistSize)) / dir->nEntries)); #else vim_XawScrollbarSetThumb( selFileVScrolls[n], (float) (((double) dir->vOrigin) / dir->nEntries), (float) (((double) ((dir->nEntries < SFlistSize) ? dir->nEntries : SFlistSize)) / dir->nEntries), (double)dir->nEntries); #endif } } if (SFbuttonPressed) SFscrollTimerId = XtAppAddTimeOut(SFapp, SFscrollTimerInterval(), SFscrollTimer, (XtPointer)(long_u)n); } static int SFnewInvertEntry(n, event) int n; XMotionEvent *event; { int x, y; int nw; static int SFscrollTimerAdded = 0; x = event->x; y = event->y; if (SFdirPtr + n >= SFdirEnd) return -1; if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY)) { SFDir *dir = &(SFdirs[SFdirPtr + n]); if (SFscrollTimerAdded) { SFscrollTimerAdded = 0; XtRemoveTimeOut(SFscrollTimerId); } nw = (y - SFlowerY) / SFentryHeight; if (dir->vOrigin + nw >= dir->nEntries) return -1; return nw; } else { if (SFbuttonPressed) { SFcurrentListY = y; if (!SFscrollTimerAdded) { SFscrollTimerAdded = 1; SFscrollTimerId = XtAppAddTimeOut(SFapp, SFscrollTimerInterval(), SFscrollTimer, (XtPointer)(long_u)n); } } return -1; } } static void SFenterList(w, n, event) Widget w UNUSED; int n; XEnterWindowEvent *event; { int nw; /* sanity */ if (SFcurrentInvert[n] != -1) { SFinvertEntry(n); SFcurrentInvert[n] = -1; } nw = SFnewInvertEntry(n, (XMotionEvent *) event); if (nw != -1) { SFcurrentInvert[n] = nw; SFinvertEntry(n); } } static void SFleaveList(w, n, event) Widget w UNUSED; int n; XEvent *event UNUSED; { if (SFcurrentInvert[n] != -1) { SFinvertEntry(n); SFcurrentInvert[n] = -1; } } static void SFmotionList(w, n, event) Widget w UNUSED; int n; XMotionEvent *event; { int nw; nw = SFnewInvertEntry(n, event); if (nw != SFcurrentInvert[n]) { if (SFcurrentInvert[n] != -1) SFinvertEntry(n); SFcurrentInvert[n] = nw; if (nw != -1) SFinvertEntry(n); } } static void SFvFloatSliderMovedCallback(w, n, fnew) Widget w; XtPointer n; XtPointer fnew; { int nw; nw = (*(float *)fnew) * SFdirs[SFdirPtr + (int)(long)n].nEntries; SFvSliderMovedCallback(w, (int)(long)n, nw); } static void SFvSliderMovedCallback(w, n, nw) Widget w UNUSED; int n; int nw; { int old; Window win; SFDir *dir; dir = &(SFdirs[SFdirPtr + n]); old = dir->vOrigin; dir->vOrigin = nw; if (old == nw) return; win = XtWindow(selFileLists[n]); if (ABS(nw - old) < SFlistSize) { if (nw > old) { XCopyArea( SFdisplay, win, win, SFscrollGC, SFlineToTextH, SFlowerY + (nw - old) * SFentryHeight, SFentryWidth + SFlineToTextH, (SFlistSize - (nw - old)) * SFentryHeight, SFlineToTextH, SFlowerY); XClearArea( SFdisplay, win, SFlineToTextH, SFlowerY + (SFlistSize - (nw - old)) * SFentryHeight, SFentryWidth + SFlineToTextH, (nw - old) * SFentryHeight, False); SFdrawStrings(win, dir, SFlistSize - (nw - old), SFlistSize - 1); } else { XCopyArea( SFdisplay, win, win, SFscrollGC, SFlineToTextH, SFlowerY, SFentryWidth + SFlineToTextH, (SFlistSize - (old - nw)) * SFentryHeight, SFlineToTextH, SFlowerY + (old - nw) * SFentryHeight); XClearArea( SFdisplay, win, SFlineToTextH, SFlowerY, SFentryWidth + SFlineToTextH, (old - nw) * SFentryHeight, False); SFdrawStrings(win, dir, 0, old - nw); } } else { XClearArea( SFdisplay, win, SFlineToTextH, SFlowerY, SFentryWidth + SFlineToTextH, SFlistSize * SFentryHeight, False); SFdrawStrings(win, dir, 0, SFlistSize - 1); } } static void SFvAreaSelectedCallback(w, n, pnew) Widget w; XtPointer n; XtPointer pnew; { SFDir *dir; int nw = (int)(long)pnew; dir = &(SFdirs[SFdirPtr + (int)(long)n]); #ifdef FEAT_GUI_NEXTAW if (nw < 0) { if (nw > -SFvScrollHeight) nw = -1; else nw = -SFlistSize; } else if (nw > 0) { if (nw < SFvScrollHeight) nw = 1; else nw = SFlistSize; } #endif nw += dir->vOrigin; if (nw > dir->nEntries - SFlistSize) nw = dir->nEntries - SFlistSize; if (nw < 0) nw = 0; if (dir->nEntries) { float f; f = ((double) nw) / dir->nEntries; #ifdef FEAT_GUI_NEXTAW XawScrollbarSetThumb( w, f, (float) (((double) ((dir->nEntries < SFlistSize) ? dir->nEntries : SFlistSize)) / dir->nEntries)); #else vim_XawScrollbarSetThumb( w, f, (float) (((double) ((dir->nEntries < SFlistSize) ? dir->nEntries : SFlistSize)) / dir->nEntries), (double)dir->nEntries); #endif } SFvSliderMovedCallback(w, (int)(long)n, nw); } static void SFhSliderMovedCallback(w, n, nw) Widget w UNUSED; XtPointer n; XtPointer nw; { SFDir *dir; int save; dir = &(SFdirs[SFdirPtr + (int)(long)n]); save = dir->hOrigin; dir->hOrigin = (*(float *)nw) * dir->nChars; if (dir->hOrigin == save) return; SFdrawList((int)(long)n, SF_DO_NOT_SCROLL); } static void SFhAreaSelectedCallback(w, n, pnew) Widget w; XtPointer n; XtPointer pnew; { SFDir *dir; int nw = (int)(long)pnew; dir = &(SFdirs[SFdirPtr + (int)(long)n]); #ifdef FEAT_GUI_NEXTAW if (nw < 0) { if (nw > -SFhScrollWidth) nw = -1; else nw = -SFcharsPerEntry; } else if (nw > 0) { if (nw < SFhScrollWidth) nw = 1; else nw = SFcharsPerEntry; } #endif nw += dir->hOrigin; if (nw > dir->nChars - SFcharsPerEntry) nw = dir->nChars - SFcharsPerEntry; if (nw < 0) nw = 0; if (dir->nChars) { float f; f = ((double) nw) / dir->nChars; #ifdef FEAT_GUI_NEXTAW XawScrollbarSetThumb( w, f, (float) (((double) ((dir->nChars < SFcharsPerEntry) ? dir->nChars : SFcharsPerEntry)) / dir->nChars)); #else vim_XawScrollbarSetThumb( w, f, (float) (((double) ((dir->nChars < SFcharsPerEntry) ? dir->nChars : SFcharsPerEntry)) / dir->nChars), (double)dir->nChars); #endif SFhSliderMovedCallback(w, n, (XtPointer)&f); } } static void SFpathSliderMovedCallback(w, client_data, nw) Widget w UNUSED; XtPointer client_data UNUSED; XtPointer nw; { SFDir *dir; int n; XawTextPosition pos; int SFdirPtrSave; SFdirPtrSave = SFdirPtr; SFdirPtr = (*(float *)nw) * SFdirEnd; if (SFdirPtr == SFdirPtrSave) return; SFdrawLists(SF_DO_SCROLL); n = 2; while (SFdirPtr + n >= SFdirEnd) n--; dir = &(SFdirs[SFdirPtr + n]); pos = dir->path - SFcurrentPath; if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) { pos -= strlen(SFstartDir); if (pos < 0) pos = 0; } XawTextSetInsertionPoint(selFileField, pos); } static void SFpathAreaSelectedCallback(w, client_data, pnew) Widget w; XtPointer client_data UNUSED; XtPointer pnew; { int nw = (int)(long)pnew; float f; #ifdef FEAT_GUI_NEXTAW if (nw < 0) { if (nw > -SFpathScrollWidth) nw = -1; else nw = -3; } else if (nw > 0) { if (nw < SFpathScrollWidth) nw = 1; else nw = 3; } #endif nw += SFdirPtr; if (nw > SFdirEnd - 3) nw = SFdirEnd - 3; if (nw < 0) nw = 0; f = ((double) nw) / SFdirEnd; #ifdef FEAT_GUI_NEXTAW XawScrollbarSetThumb( w, f, (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd)); #else vim_XawScrollbarSetThumb( w, f, (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd), (double)SFdirEnd); #endif SFpathSliderMovedCallback(w, (XtPointer) NULL, (XtPointer)&f); } static Boolean SFworkProc() { SFDir *dir; SFEntry *entry; for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) { if (!(dir->nEntries)) continue; for (entry = &(dir->entries[dir->nEntries - 1]); entry >= dir->entries; entry--) { if (!(entry->statDone)) { (void)SFstatAndCheck(dir, entry); return False; } } } SFworkProcAdded = 0; return True; } /***************** Dir.c */ static int SFcompareEntries(p, q) const void *p; const void *q; { return strcmp(((SFEntry *)p)->real, ((SFEntry *)q)->real); } static int SFgetDir(dir) SFDir *dir; { SFEntry *result = NULL; int Alloc = 0; int i; DIR *dirp; struct dirent *dp; char *str; int len; int maxChars; struct stat statBuf; maxChars = strlen(dir->dir) - 1; dir->entries = NULL; dir->nEntries = 0; dir->nChars = 0; result = NULL; i = 0; dirp = opendir("."); if (!dirp) return 1; (void)mch_stat(".", &statBuf); dir->mtime = statBuf.st_mtime; while ((dp = readdir(dirp))) { /* Ignore "." and ".." */ if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue; if (i >= Alloc) { Alloc = 2 * (Alloc + 1); result = (SFEntry *) XtRealloc((char *) result, (unsigned) (Alloc * sizeof(SFEntry))); } result[i].statDone = 0; str = dp->d_name; len = strlen(str); result[i].real = XtMalloc((unsigned) (len + 2)); (void) strcat(strcpy(result[i].real, str), " "); if (len > maxChars) maxChars = len; result[i].shown = result[i].real; i++; } qsort((char *) result, (size_t) i, sizeof(SFEntry), SFcompareEntries); dir->entries = result; dir->nEntries = i; dir->nChars = maxChars + 1; closedir(dirp); return 0; } /***************** SFinternal.h */ #include <sys/param.h> #include <X11/cursorfont.h> #include <X11/Composite.h> #include <X11/Shell.h> #ifdef FEAT_GUI_NEXTAW # include <X11/neXtaw/Form.h> # include <X11/neXtaw/Command.h> # include <X11/neXtaw/Label.h> #else #include <X11/Xaw/Form.h> #include <X11/Xaw/Command.h> #include <X11/Xaw/Label.h> #endif static char *oneLineTextEditTranslations = "\ <Key>Return: redraw-display()\n\ Ctrl<Key>M: redraw-display()\n\ "; static void SFexposeList __ARGS((Widget w, XtPointer n, XEvent *event, Boolean *cont)); static void SFexposeList(w, n, event, cont) Widget w UNUSED; XtPointer n; XEvent *event; Boolean *cont UNUSED; { if ((event->type == NoExpose) || event->xexpose.count) return; SFdrawList((int)(long)n, SF_DO_NOT_SCROLL); } static void SFmodVerifyCallback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont)); static void SFmodVerifyCallback(w, client_data, event, cont) Widget w UNUSED; XtPointer client_data UNUSED; XEvent *event; Boolean *cont UNUSED; { char buf[2]; if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) && ((*buf) == '\r')) SFstatus = SEL_FILE_OK; else SFstatus = SEL_FILE_TEXT; } static void SFokCallback __ARGS((Widget w, XtPointer cl, XtPointer cd)); static void SFokCallback(w, cl, cd) Widget w UNUSED; XtPointer cl UNUSED; XtPointer cd UNUSED; { SFstatus = SEL_FILE_OK; } static XtCallbackRec SFokSelect[] = { { SFokCallback, (XtPointer) NULL }, { NULL, (XtPointer) NULL }, }; static void SFcancelCallback __ARGS((Widget w, XtPointer cl, XtPointer cd)); static void SFcancelCallback(w, cl, cd) Widget w UNUSED; XtPointer cl UNUSED; XtPointer cd UNUSED; { SFstatus = SEL_FILE_CANCEL; } static XtCallbackRec SFcancelSelect[] = { { SFcancelCallback, (XtPointer) NULL }, { NULL, (XtPointer) NULL }, }; static void SFdismissAction __ARGS((Widget w, XEvent *event, String *params, Cardinal *num_params)); static void SFdismissAction(w, event, params, num_params) Widget w UNUSED; XEvent *event; String *params UNUSED; Cardinal *num_params UNUSED; { if (event->type == ClientMessage && (Atom)event->xclient.data.l[0] != SFwmDeleteWindow) return; SFstatus = SEL_FILE_CANCEL; } static char *wmDeleteWindowTranslation = "\ <Message>WM_PROTOCOLS: SelFileDismiss()\n\ "; static XtActionsRec actions[] = { {"SelFileDismiss", SFdismissAction}, }; static void SFsetColors(bg, fg, scroll_bg, scroll_fg) guicolor_T bg; guicolor_T fg; guicolor_T scroll_bg; guicolor_T scroll_fg; { if (selFileForm) { XtVaSetValues(selFileForm, XtNbackground, bg, XtNforeground, fg, XtNborderColor, bg, NULL); } { int i; for (i = 0; i < 3; ++i) { if (selFileLists[i]) { XtVaSetValues(selFileLists[i], XtNbackground, bg, XtNforeground, fg, XtNborderColor, fg, NULL); } } } if (selFileOK) { XtVaSetValues(selFileOK, XtNbackground, bg, XtNforeground, fg, XtNborderColor, fg, NULL); } if (selFileCancel) { XtVaSetValues(selFileCancel, XtNbackground, bg, XtNforeground, fg, XtNborderColor, fg, NULL); } if (selFilePrompt) { XtVaSetValues(selFilePrompt, XtNbackground, bg, XtNforeground, fg, NULL); } if (gui.dpy) { XSetBackground(gui.dpy, SFtextGC, bg); XSetForeground(gui.dpy, SFtextGC, fg); XSetForeground(gui.dpy, SFlineGC, fg); /* This is an xor GC, so combine the fg and background */ XSetBackground(gui.dpy, SFinvertGC, fg ^ bg); XSetForeground(gui.dpy, SFinvertGC, fg ^ bg); } if (selFileHScroll) { XtVaSetValues(selFileHScroll, XtNbackground, scroll_bg, XtNforeground, scroll_fg, XtNborderColor, fg, NULL); } { int i; for (i = 0; i < 3; i++) { XtVaSetValues(selFileVScrolls[i], XtNbackground, scroll_bg, XtNforeground, scroll_fg, XtNborderColor, fg, NULL); XtVaSetValues(selFileHScrolls[i], XtNbackground, scroll_bg, XtNforeground, scroll_fg, XtNborderColor, fg, NULL); } } } static void SFcreateWidgets(toplevel, prompt, ok, cancel) Widget toplevel; char *prompt; char *ok; char *cancel; { Cardinal n; int listWidth, listHeight; int listSpacing = 10; int scrollThickness = 15; int hScrollX, hScrollY; int vScrollX, vScrollY; selFile = XtVaAppCreateShell("selFile", "SelFile", transientShellWidgetClass, SFdisplay, XtNtransientFor, toplevel, XtNtitle, prompt, NULL); /* Add WM_DELETE_WINDOW protocol */ XtAppAddActions(XtWidgetToApplicationContext(selFile), actions, XtNumber(actions)); XtOverrideTranslations(selFile, XtParseTranslationTable(wmDeleteWindowTranslation)); selFileForm = XtVaCreateManagedWidget("selFileForm", formWidgetClass, selFile, XtNdefaultDistance, 30, XtNforeground, SFfore, XtNbackground, SFback, XtNborderColor, SFback, NULL); selFilePrompt = XtVaCreateManagedWidget("selFilePrompt", labelWidgetClass, selFileForm, XtNlabel, prompt, XtNresizable, True, XtNtop, XtChainTop, XtNbottom, XtChainTop, XtNleft, XtChainLeft, XtNright, XtChainLeft, XtNborderWidth, 0, XtNforeground, SFfore, XtNbackground, SFback, NULL); /* XtVaGetValues(selFilePrompt, XtNforeground, &SFfore, XtNbackground, &SFback, NULL); */ SFinitFont(); SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth + SFbesideText; SFentryHeight = SFaboveAndBelowText + SFcharHeight + SFaboveAndBelowText; listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 + scrollThickness; listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + SFlineToTextV + SFlistSize * SFentryHeight + SFlineToTextV + 1 + scrollThickness; SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4; hScrollX = -1; hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + SFlineToTextV + SFlistSize * SFentryHeight + SFlineToTextV; SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH; vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH; vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV; SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight + SFlineToTextV; SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1; SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + SFlineToTextV; SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 + SFlineToTextV + SFlistSize * SFentryHeight - 1; SFtextX = SFlineToTextH + SFbesideText; SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent; SFsegs[0].x1 = 0; SFsegs[0].y1 = vScrollY; SFsegs[0].x2 = vScrollX - 1; SFsegs[0].y2 = vScrollY; SFsegs[1].x1 = vScrollX; SFsegs[1].y1 = 0; SFsegs[1].x2 = vScrollX; SFsegs[1].y2 = vScrollY - 1; SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH; SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 = SFlineToTextH + SFentryWidth - 1; selFileField = XtVaCreateManagedWidget("selFileField", asciiTextWidgetClass, selFileForm, XtNwidth, 3 * listWidth + 2 * listSpacing + 4, XtNborderColor, SFfore, XtNfromVert, selFilePrompt, XtNvertDistance, 10, XtNresizable, True, XtNtop, XtChainTop, XtNbottom, XtChainTop, XtNleft, XtChainLeft, XtNright, XtChainLeft, XtNstring, SFtextBuffer, XtNlength, MAXPATHL, XtNeditType, XawtextEdit, XtNwrap, XawtextWrapWord, XtNresize, XawtextResizeHeight, XtNuseStringInPlace, True, NULL); XtOverrideTranslations(selFileField, XtParseTranslationTable(oneLineTextEditTranslations)); XtSetKeyboardFocus(selFileForm, selFileField); selFileHScroll = XtVaCreateManagedWidget("selFileHScroll", #ifdef FEAT_GUI_NEXTAW scrollbarWidgetClass, selFileForm, #else vim_scrollbarWidgetClass, selFileForm, #endif XtNorientation, XtorientHorizontal, XtNwidth, SFpathScrollWidth, XtNheight, scrollThickness, XtNborderColor, SFfore, XtNfromVert, selFileField, XtNvertDistance, 30, XtNtop, XtChainTop, XtNbottom, XtChainTop, XtNleft, XtChainLeft, XtNright, XtChainLeft, XtNforeground, gui.scroll_fg_pixel, XtNbackground, gui.scroll_bg_pixel, #ifndef FEAT_GUI_NEXTAW XtNlimitThumb, 1, #endif NULL); XtAddCallback(selFileHScroll, XtNjumpProc, (XtCallbackProc) SFpathSliderMovedCallback, (XtPointer)NULL); XtAddCallback(selFileHScroll, XtNscrollProc, (XtCallbackProc) SFpathAreaSelectedCallback, (XtPointer)NULL); selFileLists[0] = XtVaCreateManagedWidget("selFileList1", compositeWidgetClass, selFileForm, XtNwidth, listWidth, XtNheight, listHeight, XtNforeground, SFfore, XtNbackground, SFback, XtNborderColor, SFfore, XtNfromVert, selFileHScroll, XtNvertDistance, 10, XtNtop, XtChainTop, XtNbottom, XtChainTop, XtNleft, XtChainLeft, XtNright, XtChainLeft, NULL); selFileLists[1] = XtVaCreateManagedWidget("selFileList2", compositeWidgetClass, selFileForm, XtNwidth, listWidth, XtNheight, listHeight, XtNforeground, SFfore, XtNbackground, SFback, XtNborderColor, SFfore, XtNfromHoriz, selFileLists[0], XtNfromVert, selFileHScroll, XtNhorizDistance, listSpacing, XtNvertDistance, 10, XtNtop, XtChainTop, XtNbottom, XtChainTop, XtNleft, XtChainLeft, XtNright, XtChainLeft, NULL); selFileLists[2] = XtVaCreateManagedWidget("selFileList3", compositeWidgetClass, selFileForm, XtNwidth, listWidth, XtNheight, listHeight, XtNforeground, SFfore, XtNbackground, SFback, XtNborderColor, SFfore, XtNfromHoriz, selFileLists[1], XtNfromVert, selFileHScroll, XtNhorizDistance, listSpacing, XtNvertDistance, 10, XtNtop, XtChainTop, XtNbottom, XtChainTop, XtNleft, XtChainLeft, XtNright, XtChainLeft, NULL); for (n = 0; n < 3; n++) { selFileVScrolls[n] = XtVaCreateManagedWidget("selFileVScroll", #ifdef FEAT_GUI_NEXTAW scrollbarWidgetClass, selFileLists[n], #else vim_scrollbarWidgetClass, selFileLists[n], #endif XtNx, vScrollX, XtNy, vScrollY, XtNwidth, scrollThickness, XtNheight, SFvScrollHeight, XtNborderColor, SFfore, XtNforeground, gui.scroll_fg_pixel, XtNbackground, gui.scroll_bg_pixel, #ifndef FEAT_GUI_NEXTAW XtNlimitThumb, 1, #endif NULL); XtAddCallback(selFileVScrolls[n], XtNjumpProc, (XtCallbackProc)SFvFloatSliderMovedCallback, (XtPointer)(long_u)n); XtAddCallback(selFileVScrolls[n], XtNscrollProc, (XtCallbackProc)SFvAreaSelectedCallback, (XtPointer)n); selFileHScrolls[n] = XtVaCreateManagedWidget("selFileHScroll", #ifdef FEAT_GUI_NEXTAW scrollbarWidgetClass, selFileLists[n], #else vim_scrollbarWidgetClass, selFileLists[n], #endif XtNorientation, XtorientHorizontal, XtNx, hScrollX, XtNy, hScrollY, XtNwidth, SFhScrollWidth, XtNheight, scrollThickness, XtNborderColor, SFfore, XtNforeground, gui.scroll_fg_pixel, XtNbackground, gui.scroll_bg_pixel, #ifndef FEAT_GUI_NEXTAW XtNlimitThumb, 1, #endif NULL); XtAddCallback(selFileHScrolls[n], XtNjumpProc, (XtCallbackProc)SFhSliderMovedCallback, (XtPointer)(long_u)n); XtAddCallback(selFileHScrolls[n], XtNscrollProc, (XtCallbackProc)SFhAreaSelectedCallback, (XtPointer)n); } selFileOK = XtVaCreateManagedWidget("selFileOK", commandWidgetClass, selFileForm, XtNlabel, ok, XtNresizable, True, XtNcallback, SFokSelect, XtNforeground, SFfore, XtNbackground, SFback, XtNborderColor, SFfore, XtNfromHoriz, selFileLists[0], XtNfromVert, selFileLists[0], XtNvertDistance, 30, XtNtop, XtChainTop, XtNbottom, XtChainTop, XtNleft, XtChainLeft, XtNright, XtChainLeft, NULL); selFileCancel = XtVaCreateManagedWidget("selFileCancel", commandWidgetClass, selFileForm, XtNlabel, cancel, XtNresizable, True, XtNcallback, SFcancelSelect, XtNforeground, SFfore, XtNbackground, SFback, XtNborderColor, SFfore, XtNfromHoriz, selFileOK, XtNfromVert, selFileLists[0], XtNhorizDistance, 30, XtNvertDistance, 30, XtNtop, XtChainTop, XtNbottom, XtChainTop, XtNleft, XtChainLeft, XtNright, XtChainLeft, NULL); XtSetMappedWhenManaged(selFile, False); XtRealizeWidget(selFile); /* Add WM_DELETE_WINDOW protocol */ SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False); XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1); SFcreateGC(); for (n = 0; n < 3; n++) { XtAddEventHandler(selFileLists[n], ExposureMask, True, (XtEventHandler)SFexposeList, (XtPointer)(long_u)n); XtAddEventHandler(selFileLists[n], EnterWindowMask, False, (XtEventHandler)SFenterList, (XtPointer)(long_u)n); XtAddEventHandler(selFileLists[n], LeaveWindowMask, False, (XtEventHandler)SFleaveList, (XtPointer)(long_u)n); XtAddEventHandler(selFileLists[n], PointerMotionMask, False, (XtEventHandler)SFmotionList, (XtPointer)(long_u)n); XtAddEventHandler(selFileLists[n], ButtonPressMask, False, (XtEventHandler)SFbuttonPressList, (XtPointer)(long_u)n); XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False, (XtEventHandler)SFbuttonReleaseList, (XtPointer)(long_u)n); } XtAddEventHandler(selFileField, KeyPressMask, False, SFmodVerifyCallback, (XtPointer)NULL); SFapp = XtWidgetToApplicationContext(selFile); } static void SFtextChanged() { #if defined(FEAT_XFONTSET) && defined(XtNinternational) if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide) { wchar_t *wcbuf=(wchar_t *)SFtextBuffer; if ((wcbuf[0] == L'/') || (wcbuf[0] == L'~')) { (void) wcstombs(SFcurrentPath, wcbuf, MAXPATHL); SFtextPos = XawTextGetInsertionPoint(selFileField); } else { strcpy(SFcurrentPath, SFstartDir); (void) wcstombs(SFcurrentPath + strlen(SFcurrentPath), wcbuf, MAXPATHL); SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir); } } else #endif if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~')) { (void) strcpy(SFcurrentPath, SFtextBuffer); SFtextPos = XawTextGetInsertionPoint(selFileField); } else { (void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer); SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir); } if (!SFworkProcAdded) { (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL); SFworkProcAdded = 1; } SFupdatePath(); } static char * SFgetText() { #if defined(FEAT_XFONTSET) && defined(XtNinternational) char *buf; if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide) { wchar_t *wcbuf; int mbslength; XtVaGetValues(selFileField, XtNstring, &wcbuf, NULL); mbslength = wcstombs(NULL, wcbuf, 0); /* Hack: some broken wcstombs() returns zero, just get a large buffer */ if (mbslength == 0 && wcbuf != NULL && wcbuf[0] != 0) mbslength = MAXPATHL; buf=(char *)XtMalloc(mbslength + 1); wcstombs(buf, wcbuf, mbslength +1); return buf; } #endif return (char *)vim_strsave((char_u *)SFtextBuffer); } static void SFprepareToReturn() { SFstatus = SEL_FILE_NULL; XtRemoveGrab(selFile); XtUnmapWidget(selFile); XtRemoveTimeOut(SFdirModTimerId); if (SFchdir(SFstartDir)) { EMSG(_("E614: vim_SelFile: can't return to current directory")); SFstatus = SEL_FILE_CANCEL; } } char * vim_SelFile(toplevel, prompt, init_path, show_entry, x, y, fg, bg, scroll_fg, scroll_bg) Widget toplevel; char *prompt; char *init_path; int (*show_entry)(); int x, y; guicolor_T fg, bg; guicolor_T scroll_fg, scroll_bg; /* The "Scrollbar" group colors */ { static int firstTime = 1; XEvent event; char *name_return; if (prompt == NULL) prompt = _("Pathname:"); SFfore = fg; SFback = bg; if (mch_dirname((char_u *)SFstartDir, MAXPATHL) == FAIL) { EMSG(_("E615: vim_SelFile: can't get current directory")); return NULL; } if (firstTime) { firstTime = 0; SFdisplay = XtDisplay(toplevel); SFcreateWidgets(toplevel, prompt, _("OK"), _("Cancel")); } else { XtVaSetValues(selFilePrompt, XtNlabel, prompt, NULL); XtVaSetValues(selFile, XtNtitle, prompt, NULL); SFsetColors(bg, fg, scroll_bg, scroll_fg); } XtVaSetValues(selFile, XtNx, x, XtNy, y, NULL); XtMapWidget(selFile); (void)strcat(SFstartDir, "/"); (void)strcpy(SFcurrentDir, SFstartDir); if (init_path) { if (init_path[0] == '/') { (void)strcpy(SFcurrentPath, init_path); if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) SFsetText(SFcurrentPath); else SFsetText(&(SFcurrentPath[strlen(SFstartDir)])); } else { (void)strcat(strcpy(SFcurrentPath, SFstartDir), init_path); SFsetText(&(SFcurrentPath[strlen(SFstartDir)])); } } else (void)strcpy(SFcurrentPath, SFstartDir); SFfunc = show_entry; SFtextChanged(); XtAddGrab(selFile, True, True); SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000, SFdirModTimer, (XtPointer) NULL); for (;;) { XtAppNextEvent(SFapp, &event); XtDispatchEvent(&event); switch (SFstatus) { case SEL_FILE_TEXT: SFstatus = SEL_FILE_NULL; SFtextChanged(); break; case SEL_FILE_OK: name_return = SFgetText(); SFprepareToReturn(); return name_return; case SEL_FILE_CANCEL: SFprepareToReturn(); return NULL; case SEL_FILE_NULL: break; } } } #endif /* FEAT_BROWSE */