/**
 *
 * $Header: /usr/local/hungryCVS/hungry/lesstif/lib/Xm/FileSB.c,v 1.16 1997/08/31 02:41:50 miers Exp $
 *
 * Copyright (C) 1997 Free Software Foundation, Inc.
 *
 * This file is part of the GNU LessTif Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **/

static char rcsid[] = "$Header: /usr/local/hungryCVS/hungry/lesstif/lib/Xm/FileSB.c,v 1.16 1997/08/31 02:41:50 miers Exp $";

#include <LTconfig.h>
#include <XmI/XmI.h>

#include <Xm/XmP.h>
#include <Xm/List.h>
#include <Xm/SelectioBP.h>
#include <Xm/FileSBP.h>
#include <Xm/RowColumnP.h>
#include <Xm/ScrolledWP.h>
#include <Xm/ScrollBarP.h>
#include <Xm/XmosP.h>
#include <Xm/TextF.h>
#include <Xm/DialogS.h>
#include <X11/Xfuncs.h>

#include <XmI/DebugUtil.h>

/* Forward Declarations */

static void class_initialize();

static void class_part_initialize(WidgetClass w_class);

static void initialize(Widget request, Widget new_w,
		       ArgList args, Cardinal *num_args);

static void destroy(Widget w);

static Boolean set_values(Widget current, Widget request, Widget new_w,
			  ArgList args, Cardinal *num_args);

static XmGeoMatrix geoMatrixCreate(Widget _w, Widget _from,
				   XtWidgetGeometry *_pref);

static Boolean noGeoRequest(XmGeoMatrix _geoSpec);

static void defaultDirSearchProc(Widget widget, XtPointer search_data);

static void defaultFileSearchProc(Widget widget, XtPointer search_data);

static void defaultQualifySearchDataProc(Widget widget, XtPointer input_data, XtPointer output_data);

static void _XmFileSelectionSearch(Widget w);

static void _XmFsbButton(Widget w, XtPointer client, XtPointer call);

/* Extern */
Boolean _XmSelectionBoxMatch(XmSelectionBoxWidget w);

/*
 * Resources for the FileSelection Box class
 */
#define Offset(field) XtOffsetOf(XmFileSelectionBoxRec, file_selection_box.field)
#define SBOffset(field) XtOffsetOf(XmFileSelectionBoxRec, selection_box.field)
static XtResource resources[] =
{
    {
	XmNdirectory, XmCDirectory, XmRXmString,
	sizeof(XmString), Offset(directory),
	XmRXmString, (XtPointer)NULL
    },
    {
	XmNpattern, XmCPattern, XmRXmString,
	sizeof(XmString), Offset(pattern),
	XmRImmediate, (XtPointer)NULL
    },
    {
	XmNdirListLabelString, XmCDirListLabelString, XmRXmString,
	sizeof(XmString), Offset(dir_list_label_string),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
    },
    {
	XmNdirListItems, XmCDirListItems, XmRXmStringTable,
	sizeof(XmStringTable), Offset(dir_list_items),
	XmRImmediate, (XtPointer)NULL
    },
    {
	XmNdirListItemCount, XmCDirListItemCount, XmRInt,
	sizeof(int), Offset(dir_list_item_count),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
    },
    {
	XmNfilterLabelString, XmCFilterLabelString, XmRXmString,
	sizeof(XmString), Offset(filter_label_string),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
    },
    {
	XmNdirMask, XmCDirMask, XmRXmString,
	sizeof(XmString), Offset(dir_mask),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
    },
    {
	XmNnoMatchString, XmCNoMatchString, XmRXmString,
	sizeof(XmString), Offset(no_match_string),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
    },
    {
	XmNqualifySearchDataProc, XmCQualifySearchDataProc, XmRProc,
	sizeof(XmQualifyProc), Offset(qualify_search_data_proc),
	XmRImmediate, (XtPointer)defaultQualifySearchDataProc
    },
    {
	XmNdirSearchProc, XmCDirSearchProc, XmRProc,
	sizeof(XmSearchProc), Offset(dir_search_proc),
	XmRImmediate, (XtPointer)defaultDirSearchProc
    },
    {
	XmNfileSearchProc, XmCFileSearchProc, XmRProc,
	sizeof(XmSearchProc), Offset(file_search_proc),
	XmRImmediate, (XtPointer)defaultFileSearchProc
    },
    {
	XmNfileTypeMask, XmCFileTypeMask, XmRFileTypeMask,
	sizeof(unsigned char), Offset(file_type_mask),
	XmRImmediate, (XtPointer)XmFILE_REGULAR
    },
    {
	XmNlistUpdated, XmCListUpdated, XmRBoolean,
	sizeof(Boolean), Offset(list_updated),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNdirectoryValid, XmCDirectoryValid, XmRBoolean,
	sizeof(Boolean), Offset(directory_valid),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNdirSpec, XmCDirSpec, XmRXmString,
	sizeof(XmString), SBOffset(text_string),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
    },
    {
	XmNautoUnmanage, XmCAutoUnmanage, XmRBoolean,
	sizeof(Boolean), XtOffsetOf(XmFileSelectionBoxRec, bulletin_board.auto_unmanage),
	XmRImmediate, (XtPointer)False
    },
    {
	XmNfileListLabelString, XmCFileListLabelString, XmRXmString,
	sizeof(XmString), SBOffset(list_label_string),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
    },
    {
	XmNapplyLabelString, XmCApplyLabelString, XmRXmString,
	sizeof(XmString), SBOffset(apply_label_string),
	XmRString, (XtPointer)"Filter"
    },
    {
	XmNdialogType, XmCDialogType, XmRSelectionType,
	sizeof(unsigned char), SBOffset(dialog_type),
	XmRImmediate, (XtPointer)XmDIALOG_FILE_SELECTION
    },
    {
	XmNfileListItems, XmCItems, XmRXmStringTable,
	sizeof(XmStringTable), SBOffset(list_items),
	XmRImmediate, (XtPointer)NULL
    },
    {
	XmNfileListItemCount, XmCItemCount, XmRInt,
	sizeof(int), SBOffset(list_item_count),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
    }
};

/* Synthetic resources */
void FSBGetDirListItemCount(Widget wid, int resource_offset, XtArgVal *value);

void FSBGetDirListItems(Widget wid, int resource_offset, XtArgVal *value);

void FSBGetDirListLabelString(Widget wid, int resource_offset, XtArgVal *value);

void FSBGetDirMask(Widget wid, int resource_offset, XtArgVal *value);

void FSBGetDirectory(Widget wid, int resource_offset, XtArgVal *value);

void FSBGetFilterLabelString(Widget wid, int resource_offset, XtArgVal *value);

void FSBGetListItemCount(Widget wid, int resource_offset, XtArgVal *value);

void FSBGetListItems(Widget wid, int resource_offset, XtArgVal *value);

void FSBGetNoMatchString(Widget wid, int resource_offset, XtArgVal *value);

void FSBGetPattern(Widget wid, int resource_offset, XtArgVal *value);

static XmSyntheticResource syn_resources[] =
{
    {
	XmNdirectory,
	sizeof(XmString), Offset(directory),
	FSBGetDirectory, NULL
    },
    {
	XmNdirListLabelString,
	sizeof(XmString), Offset(directory),
	FSBGetDirListLabelString, NULL
    },
    {
	XmNdirListItems,
	sizeof(XmStringTable), Offset(dir_list_items),
	FSBGetDirListItems, NULL
    },
    {
	XmNdirListItemCount,
	sizeof(int), Offset(dir_list_item_count),
	FSBGetDirListItemCount, NULL
    },
    {
	XmNfilterLabelString,
	sizeof(XmString), Offset(filter_label_string),
	FSBGetFilterLabelString, NULL
    },
    {
	XmNdirMask,
	sizeof(XmString), Offset(dir_mask),
	FSBGetDirMask, NULL
    },
    {
	XmNdirSpec,
	sizeof(XmString), SBOffset(text_string),
	_XmExportXmString, NULL
    },
    {
	XmNfileListLabelString,
	sizeof(XmString), SBOffset(list_label_string),
	_XmExportXmString, NULL
    },
    {
	XmNfileListItems,
	sizeof(XmStringTable), SBOffset(list_items),
	FSBGetListItems, NULL
    },
    {
	XmNfileListItemCount,
	sizeof(XmStringTable), SBOffset(list_item_count),
	FSBGetListItemCount, NULL
    },
    {
	XmNnoMatchString,
	sizeof(XmString), Offset(no_match_string),
	FSBGetNoMatchString, NULL
    },
    {
	XmNpattern,
	sizeof(XmString), Offset(pattern),
	FSBGetPattern, NULL
    }
};

/* *INDENT-OFF* */
static XmBaseClassExtRec _XmFileSBCoreClassExtRec = {
    /* next_extension            */ NULL,
    /* record_type               */ NULLQUARK,                             
    /* version                   */ XmBaseClassExtVersion,
    /* size                      */ sizeof(XmBaseClassExtRec),
    /* initialize_prehook        */ NULL,
    /* set_values_prehook        */ NULL,
    /* initialize_posthook       */ NULL,
    /* set_values_posthook       */ NULL,
    /* secondary_object_class    */ NULL,
    /* secondary_object_create   */ NULL,
    /* get_secondary_resources   */ NULL,
    /* fast_subclass             */ { 0 },
    /* get_values_prehook        */ NULL,
    /* get_values_posthook       */ NULL,
    /* class_part_init_prehook   */ NULL,
    /* class_part_init_posthook  */ NULL,
    /* ext_resources             */ NULL,
    /* compiled_ext_resources    */ NULL,
    /* num_ext_resources         */ 0,
    /* use_sub_resources         */ False,
    /* widget_navigable          */ 0,/*******XmInheritWidgetNavigable,*/
    /* focus_change              */ 0,/********XmInheritFocusChange,*/
    /* wrapper_data              */ NULL
};

