1 /*********************************************************************/
2 /* bibView: Administration of BibTeX-Databases */
3 /* (Verwaltung von BibTeX-Literaturdatenbanken) */
4 /* */
5 /* Module: FileNom.c */
6 /* */
7 /* - File Selection Box */
8 /* Adapted and modified Widget from aXe editor */
9 /* */
10 /* Author: Holger Martin, martinh@informatik.tu-muenchen.de */
11 /* Peter M. Urban, urban@informatik.tu-muenchen.de */
12 /* */
13 /* History: */
14 /* 11.22.91 HM created */
15 /* 05.26.92 Version 1.0 released */
16 /* */
17 /* Copyright 1992 TU MUENCHEN */
18 /* See ./Copyright for complete rights and liability information. */
19 /* */
20 /*********************************************************************/
21
22 /*
23 * Copyright 1991 The University of Newcastle upon Tyne
24 *
25 * Permission to use, copy, modify and distribute this software and its
26 * documentation for any purpose other than its commercial exploitation
27 * is hereby granted without fee, provided that the above copyright
28 * notice appear in all copies and that both that copyright notice and
29 * this permission notice appear in supporting documentation, and that
30 * the name of The University of Newcastle upon Tyne not be used in
31 * advertising or publicity pertaining to distribution of the software
32 * without specific, written prior permission. The University of
33 * Newcastle upon Tyne makes no representations about the suitability of
34 * this software for any purpose. It is provided "as is" without express
35 * or implied warranty.
36 *
37 * THE UNIVERSITY OF NEWCASTLE UPON TYNE DISCLAIMS ALL WARRANTIES WITH
38 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
39 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
40 * NEWCASTLE UPON TYNE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
41 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
42 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
43 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
44 * PERFORMANCE OF THIS SOFTWARE.
45 *
46 * Author: Jim Wight (j.k.wight@newcastle.ac.uk)
47 * Computing Laboratory, University of Newcastle upon Tyne, UK
48 */
49
50 #include <X11/IntrinsicP.h>
51 #include <X11/StringDefs.h>
52 #include <X11/Xaw/MenuButton.h>
53 #include <X11/Xaw/SimpleMenu.h>
54 #include <X11/Xaw/SmeBSB.h>
55 #include <X11/Xaw/Viewport.h>
56 #include <X11/Xaw/List.h>
57 #include <X11/Xaw/Scrollbar.h>
58 #include <X11/Xaw/AsciiText.h>
59 #include <X11/Xaw/Command.h>
60 #include <X11/Xos.h>
61
62 #include <sys/param.h>
63 #include <sys/stat.h>
64 #include <errno.h>
65 #ifndef HAVE_DIR
66 #include <dirent.h>
67 #include <limits.h> /* for _POSIX_PATH_MAX */
68 #include <stdlib.h> /* for `qsort'. */
69 #else
70 #include <sys/dir.h>
71 #define dirent direct
72 #include <limits.h> /* for _POSIX_PATH_MAX */
73 #include <stdlib.h> /* for `qsort'. */
74 #endif
75 #include <stdio.h>
76 #include <pwd.h>
77
78 extern char *getenv();
79
80 extern char *actual_path;
81
82
83 #include "FileNomP.h"
84
85 #define Offset(field) XtOffsetOf(FileNominatorRec, fileNominator.field)
86
87 #ifdef ACTION_PROBLEM
88 static int first_in = 1;
89 #endif
90
91 static XtResource resources[] = {
92 {XtNselectCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
93 Offset(select_callback), XtRCallback, (XtPointer) NULL},
94 {XtNselectMenu, XtCSelectMenu, XtRString, sizeof(String),
95 Offset(select_menu), XtRString, (XtPointer) NULL},
96 {XtNcancelCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
97 Offset(cancel_callback), XtRCallback, (XtPointer) NULL},
98 {XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
99 Offset(margin), XtRImmediate, (XtPointer) 10},
100 {XtNnumberRows, XtCNumberStrings, XtRInt, sizeof(int),
101 Offset(number_rows), XtRImmediate, (XtPointer) 15},
102 {XtNshowDotFiles, XtCShowDotFiles, XtRBoolean, sizeof(Boolean),
103 Offset(show_dot_files), XtRImmediate, (XtPointer) True},
104 {XtNbellLevel, XtCBellLevel, XtRInt, sizeof(int),
105 Offset(bell_level), XtRImmediate, (XtPointer) 100},
106 };
107
108 #undef Offset
109
110 #define Child(w,child) (((FileNominatorWidget) w)->fileNominator.child)
111 #define List(w) (((FileNominatorWidget) w)->fileNominator.listList)
112 #define Rows(w) (((FileNominatorWidget) w)->fileNominator.number_rows)
113 #define CurrentDir(w) (((FileNominatorWidget) w)->fileNominator.currentDir)
114 #define WatchingChanges(w) (((FileNominatorWidget) w)->fileNominator.watchingChanges)
115 #define Nomination(w) (((FileNominatorWidget) w)->fileNominator.nomination)
116 #define ShowDotFiles(w) (((FileNominatorWidget) w)->fileNominator.show_dot_files)
117 #define BellLevel(w) (((FileNominatorWidget) w)->fileNominator.bell_level)
118
119
120
121 static struct passwd *my_passwd;
122
123 static char pathTranslations[] =
124 "<BtnDown>:reset() MakeMenu() XawPositionSimpleMenu(menu) MenuPopup(menu)";
125
126 static char listTranslations[] =
127 "<Btn1Up>(2): Set() Nominate() Unset()\n\
128 <Btn1Down>,<Btn1Up>: Set() Notify() \n\
129 <Btn2Up>: Set() Notify() Nominate() Unset()";
130
131 static char filenameTranslations[] =
132 "<Key>Return: Nominate() \n\
133 <Key>Escape: ToggleDotFiles()";
134
135 static char selectTranslations[] =
136 "<Btn1Up>: Nominate() unset()";
137
138 static char selectMenuTranslations[] =
139 "<Btn3Down>: XawPositionSimpleMenu(selectMenu) MenuPopup(selectMenu)";
140
141 static void MakeMenu(), Nominate(), ToggleDotFiles();
142
143 static XtActionsRec pathActions[] = {
144 "MakeMenu", MakeMenu,
145 "Nominate", Nominate,
146 "ToggleDotFiles", ToggleDotFiles,
147 };
148
149 static void CancelCallback();
150 static void ChangeDir();
151 static void SelectDir();
152 static void FillWindow();
153 static void ReplaceFilename();
154 static void AsciiSourceChanged();
155 static void WatchForChanges();
156 static void DontWatchForChanges();
157 static void CollapsePath();
158
159 static void Initialize(), PositionChildren(), Realize(), Destroy();
160
161 FileNominatorClassRec fileNominatorClassRec = {
162 /* Core class part */
163 {
164 /* superclass */ (WidgetClass) &widgetClassRec,
165 /* class_name */ "FileNominator",
166 /* widget_size */ sizeof(FileNominatorRec),
167 /* class_initialize */ NULL,
168 /* class_part_initialize */ NULL,
169 /* class_inited */ FALSE,
170 /* initialize */ Initialize,
171 /* initialize_hook */ NULL,
172 /* realize */ Realize,
173 /* actions */ NULL,
174 /* num_actions */ 0,
175 /* resources */ resources,
176 /* num_resources */ XtNumber(resources),
177 /* xrm_class */ NULLQUARK,
178 /* compress_motion */ TRUE,
179 /* compress_exposure */ XtExposeCompressMultiple,
180 /* compress_enterleave */ TRUE,
181 /* visible_interest */ FALSE,
182 /* destroy */ Destroy,
183 /* resize */ PositionChildren,
184 /* expose */ NULL,
185 /* set_values */ NULL,
186 /* set_values_hook */ NULL,
187 /* set_values_almost */ XtInheritSetValuesAlmost,
188 /* get_values_hook */ NULL,
189 /* accept_focus */ NULL,
190 /* version */ XtVersion,
191 /* callback offsets */ NULL,
192 /* tm_table */ NULL,
193 /* query_geometry */ XtInheritQueryGeometry,
194 /* display_accelerator */ NULL,
195 /* extension */ NULL,
196 },
197 /* FileNominator class part */
198 {
199 /* extension */ NULL,
200 }
201 };
202
203 WidgetClass fileNominatorWidgetClass = (WidgetClass) &fileNominatorClassRec;
204
205 static void
CalculateSize(fnw,width,height)206 CalculateSize(fnw, width, height)
207 FileNominatorWidget fnw;
208 Dimension *width, *height;
209 {
210 int file_width = 2 * Child(fnw,filename_widget)->core.width +
211 2 * Child(fnw,filename_widget)->core.border_width;
212 int select_width = 2 * Child(fnw,select_widget)->core.width +
213 2 * Child(fnw,select_widget)->core.border_width + fnw->fileNominator.margin +
214 Child(fnw,cancel_widget)->core.width +
215 2 * Child(fnw,cancel_widget)->core.border_width +
216 Child(fnw,path_widget)->core.width +
217 2 * Child(fnw,path_widget)->core.border_width + fnw->fileNominator.margin;
218
219 int max;
220
221 if (fnw->fileNominator.margin == 0)
222 {
223 max = select_width - 4 * (Child(fnw,select_widget)->core.border_width) >
224 file_width - 2 * Child(fnw,filename_widget)->core.border_width ?
225 select_width - 4 * (Child(fnw,select_widget)->core.border_width) :
226 file_width - 2 * Child(fnw,filename_widget)->core.border_width;
227 }
228 else
229 {
230 max = select_width > file_width ? select_width : file_width;
231 }
232 *width = max + 2 * fnw->fileNominator.margin;
233 *height = Child(fnw,viewport_widget)->core.height +
234 Child(fnw,filename_widget)->core.height +
235 Child(fnw,select_widget)->core.height +
236 4 * fnw->fileNominator.margin;
237
238 if (fnw->fileNominator.margin == 0)
239 {
240 *height += 2 * (Child(fnw,filename_widget)->core.border_width);
241 }
242 else
243 {
244 *height += 2 * (Child(fnw,filename_widget)->core.border_width +
245 Child(fnw,viewport_widget)->core.border_width +
246 Child(fnw,select_widget)->core.border_width);
247 }
248 }
249
250 static void
PositionChildren(fnw)251 PositionChildren(fnw)
252 FileNominatorWidget fnw;
253 {
254 if (fnw->fileNominator.margin == 0)
255 {
256 XtConfigureWidget(Child(fnw,filename_widget),
257 0, 0,
258 fnw->core.width,
259 fnw->core.height -
260 Child(fnw,viewport_widget)->core.height -
261 2 * Child(fnw,viewport_widget)->core.border_width -
262 Child(fnw,select_widget)->core.height,
263 0);
264 }
265 else
266 {
267 XtConfigureWidget(Child(fnw,filename_widget),
268 fnw->fileNominator.margin,
269 fnw->fileNominator.margin,
270 fnw->core.width -
271 2 * fnw->fileNominator.margin -
272 2 * Child(fnw,filename_widget)->core.border_width,
273 fnw->core.height -
274 2 * Child(fnw,filename_widget)->core.border_width -
275 Child(fnw,viewport_widget)->core.height -
276 2 * Child(fnw,viewport_widget)->core.border_width -
277 Child(fnw,select_widget)->core.height -
278 2 * Child(fnw,select_widget)->core.border_width -
279 4 * fnw->fileNominator.margin,
280 Child(fnw,filename_widget)->core.border_width);
281 }
282
283 if (fnw->fileNominator.margin == 0)
284 {
285 XtConfigureWidget(Child(fnw,viewport_widget),
286 -(Child(fnw,viewport_widget)->core.border_width),
287 Child(fnw,filename_widget)->core.height,
288 fnw->core.width,
289 Child(fnw,viewport_widget)->core.height,
290 Child(fnw,viewport_widget)->core.border_width);
291 }
292 else
293 {
294 XtConfigureWidget(Child(fnw,viewport_widget),
295 fnw->fileNominator.margin,
296 fnw->core.height -
297 Child(fnw,select_widget)->core.height -
298 2 * Child(fnw,select_widget)->core.border_width -
299 Child(fnw,viewport_widget)->core.height -
300 2 * Child(fnw,viewport_widget)->core.border_width -
301 2 * fnw->fileNominator.margin,
302 fnw->core.width -
303 2 * fnw->fileNominator.margin -
304 2 * Child(fnw,viewport_widget)->core.border_width,
305 Child(fnw,viewport_widget)->core.height,
306 Child(fnw,viewport_widget)->core.border_width);
307 }
308
309 if (fnw->fileNominator.margin == 0)
310 {
311 XtMoveWidget(Child(fnw,select_widget), -1,
312 fnw->core.height -
313 Child(fnw,select_widget)->core.height - 1);
314 }
315 else
316 {
317 XtMoveWidget(Child(fnw,select_widget), fnw->fileNominator.margin,
318 fnw->core.height -
319 fnw->fileNominator.margin -
320 2 * Child(fnw,select_widget)->core.border_width -
321 Child(fnw,select_widget)->core.height);
322 }
323
324
325 if (fnw->fileNominator.margin == 0)
326 {
327 XtMoveWidget(Child(fnw,path_widget),
328 Child(fnw,select_widget)->core.width,
329 fnw->core.height -
330 Child(fnw,select_widget)->core.height - 1);
331 }
332 else
333 {
334 XtMoveWidget(Child(fnw,path_widget),
335 Child(fnw,select_widget)->core.width +
336 2 * Child(fnw,select_widget)->core.border_width +
337 2 * fnw->fileNominator.margin,
338 fnw->core.height -
339 fnw->fileNominator.margin -
340 2 * Child(fnw,select_widget)->core.border_width -
341 Child(fnw,select_widget)->core.height);
342 }
343
344 if (fnw->fileNominator.margin == 0)
345 {
346 XtMoveWidget(Child(fnw,cancel_widget),
347 Child(fnw,select_widget)->core.width +
348 Child(fnw,path_widget)->core.width +
349 Child(fnw,select_widget)->core.border_width,
350 fnw->core.height -
351 Child(fnw,select_widget)->core.height - 1);
352 }
353 else
354 {
355 XtMoveWidget(Child(fnw,cancel_widget),
356 Child(fnw,path_widget)->core.width +
357 2 * Child(fnw,path_widget)->core.border_width +
358 Child(fnw,select_widget)->core.width +
359 2 * Child(fnw,select_widget)->core.border_width +
360 3 * fnw->fileNominator.margin,
361 fnw->core.height -
362 fnw->fileNominator.margin -
363 2 * Child(fnw,select_widget)->core.border_width -
364 Child(fnw,select_widget)->core.height);
365 }
366 }
367
368 /* ARGSUSED */
369 static void
Initialize(req,new,args,num_args)370 Initialize(req, new, args, num_args)
371 Widget req, new;
372 ArgList args;
373 Cardinal *num_args;
374 {
375 FileNominatorWidget fnw = (FileNominatorWidget) new;
376 Widget sMenu, menuEntry;
377 String menuList, p, q;
378
379 List(new) = NULL;
380 Nomination(new).directoryPart = NULL;
381 Nomination(new).filenamePart = NULL;
382 #ifdef SYSV
383 (void) getcwd(CurrentDir(new), MAXPATHLEN);
384 #else
385 (void) getwd(CurrentDir(new));
386 #endif
387
388 if (actual_path==NULL){
389 actual_path = (char *) XtMalloc(MAXPATHLEN+1);
390 strcpy(actual_path, CurrentDir(new));
391 }
392 else{
393 if (CurrentDir(new)[strlen(CurrentDir(new)) - 1] != '/')
394 {
395 strcat(CurrentDir(new), "/");
396 }
397 if (*actual_path != '/'){
398 strcat(CurrentDir(new), actual_path);
399 strcpy(actual_path, CurrentDir(new));
400 CollapsePath(actual_path, CurrentDir(new));
401 }
402 else
403 CollapsePath(actual_path, CurrentDir(new));
404 }
405 if (CurrentDir(new)[strlen(CurrentDir(new)) - 1] != '/')
406 {
407 strcat(CurrentDir(new), "/");
408 }
409 WatchingChanges(new) = False;
410
411 Child(fnw,viewport_widget)
412 = XtVaCreateWidget("viewport", viewportWidgetClass, new,
413 XtNallowVert, True,
414 XtNallowHoriz, True,
415 NULL);
416
417 Child(fnw,list_widget) =
418 XtVaCreateManagedWidget("list", listWidgetClass, Child(fnw,viewport_widget),
419 XtNdefaultColumns, 1,
420 XtNforceColumns, True,
421 NULL);
422
423 XtOverrideTranslations(Child(fnw,list_widget),
424 XtParseTranslationTable(listTranslations));
425 XtAddCallback(Child(fnw,list_widget), XtNcallback, ReplaceFilename, NULL);
426 FillWindow(fnw);
427
428 Child(fnw,filename_widget)
429 = XtVaCreateWidget("filename", asciiTextWidgetClass, new,
430 XtNeditType, XawtextEdit,
431 NULL);
432 XtOverrideTranslations(Child(fnw,filename_widget),
433 XtParseTranslationTable(filenameTranslations));
434
435 XtSetKeyboardFocus(new, Child(fnw,filename_widget));
436 WatchForChanges(fnw);
437
438 Child(fnw,select_widget)
439 = XtVaCreateWidget("select", commandWidgetClass, new,
440 XtNlabel, "OK",
441 NULL);
442 XtOverrideTranslations(Child(fnw,select_widget),
443 XtParseTranslationTable(selectTranslations));
444 if (fnw->fileNominator.select_menu)
445 {
446 sMenu = XtVaCreatePopupShell("selectMenu",
447 simpleMenuWidgetClass, Child(fnw,select_widget),
448 NULL);
449 menuList = XtNewString(fnw->fileNominator.select_menu);
450 p = menuList;
451 for (p = menuList; (q = (char *)index(p, ':')); p = q + 1)
452 {
453 *q = '\0';
454 menuEntry = XtVaCreateManagedWidget(p,
455 smeBSBObjectClass, sMenu,
456 NULL);
457 XtAddCallback(menuEntry, XtNcallback, SelectDir, NULL);
458 }
459 menuEntry = XtVaCreateManagedWidget(p,
460 smeBSBObjectClass, sMenu,
461 NULL);
462 XtAddCallback(menuEntry, XtNcallback, SelectDir, NULL);
463 XtVaSetValues(sMenu,
464 XtNpopupOnEntry, menuEntry,
465 NULL);
466
467 XtOverrideTranslations(Child(fnw,select_widget),
468 XtParseTranslationTable(selectMenuTranslations));
469
470 XtFree(menuList);
471 }
472
473 #ifdef GERMAN
474 Child(fnw,path_widget)
475 = XtVaCreateWidget("path", menuButtonWidgetClass, new,
476 XtNlabel, "Pfad",
477 NULL);
478 #else
479 Child(fnw,path_widget)
480 = XtVaCreateWidget("path", menuButtonWidgetClass, new,
481 XtNlabel, "Path",
482 NULL);
483 #endif
484 XtOverrideTranslations(Child(fnw,path_widget),
485 XtParseTranslationTable(pathTranslations));
486 #ifdef ACTION_PROBLEM
487 if (first_in == 1){
488 #endif
489 XtAppAddActions(XtWidgetToApplicationContext(new),
490 pathActions, XtNumber(pathActions));
491 XawSimpleMenuAddGlobalActions(XtWidgetToApplicationContext(new));
492 #ifdef ACTION_PROBLEM
493 first_in = 0;
494 }
495 #endif
496
497 #ifdef GERMAN
498 Child(fnw,cancel_widget)
499 = XtVaCreateWidget("cancel", commandWidgetClass, new,
500 XtNlabel, "Abbruch",
501 NULL);
502 #else
503 Child(fnw,cancel_widget)
504 = XtVaCreateWidget("cancel", commandWidgetClass, new,
505 XtNlabel, "Cancel",
506 NULL);
507 #endif
508 XtAddCallback(Child(fnw,cancel_widget), XtNcallback, CancelCallback, NULL);
509
510 CalculateSize(fnw, &fnw->core.width, &fnw->core.height);
511 PositionChildren(fnw);
512 }
513
514 static void
Realize(w,valueMask,attributes)515 Realize(w, valueMask, attributes)
516 Widget w;
517 XtValueMask *valueMask;
518 XSetWindowAttributes *attributes;
519 {
520 (*fileNominatorWidgetClass->core_class.superclass->core_class.realize)
521 (w, valueMask, attributes);
522
523 XtRealizeWidget(Child(w,viewport_widget));
524 XtRealizeWidget(Child(w,list_widget));
525 XtRealizeWidget(Child(w,filename_widget));
526 XtRealizeWidget(Child(w,select_widget));
527 XtRealizeWidget(Child(w,path_widget));
528 XtRealizeWidget(Child(w,cancel_widget));
529
530 XMapSubwindows(XtDisplay(w), XtWindow(w));
531 }
532
Destroy(w)533 static void Destroy(w)
534 Widget w;
535 {
536 int idx;
537 FileNominatorWidget fnw = (FileNominatorWidget) w;
538 XtDestroyWidget(Child(fnw,list_widget));
539 XtDestroyWidget(Child(fnw,viewport_widget));
540 XtDestroyWidget(Child(fnw,filename_widget));
541 XtDestroyWidget(Child(fnw,select_widget));
542 XtDestroyWidget(Child(fnw,path_widget));
543 XtDestroyWidget(Child(fnw,cancel_widget));
544
545 idx = 0;
546 while (List(fnw)[idx])
547 {
548 XtFree(List(fnw)[idx++]);
549 }
550 XtFree(List(fnw)[idx]);
551 XtFree((char *)List(fnw));
552
553 strcpy(actual_path, Nomination(fnw).directoryPart);
554
555 XtFree(Nomination(fnw).directoryPart);
556 XtFree(Nomination(fnw).filenamePart);
557 }
558
559 /* ARGSUSED */
560 static void
CancelCallback(w,client_data,call_data)561 CancelCallback(w, client_data, call_data)
562 Widget w;
563 XtPointer client_data, call_data;
564 {
565 XtCallCallbacks(XtParent(w), XtNcancelCallback, NULL);
566 }
567
568 /* ARGSUSED */
569 static void
DestroyMenu(w,client_data,call_data)570 DestroyMenu(w, client_data, call_data)
571 Widget w;
572 XtPointer client_data, call_data;
573 {
574 XtDestroyWidget(w);
575 }
576
577 /* ARGSUSED */
578 static void
MakeMenu(w,event,params,num_params)579 MakeMenu(w, event, params, num_params)
580 Widget w;
581 XEvent *event;
582 String *params;
583 Cardinal *num_params;
584 {
585 FileNominatorWidget fnw = (FileNominatorWidget) XtParent(w);
586 String menuName;
587 Widget menu, menuEntry;
588 char *where, *p1, *p2;
589 int menuItem = 1, len;
590
591 XtVaGetValues(w,
592 XtNmenuName, &menuName,
593 NULL);
594
595 menu = XtVaCreatePopupShell(menuName,
596 simpleMenuWidgetClass, w,
597 NULL);
598 XtAddCallback(menu, XtNpopdownCallback, DestroyMenu, NULL);
599
600 where = XtNewString(CurrentDir(fnw));
601 menuEntry = XtVaCreateManagedWidget("/",
602 smeBSBObjectClass, menu, NULL);
603 XtAddCallback(menuEntry, XtNcallback, ChangeDir, (XtPointer) menuItem++);
604 p1 = where + 1;
605 len = strlen(where);
606 while (p1 < &where[len])
607 {
608 if (!(p2 = (char *)index(p1, '/')))
609 {
610 p2 = &where[len];
611 }
612 *p2 = '\0';
613 menuEntry = XtVaCreateManagedWidget(p1,
614 smeBSBObjectClass, menu, NULL);
615 XtAddCallback(menuEntry, XtNcallback, ChangeDir,
616 (XtPointer) menuItem++);
617 p1 = p2 + 1;
618 }
619
620 XtVaSetValues(menu,
621 XtNpopupOnEntry, menuEntry,
622 NULL);
623
624 XtFree(where);
625 }
626
627 static void
ChangeDirectory(fnw,position)628 ChangeDirectory(fnw, position)
629 FileNominatorWidget fnw;
630 int position;
631 {
632 String p;
633 int m;
634
635 if (position > 0)
636 {
637 p = CurrentDir(fnw);
638 for (m = 0; m < position; ++m)
639 {
640 while(*p++ != '/')
641 ;
642 }
643 *p = '\0';
644 }
645
646 XtVaSetValues(Child(fnw, filename_widget),
647 XtNstring, "",
648 NULL);
649
650 FillWindow(fnw);
651
652 PositionChildren(fnw);
653 }
654
655 /* ARGSUSED */
656 static void
ChangeDir(w,client_data,call_data)657 ChangeDir(w, client_data, call_data)
658 Widget w;
659 XtPointer client_data, call_data;
660 {
661 FileNominatorWidget fnw
662 = (FileNominatorWidget) XtParent(XtParent(XtParent(w)));
663
664 ChangeDirectory(fnw, (int) client_data);
665 }
666
667 /* ARGSUSED */
668 static void
SelectDir(w,client_data,call_data)669 SelectDir(w, client_data, call_data)
670 Widget w;
671 XtPointer client_data, call_data;
672 {
673 FileNominatorWidget fnw
674 = (FileNominatorWidget) XtParent(XtParent(XtParent(w)));
675 String label;
676
677 XtVaGetValues(w,
678 XtNlabel, &label,
679 NULL);
680
681 XtVaSetValues(Child(fnw,filename_widget),
682 XtNstring, label,
683 NULL);
684
685 Nominate(Child(fnw,select_widget), NULL, NULL, NULL);
686 }
687
688 /* ARGSUSED */
689 static void
Nominate(w,event,params,num_params)690 Nominate(w, event, params, num_params)
691 Widget w;
692 XEvent *event;
693 String *params;
694 Cardinal *num_params;
695 {
696 FileNominatorWidget fnw;
697 char *nomination, *home, *name_ende, selection[MAXPATHLEN], *newPath, *r;
698 struct stat fstats;
699 int status, len;
700
701 if (XtIsSubclass(w, listWidgetClass))
702 {
703 fnw = (FileNominatorWidget) XtParent(XtParent(w));
704 }
705 else
706 {
707 fnw = (FileNominatorWidget) XtParent(w);
708 }
709
710 XtVaGetValues(Child(fnw,filename_widget),
711 XtNstring, &nomination,
712 NULL);
713
714 selection[0] = '\0';
715 if (*nomination == '/')
716 {
717 strcpy(selection, nomination);
718 }
719 else if (*nomination == '~' && *(nomination+1) == '\0' &&
720 (home = getenv("HOME")))
721 {
722 strcpy(selection, home);
723 strcat(selection, &nomination[1]);
724 }
725 else if (*nomination == '~')
726 { name_ende = strchr(nomination, '/');
727 if (name_ende != NULL){
728 *name_ende = '\0';
729 name_ende++;
730 }
731 my_passwd = getpwnam (&nomination[1]);
732 if (my_passwd!=NULL){
733 strcpy(selection, my_passwd->pw_dir);
734 if (name_ende != NULL){
735 strcat(selection, "/");
736 strcat(selection, name_ende);
737 }
738 }
739 else if (home = getenv("HOME"))
740 strcpy(selection, home);
741
742 }
743 else
744 {
745 if (strlen(CurrentDir(fnw)) > 1)
746 {
747 strcpy(selection, CurrentDir(fnw));
748 }
749 strcat(selection, "/");
750 strcat(selection, nomination);
751 }
752
753 len = strlen(selection);
754 if (len != 0)
755 {
756 newPath = (char *) XtMalloc(len + 2);
757 CollapsePath(selection, newPath);
758 status = stat(newPath, &fstats);
759 if (status != -1 && fstats.st_mode & S_IFDIR)
760 {
761 if (access(newPath, R_OK) == 0)
762 {
763 if (newPath[strlen(newPath) - 1] != '/')
764 {
765 strcat(newPath, "/");
766 }
767 strcpy(CurrentDir(fnw), newPath);
768 ChangeDirectory(fnw, 0);
769 }
770 else
771 {
772 XBell(XtDisplay(fnw), BellLevel(fnw));
773 }
774 }
775 else if (status == 0 || (status == -1 && errno == ENOENT))
776 {
777 status = access(newPath, R_OK | W_OK);
778 r = (char *)rindex(newPath, '/');
779 XtFree(Nomination(fnw).filenamePart);
780 Nomination(fnw).filenamePart = XtNewString(r + 1);
781 Nomination(fnw).filenameStatus = (status == 0) ? status : errno;
782 *(r + 1) = '\0';
783 XtFree(Nomination(fnw).directoryPart);
784 status = access(newPath, R_OK);
785 if (strcmp(newPath, CurrentDir(fnw)) != 0 && status == 0)
786 {
787 strcpy(CurrentDir(fnw), newPath);
788 ChangeDirectory(fnw, 0);
789 Nomination(fnw).directoryPart = XtNewString(CurrentDir(fnw));
790 }
791 else
792 {
793 Nomination(fnw).directoryPart = XtNewString(newPath);
794 }
795 Nomination(fnw).directoryStatus = (status == 0) ? status : errno;
796 XtCallCallbacks((Widget) fnw, XtNselectCallback,
797 (XtPointer) &Nomination(fnw));
798 }
799 else
800 {
801 XBell(XtDisplay(fnw), BellLevel(fnw));
802 }
803 XtFree(newPath);
804 }
805 }
806
807 #ifndef HAVE_DIR
808 /* Comparison function for dirent*, used by `qsort'. */
809 static int
direntpcmp(i,j)810 direntpcmp( i, j)
811 struct dirent **i, **j;
812 {
813 return (strcmp ((*i)->d_name, (*j)->d_name ));
814 }
815 #endif
816
817 static void
FillWindow(fnw)818 FillWindow(fnw)
819 Widget fnw;
820 {
821 XFontStruct *font;
822 Dimension height, internalHeight, rowSpacing;
823 int num, newNum, idx;
824 struct dirent **namelist;
825 #ifndef HAVE_DIR
826 DIR *dirp;
827 struct dirent *direntp;
828 int direntp_size;
829 #else
830 extern int alphasort();
831 #endif
832 char buf[MAXPATHLEN], *bp;
833 String name;
834 struct stat fstats;
835 unsigned int namlen;
836 #ifdef HAVE_DIR
837 num = scandir(CurrentDir(fnw), &namelist, (int(*)())0, alphasort);
838 #else
839 /* Read the directory `CurrentDir(fnw)'
840 and set the `dirent's in `namelist'. */
841 dirp = opendir( CurrentDir(fnw) );
842 direntp_size = sizeof(struct dirent)+ _POSIX_PATH_MAX;
843 direntp = (struct dirent *)XtMalloc( direntp_size );
844 /* Read the directory a first time, to get */
845 /* the number `num' of entries and to allocate namedir. */
846 num = 0;
847 while ( (direntp = readdir(dirp)) != NULL ) num++;
848 namelist = (struct dirent **)XtMalloc( (num+1)*sizeof(struct dirent *));
849 num = 0;
850 rewinddir( dirp );
851 while ( TRUE ) {
852 if ( (direntp = readdir(dirp)) == NULL ) break;
853 namelist[num] = (struct dirent *) XtMalloc(direntp_size);
854 bcopy(direntp, namelist[num], direntp_size);
855 num++;
856 direntp = (struct dirent *)XtMalloc( direntp_size );
857 }
858 XtFree( (char *)direntp );
859 (void)closedir( dirp );
860
861 /* Sort the directory entries in `namelist'. */
862 qsort( namelist, num, sizeof(struct dirent*), direntpcmp );
863 #endif
864
865 if (num <= 0)
866 {
867 return;
868 }
869
870 if (List(fnw))
871 {
872 idx = 0;
873 while (List(fnw)[idx])
874 {
875 XtFree(List(fnw)[idx++]);
876 }
877 XtFree(List(fnw)[idx]);
878 XtFree((char *)List(fnw));
879 }
880 List(fnw) = (String *) XtMalloc((num + 1) * sizeof(String));
881
882 strcpy(buf, CurrentDir(fnw));
883 strcat(buf, "/");
884 bp = buf + strlen(buf);
885 for(idx = 0, newNum = 0; idx < num; idx++)
886 {
887 name = namelist[idx]->d_name;
888 if (ShowDotFiles(fnw) || (!ShowDotFiles(fnw) &&
889 (*name != '.'
890 || ((strcmp(name, ".") == 0) ||
891 (strcmp(name, "..") == 0)))))
892 {
893 List(fnw)[newNum] = XtMalloc(strlen(name) + 2);
894 strcpy(List(fnw)[newNum], name);
895 strcpy(bp, name);
896 (void) stat(buf, &fstats);
897 if (fstats.st_mode & S_IFDIR)
898 {
899 strcat(List(fnw)[newNum], "/");
900 }
901 ++newNum;
902 }
903 }
904
905 for(idx = 0; idx < num; idx++)
906 {
907 XtFree((char *)namelist[idx]);
908 }
909 XtFree((char *)namelist);
910
911 List(fnw)[newNum] = NULL;
912
913 XtVaGetValues(Child(fnw,list_widget),
914 XtNfont, &font,
915 XtNinternalHeight, &internalHeight,
916 XtNrowSpacing, &rowSpacing,
917 NULL);
918
919 height = Rows(fnw) * (font->max_bounds.ascent +
920 font->max_bounds.descent + rowSpacing) -
921 rowSpacing + 2 * internalHeight;
922
923 XtVaSetValues(Child(fnw,viewport_widget),
924 XtNheight, height,
925 NULL);
926
927 XawListChange(Child(fnw,list_widget), List(fnw), newNum, -1, True);
928 }
929
930 /* ARGSUSED */
931 static void
ToggleDotFiles(w,event,params,num_params)932 ToggleDotFiles(w, event, params, num_params)
933 Widget w;
934 XEvent *event;
935 String *params;
936 Cardinal *num_params;
937 {
938 Widget fnw = XtParent(w);
939 Boolean showDotFiles;
940
941 XtVaGetValues(fnw,
942 XtNshowDotFiles, &showDotFiles,
943 NULL);
944
945 XtVaSetValues(fnw,
946 XtNshowDotFiles, !showDotFiles,
947 NULL);
948
949 XtVaSetValues(w,
950 XtNstring, "./",
951 NULL);
952
953 Nominate(Child(fnw,select_widget), NULL, NULL, NULL);
954 }
955
956 /* ARGSUSED */
957 static void
ReplaceFilename(w,client_data,call_data)958 ReplaceFilename(w, client_data, call_data)
959 Widget w;
960 XtPointer client_data, call_data;
961 {
962 FileNominatorWidget fnw
963 = (FileNominatorWidget) XtParent(XtParent(w));
964
965 XawListReturnStruct *list = XawListShowCurrent(Child(fnw,list_widget));
966
967 XtVaSetValues(Child(fnw,filename_widget),
968 XtNstring, list->string,
969 NULL);
970
971 XawTextSetInsertionPoint(Child(fnw,filename_widget),
972 (XawTextPosition) strlen(list->string));
973
974 WatchForChanges(fnw);
975 }
976
977 /* ARGSUSED */
978 static void
AsciiSourceChanged(w,client_data,call_data)979 AsciiSourceChanged(w, client_data, call_data)
980 Widget w;
981 XtPointer client_data, call_data;
982 {
983 FileNominatorWidget fnw = (FileNominatorWidget) client_data;
984
985 DontWatchForChanges(fnw);
986
987 XawListUnhighlight(Child(fnw,list_widget));
988 }
989
990 static void
WatchForChanges(fnw)991 WatchForChanges(fnw)
992 Widget fnw;
993 {
994 if (!WatchingChanges(fnw))
995 {
996 XtAddCallback(XawTextGetSource(Child(fnw,filename_widget)), XtNcallback,
997 AsciiSourceChanged, (XtPointer) fnw);
998
999 WatchingChanges(fnw) = True;
1000 }
1001 }
1002
1003 static void
DontWatchForChanges(fnw)1004 DontWatchForChanges(fnw)
1005 Widget fnw;
1006 {
1007 XtRemoveCallback(XawTextGetSource(Child(fnw,filename_widget)), XtNcallback,
1008 AsciiSourceChanged, (XtPointer) fnw);
1009
1010 WatchingChanges(fnw) = False;
1011 }
1012
1013 static void
CollapsePath(in,out)1014 CollapsePath(in, out)
1015 char *in, *out;
1016 {
1017 char *p = in, *q = out, *pend = p + strlen(p);
1018
1019 while (p < pend)
1020 {
1021 if (*p != '/')
1022 {
1023 *q++ = *p++;
1024 }
1025 else if (p + 1 < pend && *(p + 1) == '/')
1026 {
1027 ++p;
1028 }
1029 else if ( (p + 2 == pend && *(p + 1) == '.') ||
1030 (p + 2 < pend && *(p + 1) == '.' && *(p + 2) == '/') )
1031 {
1032 p += 2;
1033 }
1034 else if ( (p + 3 == pend && *(p + 1) == '.' && *(p + 2) == '.') ||
1035 (p + 3 < pend && *(p + 1) == '.'
1036 && *(p + 2) == '.' && *(p + 3) == '/') )
1037 {
1038 while (q > out && *--q != '/')
1039 ;
1040 p += 3;
1041 }
1042 else
1043 {
1044 *q++ = *p++;
1045 }
1046 }
1047 if (q == out)
1048 {
1049 *q++ = '/';
1050 }
1051
1052 while (q > out)
1053 {
1054 if (*--q != '/')
1055 break;
1056 }
1057 *++q = '\0';
1058 }
1059
1060 String
FileNominatorGetDirectory(fnw)1061 FileNominatorGetDirectory(fnw)
1062 Widget fnw;
1063 {
1064 if (XtIsSubclass(fnw, fileNominatorWidgetClass))
1065 {
1066 return CurrentDir(fnw);
1067 }
1068 else
1069 {
1070 return NULL;
1071 }
1072 }
1073
1074 String
FileNominatorGetFileName(fnw)1075 FileNominatorGetFileName(fnw)
1076 Widget fnw;
1077 {
1078 String newName;
1079
1080 if (XtIsSubclass(fnw, fileNominatorWidgetClass))
1081 {
1082
1083 FileNominatorStruct data = Nomination(fnw);
1084
1085 if (data.directoryStatus == 0)
1086 {
1087 newName = XtMalloc(strlen(data.filenamePart) + 1);
1088 strcpy(newName, data.filenamePart);
1089 strcpy(actual_path, data.directoryPart);
1090 return newName;
1091 }
1092 else
1093 return NULL;
1094 }
1095 else
1096 {
1097 return NULL;
1098 }
1099 }
1100
1101 String
FileNominatorGetFullFileName(fnw)1102 FileNominatorGetFullFileName(fnw)
1103 Widget fnw;
1104 {
1105 String newName;
1106
1107 if (XtIsSubclass(fnw, fileNominatorWidgetClass))
1108 {
1109
1110 FileNominatorStruct data = Nomination(fnw);
1111
1112 if (data.directoryStatus == 0)
1113 {
1114 newName = XtMalloc(strlen(data.directoryPart)
1115 + strlen(data.filenamePart) + 1);
1116 strcpy(newName, data.directoryPart);
1117 strcat(newName, data.filenamePart);
1118 strcpy(actual_path, data.directoryPart);
1119 return newName;
1120 }
1121 else
1122 return NULL;
1123 }
1124 else
1125 {
1126 return NULL;
1127 }
1128 }
1129
1130
1131 void
FileNominatorSetDirectory(fnw,dir)1132 FileNominatorSetDirectory(fnw, dir)
1133 Widget fnw;
1134 String dir;
1135 {
1136 if (!XtIsSubclass(fnw, fileNominatorWidgetClass))
1137 {
1138 return;
1139 }
1140
1141 /* Should do more checks */
1142 strcpy(CurrentDir(fnw), dir);
1143 if (dir[strlen(dir) - 1] != '/')
1144 {
1145 strcat(CurrentDir(fnw), "/");
1146 }
1147
1148 ChangeDirectory(fnw, 0);
1149 }
1150