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