static XmManagerClassExtRec _XmFileSBMClassExtRec = {
    /* next_extension            */ NULL,
    /* record_type               */ NULLQUARK,
    /* version                   */ XmManagerClassExtVersion,
    /* record_size               */ sizeof(XmManagerClassExtRec),
    /* traversal_children        */ NULL
};

XmFileSelectionBoxClassRec xmFileSelectionBoxClassRec = {
    /* Core class part */
    {
	/* superclass            */ (WidgetClass) &xmSelectionBoxClassRec,
        /* class_name            */ "XmFileSelectionBox",
	/* widget_size           */ sizeof(XmFileSelectionBoxRec),
	/* class_initialize      */ class_initialize,
	/* class_part_initialize */ class_part_initialize,
	/* class_inited          */ False,
	/* initialize            */ initialize,
	/* initialize_hook       */ NULL,
	/* realize               */ 0,/*************XtInheritRealize,*/
	/* actions               */ NULL,
	/* num_actions           */ 0,
	/* resources             */ resources,
	/* num_resources         */ XtNumber(resources),
	/* xrm_class             */ NULLQUARK,
	/* compress_motion       */ True,
	/* compress_exposure     */ XtExposeCompressMaximal,
	/* compress_enterleave   */ True,
	/* visible_interest      */ False,
	/* destroy               */ destroy,
	/* resize                */ 0,/************XtInheritResize,*/
	/* expose                */ 0,/*************XtInheritExpose,*/
	/* set_values            */ set_values,
	/* set_values_hook       */ NULL,
	/* set_values_almost     */ 0,/***********XtInheritSetValuesAlmost,*/
	/* get_values_hook       */ NULL,
	/* accept_focus          */ NULL,
	/* version               */ XtVersion,
	/* callback offsets      */ NULL,
	/* tm_table              */ 0,/*************XtInheritTranslations,*/
	/* query_geometry        */ 0,/***********XtInheritQueryGeometry,*/
	/* display_accelerator   */ NULL,
	/* extension             */ (XtPointer)&_XmFileSBCoreClassExtRec
    },
    /* Composite class part */
    {
	/* geometry manager */ 0,/*************XtInheritGeometryManager,*/
        /* change_managed   */ 0,/*************XtInheritChangeManaged,*/
        /* insert_child     */ 0,/************XtInheritInsertChild,*/
        /* delete_child     */ 0,/***************XtInheritDeleteChild,*/
        /* extension        */ NULL,
    },
    /* Constraint class part */
    {
	/* subresources      */ NULL,  
        /* subresource_count */ 0,     
        /* constraint_size   */ 0,     
        /* initialize        */ NULL,  
        /* destroy           */ NULL,  
        /* set_values        */ NULL,  
        /* extension         */ NULL,  
    },
    /* XmManager class part */
    {
       /* translations                 */ 0,/******XmInheritTranslations,*/
       /* syn_resources                */ syn_resources,
       /* num_syn_resources            */ XtNumber(syn_resources),
       /* syn_constraint_resources     */ NULL,
       /* num_syn_constraint_resources */ 0,
       /* parent_process               */ 0,/*******XmInheritParentProcess,*/
       /* extension                    */ (XtPointer)&_XmFileSBMClassExtRec
    },
    /* XmBulletinBoard class part */
    {
	/* always_install_accelerators  */ False,
	/* geo_matrix_create            */ geoMatrixCreate,
	/* focus_moved_proc             */ 0,/*********XmInheritFocusMovedProc,*/
	/* extension                    */ NULL,
    },
    /* XmSelectionBox part */
    {
	/* extension */ NULL,
    },
    /* XmFileSelectionBox part */
    {
	/* extension */ NULL,
    }
};
/* *INDENT-ON* */

int AMIWIN_FileSB(void)
{
_XmFileSBCoreClassExtRec.widgetNavigable=XmInheritWidgetNavigable;
_XmFileSBCoreClassExtRec.focusChange=XmInheritFocusChange;

xmFileSelectionBoxClassRec.translations=XmInheritTranslations;
xmFileSelectionBoxClassRec.parent_process=XmInheritParentProcess;
xmFileSelectionBoxClassRec.focus_moved_proc=XmInheritFocusMovedProc;
xmFileSelectionBoxClassRec.realize=XtInheritRealize;
xmFileSelectionBoxClassRec.resize=XtInheritResize;
xmFileSelectionBoxClassRec.expose=XtInheritExpose;
xmFileSelectionBoxClassRec.set_values_almost=XtInheritSetValuesAlmost;
xmFileSelectionBoxClassRec.tm_table=AMIWIN_XtInheritTranslations;
xmFileSelectionBoxClassRec.query_geometry=XtInheritQueryGeometry;
xmFileSelectionBoxClassRec.geometry_manager=XtInheritGeometryManager;
xmFileSelectionBoxClassRec.change_managed=XtInheritChangeManaged;
xmFileSelectionBoxClassRec.insert_child=XtInheritInsertChild;
xmFileSelectionBoxClassRec.delete_child=XtInheritDeleteChild;
return(0);
}


WidgetClass xmFileSelectionBoxWidgetClass = (WidgetClass)&xmFileSelectionBoxClassRec;

#define DEFAULT_NUM_VIS_ITEMS	XmFSB_MAX_WIDGETS_VERT	/* FIX ME -- can someone confirm this? */
#define DEFAULT_LIST_WIDTH	100

static void
class_initialize()
{
    _XmFileSBCoreClassExtRec.record_type = XmQmotif;
}

static void
class_part_initialize(WidgetClass widget_class)
{
    _XmFastSubclassInit(widget_class, XmFILE_SELECTION_BOX_BIT);
}

static void
initialize(Widget request, Widget new_w,
	   ArgList args, Cardinal *num_args)
{
    Arg argl[7];
    int argc;
    XmString files = NULL;

    SB_DialogType(new_w) = XmDIALOG_FILE_SELECTION;
    XtManageChild(SB_ApplyButton(new_w));
    XtManageChild(SB_HelpButton(new_w));

    if (FS_DirListItemCount(new_w) == XmUNSPECIFIED)
    {
	FS_DirListItemCount(new_w) = 0;
    }

    /*
     * dir list label
     */
    if (FS_DirListLabelString(new_w) == (XmString)XmUNSPECIFIED)
    {
	FS_DirListLabelString(new_w) =
	    _XmOSGetLocalizedString(NULL,	/* FIX ME */
				    new_w,
				    XmNdirListLabelString,
				    (String)"Directories");
    }
    else if (FS_DirListLabelString(new_w) != NULL)
    {
	FS_DirListLabelString(new_w) =
		XmStringCopy(FS_DirListLabelString(new_w));
    }

    FS_DirListLabel(new_w) = _XmBB_CreateLabelG(new_w,
						FS_DirListLabelString(new_w),
						"dirListLabel");
    argc = 0;
    XtSetArg(argl[argc], XmNalignment, XmALIGNMENT_BEGINNING);
    argc++;
    XtSetValues(FS_DirListLabel(new_w), argl, argc);
    XtManageChild(FS_DirListLabel(new_w));

    /*
     * dir list
     */
    argc = 0;
    XtSetArg(argl[argc], XmNvisibleItemCount, SB_ListVisibleItemCount(new_w));
    argc++;
    XtSetArg(argl[argc], XmNselectionPolicy, XmBROWSE_SELECT);
    argc++;
    XtSetArg(argl[argc], XmNscrollBarDisplayPolicy, XmSTATIC);
    argc++;
    XtSetArg(argl[argc], XmNlistSizePolicy, XmCONSTANT);
    argc++;

    FS_DirList(new_w) = XmCreateScrolledList(new_w, "dirList", argl, argc);

    XtManageChild(FS_DirList(new_w));
    XtAddCallback(FS_DirList(new_w), XmNdefaultActionCallback, _XmFsbButton, NULL);

    /* rws file list always has a scroll bar
     * file list
     */
    XtVaSetValues(SB_List(new_w),
		  XmNscrollBarDisplayPolicy, XmSTATIC,
		  XmNlistSizePolicy, XmCONSTANT,
		  NULL);

    /*
     * file list label
     */
    if (FS_FileListLabelString(new_w) == (XmString)XmUNSPECIFIED)
    {
	files = _XmOSGetLocalizedString(NULL,	/* FIX ME */
					new_w,
					XmNfileListLabelString,
					"Files");
    }
    else if (FS_FileListLabelString(new_w) != NULL)
    {
	XmStringFree(FS_FileListLabelString(new_w));
	files = _XmOSGetLocalizedString(NULL,	/* FIX ME */
					new_w,
					XmNfileListLabelString,
					"Files");
    }

    FS_FileListLabelString(new_w) = files;
    argc = 0;
    XtSetArg(argl[argc], XmNlabelString, FS_FileListLabelString(new_w));
    argc++;
    XtSetValues(SB_ListLabel(new_w), argl, argc);

    /*
     * filter label
     */
    if (FS_FilterLabelString(new_w) == (XmString)XmUNSPECIFIED)
    {
	FS_FilterLabelString(new_w) =
	    _XmOSGetLocalizedString(NULL,	/* FIX ME */
				    new_w,
				    XmNfilterLabelString,
				    "Filter");
    }
    else
    {
	FS_FilterLabelString(new_w) = XmStringCopy(FS_FilterLabelString(new_w));
    }

    FS_FilterLabel(new_w) = _XmBB_CreateLabelG(new_w,
					       FS_FilterLabelString(new_w),
					       "filterListLabel");
    argc = 0;
    XtSetArg(argl[argc], XmNalignment, XmALIGNMENT_BEGINNING);
    argc++;
    XtSetValues(FS_FilterLabel(new_w), argl, argc);
    XtManageChild(FS_FilterLabel(new_w));

    /*
     * filter text
     */
    argc = 0;
    FS_FilterText(new_w) = XmCreateTextField(new_w, "filterText", argl, argc);
    XtManageChild(FS_FilterText(new_w));

    /* rws
     *  Override callbacks same as the list
     *  get rid of BBautoUnmanage
     */
    XtRemoveAllCallbacks(FS_FilterText(new_w), XmNactivateCallback);
    XtAddCallback(FS_FilterText(new_w), XmNactivateCallback, _XmFsbButton, NULL);

    /*
     * Override callback on child widgets - need our own version of _XmSbButton -> _XmFsbButton
     */
    if (SB_List(new_w))
    {
	XtRemoveAllCallbacks(SB_List(new_w), XmNdefaultActionCallback);
	XtAddCallback(SB_List(new_w), XmNdefaultActionCallback, _XmFsbButton, NULL);
    }
    if (SB_OkButton(new_w))
    {
	XtRemoveAllCallbacks(SB_OkButton(new_w), XmNactivateCallback);
	XtAddCallback(SB_OkButton(new_w), XmNactivateCallback, _XmFsbButton, NULL);
    }
    if (SB_ApplyButton(new_w))
    {
	XtRemoveAllCallbacks(SB_ApplyButton(new_w), XmNactivateCallback);
	XtAddCallback(SB_ApplyButton(new_w), XmNactivateCallback, _XmFsbButton, NULL);
    }
    if (BB_CancelButton(new_w))
    {
	XtRemoveAllCallbacks(BB_CancelButton(new_w), XmNactivateCallback);
	XtAddCallback(BB_CancelButton(new_w), XmNactivateCallback, _XmFsbButton, NULL);
    }
    if (SB_HelpButton(new_w))
    {
	XtRemoveAllCallbacks(SB_HelpButton(new_w), XmNactivateCallback);
	XtAddCallback(SB_HelpButton(new_w), XmNactivateCallback, _XmFsbButton, NULL);
    }

    if (FS_NoMatchString(new_w) == (XmString)XmUNSPECIFIED)
    {
	FS_NoMatchString(new_w) = XmStringCreateLocalized(" [ .. ] ");
    }
    else if (FS_NoMatchString(new_w) != NULL)
    {
	FS_NoMatchString(new_w) = XmStringCopy(FS_NoMatchString(new_w));
    }

    _XmFileSelectionSearch(new_w);
}

