1 /*
2 * FChooser.c : A widget for choosing a file
3 *
4 * George Ferguson, ferguson@cs.rochester.edu, 21 Jan 1993.
5 *
6 * This code is derived from the FileSelector widget by Brian Totty,
7 * hence the following copyright applies:
8 *
9 * Copyright 1990,1991,1992 Brian Totty
10 *
11 * Permission to use, copy, modify, distribute, and sell this software
12 * and its documentation for any purpose is hereby granted without fee,
13 * provided that the above copyright notice appears in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation, and that the name of Brian Totty or
16 * University of Illinois not be used in advertising or publicity
17 * pertaining to distribution of the software without specific, written
18 * prior permission. Brian Totty and University of Illinois make no
19 * representations about the suitability of this software for any
20 * purpose. It is provided "as is" without express or implied warranty.
21 *
22 * Brian Totty and University of Illinois disclaim all warranties with
23 * regard to this software, including all implied warranties of
24 * merchantability and fitness, in no event shall Brian Totty or
25 * University of Illinois be liable for any special, indirect or
26 * consequential damages or any damages whatsoever resulting from loss of
27 * use, data or profits, whether in an action of contract, negligence or
28 * other tortious action, arising out of or in connection with the use or
29 * performance of this software.
30 *
31 * Author:
32 * Brian Totty
33 * Department of Computer Science
34 * University Of Illinois at Urbana-Champaign
35 * 1304 West Springfield Avenue
36 * Urbana, IL 61801
37 *
38 * totty@cs.uiuc.edu
39 *
40 */
41
42 #include <X11/Xlib.h>
43 #include <X11/Xos.h>
44 #include <X11/IntrinsicP.h>
45 #include <X11/Intrinsic.h>
46 #include <X11/StringDefs.h>
47 #include <X11/cursorfont.h>
48 #include <X11/CompositeP.h>
49 #include <X11/Composite.h>
50 #ifdef USE_XAW3D
51 #include <X11/Xaw3d/MenuButton.h>
52 #include <X11/Xaw3d/SimpleMenu.h>
53 #include <X11/Xaw3d/SmeBSB.h>
54 #include <X11/Xaw3d/Viewport.h>
55 #include <X11/Xaw3d/List.h>
56 #else
57 #include <X11/Xaw/MenuButton.h>
58 #include <X11/Xaw/SimpleMenu.h>
59 #include <X11/Xaw/SmeBSB.h>
60 #include <X11/Xaw/Viewport.h>
61 #include <X11/Xaw/List.h>
62 #endif
63
64 #include "DirMgr.h"
65 #include "FChooserP.h"
66 #include "FChooser.h"
67
68 /*---------------------------------------------------------------------------*
69
70 I N T E R N A L R O U T I N E S
71
72 *---------------------------------------------------------------------------*/
73
74 #if (!NeedFunctionPrototypes)
75
76 static void Initialize();
77 static void Realize();
78 static void Destroy();
79 static void Resize();
80 static Boolean SetValues();
81 static XtGeometryResult GeometryManager();
82 static void ChildrenCreate();
83 static void ChildrenRealize();
84 static void ChildrenUpdate();
85 static void DirectoryCallback();
86 static void FileCallback();
87 static void SelectFileByIndex();
88 static Boolean SelectFileByName();
89 static void UnselectAll();
90 static void Notify();
91 static void GotoDeepestLegalDirectory();
92 static void UpdateLists();
93 static void Chdir();
94
95 #else
96
97 static void Initialize(Widget request, Widget new);
98 static void Realize(Widget w, XtValueMask *valueMask,
99 XSetWindowAttributes *attrs);
100 static void Destroy(XfwfFileChooserWidget fcw);
101 static void Resize(Widget w);
102 static Boolean SetValues(Widget current, Widget request, Widget new);
103 static XtGeometryResult GeometryManager(Widget w,
104 XtWidgetGeometry *request,
105 XtWidgetGeometry *reply);
106 static void ChildrenCreate(XfwfFileChooserWidget fcw);
107 static void ChildrenRealize(XfwfFileChooserWidget fcw);
108 static void ChildrenUpdate(XfwfFileChooserWidget fcw);
109 static void DirectoryCallback(Widget w, XtPointer client_data,
110 XtPointer call_data);
111 static void FileCallback(Widget w, XtPointer client_data,
112 XtPointer call_data);
113 static void SelectFileByIndex(XfwfFileChooserWidget fcw, int index);
114 static Boolean SelectFileByName(XfwfFileChooserWidget fcw, char *name);
115 static void UnselectAll(XfwfFileChooserWidget fcw);
116 static void Notify(XfwfFileChooserWidget fcw);
117 static void GotoDeepestLegalDirectory(XfwfFileChooserWidget fcw);
118 static void UpdateLists(XfwfFileChooserWidget fcw);
119 static void Chdir(XfwfFileChooserWidget fcw);
120
121 #endif
122
123 /*---------------------------------------------------------------------------*
124
125 R E S O U R C E I N I T I A L I Z A T I O N
126
127 *---------------------------------------------------------------------------*/
128
129 #define FCFieldOffset(FIELD) XtOffset(XfwfFileChooserWidget,fileChooser.FIELD)
130 #define CoreFieldOffset(FIELD) XtOffset(Widget,core.FIELD)
131
132 static XtResource resources[] = {
133 { XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
134 CoreFieldOffset(width), XtRString, "500" },
135 { XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
136 CoreFieldOffset(height), XtRString, "250" },
137 { XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
138 CoreFieldOffset(background_pixel), XtRString, "white" },
139 { XtNcurrentDirectory, XtCPathname, XtRString, sizeof(String),
140 FCFieldOffset(current_dir), XtRString, NULL },
141 { XtNcurrentFile, XtCFilename, XtRString, sizeof(String),
142 FCFieldOffset(current_file), XtRString, NULL },
143 { XtNcallback, XtCCallback, XtRCallback,
144 sizeof(XtCallbackList), FCFieldOffset(callbacks), XtRCallback, NULL},
145 {XtNsortMode, XtCValue, XtRInt, sizeof(int),
146 FCFieldOffset(sort_mode), XtRString, "2"},
147 {XtNpattern, XtCFile, XtRString, sizeof(String),
148 FCFieldOffset(pattern), XtRString, NULL},
149 };
150
151 #undef FCFieldOffset
152 #undef CoreFieldOffset
153
154 /*---------------------------------------------------------------------------*
155
156 C L A S S A L L O C A T I O N
157
158 *---------------------------------------------------------------------------*/
159
160 XfwfFileChooserClassRec xfwfFileChooserClassRec = {
161 {
162 /* superclass */ (WidgetClass)&compositeClassRec,
163 /* class_name */ "XfwfFileChooser",
164 /* widget_size */ sizeof(XfwfFileChooserRec),
165 /* class_initialize */ NULL,
166 /* class_part_initialize*/ NULL,
167 /* class_inited */ FALSE,
168 /* initialize */ (XtInitProc)Initialize,
169 /* initialize_hook */ NULL,
170 /* realize */ (XtRealizeProc)Realize,
171 /* actions */ NULL,
172 /* num_actions */ 0,
173 /* resources */ resources,
174 /* resource_count */ XtNumber(resources),
175 /* xrm_class */ NULLQUARK,
176 /* compress_motion */ TRUE,
177 /* compress_exposure */ TRUE,
178 /* compress_enterleave */ TRUE,
179 /* visible_interest */ FALSE,
180 /* destroy */ (XtWidgetProc)Destroy,
181 /* resize */ (XtWidgetProc)Resize,
182 /* expose */ XtInheritExpose,
183 /* set_values */ (XtSetValuesFunc)SetValues,
184 /* set_values_hook */ NULL,
185 /* set_values_almost */ XtInheritSetValuesAlmost,
186 /* get_values_hook */ NULL,
187 /* accept_focus */ NULL,
188 /* version */ XtVersion,
189 /* callback_private */ NULL,
190 /* tm_table */ NULL,
191 /* query_geometry */ XtInheritQueryGeometry,
192 /* display_accelerator */ XtInheritDisplayAccelerator,
193 /* extension */ NULL
194 }, /* Core Part */
195 {
196 /* geometry_manager */ GeometryManager,
197 /* change_managed */ XtInheritChangeManaged,
198 /* insert_child */ XtInheritInsertChild,
199 /* delete_child */ XtInheritDeleteChild,
200 /* extension */ NULL
201 }, /* Composite Part */
202 {
203 /* no extra class data */ 0
204 } /* FileSelector Part */
205 };
206
207 WidgetClass xfwfFileChooserWidgetClass =
208 (WidgetClass)&xfwfFileChooserClassRec;
209
210 /*---------------------------------------------------------------------------*
211
212 E X P O R T E D M E T H O D S
213
214 *---------------------------------------------------------------------------*/
215
216
217 /*---------------------------------------------------------------------------*
218
219 Initialize()
220
221 This procedure is called by the X toolkit to initialize
222 the FileChooser widget instance. The hook to this routine is in the
223 initialize part of the core part of the class.
224
225 *---------------------------------------------------------------------------*/
226
227 /* ARGSUSED */
228 static void
Initialize(request,new)229 Initialize(request,new)
230 Widget request,new;
231 {
232 XfwfFileChooserWidget fcw = (XfwfFileChooserWidget)new;
233 char *str,*initial_file,path[MAXPATHLEN + 2];
234 static char *star = "*";
235
236 FCBusyCursor(fcw) = XCreateFontCursor(XtDisplay(fcw),XC_watch);
237 FCDirMenu(fcw) = NULL;
238 FCDirMenuButton(fcw) = NULL;
239 FCFileList(fcw) = NULL;
240 FCDirMgr(fcw) = NULL;
241 FCFileNames(fcw) = NULL;
242 FCNumFileNames(fcw) = 0;
243 FCDirNames(fcw) = NULL;
244 FCNumDirNames(fcw) = 0;
245
246 str = (char *)XtCalloc((MAXPATHLEN + 2),sizeof(char));
247 if (FCCurrentDirectory(fcw) != NULL) { /* User Specified Path */
248 strcpy(str,FCCurrentDirectory(fcw));
249 } else {
250 getwd(path);
251 strcpy(str,path);
252 }
253 FCCurrentDirectory(fcw) = str;
254
255 str = (char *)XtCalloc((MAXPATHLEN + 2),sizeof(char));
256 initial_file = FCCurrentFile(fcw);
257 FCCurrentFile(fcw) = str;
258
259 if (FCCorePart(request)->width <= 0)
260 FCCorePart(new)->width = 500;
261 if (FCCorePart(request)->height <= 0)
262 FCCorePart(new)->height = 200;
263
264 if (FCPattern(fcw) == NULL)
265 FCPattern(fcw) = star;
266 FCPattern(fcw) = XtNewString(FCPattern(fcw));
267
268 ChildrenCreate(fcw);
269 GotoDeepestLegalDirectory(fcw);
270 if (initial_file)
271 SelectFileByName(fcw,initial_file);
272 } /* End Initialize */
273
274 /*---------------------------------------------------------------------------*
275
276 Realize()
277
278 This function is called to realize a FileChooser widget.
279
280 *---------------------------------------------------------------------------*/
281
Realize(w,valueMask,attrs)282 static void Realize(w,valueMask,attrs)
283 Widget w;
284 XtValueMask *valueMask;
285 XSetWindowAttributes *attrs;
286 {
287 XfwfFileChooserWidget fcw = (XfwfFileChooserWidget)w;
288
289 XtCreateWindow(w,InputOutput,(Visual *)CopyFromParent,*valueMask,attrs);
290 ChildrenRealize(fcw);
291 ChildrenUpdate(fcw);
292 Resize(w);
293 Notify(fcw);
294 } /* End Realize */
295
296 /*---------------------------------------------------------------------------*
297
298 Destroy()
299
300 This function is called to destroy a FileChooser widget.
301
302 *---------------------------------------------------------------------------*/
303
304 static void
Destroy(fcw)305 Destroy(fcw)
306 XfwfFileChooserWidget fcw;
307 {
308 int i;
309
310 XtFree(FCCurrentDirectory(fcw));
311 XtFree(FCCurrentFile(fcw));
312 XtFree(FCPattern(fcw));
313 if (FCFileNames(fcw) != NULL) {
314 for (i=0; i < FCNumFileNames(fcw); i++)
315 XtFree(FCFileNames(fcw)[i]);
316 XtFree(FCFileNames(fcw));
317 }
318 if (FCDirNames(fcw) != NULL) {
319 for (i=0; i < FCNumDirNames(fcw); i++)
320 XtFree(FCDirNames(fcw)[i]);
321 XtFree(FCDirNames(fcw));
322 }
323 } /* End Destroy */
324
325 /*---------------------------------------------------------------------------*
326
327 Resize()
328
329 This function is called to resize a FileChooser widget.
330
331 *---------------------------------------------------------------------------*/
332
333 static void
Resize(w)334 Resize(w)
335 Widget w;
336 {
337 XfwfFileChooserWidget fcw = (XfwfFileChooserWidget)w;
338
339 ChildrenUpdate(fcw);
340 } /* End Resize */
341
342 /*---------------------------------------------------------------------------*
343
344 SetValues()
345
346 This function is the external interface for setting resources.
347
348 *---------------------------------------------------------------------------*/
349
350 /* ARGSUSED */
351 static Boolean
SetValues(current,request,new)352 SetValues(current,request,new)
353 Widget current,request,new;
354 {
355 XfwfFileChooserWidget fcw_current = (XfwfFileChooserWidget)current;
356 XfwfFileChooserWidget fcw_new = (XfwfFileChooserWidget)new;
357 XfwfFileChooserWidget fcw_request = (XfwfFileChooserWidget)request;
358
359 if (FCCurrentDirectory(fcw_current) != FCCurrentDirectory(fcw_new)){
360 /* strcpy(FCCurrentDirectory(fcw_current),FCCurrentDirectory(fcw_new));
361 FCCurrentDirectory(fcw_new) = FCCurrentDirectory(fcw_current); */
362 /* didn't understand why to copy the new string into old space and
363 use this for the new widget ?! - ACZ */
364 Chdir(fcw_new);
365 }
366 if (FCCurrentFile(fcw_current) != FCCurrentFile(fcw_new)) {
367 char *new_name;
368
369 new_name = FCCurrentFile(fcw_new);
370 FCCurrentFile(fcw_new) = FCCurrentFile(fcw_current);
371 SelectFileByName(fcw_new,new_name);
372 }
373 if (FCPattern(fcw_current) != FCPattern(fcw_new)) {
374 /* XtFree(FCPattern(fcw_current));
375 FCPattern(fcw_new) = XtNewString(FCPattern(fcw_request)); */
376 /* above was XtNewString(FCPattern(fcw_current)) - ACZ */
377 Chdir(fcw_new);
378 }
379 if (FCSortMode(fcw_current) != FCSortMode(fcw_new)) {
380 Chdir(fcw_new);
381 }
382 return(False);
383 } /* End SetValues() */
384
385 /*---------------------------------------------------------------------------*
386
387 GeometryManager(w,request,reply)
388
389 This routine acts as the geometry_manager method for the
390 FileChooser widget. It is called when a child wants to
391 resize/reposition itself.
392
393 Currently, we allow all requests.
394
395 *---------------------------------------------------------------------------*/
396
397 /* ARGSUSED */
398 static XtGeometryResult
GeometryManager(w,request,reply)399 GeometryManager(w,request,reply)
400 Widget w;
401 XtWidgetGeometry *request;
402 XtWidgetGeometry *reply;
403 {
404 return(XtGeometryYes);
405 } /* End GeometryManager */
406
407 /*---------------------------------------------------------------------------*
408
409 L O C A L R O U T I N E S
410
411 *---------------------------------------------------------------------------*/
412
413 /*---------------------------------------------------------------------------*
414
415 ChildrenCreate(fcw)
416
417 This routine creates the initial child widgets for the
418 file selector widget and places them in the widget fcw.
419 No placement or resizing is done. That is done by
420 ChildrenUpdate().
421
422 *---------------------------------------------------------------------------*/
423
424 static void
ChildrenCreate(fcw)425 ChildrenCreate(fcw)
426 XfwfFileChooserWidget fcw;
427 {
428 static char *str = NULL;
429
430 FCDirMenuButton(fcw) =
431 XtVaCreateManagedWidget(FC_DIR_MENU_BUTTON_NAME,menuButtonWidgetClass,
432 (Widget)fcw,
433 XtNmenuName, FC_DIR_MENU_NAME,
434 NULL);
435
436 FCFileViewport(fcw) =
437 XtVaCreateManagedWidget(FC_FILE_VIEWPORT_NAME,viewportWidgetClass,
438 (Widget)fcw,
439 XtNallowVert, True,
440 XtNforceBars, True,
441 XtNuseRight, True,
442 NULL);
443
444 FCFileList(fcw) = XtVaCreateManagedWidget(FC_FILE_LIST_NAME,listWidgetClass,
445 FCFileViewport(fcw),
446 XtNlist, &str,
447 XtNdefaultColumns, 1,
448 XtNforceColumns, True,
449 XtNverticalList, True,
450 /* XtNborderWidth, 0, */
451 NULL);
452
453 XtAddCallback(FCFileList(fcw),XtNcallback,
454 (XtCallbackProc)FileCallback,(XtPointer)fcw);
455 } /* End ChildrenCreate */
456
457 /*---------------------------------------------------------------------------*
458
459 ChildrenRealize(fcw)
460
461 This routine realizes the child widgets. The widgets must
462 already have been created and initialized. Their coordinates
463 should already have been set.
464
465 *---------------------------------------------------------------------------*/
466
467 static void
ChildrenRealize(fcw)468 ChildrenRealize(fcw)
469 XfwfFileChooserWidget fcw;
470 {
471 XtRealizeWidget(FCDirMenuButton(fcw));
472 XtRealizeWidget(FCFileViewport(fcw));
473 XtRealizeWidget(FCFileList(fcw));
474 } /* End ChildrenRealize */
475
476 /*---------------------------------------------------------------------------*
477
478 ChildrenUpdate(fcw)
479
480 This routine takes a FileChooser widget fcw and updates
481 the child widgets by recalculating their coordinates based
482 on the current size of the FileChooser, and setting the
483 appropriate resources.
484
485 We go to some trouble to get something useful displayed in the
486 FCDirMenuButton(fcw) if the current directory name is too long
487 to fit in the button. It would be nice if the "justify" resource
488 of the MenuButton widget did this, but...
489
490 *---------------------------------------------------------------------------*/
491
492 static void
ChildrenUpdate(fcw)493 ChildrenUpdate(fcw)
494 XfwfFileChooserWidget fcw;
495 {
496 Dimension w,h;
497 int gap;
498 Dimension menuButtonW,menuButtonH,fileListW,fileListH;
499 Position menuButtonX,menuButtonY,fileListX,fileListY;
500 XtWidgetGeometry parent_idea,child_idea;
501 XFontStruct *fs;
502 char *label;
503 Dimension intw;
504
505 if (!XtIsRealized((Widget)fcw)) {
506 return;
507 }
508 w = CoreWidth(fcw);
509 h = CoreHeight(fcw);
510 gap = 3;
511
512 intw = 8;
513
514 XtVaGetValues(FCDirMenuButton(fcw), XtNfont, &fs, NULL);
515 /* Get The Child Widgets Current Widths And Heights */
516 /* (although we don't actually use the existing values... */
517 menuButtonW = CoreWidth(FCDirMenuButton(fcw));
518 menuButtonH = CoreHeight(FCDirMenuButton(fcw));
519
520 /* Adjust Widths */
521 menuButtonW = w;
522 fileListW = w;
523
524 /* Adjust menu button label if too small */
525 /* It would be nice if the "justify" resource of MenuButton did this... */
526 label = FCCurrentDirectory(fcw);
527 if (XTextWidth(fs,label,strlen(label)) > menuButtonW-intw) {
528 char newLabel[MAXPATHLEN];
529 /* cut away chars from left side until it fits into the button */
530 while (*label && XTextWidth(fs,label,strlen(label))>menuButtonW-intw) {
531 label += 1;
532 }
533 if (*label)
534 label += 1;
535 strcpy(newLabel,""); /* was "<" - ACZ */
536 strcat(newLabel,label);
537 XtVaSetValues(FCDirMenuButton(fcw), XtNlabel, newLabel, NULL);
538 } else {
539 XtVaSetValues(FCDirMenuButton(fcw), XtNlabel, label, NULL);
540 }
541 /* Adjust Heights */
542 fileListH = h - menuButtonH - gap;
543 /* Listen To Child Height Request For List */
544 /*
545 parent_idea.request_mode = CWWidth | CWHeight;
546 parent_idea.width = fileListW;
547 parent_idea.height = fileListH;
548 XtQueryGeometry(FCFileList(fcw),&parent_idea,&child_idea);
549 if ((child_idea.request_mode & CWHeight) &&
550 (child_idea.height < parent_idea.height)) {
551 fileListH = child_idea.height;
552 }
553 */
554 /* Vertical Positions */
555 menuButtonY = 0;
556 fileListY = menuButtonH + gap;
557 /* Horizontal Positions */
558 menuButtonX = 0;
559 fileListX = 0;
560
561 /* Move them */
562 XtMoveWidget(FCDirMenuButton(fcw),menuButtonX,menuButtonY);
563 XtMoveWidget(FCFileViewport(fcw),fileListX,fileListY);
564 /* Resize them */
565 XtResizeWidget(FCDirMenuButton(fcw),menuButtonW,menuButtonH,
566 CoreBorderWidth(FCDirMenuButton(fcw)));
567 XtResizeWidget(FCFileViewport(fcw),fileListW,fileListH,
568 CoreBorderWidth(FCFileViewport(fcw)));
569 } /* End ChildrenUpdate */
570
571 /*---------------------------------------------------------------------------*
572
573 I N T E R N A L C A L L B A C K S
574
575 *---------------------------------------------------------------------------*/
576
577 /*---------------------------------------------------------------------------*
578
579 DirectoryCallback(w,client_data,call_data)
580
581 This is called when the user selects an ancestor directory from
582 the menu. The argument "w" is the selected object (hence the two
583 calls to XtParent()) and "client_data" is it's index in the menu.
584
585 *---------------------------------------------------------------------------*/
586
587 /*ARGSUSED*/
588 static void
DirectoryCallback(w,client_data,call_data)589 DirectoryCallback(w,client_data,call_data)
590 Widget w;
591 XtPointer client_data; /* index */
592 XtPointer call_data; /* not used */
593 {
594 int index = (int)client_data;
595 XfwfFileChooserWidget fcw = (XfwfFileChooserWidget)XtParent(XtParent(w));
596 int i;
597
598 strcpy(FCCurrentDirectory(fcw),"/");
599 for (i = 1; i <= index; i++) {
600 strcat(FCCurrentDirectory(fcw),FCDirNames(fcw)[i]);
601 strcat(FCCurrentDirectory(fcw),"/");
602 }
603 Chdir(fcw);
604 } /* End DirectoryCallback */
605
606 /*---------------------------------------------------------------------------*
607
608 FileCallback(w,client_data,call_data)
609
610 This is called when the user selects a file in the fileList.
611 The argument "client_data" is the FileChooser widget, "call_data"
612 is a pointer to the standard List widget callback information.
613
614 *---------------------------------------------------------------------------*/
615
616 /*ARGSUSED*/
617 static void
FileCallback(w,client_data,call_data)618 FileCallback(w,client_data,call_data)
619 Widget w;
620 XtPointer client_data; /* fcw */
621 XtPointer call_data; /* return struct */
622 {
623 XfwfFileChooserWidget fcw = (XfwfFileChooserWidget)client_data;
624 XawListReturnStruct *ret = (XawListReturnStruct *)call_data;
625
626 if (ret->list_index == -1) {
627 UnselectAll(fcw); /* Click On Blank Space */
628 Notify(fcw);
629 } else {
630 SelectFileByIndex(fcw,ret->list_index);
631 }
632 } /* End FileCallback */
633
634 /*---------------------------------------------------------------------------*
635
636 I N T E R N A L S U P P O R T R O U T I N E S
637
638 *---------------------------------------------------------------------------*/
639
640 static void
SelectFileByIndex(fcw,index)641 SelectFileByIndex(fcw,index)
642 XfwfFileChooserWidget fcw;
643 int index;
644 {
645 DirEntry *dir_entry;
646
647 DirectoryMgrGotoItem(FCDirMgr(fcw),index);
648 if ((dir_entry=DirectoryMgrCurrentEntry(FCDirMgr(fcw))) == NULL) {
649 fprintf(stderr,"SelectFileByIndex: Entry %d invalid\n",index);
650 exit(-1);
651 }
652 if (DirEntryIsDir(dir_entry) || DirEntryIsDirectoryLink(dir_entry)) {
653 strcat(FCCurrentDirectory(fcw),DirEntryFileName(dir_entry));
654 Chdir(fcw);
655 } else if (!DirEntryIsBrokenLink(dir_entry)) { /* File */
656 strcpy(FCCurrentFile(fcw),DirEntryFileName(dir_entry));
657 XawListHighlight(FCFileList(fcw),index);
658 Notify(fcw);
659 } else { /* Broken Link */
660 XBell(XtDisplay(fcw),0);
661 UnselectAll(fcw);
662 }
663 } /* End SelectFileByIndex */
664
665 static Boolean
SelectFileByName(fcw,name)666 SelectFileByName(fcw,name)
667 XfwfFileChooserWidget fcw;
668 char *name;
669 {
670 if (DirectoryMgrGotoNamedItem(FCDirMgr(fcw),name) == FALSE) {
671 return(False);
672 }
673 SelectFileByIndex(fcw,DirectoryMgrCurrentIndex(FCDirMgr(fcw)));
674 return(True);
675 } /* End SelectFileByName */
676
677 static void
UnselectAll(fcw)678 UnselectAll(fcw)
679 XfwfFileChooserWidget fcw;
680 {
681 Boolean selected = FCCurrentFile(fcw)[0] != '\0';
682
683 FCCurrentFile(fcw)[0] = '\0';
684 XawListUnhighlight(FCFileList(fcw));
685 if (selected)
686 Notify(fcw);
687 } /* End UnselectAll */
688
689 static void
Notify(fcw)690 Notify(fcw)
691 XfwfFileChooserWidget fcw;
692 {
693 XfwfFileChooserReturnStruct ret;
694
695 if (FCCurrentFile(fcw)[0] != '\0') {
696 ret.directory = FCCurrentDirectory(fcw);
697 ret.file = FCCurrentFile(fcw);
698 } else {
699 ret.directory = NULL;
700 ret.file = NULL;
701 }
702 XtCallCallbacks((Widget)fcw,XtNcallback,(XtPointer)&ret);
703 } /* End Notify */
704
705 /*---------------------------------------------------------------------------*
706
707 GotoDeepestLegalDirectory(fcw)
708
709 This function takes a FileChooser widget <fcw> and modifies the
710 directory string in FCCurrentDirectory(fcw) to be the deepest
711 legal directory above the string. Partial or incorrect directory
712 names are stripped starting at the end.
713
714 It then calls UpdateLists() to reset the information dislayed in
715 the FileChooser.
716
717 *---------------------------------------------------------------------------*/
718
719 static void
GotoDeepestLegalDirectory(fcw)720 GotoDeepestLegalDirectory(fcw)
721 XfwfFileChooserWidget fcw;
722 {
723 char *dir,*end;
724 char temp[MAXPATHLEN + 2];
725
726 dir = FCCurrentDirectory(fcw);
727 for (end=dir; *end != '\0'; ++end)
728 /*EMPTY*/;
729 while (1) {
730 if (DirectoryPathExpand(dir,temp) == NULL) {
731 while (*end != '/' && end != dir) {
732 end -= 1;
733 }
734 *end = '\0';
735 } else {
736 strcpy(FCCurrentDirectory(fcw),temp);
737 break;
738 }
739 }
740 UnselectAll(fcw);
741 UpdateLists(fcw);
742 } /* End GotoDeepestLegalDirectory */
743
744 /*---------------------------------------------------------------------------*
745
746 UpdateLists(fcw)
747
748 This routine resets the information displayed in a FileChooser
749 widget by doing the following:
750 1. It changes the cursor to the value of the "busyCursor" resource.
751 2. The old directory manager (FCDirMgr(fcw)) is closed and a
752 new one opened based on the value of FCCurrentDirectory(fcw).
753 3. Any old string arrays are freed, and any existing directory
754 menu is destroyed.
755 4. A new array of strings (FCFileNames(fcw)) is allocated and filled
756 with the names of the files in the directory, then this array
757 is used to set what is displayed in the FCFileList(fcw) widget.
758 5. A new array of strings (FCDirNames(fcw)) is allocated and filled
759 with the names of the ancestor directories. These are also used
760 to create a new FCDirMenu(fcw), and the label FCDirMenuButton(fcw)
761 is set to the name of the directory.
762 6. Finally, the cursor is restored.
763
764 *---------------------------------------------------------------------------*/
765
766 static void
UpdateLists(fcw)767 UpdateLists(fcw)
768 XfwfFileChooserWidget fcw;
769 {
770 int i,count;
771 char *dir,*start;
772 DirEntry *dir_entry;
773 char temp[MAXPATHLEN + 2];
774 Widget menuItem;
775
776 if (XtIsRealized((Widget)fcw)) {
777 /* This is puke-ola. */
778 XDefineCursor(XtDisplay(fcw),XtWindow(fcw),FCBusyCursor(fcw));
779 XDefineCursor(XtDisplay(fcw),XtWindow(FCFileList(fcw)),
780 FCBusyCursor(fcw));
781 XDefineCursor(XtDisplay(fcw),XtWindow(FCDirMenuButton(fcw)),
782 FCBusyCursor(fcw));
783 XFlush(XtDisplay(fcw));
784 }
785 if (FCDirMgr(fcw))
786 DirectoryMgrClose(FCDirMgr(fcw));
787 FCDirMgr(fcw) = DirectoryMgrSimpleOpen(FCCurrentDirectory(fcw),
788 FCSortMode(fcw),FCPattern(fcw));
789
790 /* Throw away old info */
791 if (FCFileNames(fcw) != NULL) {
792 for (i = 0; i < FCNumFileNames(fcw); i++)
793 XtFree(FCFileNames(fcw)[i]);
794 XtFree((char *)FCFileNames(fcw));
795 }
796 if (FCDirNames(fcw) != NULL) {
797 for (i = 0; i < FCNumDirNames(fcw); i++)
798 XtFree(FCDirNames(fcw)[i]);
799 XtFree((char *)FCDirNames(fcw));
800 }
801 if (FCDirMenu(fcw) != NULL)
802 XtDestroyWidget(FCDirMenu(fcw));
803
804 /* Count how many files and dirs we have now */
805 FCNumFileNames(fcw) = DirectoryMgrFilteredCount(FCDirMgr(fcw));
806 FCNumDirNames(fcw) = 1;
807 for (dir=FCCurrentDirectory(fcw)+1; *dir != '\0'; dir++) {
808 if (*dir == '/')
809 FCNumDirNames(fcw) += 1;
810 }
811
812 /* Make the array of filenames and set the fileList widget */
813 FCFileNames(fcw) = (char **)XtCalloc(FCNumFileNames(fcw)+1,sizeof(char *));
814 for (i=0; i < FCNumFileNames(fcw); i++) {
815 dir_entry = DirectoryMgrNextEntry(FCDirMgr(fcw));
816 if (dir_entry == NULL)
817 XtError("Inconsistent Directory");
818 strcpy(temp,DirEntryFileName(dir_entry));
819 if (DirEntryIsDir(dir_entry))
820 strcat(temp,"/");
821 else if (DirEntryIsBrokenLink(dir_entry))
822 strcat(temp," X");
823 else if (DirEntryIsDirectoryLink(dir_entry))
824 strcat(temp,"/");
825 else if (DirEntryIsSymLink(dir_entry))
826 strcat(temp," @");
827 FCFileNames(fcw)[i] = XtNewString(temp);
828 }
829 FCFileNames(fcw)[i] = NULL;
830 XawListChange(FCFileList(fcw),FCFileNames(fcw),0,0,True);
831
832 /* Make the array of dirnames and build a new dirMenu widget */
833 FCDirNames(fcw) = (char **)XtCalloc(FCNumDirNames(fcw)+1,sizeof(char *));
834 FCDirNames(fcw)[0] = XtNewString("/");
835 FCDirMenu(fcw) = XtCreatePopupShell(FC_DIR_MENU_NAME,simpleMenuWidgetClass,
836 (Widget)fcw,NULL,0);
837 menuItem = XtCreateManagedWidget("/",smeBSBObjectClass,FCDirMenu(fcw),
838 NULL,0);
839 XtAddCallback(menuItem,XtNcallback,DirectoryCallback,(XtPointer)0);
840 start = FCCurrentDirectory(fcw);
841 for (i = 1; i < FCNumDirNames(fcw); i++) {
842 while (*start != '\0' && *start == '/')
843 start += 1;
844 count = 0;
845 while (*start != '\0' && *start != '/')
846 temp[count++] = *start++;
847 temp[count] = '\0';
848 FCDirNames(fcw)[i] = XtNewString(temp);
849 menuItem = XtVaCreateManagedWidget("dirMenuItem",smeBSBObjectClass,
850 FCDirMenu(fcw),
851 XtNlabel, temp,
852 NULL);
853 XtAddCallback(menuItem,XtNcallback,DirectoryCallback,(XtPointer)i);
854 }
855 XtVaSetValues(FCDirMenuButton(fcw), XtNlabel,FCCurrentDirectory(fcw), NULL);
856 if (XtIsRealized((Widget)fcw)) {
857 XUndefineCursor(XtDisplay(fcw),XtWindow(fcw));
858 XUndefineCursor(XtDisplay(fcw),XtWindow(FCFileList(fcw)));
859 XUndefineCursor(XtDisplay(fcw),XtWindow(FCDirMenuButton(fcw)));
860 }
861 } /* End UpdateLists */
862
863
Chdir(fcw)864 static void Chdir(fcw)
865 XfwfFileChooserWidget fcw;
866 {
867 GotoDeepestLegalDirectory(fcw);
868 ChildrenUpdate(fcw);
869 } /* End Chdir */
870
871 /*---------------------------------------------------------------------------*
872
873 E X T E R N A L R O U T I N E S
874
875 *---------------------------------------------------------------------------*/
876
877 void
XfwfFileChooserChangeDirectory(fcw,dir)878 XfwfFileChooserChangeDirectory(fcw,dir)
879 XfwfFileChooserWidget fcw;
880 char *dir;
881 {
882 strcpy(FCCurrentDirectory(fcw),dir);
883 Chdir(fcw);
884 } /* End XfwfFileChooserChangeDirectory */
885
886 void
XfwfFileChooserRefresh(fcw)887 XfwfFileChooserRefresh(fcw)
888 XfwfFileChooserWidget fcw;
889 {
890 XfwfFileChooserChangeDirectory(fcw,".");
891 } /* End XfwfFileChooserRefresh */
892
893 char *
XfwfFileChooserCurrentDirectory(fcw)894 XfwfFileChooserCurrentDirectory(fcw)
895 XfwfFileChooserWidget fcw;
896 {
897 return(FCCurrentDirectory(fcw));
898 } /* End XfwfFileChooserCurrentDirectory */
899
900 char *
XfwfFileChooserCurrentFile(fcw)901 XfwfFileChooserCurrentFile(fcw)
902 XfwfFileChooserWidget fcw;
903 {
904 return(FCCurrentFile(fcw));
905 } /* End XfwfFileChooserCurrentFile */
906
907