PageRenderTime 48ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/xboard-4.5.2a/filebrowser/selfile.c

#
C | 873 lines | 690 code | 130 blank | 53 comment | 79 complexity | 6937f12c4b73aab7c5d89caf450c777c MD5 | raw file
Possible License(s): GPL-3.0, MPL-2.0-no-copyleft-exception
  1. /*
  2. * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
  3. *
  4. * Permission to use, copy, modify, and distribute this software and its
  5. * documentation for any purpose and without fee is hereby granted, provided
  6. * that the above copyright notice appear in all copies and that both that
  7. * copyright notice and this permission notice appear in supporting
  8. * documentation, and that the name of Software Research Associates not be used
  9. * in advertising or publicity pertaining to distribution of the software
  10. * without specific, written prior permission. Software Research Associates
  11. * makes no representations about the suitability of this software for any
  12. * purpose. It is provided "as is" without express or implied warranty.
  13. *
  14. * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  15. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  16. * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
  17. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  18. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  19. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  20. * PERFORMANCE OF THIS SOFTWARE.
  21. *
  22. * Author: Erik M. van der Poel
  23. * Software Research Associates, Inc., Tokyo, Japan
  24. * erik@sra.co.jp
  25. */
  26. /*
  27. * Author's address:
  28. *
  29. * erik@sra.co.jp
  30. * OR
  31. * erik%sra.co.jp@uunet.uu.net
  32. * OR
  33. * erik%sra.co.jp@mcvax.uucp
  34. * OR
  35. * try junet instead of co.jp
  36. * OR
  37. * Erik M. van der Poel
  38. * Software Research Associates, Inc.
  39. * 1-1-1 Hirakawa-cho, Chiyoda-ku
  40. * Tokyo 102 Japan. TEL +81-3-234-2692
  41. */
  42. #include <stdio.h>
  43. #include <errno.h>
  44. /* BSD 4.3 errno.h does not declare errno */
  45. extern int errno;
  46. //extern int sys_nerr;
  47. //extern char *sys_errlist[]; // [HGM] this produced a compile error in Ubuntu 8.04
  48. #include <sys/param.h>
  49. #include <X11/cursorfont.h>
  50. #include <X11/Intrinsic.h>
  51. #include <X11/StringDefs.h>
  52. #include <X11/Composite.h>
  53. #include <X11/Shell.h>
  54. #include <X11/Xaw/Form.h>
  55. #include <X11/Xaw/Command.h>
  56. #include <X11/Xaw/Scrollbar.h>
  57. #include <X11/Xaw/Label.h>
  58. #include <X11/Xaw/Cardinals.h>
  59. #include "selfile.h"
  60. #include "xstat.h"
  61. /* added missing prototypes */
  62. extern void SFdrawList(int,int);
  63. extern void SFinitFont();
  64. extern void SFcreateGC();
  65. extern int SFchdir(char *);
  66. extern void SFupdatePath();
  67. extern void SFsetText(char *);
  68. extern char SFstatChar(struct stat*);
  69. #ifndef MAXPATHLEN
  70. #define MAXPATHLEN 1024
  71. #endif /* ndef MAXPATHLEN */
  72. #if !defined(SVR4) && !defined(SYSV) && !defined(USG)
  73. extern char *getwd();
  74. #endif /* !defined(SVR4) && !defined(SYSV) && !defined(USG) */
  75. int SFstatus = SEL_FILE_NULL;
  76. char
  77. SFstartDir[MAXPATHLEN],
  78. SFcurrentPath[MAXPATHLEN],
  79. SFlastPath[MAXPATHLEN],
  80. SFcurrentDir[MAXPATHLEN];
  81. Widget
  82. selFile,
  83. selFileCancel,
  84. selFileField,
  85. selFileMess,
  86. filterField,
  87. selFileForm,
  88. selFileHScroll,
  89. selFileHScrolls[3],
  90. selFileLists[3],
  91. selFileOK,
  92. selFilePrompt,
  93. selFileVScrolls[3];
  94. Display *SFdisplay;
  95. Pixel SFfore, SFback;
  96. Atom SFwmDeleteWindow;
  97. XSegment SFsegs[2], SFcompletionSegs[2];
  98. XawTextPosition SFtextPos;
  99. int SFupperX, SFlowerY, SFupperY;
  100. int SFtextX, SFtextYoffset;
  101. int SFentryWidth, SFentryHeight;
  102. int SFlineToTextH = 3;
  103. int SFlineToTextV = 3;
  104. int SFbesideText = 3;
  105. int SFaboveAndBelowText = 2;
  106. int SFcharsPerEntry = 15;
  107. int SFlistSize = 10;
  108. int SFworkProcAdded = 0;
  109. XtAppContext SFapp;
  110. int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
  111. char SFtextBuffer[MAXPATHLEN];
  112. char SFfilterBuffer[MAXPATHLEN];
  113. XtIntervalId SFdirModTimerId;
  114. int (*SFfunc)();
  115. Boolean SFpathFlag; // [HGM]
  116. static char *oneLineTextEditTranslations = "\
  117. <Key>Return: redraw-display()\n\
  118. Ctrl<Key>M: redraw-display()\n\
  119. ";
  120. /* ARGSUSED */
  121. static void
  122. SFexposeList(w, n, event, cont)
  123. Widget w;
  124. XtPointer n;
  125. XEvent *event;
  126. Boolean *cont;
  127. {
  128. if ((event->type == NoExpose) || event->xexpose.count) {
  129. return;
  130. }
  131. SFdrawList((int)(intptr_t)n, SF_DO_NOT_SCROLL);
  132. }
  133. void
  134. SFpurge()
  135. {
  136. if(SFdirs) XtFree((XtPointer) SFdirs);
  137. SFdirs = NULL; // kludge to throw away all cached info
  138. }
  139. /* ARGSUSED */
  140. static void
  141. SFmodVerifyCallback(w, client_data, event, cont)
  142. Widget w;
  143. XtPointer client_data;
  144. XEvent *event;
  145. Boolean *cont;
  146. {
  147. char buf[2];
  148. if (
  149. (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
  150. ((*buf) == '\r' || *buf == 033)
  151. ) {
  152. if(client_data) {
  153. Arg args[10]; char *p;
  154. if(*buf == 033) { // [HGM] esc in filter: restore and give focus to path
  155. XtSetArg(args[0], XtNstring, SFfilterBuffer);
  156. XtSetValues(filterField, args, 1);
  157. XtSetKeyboardFocus(selFileForm, selFileField);
  158. SFstatus = SEL_FILE_TEXT;
  159. return;
  160. } else
  161. if(!SFpathFlag) // [HGM] cr: fetch current extenson filter
  162. {
  163. XtSetArg(args[0], XtNstring, &p);
  164. XtGetValues(filterField, args, 1);
  165. if(strcmp(SFfilterBuffer, p)) SFpurge();
  166. strncpy(SFfilterBuffer, p, 40);
  167. SFstatus = SEL_FILE_TEXT;
  168. }
  169. return;
  170. }
  171. SFstatus = (*buf == 033 ? SEL_FILE_CANCEL : SEL_FILE_OK);
  172. } else {
  173. if(!client_data) SFstatus = SEL_FILE_TEXT;
  174. }
  175. }
  176. /* ARGSUSED */
  177. static void
  178. SFokCallback(w, cl, cd)
  179. Widget w;
  180. XtPointer cl, cd;
  181. {
  182. SFstatus = SEL_FILE_OK;
  183. }
  184. static XtCallbackRec SFokSelect[] = {
  185. { SFokCallback, (XtPointer) NULL },
  186. { NULL, (XtPointer) NULL },
  187. };
  188. /* ARGSUSED */
  189. static void
  190. SFcancelCallback(w, cl, cd)
  191. Widget w;
  192. XtPointer cl, cd;
  193. {
  194. SFstatus = SEL_FILE_CANCEL;
  195. }
  196. static XtCallbackRec SFcancelSelect[] = {
  197. { SFcancelCallback, (XtPointer) NULL },
  198. { NULL, (XtPointer) NULL },
  199. };
  200. /* ARGSUSED */
  201. static void
  202. SFdismissAction(w, event, params, num_params)
  203. Widget w;
  204. XEvent *event;
  205. String *params;
  206. Cardinal *num_params;
  207. {
  208. if (event->type == ClientMessage &&
  209. event->xclient.data.l[0] != SFwmDeleteWindow) return;
  210. SFstatus = SEL_FILE_CANCEL;
  211. }
  212. static char *wmDeleteWindowTranslation = "\
  213. <Message>WM_PROTOCOLS: SelFileDismiss()\n\
  214. ";
  215. static XtActionsRec actions[] = {
  216. {"SelFileDismiss", SFdismissAction},
  217. };
  218. void SFsetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b)
  219. {
  220. XtSetKeyboardFocus((Widget) data, w);
  221. }
  222. void SFwheelProc(Widget w, XtPointer data, XEvent *event, Boolean *b)
  223. { // [HGM] mouse-wheel callback scrolls lists
  224. int dir, n = (intptr_t) data;
  225. if(event->xbutton.button == Button4) dir = -2; // kludge to indicate relative motion
  226. if(event->xbutton.button == Button5) dir = -1;
  227. SFvSliderMovedCallback(w, n, dir);
  228. }
  229. static void
  230. SFcreateWidgets(toplevel, prompt, ok, cancel)
  231. Widget toplevel;
  232. char *prompt;
  233. char *ok;
  234. char *cancel;
  235. {
  236. Cardinal i, n;
  237. int listWidth, listHeight;
  238. int listSpacing = 10;
  239. int scrollThickness = 15;
  240. int hScrollX, hScrollY;
  241. int vScrollX, vScrollY;
  242. Cursor
  243. xtermCursor,
  244. sbRightArrowCursor,
  245. dotCursor;
  246. Arg arglist[20];
  247. i = 0;
  248. XtSetArg(arglist[i], XtNtransientFor, toplevel); i++;
  249. selFile = XtAppCreateShell("Browse", "SelFile",
  250. transientShellWidgetClass, SFdisplay, arglist, i);
  251. /* Add WM_DELETE_WINDOW protocol */
  252. XtAppAddActions(XtWidgetToApplicationContext(selFile),
  253. actions, XtNumber(actions));
  254. XtOverrideTranslations(selFile,
  255. XtParseTranslationTable(wmDeleteWindowTranslation));
  256. i = 0;
  257. XtSetArg(arglist[i], XtNdefaultDistance, 30); i++;
  258. selFileForm = XtCreateManagedWidget("selFileForm",
  259. formWidgetClass, selFile, arglist, i);
  260. i = 0;
  261. XtSetArg(arglist[i], XtNlabel, prompt); i++;
  262. XtSetArg(arglist[i], XtNresizable, True); i++;
  263. XtSetArg(arglist[i], XtNtop, XtChainTop); i++;
  264. XtSetArg(arglist[i], XtNbottom, XtChainTop); i++;
  265. XtSetArg(arglist[i], XtNleft, XtChainLeft); i++;
  266. XtSetArg(arglist[i], XtNright, XtChainLeft); i++;
  267. XtSetArg(arglist[i], XtNborderWidth, 0); i++;
  268. selFilePrompt = XtCreateManagedWidget("selFilePrompt",
  269. labelWidgetClass, selFileForm, arglist, i);
  270. i = 0;
  271. XtSetArg(arglist[i], XtNforeground, &SFfore); i++;
  272. XtSetArg(arglist[i], XtNbackground, &SFback); i++;
  273. XtGetValues(selFilePrompt, arglist, i);
  274. SFinitFont();
  275. SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth +
  276. SFbesideText;
  277. SFentryHeight = SFaboveAndBelowText + SFcharHeight +
  278. SFaboveAndBelowText;
  279. listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
  280. scrollThickness;
  281. listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
  282. SFlineToTextV + SFlistSize * SFentryHeight +
  283. SFlineToTextV + 1 + scrollThickness;
  284. SFpathScrollWidth = NR * listWidth + (NR-1) * listSpacing + 4;
  285. hScrollX = -1;
  286. hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
  287. SFlineToTextV + SFlistSize * SFentryHeight +
  288. SFlineToTextV;
  289. SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
  290. vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
  291. vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
  292. SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
  293. SFlineToTextV;
  294. SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
  295. SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
  296. SFlineToTextV;
  297. SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
  298. SFlineToTextV + SFlistSize * SFentryHeight - 1;
  299. SFtextX = SFlineToTextH + SFbesideText;
  300. SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
  301. SFsegs[0].x1 = 0;
  302. SFsegs[0].y1 = vScrollY;
  303. SFsegs[0].x2 = vScrollX - 1;
  304. SFsegs[0].y2 = vScrollY;
  305. SFsegs[1].x1 = vScrollX;
  306. SFsegs[1].y1 = 0;
  307. SFsegs[1].x2 = vScrollX;
  308. SFsegs[1].y2 = vScrollY - 1;
  309. SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
  310. SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
  311. SFlineToTextH + SFentryWidth - 1;
  312. i = 0;
  313. XtSetArg(arglist[i], XtNwidth, NR * listWidth + (NR - 1) * listSpacing + 4);
  314. i++;
  315. XtSetArg(arglist[i], XtNborderColor, SFfore); i++;
  316. XtSetArg(arglist[i], XtNfromVert, selFilePrompt); i++;
  317. XtSetArg(arglist[i], XtNvertDistance, 5); i++;
  318. XtSetArg(arglist[i], XtNresizable, True); i++;
  319. XtSetArg(arglist[i], XtNtop, XtChainTop); i++;
  320. XtSetArg(arglist[i], XtNbottom, XtChainTop); i++;
  321. XtSetArg(arglist[i], XtNleft, XtChainLeft); i++;
  322. XtSetArg(arglist[i], XtNright, XtChainLeft); i++;
  323. XtSetArg(arglist[i], XtNstring, SFtextBuffer); i++;
  324. XtSetArg(arglist[i], XtNlength, MAXPATHLEN); i++;
  325. XtSetArg(arglist[i], XtNeditType, XawtextEdit); i++;
  326. XtSetArg(arglist[i], XtNwrap, XawtextWrapWord); i++;
  327. XtSetArg(arglist[i], XtNresize, XawtextResizeHeight); i++;
  328. XtSetArg(arglist[i], XtNuseStringInPlace, True); i++;
  329. selFileField = XtCreateManagedWidget("selFileField",
  330. asciiTextWidgetClass, selFileForm, arglist, i);
  331. XtOverrideTranslations(selFileField,
  332. XtParseTranslationTable(oneLineTextEditTranslations));
  333. XtAddEventHandler(selFileField, ButtonPressMask, False, SFsetFocus, (XtPointer) selFileForm);
  334. i = 0;
  335. XtSetArg(arglist[i], XtNlabel, "Filter on extensions:"); i++;
  336. XtSetArg(arglist[i], XtNvertDistance, 5); i++;
  337. XtSetArg(arglist[i], XtNfromVert, selFileField); i++;
  338. XtSetArg(arglist[i], XtNresizable, True); i++;
  339. XtSetArg(arglist[i], XtNtop, XtChainTop); i++;
  340. XtSetArg(arglist[i], XtNbottom, XtChainTop); i++;
  341. XtSetArg(arglist[i], XtNleft, XtChainLeft); i++;
  342. XtSetArg(arglist[i], XtNright, XtChainLeft); i++;
  343. XtSetArg(arglist[i], XtNborderWidth, 0); i++;
  344. selFileMess = XtCreateManagedWidget("selFileMess",
  345. labelWidgetClass, selFileForm, arglist, i);
  346. i = 0;
  347. XtSetArg(arglist[i], XtNwidth, NR * listWidth + (NR - 1) * listSpacing + 4);
  348. i++;
  349. XtSetArg(arglist[i], XtNborderColor, SFfore); i++;
  350. XtSetArg(arglist[i], XtNvertDistance, 5); i++;
  351. XtSetArg(arglist[i], XtNfromVert, selFileMess); i++;
  352. XtSetArg(arglist[i], XtNresizable, True); i++;
  353. XtSetArg(arglist[i], XtNtop, XtChainTop); i++;
  354. XtSetArg(arglist[i], XtNbottom, XtChainTop); i++;
  355. XtSetArg(arglist[i], XtNleft, XtChainLeft); i++;
  356. XtSetArg(arglist[i], XtNright, XtChainLeft); i++;
  357. XtSetArg(arglist[i], XtNlength, MAXPATHLEN); i++;
  358. XtSetArg(arglist[i], XtNeditType, XawtextEdit); i++;
  359. XtSetArg(arglist[i], XtNwrap, XawtextWrapWord); i++;
  360. XtSetArg(arglist[i], XtNresize, XawtextResizeHeight); i++;
  361. XtSetArg(arglist[i], XtNuseStringInPlace, False); i++;
  362. filterField = XtCreateManagedWidget("filterField",
  363. asciiTextWidgetClass, selFileForm, arglist, i);
  364. XtOverrideTranslations(filterField,
  365. XtParseTranslationTable(oneLineTextEditTranslations));
  366. XtAddEventHandler(filterField, ButtonPressMask, False, SFsetFocus, (XtPointer) selFileForm);
  367. i = 0;
  368. XtSetArg(arglist[i], XtNorientation, XtorientHorizontal); i++;
  369. XtSetArg(arglist[i], XtNwidth, SFpathScrollWidth); i++;
  370. XtSetArg(arglist[i], XtNheight, scrollThickness); i++;
  371. XtSetArg(arglist[i], XtNborderColor, SFfore); i++;
  372. XtSetArg(arglist[i], XtNfromVert, filterField); i++;
  373. XtSetArg(arglist[i], XtNvertDistance, 10); i++;
  374. XtSetArg(arglist[i], XtNtop, XtChainTop); i++;
  375. XtSetArg(arglist[i], XtNbottom, XtChainTop); i++;
  376. XtSetArg(arglist[i], XtNleft, XtChainLeft); i++;
  377. XtSetArg(arglist[i], XtNright, XtChainLeft); i++;
  378. selFileHScroll = XtCreateManagedWidget("selFileHScroll",
  379. scrollbarWidgetClass, selFileForm, arglist, i);
  380. XtAddCallback(selFileHScroll, XtNjumpProc,
  381. SFpathSliderMovedCallback, (XtPointer) NULL);
  382. XtAddCallback(selFileHScroll, XtNscrollProc,
  383. SFpathAreaSelectedCallback, (XtPointer) NULL);
  384. i = 0;
  385. XtSetArg(arglist[i], XtNwidth, listWidth); i++;
  386. XtSetArg(arglist[i], XtNheight, listHeight); i++;
  387. XtSetArg(arglist[i], XtNborderColor, SFfore); i++;
  388. XtSetArg(arglist[i], XtNfromVert, selFileHScroll); i++;
  389. XtSetArg(arglist[i], XtNvertDistance, 10); i++;
  390. XtSetArg(arglist[i], XtNtop, XtChainTop); i++;
  391. XtSetArg(arglist[i], XtNbottom, XtChainTop); i++;
  392. XtSetArg(arglist[i], XtNleft, XtChainLeft); i++;
  393. XtSetArg(arglist[i], XtNright, XtChainLeft); i++;
  394. selFileLists[0] = XtCreateManagedWidget("selFileList1",
  395. compositeWidgetClass, selFileForm, arglist, i);
  396. #if (NR == 3)
  397. i = 0;
  398. XtSetArg(arglist[i], XtNwidth, listWidth); i++;
  399. XtSetArg(arglist[i], XtNheight, listHeight); i++;
  400. XtSetArg(arglist[i], XtNborderColor, SFfore); i++;
  401. XtSetArg(arglist[i], XtNfromHoriz, selFileLists[0]); i++;
  402. XtSetArg(arglist[i], XtNfromVert, selFileHScroll); i++;
  403. XtSetArg(arglist[i], XtNhorizDistance, listSpacing); i++;
  404. XtSetArg(arglist[i], XtNvertDistance, 10); i++;
  405. XtSetArg(arglist[i], XtNtop, XtChainTop); i++;
  406. XtSetArg(arglist[i], XtNbottom, XtChainTop); i++;
  407. XtSetArg(arglist[i], XtNleft, XtChainLeft); i++;
  408. XtSetArg(arglist[i], XtNright, XtChainLeft); i++;
  409. selFileLists[1] = XtCreateManagedWidget("selFileList2",
  410. compositeWidgetClass, selFileForm, arglist, i);
  411. i = 0;
  412. XtSetArg(arglist[i], XtNwidth, listWidth); i++;
  413. XtSetArg(arglist[i], XtNheight, listHeight); i++;
  414. XtSetArg(arglist[i], XtNborderColor, SFfore); i++;
  415. XtSetArg(arglist[i], XtNfromHoriz, selFileLists[1]); i++;
  416. XtSetArg(arglist[i], XtNfromVert, selFileHScroll); i++;
  417. XtSetArg(arglist[i], XtNhorizDistance, listSpacing); i++;
  418. XtSetArg(arglist[i], XtNvertDistance, 10); i++;
  419. XtSetArg(arglist[i], XtNtop, XtChainTop); i++;
  420. XtSetArg(arglist[i], XtNbottom, XtChainTop); i++;
  421. XtSetArg(arglist[i], XtNleft, XtChainLeft); i++;
  422. XtSetArg(arglist[i], XtNright, XtChainLeft); i++;
  423. selFileLists[2] = XtCreateManagedWidget("selFileList3",
  424. compositeWidgetClass, selFileForm, arglist, i);
  425. #endif
  426. for (n = 0; n < NR; n++) {
  427. i = 0;
  428. XtSetArg(arglist[i], XtNx, vScrollX); i++;
  429. XtSetArg(arglist[i], XtNy, vScrollY); i++;
  430. XtSetArg(arglist[i], XtNwidth, scrollThickness); i++;
  431. XtSetArg(arglist[i], XtNheight, SFvScrollHeight); i++;
  432. XtSetArg(arglist[i], XtNborderColor, SFfore); i++;
  433. selFileVScrolls[n] = XtCreateManagedWidget("selFileVScroll",
  434. scrollbarWidgetClass, selFileLists[n], arglist, i);
  435. XtAddCallback(selFileVScrolls[n], XtNjumpProc,
  436. SFvFloatSliderMovedCallback, (XtPointer)(intptr_t) n);
  437. XtAddCallback(selFileVScrolls[n], XtNscrollProc,
  438. SFvAreaSelectedCallback, (XtPointer)(intptr_t) n);
  439. i = 0;
  440. XtSetArg(arglist[i], XtNorientation, XtorientHorizontal);
  441. i++;
  442. XtSetArg(arglist[i], XtNx, hScrollX); i++;
  443. XtSetArg(arglist[i], XtNy, hScrollY); i++;
  444. XtSetArg(arglist[i], XtNwidth, SFhScrollWidth); i++;
  445. XtSetArg(arglist[i], XtNheight, scrollThickness); i++;
  446. XtSetArg(arglist[i], XtNborderColor, SFfore); i++;
  447. selFileHScrolls[n] = XtCreateManagedWidget("selFileHScroll",
  448. scrollbarWidgetClass, selFileLists[n], arglist, i);
  449. XtAddCallback(selFileHScrolls[n], XtNjumpProc,
  450. SFhSliderMovedCallback, (XtPointer)(intptr_t) n);
  451. XtAddCallback(selFileHScrolls[n], XtNscrollProc,
  452. SFhAreaSelectedCallback, (XtPointer)(intptr_t) n);
  453. XtAddEventHandler(selFileVScrolls[n], ButtonPressMask, False,
  454. SFwheelProc, (XtPointer)(intptr_t) n); // [HGM] couplemouse wheel to v-scroll
  455. }
  456. i = 0;
  457. XtSetArg(arglist[i], XtNlabel, ok); i++;
  458. XtSetArg(arglist[i], XtNresizable, True); i++;
  459. XtSetArg(arglist[i], XtNcallback, SFokSelect); i++;
  460. XtSetArg(arglist[i], XtNborderColor, SFfore); i++;
  461. XtSetArg(arglist[i], XtNfromVert, selFileLists[0]); i++;
  462. XtSetArg(arglist[i], XtNvertDistance, 30); i++;
  463. XtSetArg(arglist[i], XtNtop, XtChainTop); i++;
  464. XtSetArg(arglist[i], XtNbottom, XtChainTop); i++;
  465. XtSetArg(arglist[i], XtNleft, XtChainLeft); i++;
  466. XtSetArg(arglist[i], XtNright, XtChainLeft); i++;
  467. selFileOK = XtCreateManagedWidget("selFileOK", commandWidgetClass,
  468. selFileForm, arglist, i);
  469. i = 0;
  470. XtSetArg(arglist[i], XtNlabel, cancel); i++;
  471. XtSetArg(arglist[i], XtNresizable, True); i++;
  472. XtSetArg(arglist[i], XtNcallback, SFcancelSelect); i++;
  473. XtSetArg(arglist[i], XtNborderColor, SFfore); i++;
  474. XtSetArg(arglist[i], XtNfromHoriz, selFileOK); i++;
  475. XtSetArg(arglist[i], XtNfromVert, selFileLists[0]); i++;
  476. XtSetArg(arglist[i], XtNhorizDistance, 30); i++;
  477. XtSetArg(arglist[i], XtNvertDistance, 30); i++;
  478. XtSetArg(arglist[i], XtNtop, XtChainTop); i++;
  479. XtSetArg(arglist[i], XtNbottom, XtChainTop); i++;
  480. XtSetArg(arglist[i], XtNleft, XtChainLeft); i++;
  481. XtSetArg(arglist[i], XtNright, XtChainLeft); i++;
  482. selFileCancel = XtCreateManagedWidget("selFileCancel",
  483. commandWidgetClass, selFileForm, arglist, i);
  484. XtSetMappedWhenManaged(selFile, False);
  485. XtRealizeWidget(selFile);
  486. /* Add WM_DELETE_WINDOW protocol */
  487. SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
  488. XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
  489. SFcreateGC();
  490. xtermCursor = XCreateFontCursor(SFdisplay, XC_xterm);
  491. sbRightArrowCursor = XCreateFontCursor(SFdisplay, XC_sb_right_arrow);
  492. dotCursor = XCreateFontCursor(SFdisplay, XC_dot);
  493. XDefineCursor(SFdisplay, XtWindow(selFileForm), xtermCursor);
  494. XDefineCursor(SFdisplay, XtWindow(selFileField), xtermCursor);
  495. XDefineCursor(SFdisplay, XtWindow(filterField), xtermCursor);
  496. for (n = 0; n < NR; n++) {
  497. XDefineCursor(SFdisplay, XtWindow(selFileLists[n]),
  498. sbRightArrowCursor);
  499. }
  500. XDefineCursor(SFdisplay, XtWindow(selFileOK), dotCursor);
  501. XDefineCursor(SFdisplay, XtWindow(selFileCancel), dotCursor);
  502. for (n = 0; n < NR; n++) {
  503. XtAddEventHandler(selFileLists[n], ExposureMask, True,
  504. SFexposeList, (XtPointer)(intptr_t) n);
  505. XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
  506. SFenterList, (XtPointer)(intptr_t) n);
  507. XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
  508. SFleaveList, (XtPointer)(intptr_t) n);
  509. XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
  510. SFmotionList, (XtPointer)(intptr_t) n);
  511. XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
  512. SFbuttonPressList, (XtPointer)(intptr_t) n);
  513. XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
  514. SFbuttonReleaseList, (XtPointer)(intptr_t) n);
  515. }
  516. XtAddEventHandler(selFileField, KeyPressMask, False,
  517. SFmodVerifyCallback, (XtPointer) NULL);
  518. XtAddEventHandler(filterField, KeyReleaseMask, False,
  519. SFmodVerifyCallback, (XtPointer) 1);
  520. XtSetKeyboardFocus(selFileForm, selFileField);
  521. SFapp = XtWidgetToApplicationContext(selFile);
  522. }
  523. /* position widget under the cursor */
  524. void
  525. SFpositionWidget(w)
  526. Widget w;
  527. {
  528. Arg args[3];
  529. Cardinal num_args;
  530. Dimension width, height, b_width;
  531. int x, y, max_x, max_y;
  532. Window root, child;
  533. int dummyx, dummyy;
  534. unsigned int dummymask;
  535. XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &x, &y,
  536. &dummyx, &dummyy, &dummymask);
  537. num_args = 0;
  538. XtSetArg(args[num_args], XtNwidth, &width); num_args++;
  539. XtSetArg(args[num_args], XtNheight, &height); num_args++;
  540. XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
  541. XtGetValues(w, args, num_args);
  542. width += 2 * b_width;
  543. height += 2 * b_width;
  544. x -= ( (Position) width/2 );
  545. if (x < 0) x = 0;
  546. if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x;
  547. y -= ( (Position) height/2 );
  548. if (y < 0) y = 0;
  549. if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y;
  550. num_args = 0;
  551. XtSetArg(args[num_args], XtNx, x); num_args++;
  552. XtSetArg(args[num_args], XtNy, y); num_args++;
  553. XtSetValues(w, args, num_args);
  554. }
  555. FILE *
  556. SFopenFile(name, mode, prompt, failed)
  557. char *name;
  558. char *mode;
  559. char *prompt;
  560. char *failed;
  561. {
  562. Arg args[1];
  563. FILE *fp;
  564. SFchdir(SFstartDir);
  565. if ((fp = fopen(name, mode)) == NULL) {
  566. char *buf;
  567. if (1) { // [HGM] always use strerror
  568. buf = XtMalloc(strlen(failed) + strlen(strerror(errno)) +
  569. strlen(prompt) + 2);
  570. strcpy(buf, failed);
  571. strcat(buf, strerror(errno));
  572. strcat(buf, "\n");
  573. strcat(buf, prompt);
  574. } else {
  575. buf = XtMalloc(strlen(failed) + strlen(prompt) + 2);
  576. strcpy(buf, failed);
  577. strcat(buf, "\n");
  578. strcat(buf, prompt);
  579. }
  580. XtSetArg(args[0], XtNlabel, buf);
  581. XtSetValues(selFilePrompt, args, ONE);
  582. XtFree(buf);
  583. return NULL;
  584. }
  585. return fp;
  586. }
  587. void
  588. SFtextChanged()
  589. {
  590. if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~')) {
  591. (void) strncpy(SFcurrentPath, SFtextBuffer, MAXPATHLEN);
  592. SFtextPos = XawTextGetInsertionPoint(selFileField);
  593. } else {
  594. (void) strcat(strncpy(SFcurrentPath, SFstartDir, MAXPATHLEN), SFtextBuffer);
  595. SFtextPos = XawTextGetInsertionPoint(selFileField) +
  596. strlen(SFstartDir);
  597. }
  598. if (!SFworkProcAdded) {
  599. (void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);
  600. SFworkProcAdded = 1;
  601. }
  602. SFupdatePath();
  603. return;
  604. }
  605. static char *
  606. SFgetText()
  607. {
  608. return strcpy(XtMalloc((unsigned) (strlen(SFtextBuffer) + 1)),
  609. SFtextBuffer);
  610. }
  611. static void
  612. SFprepareToReturn()
  613. {
  614. SFstatus = SEL_FILE_NULL;
  615. XtRemoveGrab(selFile);
  616. XtUnmapWidget(selFile);
  617. XtRemoveTimeOut(SFdirModTimerId);
  618. if (SFchdir(SFstartDir)) {
  619. XtAppError(
  620. SFapp,
  621. "XsraSelFile: can't return to current directory"
  622. );
  623. }
  624. return;
  625. }
  626. FILE *
  627. XsraSelFile(toplevel, prompt, ok, cancel, failed,
  628. init_path, filter, mode, show_entry, name_return)
  629. Widget toplevel;
  630. char *prompt;
  631. char *ok;
  632. char *cancel;
  633. char *failed;
  634. char *init_path;
  635. char *filter;
  636. char *mode;
  637. int (*show_entry)();
  638. char **name_return;
  639. {
  640. static int firstTime = 1;
  641. Cardinal i;
  642. Arg arglist[20];
  643. XEvent event;
  644. FILE *fp;
  645. if (!prompt) {
  646. prompt = "Pathname:";
  647. }
  648. if (!ok) {
  649. ok = "OK";
  650. }
  651. if (!cancel) {
  652. cancel = "Cancel";
  653. }
  654. if(SFpathFlag != (mode && mode[0] == 'p') || strcmp(SFfilterBuffer, filter)) {
  655. SFpurge();
  656. SFpathFlag = (mode && mode[0] == 'p'); // [HGM] ignore everything that is not a directory
  657. }
  658. if (firstTime) {
  659. firstTime = 0;
  660. SFdisplay = XtDisplay(toplevel);
  661. SFcreateWidgets(toplevel, prompt, ok, cancel);
  662. } else {
  663. i = 0;
  664. XtSetArg(arglist[i], XtNlabel, prompt); i++;
  665. XtSetValues(selFilePrompt, arglist, i);
  666. i = 0;
  667. XtSetArg(arglist[i], XtNlabel, ok); i++;
  668. XtSetValues(selFileOK, arglist, i);
  669. i = 0;
  670. XtSetArg(arglist[i], XtNlabel, cancel); i++;
  671. XtSetValues(selFileCancel, arglist, i);
  672. }
  673. i = 0;
  674. XtSetArg(arglist[i], XtNstring, filter); i++;
  675. XtSetValues(filterField, arglist, i);
  676. safeStrCpy(SFfilterBuffer, filter, MAXPATHLEN);
  677. safeStrCpy(SFlastPath, SFtextBuffer, MAXPATHLEN); // remember for cancel
  678. SFpositionWidget(selFile);
  679. XtMapWidget(selFile);
  680. #if defined(SVR4) || defined(SYSV) || defined(USG) || 1
  681. if (!getcwd(SFstartDir, MAXPATHLEN)) { // [HGM] always do this, as I do not know when exactly to do it
  682. #else /* defined(SVR4) || defined(SYSV) || defined(USG) */
  683. if (!getwd(SFstartDir)) {
  684. #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
  685. XtAppError(SFapp, "XsraSelFile: can't get current directory");
  686. }
  687. (void) strcat(SFstartDir, "/");
  688. (void) strncpy(SFcurrentDir, SFstartDir, MAXPATHLEN);
  689. if (init_path) {
  690. if (init_path[0] == '/') {
  691. (void) strncpy(SFcurrentPath, init_path, MAXPATHLEN);
  692. if (strncmp(
  693. SFcurrentPath,
  694. SFstartDir,
  695. strlen(SFstartDir)
  696. )) {
  697. SFsetText(SFcurrentPath);
  698. } else {
  699. SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
  700. }
  701. } else {
  702. (void) strcat(strncpy(SFcurrentPath, SFstartDir, MAXPATHLEN),
  703. init_path);
  704. SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
  705. }
  706. } else {
  707. (void) strncpy(SFcurrentPath, SFstartDir, MAXPATHLEN);
  708. }
  709. SFfunc = show_entry;
  710. SFtextChanged();
  711. XtAddGrab(selFile, True, True);
  712. SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
  713. SFdirModTimer, (XtPointer) NULL);
  714. while (1) {
  715. XtAppNextEvent(SFapp, &event);
  716. XtDispatchEvent(&event);
  717. switch (SFstatus) {
  718. case SEL_FILE_TEXT:
  719. SFstatus = SEL_FILE_NULL;
  720. SFtextChanged();
  721. break;
  722. case SEL_FILE_OK:
  723. *name_return = SFgetText();
  724. if(mode && (mode[0] == 'p' || mode[0] == 'f')) { // [HGM] for use in file-option browse button
  725. SFprepareToReturn();
  726. return stderr;
  727. }
  728. if ((*name_return)[strlen(*name_return)-1] != '/' && // [HGM] refuse directories
  729. (fp = SFopenFile(*name_return, mode, prompt, failed))) {
  730. SFprepareToReturn();
  731. return fp;
  732. }
  733. SFstatus = SEL_FILE_NULL;
  734. break;
  735. case SEL_FILE_CANCEL:
  736. SFprepareToReturn();
  737. SFsetText(SFlastPath);
  738. return NULL;
  739. case SEL_FILE_NULL:
  740. break;
  741. }
  742. }
  743. }