static void
destroy(Widget w)
{
    XmStringFree(FS_DirListLabelString(w));
    XmStringFree(FS_FileListLabelString(w));
    XmStringFree(FS_FilterLabelString(w));
    XmStringFree(FS_NoMatchString(w));
}

static Boolean
set_values(Widget old, Widget request, Widget new_w,
	   ArgList args, Cardinal *num_args)
{
    Arg al[10];
    int ac;
    Boolean refresh = False;

    DEBUGOUT(XdbDebug(__FILE__, new_w,
		       "XmSelectionBox %s SetValues\n", XtName(new_w)));

    /* this is required */
    BB_InSetValues(new_w) = True;

    /* dir list */
    if (FS_DirListItems(new_w) != FS_DirListItems(old) ||
	FS_DirListItemCount(new_w) != FS_DirListItemCount(old))
    {
	/* FIX ME: the items should be copied */
	ac = 0;
	XtSetArg(al[ac], XmNitems, FS_DirListItems(new_w)); ac++;
	XtSetArg(al[ac], XmNitemCount, FS_DirListItemCount(new_w)); ac++;
	XtSetValues(FS_DirList(new_w), al, ac);

	refresh = True;
    }

    /* dir list label string */
    if (FS_DirListLabelString(new_w) != FS_DirListLabelString(old))
    {
	FS_DirListLabelString(new_w) =
		XmStringCopy(FS_DirListLabelString(new_w));
	XmStringFree(FS_DirListLabelString(old));

	ac = 0;
	XtSetArg(al[ac], XmNlabelString, FS_FilterLabelString(new_w)); ac++;


	refresh = True;
    }

    /* label string */
    if (FS_FilterLabelString(new_w) != FS_FilterLabelString(old))
    {
	ac = 0;
	FS_FilterLabelString(new_w) = XmStringCopy(FS_FilterLabelString(new_w));
	XmStringFree(FS_FilterLabelString(old));

	XtSetArg(al[ac], XmNlabelString, FS_FilterLabelString(new_w)); ac++;
	XtSetValues(FS_FilterLabel(new_w), al, ac);

	refresh = True;
    }

    if (FS_DirSpec(new_w) != FS_DirSpec(old))
    {
	String value;

	XmStringGetLtoR(FS_DirSpec(new_w), XmFONTLIST_DEFAULT_TAG, &value);

	XtVaSetValues(SB_Text(new_w), XmNvalue, value, NULL);
	XtFree(value);

	refresh = True;
    }

    if (FS_Directory(new_w) != FS_Directory(old) ||
	FS_DirMask(new_w) != FS_DirMask(old) ||
	FS_Pattern(new_w) != FS_Pattern(old) ||
	FS_FileTypeMask(new_w) != FS_FileTypeMask(old) ||
	FS_QualifySearchDataProc(new_w) != FS_QualifySearchDataProc(old) ||
	FS_DirSearchProc(new_w) != FS_DirSearchProc(old) ||
	FS_FileSearchProc(new_w) != FS_FileSearchProc(old))
    {
	_XmFileSelectionSearch(new_w);
    }

    /* the next 8 lines are required for every BB subclass that uses
       the GeoMatrix */
    BB_InSetValues(new_w) = False;

    if (refresh && (XtClass(new_w) == xmFileSelectionBoxWidgetClass))
    {
	_XmBulletinBoardSizeUpdate(new_w);
	return False;
    }

    return refresh;
}

static Dimension
GetPreferredListWidth(Widget w)
{
    int i;
    String Item;
    String tmp;
    XmString Xmtmp;
    Dimension tmpWidth;
    Dimension Width = 20;
    XmFontList fl;
    int NumItems;
    XmStringTable Items;
    Dimension spacing = 0;
    Dimension sbwidth = 0;
    Dimension sbmargin = 0;
    Dimension listmargin = 0;
    Dimension highlight = 0;
    Widget sb;

    XtVaGetValues(w,
		  XmNhighlightThickness, &highlight,
		  XmNlistMarginWidth, &listmargin,
		  XmNitemCount, &NumItems,
		  XmNitems, &Items,	/* This is _not_ a copy. Do not free */
		  XmNfontList, &fl,
		  NULL);

    for (i = 0; i < NumItems; i++)
    {
	XmStringGetLtoR(Items[i], XmFONTLIST_DEFAULT_TAG, &Item);

	if ((tmp = strrchr(Item, '/')) != NULL)
	{
	    tmp++;
	}
	else
	{
	    tmp = Item;
	}

	Xmtmp = XmStringCreateLtoR(tmp, XmFONTLIST_DEFAULT_TAG);

	tmpWidth = XmStringWidth(fl, Xmtmp);

	Width = Width < tmpWidth ? tmpWidth : Width;

	XmStringFree(Xmtmp);

	XtFree(Item);
    }

    Width += 6;			/* Can someone explain this? What am I missing */
    Width += (listmargin * 2);
    Width += (highlight * 2);

    XtVaGetValues(XtParent(w),
		  XmNspacing, &spacing,
		  XmNscrolledWindowMarginWidth, &sbmargin,
		  XmNverticalScrollBar, &sb,
		  NULL);

    Width += (sbmargin * 2);

    if (XtIsManaged(sb))
    {
	XtVaGetValues(sb,
		      XmNwidth, &sbwidth,
		      NULL);
	Width += sbwidth + spacing;
    }

    return (Width);
}

/*
 * XmGeoSegmentFixUpProc
 */
static void
_XmTextFix(XmGeoMatrix geoSpec,
	   int action,
	   XmGeoMajorLayout layoutPtr,
	   XmKidGeometry rowPtr)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmTextFix\n"));

    if (!XmIsTextField(rowPtr->kid))
    {
	return;
    }

    switch (action)
    {
    case XmGET_PREFERRED_SIZE:
	rowPtr->box.width = 0;
	break;

    case XmGEO_POST_SET:
	XmTextFieldSetInsertionPosition(rowPtr->kid,
					XmTextFieldGetLastPosition(rowPtr->kid));
	break;

    default:
	break;
    }
}

/*
 * XmGeoSegmentFixUpProc
 */
static void
_XmDirListFix(XmGeoMatrix geoSpec,
	      int action,
	      XmGeoMajorLayout layoutPtr,
	      XmKidGeometry rowPtr)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "_XmDirListFix\n"));

    switch (action)
    {
    case XmGET_ACTUAL_SIZE:
	break;

    case XmGET_PREFERRED_SIZE:
	while (rowPtr->kid)
	{
	    if (XmIsScrolledWindow(rowPtr->kid))
	    {
		rowPtr->box.width =
		    GetPreferredListWidth(SW_WorkWindow(rowPtr->kid));
	    }
	    rowPtr++;
	}
	break;

    case XmGEO_POST_SET:
	/*
	 * fix up the Horizontal scroll bars in here
	 */
	while (rowPtr->kid)
	{
	    if (XmIsScrolledWindow(rowPtr->kid))
	    {
		Widget hsb;

		hsb = (Widget)SW_HSB(rowPtr->kid);
		if (hsb && XtIsManaged(hsb))
		{
		    XmListSetHorizPos(SW_WorkWindow(rowPtr->kid),
				      SCB_Maximum(hsb) - SCB_SliderSize(hsb) -
			    GetPreferredListWidth(SW_WorkWindow(rowPtr->kid)) +
				      rowPtr->box.width);
		}
	    }
	    rowPtr++;
	}
	break;

    case XmGEO_PRE_SET:
	if (XmIsScrolledWindow(rowPtr->kid) &&
	    XmIsScrolledWindow(rowPtr[1].kid) &&
	    (XmIsLabel(rowPtr[-2].kid) || XmIsLabelGadget(rowPtr[-2].kid)))
	{
	    XmKidGeometry fileList = &rowPtr[1];
	    XmKidGeometry fileListLabel = &rowPtr[-2];
	    XmKidGeometry dirList = &rowPtr[0];
	    Dimension DirPrefWidth;
	    Dimension FilePrefWidth;

	    DirPrefWidth = GetPreferredListWidth(FS_DirList(XtParent(dirList->kid)));
	    FilePrefWidth = GetPreferredListWidth(SB_List(XtParent(fileList->kid)));

	    /*
	     * Position the file list
	     * It is the width that it wants to be
	     */
	    fileList->box.width = FilePrefWidth;
	    fileList->box.x = geoSpec->width
		- fileList->box.width
		- geoSpec->margin_w
		- 2 * fileList->box.border_width;
	    /*
	     * Position the file list label
	     */
	    fileListLabel->box.x = fileList->box.x;
	    /*
	     * Position the dir list
	     * It takes up the rest of the space in this row
	     */
	    dirList->box.width = fileList->box.x
		- geoSpec->margin_w
		- layoutPtr->row.space_between
		- 2 * dirList->box.border_width;
	}
	break;

    default:
	break;
    }
}

static XmGeoMatrix
geoMatrixCreate(Widget _w, Widget _from, XtWidgetGeometry *_pref)
{
    XmGeoMatrix geoSpec;
    register XmGeoRowLayout layoutPtr;
    register XmKidGeometry boxPtr;
    Cardinal numKids;
    Boolean newRow;
    int nrows, i, nextras;
    Widget *extras = NULL;

    numKids = MGR_NumChildren(_w);

    nextras = 0;
    extras = NULL;
    for (i = 0; i < numKids; i++)
    {
	if (MGR_Children(_w)[i] != SB_ListLabel(_w) &&
	    (SB_List(_w)
	     ? MGR_Children(_w)[i] != XtParent(SB_List(_w))
	     : True) &&
	    MGR_Children(_w)[i] != SB_SelectionLabel(_w) &&
	    MGR_Children(_w)[i] != SB_Text(_w) &&
	    MGR_Children(_w)[i] != SB_Separator(_w) &&
	    MGR_Children(_w)[i] != SB_OkButton(_w) &&
	    MGR_Children(_w)[i] != SB_ApplyButton(_w) &&
	    MGR_Children(_w)[i] != SB_HelpButton(_w) &&
	    MGR_Children(_w)[i] != BB_CancelButton(_w) &&
	    MGR_Children(_w)[i] != FS_FilterLabel(_w) &&
	    MGR_Children(_w)[i] != FS_FilterText(_w) &&
	    MGR_Children(_w)[i] != FS_DirListLabel(_w) &&
	    (FS_DirList(_w)
	     ? MGR_Children(_w)[i] != XtParent(FS_DirList(_w))
	     : True))
	{
	    nextras++;
	}
    }

    if (nextras)
    {
	extras = (Widget *)XtMalloc(sizeof(Widget) * nextras);
    }

    nextras = 0;
    for (i = 0; i < numKids; i++)
    {
	if (MGR_Children(_w)[i] != SB_ListLabel(_w) &&
	    (SB_List(_w)
	     ? MGR_Children(_w)[i] != XtParent(SB_List(_w))
	     : True) &&
	    MGR_Children(_w)[i] != SB_SelectionLabel(_w) &&
	    MGR_Children(_w)[i] != SB_Text(_w) &&
	    MGR_Children(_w)[i] != SB_Separator(_w) &&
	    MGR_Children(_w)[i] != SB_OkButton(_w) &&
	    MGR_Children(_w)[i] != SB_ApplyButton(_w) &&
	    MGR_Children(_w)[i] != SB_HelpButton(_w) &&
	    MGR_Children(_w)[i] != BB_CancelButton(_w) &&
	    MGR_Children(_w)[i] != FS_FilterLabel(_w) &&
	    MGR_Children(_w)[i] != FS_FilterText(_w) &&
	    MGR_Children(_w)[i] != FS_DirListLabel(_w) &&
	    (FS_DirList(_w)
	     ? MGR_Children(_w)[i] != XtParent(FS_DirList(_w))
	     : True))
	{
	    extras[nextras] = MGR_Children(_w)[i];
	    nextras++;
	}
    }

    nrows = 0;

    numKids = MGR_NumChildren(_w);

    /* note the starting from one.  The zero'th child is the "work area" */
    if (nextras > 0)
    {
	for (i = 1; i < nextras; i++)
	{
	    if (XmIsMenuBar(extras[i]) && XtIsManaged(extras[i]))
	    {
		nrows++;
	    }
	}
	if (extras[0] && XtIsManaged(extras[0]))
	{
	    nrows++;
	}
    }

    if (FS_FilterLabel(_w) && XtIsManaged(FS_FilterLabel(_w)))
    {
	nrows++;
    }

    if (FS_FilterText(_w) && XtIsManaged(FS_FilterText(_w)))
    {
	nrows++;
    }

    if ((FS_DirListLabel(_w) && XtIsManaged(FS_DirListLabel(_w))) ||
	(SB_ListLabel(_w) && XtIsManaged(SB_ListLabel(_w))))
    {
	nrows++;
    }

    if ((FS_DirList(_w) && XtIsManaged(FS_DirList(_w))) ||
	(SB_List(_w) && XtIsManaged(SB_List(_w))))
    {
	nrows++;
    }

    if (SB_SelectionLabel(_w) && XtIsManaged(SB_SelectionLabel(_w)))
    {
	nrows++;
    }

    if (SB_Text(_w) && XtIsManaged(SB_Text(_w)))
    {
	nrows++;
    }

    if (SB_Separator(_w) && XtIsManaged(SB_Separator(_w)))
    {
	nrows++;
    }

    if ((BB_CancelButton(_w) && XtIsManaged(BB_CancelButton(_w))) ||
	(SB_OkButton(_w) && XtIsManaged(SB_OkButton(_w))) ||
	(SB_ApplyButton(_w) && XtIsManaged(SB_ApplyButton(_w))) ||
	(SB_HelpButton(_w) && XtIsManaged(SB_HelpButton(_w))))
    {
	nrows++;
    }
    else
    {
	for (i = 1; i < nextras; i++)
	{
	    if (extras[i] && XtIsManaged(extras[i]) &&
		(XmIsPushButton(extras[i]) || XmIsPushButtonGadget(extras[i])))
	    {
		nrows++;
		break;
	    }
	}
    }

    geoSpec = _XmGeoMatrixAlloc(nrows, numKids, 0);
    geoSpec->composite = (Widget)_w;
    geoSpec->instigator = (Widget)_from;
    if (_pref)
    {
	geoSpec->instig_request = *_pref;
    }
    geoSpec->margin_w = BB_MarginWidth(_w) + MGR_ShadowThickness(_w);
    geoSpec->margin_h = BB_MarginHeight(_w) + MGR_ShadowThickness(_w);
    geoSpec->no_geo_request = noGeoRequest;
    geoSpec->uniform_border = True;
    geoSpec->border = XtBorderWidth(_w);

    layoutPtr = &(geoSpec->layouts->row);
    boxPtr = geoSpec->boxes;

    for (i = 1; i < nextras; i++)
    {
	if (XmIsMenuBar(extras[i]) && XtIsManaged(extras[i]) &&
	    _XmGeoSetupKid(boxPtr, extras[i]))
	{
	    layoutPtr->fix_up = _XmMenuBarFix;
	    layoutPtr->space_above = 0;
	    boxPtr += 2;
	    layoutPtr++;
	    break;
	}
    }

    if (SB_ChildPlacement(_w) == XmPLACE_TOP && nextras &&
	extras[0] && XtIsManaged(extras[0]) &&
	_XmGeoSetupKid(boxPtr, extras[0]))
    {
	layoutPtr->stretch_height = 1;
	layoutPtr->fill_mode = XmGEO_EXPAND;
	layoutPtr->even_width = 1;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	layoutPtr++;
	boxPtr += 2;
	nrows++;
    }

    if (FS_FilterLabel(_w) && XtIsManaged(FS_FilterLabel(_w)) &&
	_XmGeoSetupKid(boxPtr, FS_FilterLabel(_w)))
    {
	layoutPtr->fill_mode = XmGEO_EXPAND;
	layoutPtr->even_width = 0;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	layoutPtr++;
	boxPtr += 2;
    }

    if (FS_FilterText(_w) && XtIsManaged(FS_FilterText(_w)) &&
	_XmGeoSetupKid(boxPtr, FS_FilterText(_w)))
    {
	layoutPtr->fix_up = _XmTextFix;
	layoutPtr->fill_mode = XmGEO_EXPAND;
	layoutPtr->space_above = 0;	/* BB_MarginHeight(_w); */
	layoutPtr++;
	boxPtr += 2;
    }

    newRow = False;
    if (FS_DirListLabel(_w) && XtIsManaged(FS_DirListLabel(_w)) &&
	_XmGeoSetupKid(boxPtr, FS_DirListLabel(_w)))
    {
	layoutPtr->fill_mode = XmGEO_EXPAND;
	layoutPtr->fit_mode = XmGEO_PROPORTIONAL;
	layoutPtr->even_width = 0;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	layoutPtr->space_between = BB_MarginWidth(_w);
	newRow = True;
	boxPtr++;
    }

    if (SB_ListLabel(_w) && XtIsManaged(SB_ListLabel(_w)) &&
	_XmGeoSetupKid(boxPtr, SB_ListLabel(_w)))
    {
	layoutPtr->fill_mode = XmGEO_EXPAND;
	layoutPtr->fit_mode = XmGEO_PROPORTIONAL;
	layoutPtr->even_width = 0;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	layoutPtr->space_between = BB_MarginWidth(_w);
	newRow = True;
	boxPtr++;
    }

    if (newRow)
    {
	layoutPtr++;
	boxPtr++;
    }

    newRow = False;
    if (FS_DirList(_w) && XtIsManaged(FS_DirList(_w)) &&
	_XmGeoSetupKid(boxPtr, XtParent(FS_DirList(_w))))
    {
	layoutPtr->fix_up = _XmDirListFix;
	layoutPtr->stretch_height = 1;
	layoutPtr->fill_mode = XmGEO_PACK;
	layoutPtr->fit_mode = XmGEO_PROPORTIONAL;
	layoutPtr->even_width = (Dimension)False;
	layoutPtr->even_height = 1;
	layoutPtr->sticky_end = True;
	layoutPtr->space_above =
	    (FS_DirListLabel(_w) && XtIsManaged(FS_DirListLabel(_w)))
	    ? BB_MarginHeight(_w)
	    : 0;
	layoutPtr->min_height = 40;
	layoutPtr->space_between = BB_MarginWidth(_w);
	newRow = True;
	boxPtr++;
    }

    if (SB_List(_w) && XtIsManaged(SB_List(_w)) &&
	_XmGeoSetupKid(boxPtr, XtParent(SB_List(_w))))
    {
	layoutPtr->fix_up = _XmDirListFix;
	layoutPtr->stretch_height = 1;
	layoutPtr->fill_mode = XmGEO_PACK;
	layoutPtr->fit_mode = XmGEO_PROPORTIONAL;
	layoutPtr->even_width = (Dimension)False;
	layoutPtr->even_height = 1;
	layoutPtr->sticky_end = True;
	layoutPtr->space_above =
	    (SB_ListLabel(_w) && XtIsManaged(SB_ListLabel(_w)))
	    ? BB_MarginHeight(_w)
	    : 0;
	layoutPtr->min_height = 40;
	layoutPtr->space_between = BB_MarginWidth(_w);
	newRow = True;
	boxPtr++;
    }

    if (newRow)
    {
	layoutPtr++;
	boxPtr++;
    }

    if (SB_ChildPlacement(_w) == XmPLACE_ABOVE_SELECTION && nextras &&
	extras[0] && XtIsManaged(extras[0]) &&
	_XmGeoSetupKid(boxPtr, extras[0]))
    {
	layoutPtr->stretch_height = 1;
	layoutPtr->fill_mode = XmGEO_EXPAND;
	layoutPtr->even_width = 1;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	layoutPtr++;
	boxPtr += 2;
	nrows++;
    }

    if (SB_SelectionLabel(_w) && XtIsManaged(SB_SelectionLabel(_w)) &&
	_XmGeoSetupKid(boxPtr, SB_SelectionLabel(_w)))
    {
	layoutPtr->fill_mode = XmGEO_EXPAND;
	layoutPtr->even_width = 0;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	layoutPtr++;
	boxPtr += 2;
    }

    if (SB_Text(_w) && XtIsManaged(SB_Text(_w)) &&
	_XmGeoSetupKid(boxPtr, SB_Text(_w)))
    {
	layoutPtr->fix_up = _XmTextFix;
	layoutPtr->fill_mode = XmGEO_EXPAND;
	layoutPtr->even_height = 1;
	layoutPtr->even_width = 0;
	layoutPtr->space_above = 0;	/* BB_MarginHeight(_w); */
	layoutPtr++;
	boxPtr += 2;
    }

    if (SB_ChildPlacement(_w) == XmPLACE_BELOW_SELECTION && nextras &&
	extras[0] && XtIsManaged(extras[0]) &&
	_XmGeoSetupKid(boxPtr, extras[0]))
    {
	layoutPtr->stretch_height = 1;
	layoutPtr->fill_mode = XmGEO_EXPAND;
	layoutPtr->even_width = 1;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	layoutPtr++;
	boxPtr += 2;
	nrows++;
    }

    if (SB_Separator(_w) && XtIsManaged(SB_Separator(_w)) &&
	_XmGeoSetupKid(boxPtr, SB_Separator(_w)))
    {
	layoutPtr->fix_up = _XmSeparatorFix;
	layoutPtr->space_above = BB_MarginHeight(_w);
	boxPtr += 2;
	layoutPtr++;
    }

    newRow = False;
    if (SB_OkButton(_w) && XtIsManaged(SB_OkButton(_w)) &&
	_XmGeoSetupKid(boxPtr++, SB_OkButton(_w)))
    {
	layoutPtr->fill_mode = XmGEO_CENTER;
	layoutPtr->fit_mode = XmGEO_WRAP;
	layoutPtr->even_width = 1;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	newRow = True;
    }

    for (i = 1; i < nextras; i++)
    {
	if (extras[i] && XtIsManaged(extras[i]) &&
	    (XmIsPushButton(extras[i]) || XmIsPushButtonGadget(extras[i])) &&
	    _XmGeoSetupKid(boxPtr++, extras[i]))
	{
	    _XmBulletinBoardSetDefaultShadow(extras[i]);
	    layoutPtr->fill_mode = XmGEO_CENTER;
	    layoutPtr->fit_mode = XmGEO_WRAP;
	    layoutPtr->even_width = 1;
	    layoutPtr->even_height = 1;
	    layoutPtr->space_above = BB_MarginHeight(_w);
	    newRow = True;
	}
    }

    if (SB_ApplyButton(_w) && XtIsManaged(SB_ApplyButton(_w)) &&
	_XmGeoSetupKid(boxPtr++, SB_ApplyButton(_w)))
    {
	layoutPtr->fill_mode = XmGEO_CENTER;
	layoutPtr->fit_mode = XmGEO_WRAP;
	layoutPtr->even_width = 1;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	newRow = True;
    }

    if (BB_CancelButton(_w) && XtIsManaged(BB_CancelButton(_w)) &&
	_XmGeoSetupKid(boxPtr++, BB_CancelButton(_w)))
    {
	layoutPtr->fill_mode = XmGEO_CENTER;
	layoutPtr->fit_mode = XmGEO_WRAP;
	layoutPtr->even_width = 1;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	newRow = True;
    }

    if (SB_HelpButton(_w) && XtIsManaged(SB_HelpButton(_w)) &&
	_XmGeoSetupKid(boxPtr++, SB_HelpButton(_w)))
    {
	layoutPtr->fill_mode = XmGEO_CENTER;
	layoutPtr->fit_mode = XmGEO_WRAP;
	layoutPtr->even_width = 1;
	layoutPtr->even_height = 1;
	layoutPtr->space_above = BB_MarginHeight(_w);
	newRow = True;
    }

    if (newRow)
    {
	layoutPtr++;
	boxPtr++;
    }

    layoutPtr->space_above = 0;	/* BB_MarginHeight(_w); */
    layoutPtr->end = True;
    if (nextras)
    {
	XtFree((char *)extras);
    }

    return (geoSpec);
}

static Boolean
noGeoRequest(XmGeoMatrix _geoSpec)
{
    if (BB_InSetValues(_geoSpec->composite) &&
	(XtClass(_geoSpec->composite) == xmFileSelectionBoxWidgetClass))
    {
	return True;
    }

    return False;
}

/******************************* SEARCHING **********************************/

static void
defaultDirSearchProc(Widget widget,
		     XtPointer data)
{
    String *entries, dir, pat;
    XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *)data;
    unsigned int numents, numalloc, argc, i, max;
    Arg argl[5];
    XmString *table;

    /*
     * Guys, there are memory leaks here. Results from XmStringGetLtoR must be
     * freed by the caller, which you cannot do on "" or "*".
     *
     * FIX ME later on ;-)
     * Danny 25/5/1996
     */
    if (!XmStringGetLtoR(cbs->dir, XmFONTLIST_DEFAULT_TAG, &dir))
    {
	dir = XtNewString("");
    }

    if (!XmStringGetLtoR(cbs->pattern, XmFONTLIST_DEFAULT_TAG, &pat))
    {
	pat = XtNewString("*");
    }

    entries = NULL;
    numents = numalloc = 0;

    /*
     * I think pattern should always be "*" for directories.
     * It's what happens if you run testXm/filesb/test1 in its directory.
     * At startup the widget shows the "." ".." and "CVS" directories.
     * After appending "*.c" to the filter, the directory list is NOT changed,
     * but the file list is.
     *
     * Danny 25/5/1996
     */
    pat = XtNewString("*");
    _XmOSGetDirEntries(dir, pat, XmFILE_DIRECTORY, False, True,
		       &entries, &numents, &numalloc);

    max = 64;
    table = (XmString *)XtCalloc(max, sizeof(XmString));
    for (i = 0; i < numents; i++)
    {
	if (i == max)
	{
	    max *= 2;
	    table = (XmString *)XtRealloc((char *)table, max * sizeof(XmString));
	}

	table[i] = XmStringCreateLtoR(entries[i], XmFONTLIST_DEFAULT_TAG);

	XtFree(entries[i]);
    }
    XtFree((char *)entries);
    XtFree(dir);
    XtFree(pat);

    argc = 0;
    XtSetArg(argl[argc], XmNitems, table); argc++;
    XtSetArg(argl[argc], XmNitemCount, numents); argc++;
    XtSetValues(FS_DirList(widget), argl, argc);

    FS_DirectoryValid(widget) = True;
    FS_ListUpdated(widget) = True;
}

static void
defaultFileSearchProc(Widget widget,
		      XtPointer data)
{
    String *entries, dir, pat;
    XmFileSelectionBoxCallbackStruct *cbs =
	(XmFileSelectionBoxCallbackStruct *)data;
    unsigned int numents, numalloc, argc, i, max;
    Arg argl[5];
    XmString *table;

    DEBUGOUT(XdbDebug(__FILE__, widget, "defaultFileSearchProc\n"));

    if (!XmStringGetLtoR(cbs->dir, XmFONTLIST_DEFAULT_TAG, &dir))
    {
	dir = XtNewString("");
	DEBUGOUT(XdbDebug(__FILE__, widget,
			  "defaultFileSearchProc: empty directory\n"));
    }
    else
    {
	DEBUGOUT(XdbDebug(__FILE__, widget,
			  "defaultFileSearchProc: directory '%s'\n", dir));
    }

    if (!XmStringGetLtoR(cbs->pattern, XmFONTLIST_DEFAULT_TAG, &pat))
    {
	pat = XtNewString("*");
	DEBUGOUT(XdbDebug(__FILE__, widget,
			  "defaultFileSearchProc: default pattern '*'\n"));
    }
    else
    {
	DEBUGOUT(XdbDebug(__FILE__, widget,
			  "defaultFileSearchProc: pattern '%s'\n", pat));
    }

    entries = NULL;
    numents = numalloc = 0;

    _XmOSBuildFileList(dir, pat, FS_FileTypeMask(widget),
		       &entries, &numents, &numalloc);

    max = 64;
    table = (XmString *)XtCalloc(max, sizeof(XmString));

    for (i = 0; i < numents; i++)
    {
	if (i == max)
	{
	    max *= 2;
	    table = (XmString *)XtRealloc((char *)table,
					  max * sizeof(XmString));
	}
	table[i] = XmStringCreateLtoR(entries[i], XmFONTLIST_DEFAULT_TAG);
	XtFree(entries[i]);
    }
    XtFree((char *)entries);
    XtFree(dir);
    XtFree(pat);

    argc = 0;
    XtSetArg(argl[argc], XmNfileListItems, table); argc++;
    XtSetArg(argl[argc], XmNfileListItemCount, numents); argc++;
    XtSetValues(widget, argl, argc);

    FS_ListUpdated(widget) = True;
}


/*
 * dir part.  Must return an allocated string, even if of zero length.
 */
static void
getDirPart(Widget w,
	   XmFileSelectionBoxCallbackStruct *in,
	   String *directory)
{
    String dir, tmp, tmp2;

DEBUGOUT(printf("getDirPart----------------------0\n"));
    dir = XtMalloc(1);
    *dir = 0;

    /*
     * if dir isn't null, we want it
     */
    if (in->dir != NULL)
    {
	if (XmStringGetLtoR(in->dir, XmFONTLIST_DEFAULT_TAG, &tmp))
	{
	    dir = XtRealloc(dir, strlen(tmp) + 1);
	    bcopy(tmp, dir, strlen(tmp));
	    dir[strlen(tmp)] = 0;

	    XtFree(tmp);
	}
	*directory = dir;

DEBUGOUT(printf("getDirPart----------------------exit1\n"));
	return;
    }

DEBUGOUT(printf("getDirPart----------------------1\n"));
    /*
     * else if the mask isn't null, get the dir from it
     */
    if (in->mask != NULL && in->mask != (XmString)XmUNSPECIFIED)
    {
	if (XmStringGetLtoR(in->mask, XmFONTLIST_DEFAULT_TAG, &tmp))
	{
	    tmp2 = _XmOSFindPatternPart(tmp);

	    if (tmp2 != tmp)
	    {
		dir = XtRealloc(dir, tmp2 - tmp + 1);
		bcopy(tmp, dir, tmp2 - tmp);
		dir[tmp2 - tmp] = 0;
	    }

	    XtFree(tmp);
	}
	*directory = dir;

DEBUGOUT(printf("getDirPart----------------------exit2\n"));
	return;
    }

    /*
     * else it comes from XmNdirectory
     */
    if (FS_Directory(w) != NULL && FS_Directory(w) != (XmString)XmUNSPECIFIED &&
	XmStringGetLtoR(FS_Directory(w),
			XmFONTLIST_DEFAULT_TAG, &tmp))
    {
	dir = XtRealloc(dir, strlen(tmp) + 1);
	bcopy(tmp, dir, strlen(tmp));
	dir[strlen(tmp)] = 0;

	XtFree(tmp);
    }

    *directory = dir;
DEBUGOUT(printf("getDirPart----------------------exit3\n"));
}

/*
 * pattern part.  Must return an allocated string, even if of zero length.
 */
static void
getPatPart(Widget w,
	   XmFileSelectionBoxCallbackStruct *in,
	   String *pattern)
{
    String pat, tmp, tmp2;
DEBUGOUT(printf("getPatPart----------------------0\n"));

    pat = XtMalloc(1);
    *pat = 0;

    /*
     * if we have an input pattern, use it
     */
    if (in->pattern != NULL && in->pattern != (XmString)XmUNSPECIFIED)
    {
	if (XmStringGetLtoR(in->pattern, XmFONTLIST_DEFAULT_TAG, &tmp))
	{
	    pat = XtRealloc(pat, strlen(tmp) + 1);
	    bcopy(tmp, pat, strlen(tmp));
	    pat[strlen(tmp)] = 0;
	    XtFree(tmp);
	}

	*pattern = pat;

DEBUGOUT(printf("getPatPart----------------------exit1\n"));
	return;
    }
DEBUGOUT(printf("getPatPart----------------------1\n"));

    /*
     * else if we have a mask, get the pattern from it
     */
    if (in->mask != NULL && in->mask != (XmString)XmUNSPECIFIED)
    {
	if (XmStringGetLtoR(in->mask, XmFONTLIST_DEFAULT_TAG, &tmp))
	{
	    tmp2 = _XmOSFindPatternPart(tmp);
	    if (tmp2 != tmp)
	    {
		pat = XtRealloc(pat, strlen(tmp2) + 1);
		bcopy(tmp2, pat, strlen(tmp2));
		pat[strlen(tmp2)] = 0;
	    }

	    XtFree(tmp);
	}

	*pattern = pat;

DEBUGOUT(printf("getPatPart----------------------exit2\n"));
	return;
    }

    /*
     * else it comes from XmNpattern
     */
    if (FS_Pattern(w) != NULL && FS_Pattern(w) != (XmString)XmUNSPECIFIED)
    {
	if (XmStringGetLtoR(FS_Pattern(w),
			    XmFONTLIST_DEFAULT_TAG, &tmp))
	{
	    pat = XtRealloc(pat, strlen(tmp) + 1);
	    bcopy(tmp, pat, strlen(tmp));
	    pat[strlen(tmp)] = 0;
	    XtFree(tmp);
	}
    }

    *pattern = pat;
DEBUGOUT(printf("getPatPart----------------------exit3\n"));
}

static void
defaultQualifySearchDataProc(Widget w,
			     XtPointer input_data,
			     XtPointer output_data)
{
    String dir = NULL, pat = NULL, directory = NULL, pattern = NULL;
    String mask = NULL;
    XmFileSelectionBoxCallbackStruct *in =
	(XmFileSelectionBoxCallbackStruct *)input_data;
    XmFileSelectionBoxCallbackStruct *out =
	(XmFileSelectionBoxCallbackStruct *)output_data;

DEBUGOUT(printf("defaultQualifySearchDataProc----------0\n"));
    /*
     * heuristic as by OSF/Motif Programmer's Reference Release 1.2.
     * What a pain in the a**
     */

    /*
     * first, if we have both dir and pattern we're ok.
     */
    if (in->dir != NULL && in->pattern != NULL)
    {
	XmStringGetLtoR(in->dir, XmFONTLIST_DEFAULT_TAG, &dir);

	XmStringGetLtoR(in->pattern, XmFONTLIST_DEFAULT_TAG, &pat);

	if (!dir)
	{
	    dir = XtNewString("");
	}
	if (!pat)
	{
	    pat = XtNewString("");
	}
    }
    /*
     * otherwise, get the pieces and qualify them
     */
    else
    {
	getDirPart(w, in, &dir);
	getPatPart(w, in, &pat);

	/*
	 * the subroutines MUST ensure this works, or not return
	 */
    }
DEBUGOUT(printf("defaultQualifySearchDataProc----------1\n"));

    _XmOSQualifyFileSpec(dir, pat, &directory, &pattern);
    DEBUGOUT(XdbDebug(__FILE__, w, "defaultQualifySearchDataProc\n\tdir %s\n\tpat %s\n\tdirectory %s\n\tpattern %s\n",
    	dir, pat, directory, pattern));

DEBUGOUT(printf("defaultQualifySearchDataProc----------2\n"));
    mask = XtNewString(directory);
    mask = XtRealloc(mask, strlen(mask) + strlen(pattern) + 1);

    strcat(mask, pattern);

    out->mask = XmStringCreateSimple(mask);
    out->mask_length = XmStringLength(out->mask);
    out->pattern = XmStringCreateSimple(pattern);
    out->pattern_length = XmStringLength(out->pattern);
    out->dir = XmStringCreateSimple(directory);
    out->dir_length = XmStringLength(out->dir);

    XtFree(mask);
    XtFree(pat);
    XtFree(dir);
    XtFree(pattern);
    XtFree(directory);
DEBUGOUT(printf("defaultQualifySearchDataProc----------3\n"));

    /* This can hardly be right. Oh well. Danny 4/10/96 FIX ME */
    {
	char *s = NULL;

	XmStringGetLtoR(out->mask, XmFONTLIST_DEFAULT_TAG, &s);

	if (s)
	{
	    extern void _XmOSGetDotDot(String);

	    XmStringFree(out->mask);
	    _XmOSGetDotDot(s);
	    out->mask = XmStringCreateLtoR(s, XmFONTLIST_DEFAULT_TAG);
	    XtFree(s);
	}
    }
    /* End */
DEBUGOUT(printf("defaultQualifySearchDataProc----------4\n"));

    if (in->value == NULL || in->value == (XmString)XmUNSPECIFIED)
    {
	if (FS_DirSpec(w) && FS_DirSpec(w) != (XmString)XmUNSPECIFIED)
	{
	    out->value = XmStringCopy(FS_DirSpec(w));
	}
	else
	{
	    out->value = XmStringConcat(out->dir, out->pattern);
	}
    }
    else
    {
	out->value = XmStringCopy(in->value);
    }
DEBUGOUT(printf("defaultQualifySearchDataProc----------5\n"));

    out->length = XmStringLength(out->value);
    out->reason = in->reason;
    out->event = in->event;
DEBUGOUT(printf("defaultQualifySearchDataProc----------exit\n"));
}

/*
 * search procedure.  Algorithm per
 * OSF/M*tif Programmer's Reference Release 1.2, 1-446
 */
static void
_XmFileSelectionSearch(Widget w)
{
    XmFileSelectionBoxCallbackStruct in, out;
    Arg argl[5];
    int argc;

    DEBUGOUT(XdbDebug(__FILE__, w, "_XmFileSelectionSearch()\n"));

DEBUGOUT(printf("_XmFileSelectionSearch-0-------------------------\n"));

    /*
     * setup the callback structures
     */
    in.reason = 0;
    in.event = NULL;
    in.value = NULL;
    in.length = 0;

    in.mask = FS_DirMask(w);
    if (in.mask && in.mask != (XmString)XmUNSPECIFIED)
    {
	in.mask_length = XmStringLength(FS_DirMask(w));
    }

    in.dir = FS_Directory(w);
    if (in.dir && in.dir != (XmString)XmUNSPECIFIED)
    {
	in.dir_length = XmStringLength(FS_Directory(w));
    }

    in.pattern = FS_Pattern(w);
    if (in.pattern && in.pattern != (XmString)XmUNSPECIFIED)
    {
	in.pattern_length = XmStringLength(FS_Pattern(w));
    }

    /*
     * qualification
     */
DEBUGOUT(printf("_XmFileSelectionSearch-1-real:%08x-found:%08x---------\n",defaultQualifySearchDataProc,FS_QualifySearchDataProc(w)));


if (FS_QualifySearchDataProc(w)==0)
{
printf("Fatal error in FileSB.c: FS_QualifySearchDataProc(w) is NULL\n");
exit(1);
}
    (*FS_QualifySearchDataProc(w)) (w, (XtPointer)&in, (XtPointer)&out);

DEBUGOUT(printf("_XmFileSelectionSearch-2-------------------------\n"));
    /*
     * dir search
     */
    FS_DirectoryValid(w) = False;
    FS_ListUpdated(w) = False;
if (FS_DirSearchProc(w)==0)
{
printf("Fatal error in FileSB.c: FS_DirSearchProc(w) is NULL\n");
exit(1);
}
    (*FS_DirSearchProc(w)) (w, (XtPointer)&out);
DEBUGOUT(printf("_XmFileSelectionSearch-3-------------------------\n"));

    /*
     * file search
     */
    if (FS_DirectoryValid(w))
    {
	char *value;
DEBUGOUT(printf("_XmFileSelectionSearch-4-------------------------\n"));

	FS_ListUpdated(w) = False;
	(*FS_FileSearchProc(w)) (w, (XtPointer)&out);

	if (FS_ListUpdated(w) && SB_ListItemCount(w) == 0)
	{
	    /* rws 1 Mar 1997
	     * This does actually get into the list but, you have to left
	     * click on the list hsb before it appears?????
	     */
	    argc = 0;
	    XtSetArg(argl[argc], XmNfileListItemCount, 1); argc++;
	    XtSetArg(argl[argc], XmNfileListItems, &FS_NoMatchString(w)); argc++;
	    XtSetValues(w, argl, argc);

	    argc = 0;

	    value = XtMalloc(1);
	    *value = 0;
	    XtSetArg(argl[argc], XmNvalue, value); argc++;
	    XtSetValues(SB_Text(w), argl, argc);

	    XtFree(value);
	}
	else if (FS_ListUpdated(w))
	{
	    FS_DirSpec(w) = out.dir;
	    XmStringGetLtoR(out.dir, XmFONTLIST_DEFAULT_TAG, &value);

	    argc = 0;
	    XtSetArg(argl[argc], XmNvalue, value); argc++;
	    XtSetValues(SB_Text(w), argl, argc);

	    XtFree(value);
	}

	FS_DirMask(w) = out.mask;	/* Shouldn't we free previous contents first ? FIX ME */

	XmStringGetLtoR(FS_DirMask(w), XmFONTLIST_DEFAULT_TAG, &value);
	argc = 0;
	XtSetArg(argl[argc], XmNvalue, value); argc++;
	XtSetValues(FS_FilterText(w), argl, argc);

	XtFree(value);

	FS_Directory(w) = out.dir;
	FS_Pattern(w) = out.pattern;
    }
DEBUGOUT(printf("_XmFileSelectionSearch-5-------------------------\n"));

    if (XtClass(w) == xmFileSelectionBoxWidgetClass)
    {
	_XmBulletinBoardSizeUpdate(w);
    }
DEBUGOUT(printf("_XmFileSelectionSearch-return-------------------------\n"));
}

/************************** END WIDGET METHODS ****************************/

/************************** EXTERNAL FUNCTIONS ****************************/
Widget
XmCreateFileSelectionBox(Widget parent,
			 char *name,
			 Arg *argList,
			 Cardinal argcount)
{
    return XtCreateWidget(name,
			  xmFileSelectionBoxWidgetClass,
			  parent,
			  argList,
			  argcount);
}

Widget
XmCreateFileSelectionDialog(Widget parent,
			    char *name,
			    Arg *argList,
			    Cardinal argcount)
{
    Widget d, ret;
    char *s;
    Arg *al;
    int ac, i;

    s = _XmMakeDialogName(name);

    al = (Arg *)XtCalloc(argcount + 2, sizeof(Arg));

    ac = 0;
    XtSetArg(al[ac], XmNallowShellResize, True); ac++;
    for (i = 0; i < argcount; i++)
    {
	XtSetArg(al[ac], argList[i].name, argList[i].value); ac++;
    }

    d = XtCreateWidget(s, xmDialogShellWidgetClass, parent, al, ac);
    XtFree(s);

    XtSetArg(al[ac], XmNdialogType, XmDIALOG_FILE_SELECTION); ac++;
    ret = XtCreateWidget(name, xmFileSelectionBoxWidgetClass, d, al, ac);
    XtFree((XtPointer)al);

    return ret;
}

Widget
XmFileSelectionBoxGetChild(Widget w,
			   unsigned char child)
{
    switch (child)
    {
    case XmDIALOG_APPLY_BUTTON:
	return SB_ApplyButton(w);

    case XmDIALOG_CANCEL_BUTTON:
	return SB_CancelButton(w);

    case XmDIALOG_OK_BUTTON:
	return SB_OkButton(w);

    case XmDIALOG_FILTER_TEXT:
	return FS_FilterText(w);

    case XmDIALOG_HELP_BUTTON:
	return SB_HelpButton(w);

    case XmDIALOG_LIST:
	return SB_List(w);

    case XmDIALOG_SEPARATOR:
	return SB_Separator(w);

    case XmDIALOG_TEXT:
	return SB_Text(w);

    case XmDIALOG_LIST_LABEL:
	return SB_ListLabel(w);

    case XmDIALOG_SELECTION_LABEL:
	return SB_SelectionLabel(w);

    case XmDIALOG_FILTER_LABEL:
	return FS_FilterLabel(w);

    case XmDIALOG_DIR_LIST:
	return FS_DirList(w);

    case XmDIALOG_DIR_LIST_LABEL:
	return FS_DirListLabel(w);

    /* Still have to treat these */
    case XmDIALOG_MESSAGE_LABEL:
    case XmDIALOG_DEFAULT_BUTTON:
    case XmDIALOG_SYMBOL_LABEL:
	return BB_DefaultButton(w);
    }

    return NULL;
}

void
XmFileSelectionDoSearch(Widget w,
			XmString dirmask)
{
    if (dirmask != (XmString)NULL)
    {
	XmStringFree(FS_DirMask(w));
	XmStringFree(FS_Pattern(w));
	XmStringFree(FS_Directory(w));
	FS_DirMask(w) = dirmask;
	FS_Directory(w) = (XmString)NULL;
	FS_Pattern(w) = (XmString)NULL;
    }

    _XmFileSelectionSearch((Widget)w);
}

/*
 * Stolen from SelectionBox.c
 *
 * We need a private routine for this here, because we need to pass the
 * callback structures specific to FileSelectionBox not SelectionBox.
 *
 * This routine is called for any button child of selectionbox for the
 * XmNactivateCallback. Make mapping to XmNokCallback etc.
 * Also called for double-click in list.
 *
 * Need to implement BulletinBoard's AutoUnmanage though.
 */
static void
_XmFsbButton(Widget w, XtPointer client, XtPointer call)
{
    XmFileSelectionBoxWidget sb = (XmFileSelectionBoxWidget)XtParent(w);
    XmAnyCallbackStruct *a = (XmAnyCallbackStruct *)call;
    XmFileSelectionBoxCallbackStruct cbs;

    if (XmIsList(w))
    {				/* The lists are grandchildren... fix sb */
	sb = (XmFileSelectionBoxWidget)XtParent(sb);
    }

    cbs.event = a->event;
    cbs.value = (XmString)0;
    cbs.length = 0;

    /*
     * I think these should always be in initialised :
     *	dir, pattern, mask, and their _length companions
     * Make sure to free these at the end !
     */
    cbs.mask = XmStringCopy(FS_DirMask(sb));
    cbs.mask_length = XmStringLength(cbs.mask);
    cbs.dir = XmStringCopy(FS_Directory(sb));
    cbs.dir_length = XmStringLength(cbs.dir);
    cbs.pattern = XmStringCopy(FS_Pattern(sb));
    cbs.pattern_length = XmStringLength(cbs.pattern);

    if (w == SB_OkButton(sb) || w == SB_List(sb))
    {
	if (w == SB_OkButton(sb))
	{
	    char *s = XmTextFieldGetString(SB_Text(sb));

	    DEBUGOUT(XdbDebug(__FILE__, w, "_XmFsbButton OK '%s'\n", s));

	    cbs.value = XmStringCreateSimple(s);

	    XtFree(s);
	}
	else
	{
	    /* List double-click */

	    XmListCallbackStruct *ls = (XmListCallbackStruct *) call;

	    cbs.value = ls->item;

	    DEBUGOUT(XdbDebug(__FILE__, w, "_XmFsbButton LIST '%s'\n",
			      XdbXmString2String(cbs.value)));
	}

	cbs.length = XmStringLength(cbs.value);

	if (SB_TextString(sb))
	{
	    XmStringFree(SB_TextString(sb));
	}

	SB_TextString(sb) = XmStringCopy(cbs.value);

	if (SB_MustMatch(sb))
	{
	    if (_XmSelectionBoxMatch((XmSelectionBoxWidget)sb))
	    {
		cbs.reason = XmCR_OK;
		XtCallCallbackList((Widget)sb, SB_OkCallback(sb), &cbs);
	    }
	    else
	    {
		cbs.reason = XmCR_NO_MATCH;
		XtCallCallbackList((Widget)sb, SB_NoMatchCallback(sb), &cbs);
	    }
	}
	else
	{
	    cbs.reason = XmCR_OK;
	    XtCallCallbackList((Widget)sb, SB_OkCallback(sb), &cbs);
	}
    }
    else if (w == BB_CancelButton(sb))
    {
	cbs.reason = XmCR_CANCEL;

	DEBUGOUT(XdbDebug(__FILE__, w, "_XmFsbButton CANCEL\n"));

	XtCallCallbackList((Widget)sb, SB_CancelCallback(sb), &cbs);
    }
    else if (w == FS_FilterText(sb) || w == SB_ApplyButton(sb))
    {
	/* There is no apply button - this is Filter */
	DEBUGOUT(XdbDebug(__FILE__, w, "_XmFsbButton FILTER\n"));

	/* rws */ /*removed because of strange AMIGA-crash---XmStringFree(FS_DirMask(sb));*/
	/* rws */ /*removed because of strange AMIGA-crash---XmStringFree(FS_Pattern(sb));*/
	/* rws */ /*removed because of strange AMIGA-crash---XmStringFree(FS_Directory(sb));*/
	/* rws */ FS_DirMask(sb) = XmStringCreateSimple(XmTextFieldGetString(FS_FilterText((Widget)sb)));
	/* rws */ FS_Pattern(sb) = (XmString)NULL;
	/* rws */ FS_Directory(sb) = (XmString)NULL;
	/* rws FS_Pattern(sb) = XmStringCreateSimple(XmTextFieldGetString(FS_FilterText((Widget)sb))); */

	_XmFileSelectionSearch((Widget)sb);

    }
    else if (w == SB_HelpButton(sb))
    {
	cbs.reason = XmCR_HELP;
	DEBUGOUT(XdbDebug(__FILE__, w, "_XmFsbButton HELP\n"));
	XtCallCallbackList((Widget)sb, sb->manager.help_callback, &cbs);
    }
    else if (w == FS_DirList(sb))
    {
	/* Somebody selected a directory */
	XmListCallbackStruct *ls = (XmListCallbackStruct *) call;

	DEBUGOUT(XdbDebug(__FILE__, w, "_XmFsbButton DIRLIST\n"));

	XmStringFree(FS_DirMask(sb));
	XmStringFree(FS_Pattern(sb));
	XmStringFree(FS_Directory(sb));
	FS_DirMask(sb) = XmStringCreateSimple(XmTextFieldGetString(FS_FilterText((Widget)sb)));
	FS_Pattern(sb) = (XmString)NULL;
	FS_Directory(sb) = ls->item;
	_XmFileSelectionSearch((Widget)sb);
    }
    else
    {
	DEBUGOUT(XdbDebug(__FILE__, w, "_XmFsbButton : untreated case !!\n"));
    }

    /* Free what you've allocated */
    XmStringFree(FS_DirMask(sb));
    XmStringFree(FS_Directory(sb));
    XmStringFree(FS_Pattern(sb));

    /* AutoUnmanage */
    if (BB_AutoUnmanage(sb))
    {
	if (w == SB_OkButton(sb) || w == SB_List(sb) ||
	    w == BB_CancelButton(sb))
	{
	    Widget	shell = XtParent(sb);

	    if (XtIsManaged((Widget)sb) &&
		XtIsSubclass(shell, xmDialogShellWidgetClass) &&
		!CoreBeingDestroyed(sb))
	    {
		XtUnmanageChild((Widget)sb);
		DEBUGOUT(XdbDebug(__FILE__, (Widget)sb, "FSB AutoUnmanage\n"));

		XtCallCallbackList(shell,
				   Shell_PopdownCallback(shell),
				   NULL);
	    }
	}
	/* Not in these cases :
	 *	SB_HelpButton(sb)
	 *	FS_FilterText(sb)
	 *	SB_ApplyButton(sb)
	 *	FS_DirList(sb)
	 */
    }
}

/*
 * I assume that the following can be used in synthetic resources :
 *      FSBGetDirListItemCount
 *      FSBGetDirListItems
 *      FSBGetDirListLabelString
 *      FSBGetDirMask
 *      FSBGetDirectory
 *      FSBGetFilterLabelString
 *      FSBGetListItemCount
 *      FSBGetListItems
 *      FSBGetNoMatchString
 *      FSBGetPattern
 *
 * Rules for the copy versus reallocate question have been taken from Kenton
 * Lee's article "Avoiding Motif Memory Leaks" in his column "Advanced
 * Application Development" in The X Advisor, March 1996.
 * The article can be located under http://landru.unx.com/DD/advisor/ .
 * Other articles by Ken are available at http://www.rahul.net/kenton/bib.html
 * or http://www.rahul.net/kenton/index.shtml .
 */
void 
FSBGetDirListItemCount(Widget wid, int resource_offset, XtArgVal *value)
{
    *value = FS_DirListItemCount(wid);
}

void 
FSBGetDirListItems(Widget wid, int resource_offset, XtArgVal *value)
{
    /* According to Ken this is copied in SetValues, but not in GetValues */
    *value = (XtArgVal)FS_DirListItems(wid);
}

void 
FSBGetDirListLabelString(Widget wid, int resource_offset, XtArgVal *value)
{
    /* According to Ken this is always a copy */
    *value = (XtArgVal)XmStringCopy(FS_DirListLabelString(wid));
}

void 
FSBGetDirMask(Widget wid, int resource_offset, XtArgVal *value)
{
    /* According to Ken this is always a copy */
    *value = (XtArgVal)XmStringCopy(FS_DirMask(wid));
}

void 
FSBGetDirectory(Widget wid, int resource_offset, XtArgVal *value)
{
    /* According to Ken this is always a copy */
    *value = (XtArgVal)XmStringCopy(FS_Directory(wid));
}

void 
FSBGetFilterLabelString(Widget wid, int resource_offset, XtArgVal *value)
{
    /* According to Ken this is always a copy */
    *value = (XtArgVal)XmStringCopy(FS_FilterLabelString(wid));
}

void 
FSBGetListItemCount(Widget wid, int resource_offset, XtArgVal *value)
{
    *value = (XtArgVal)SB_ListItemCount(wid);
}

void 
FSBGetListItems(Widget wid, int resource_offset, XtArgVal *value)
{
    /* According to Ken this is copied in SetValues, but not in GetValues */
    *value = (XtArgVal)SB_ListItems(wid);
}

void 
FSBGetNoMatchString(Widget wid, int resource_offset, XtArgVal *value)
{
    /* FIX ME : a copy or the real thing ? */
    *value = (XtArgVal)FS_NoMatchString(wid);
}

void 
FSBGetPattern(Widget wid, int resource_offset, XtArgVal *value)
{
    /* FIX ME : a copy or the real thing ? */
    *value = (XtArgVal)FS_Pattern(wid);
}
