/* xtexcad  V1.2 - graphic editor for LaTeX */
/* 1991 by K.Zitzmann */
/* file_sel.c */


#define MAXPATH LAENGE+LAENGE2   /* Laenge mit Pfad */ 
#define LAENGE 21                /* Laenge Dateiname */
#define WEITE 150                /* Breite des Directoryfensters */
#define LAENGE2 50               /* Laenge Pfadname */
#define HOEHE 300                /* Hoehe des Directoryfensters */
#define ABSTAND 8                /* Abstand zwischen den einzelnen Widgets */
#define DEFAULT_X 300            /* Vorgabe fuer X Koordinate */
#define DEFAULT_Y 300            /* Vorgabe fuer Y Koordinate */

#include <strings.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <X11/IntrinsicP.h>
#include <X11/Shell.h>
#include <X11/ShellP.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/DialogP.h>
/* R4: */
/* #include <X11/Xaw/AsciiSrc.h> */
/* R5 */
#include <X11/Xaw/AsciiText.h>

#include <X11/Xaw/Text.h>

#include "extdef.h"
#include "x_stuff.h"
#include "file_sel.h"


static char *filename;                    /* Pointer auf Filename */
static Widget file_s;                     /* Popupshell fuer Fileselectbox */
static Widget list_direct,                /* Directoryeintraege im Fenster */
	      titel_zeile;                /*Label fuer angezeigte Titelzeile */

static DialogWidget path,                 /* Dialog fuer Ausgabe Path */
		    text,                 /* Eingabe Filename DialogWidget */
		    patt_t;               /* Labelfeld Ausgabe des Patterns */

static char _default[LAENGE];             /* String zum Loeschen des Labels */
static char _default2[LAENGE2];           /* String zum Loesch Titel,Path */
static char patt_global[LAENGE];          /* Pattern als globale Variable */
static int init_called=0;                 /* Widgets korrekt mit INIT_FILE_ */
					  /* SELECT initialisiert */

/* Pointer werden global benoetigt um Speicher beim Verlassen der Fileselect-*/
/* box wieder freigegeben werden kann */
static String *Liste;                     /* Liste der bearbeiteten Strings */
static char *Inhalt;                      /* Listeninhalt */ 

static char *getcwd(buf,size)
char *buf;
int size;
{
char pathname[MAXPATHLEN];

getwd(pathname);
pathname[size-1] = '\0';
strncpy(buf,pathname,size);
}

/*****************************************************************************/
/* Funktion ueberprueft, ob uebergebener Name ein Directory oder eine Datei  */
/* ist.                                                                      */
/*                                                                           */
/* Aufruf: Is_direct(name);                                                  */
/*                                                                           */
/* Parameter: char *name; Name der Datei, die als Directory getestet werden  */
/*                        soll.                                              */
/* Rueckgabe: int;  0 Uebergebener Name war kein Directory, oder Name war    */
/*                    ueberhaupt kein Eintrag in dem aktuellen Directory, der*/
/*                    opendir() zu oeffnen war.                              */
/*                  1 Uebergebener Name war Directory                        */
/*****************************************************************************/
int Is_direct(name)
    char *name;
{
    struct stat buf;

    stat(name,&buf);         
     
    if(buf.st_mode & S_IFDIR)
        return(1);              
    else
        return(0);
}

/*****************************************************************************/
/* Funktion zaehlt Eintrage im aktuellen Verzeichnis, die zum Pattern passen */
/* oder ein Directoryeintrag sind.                                           */
/*                                                                           */
/* Aufruf: count_eintraege();                                                */
/*                                                                           */
/* Parameter: keine;                                                         */
/* Rueckgabe: short; Anzahl der Eintraege im Directory, die der Bedingung    */
/*                   genuegt haben.                                          */
/*****************************************************************************/
short count_eintraege()
{
   DIR *dirp;                      /* offenes Directory */
   struct direct *datei;           /* gelesenener Directoryeintrag */
   short counter=0;                

   dirp = opendir(".");
   while((datei = readdir(dirp)) != NULL)
     if((match(datei->d_name,patt_global)) || (Is_direct(datei->d_name)))
	 counter ++;

   closedir(dirp);
   return(counter);
}
  
/*****************************************************************************/
/* Funktion ueberprueft, ob uebergeneber String zu dem uebergebenen Pattern  */
/* passt.                                                                    */
/*                                                                           */
/* Aufruf: match(string,pattern);                                            */
/*                                                                           */
/* Parameter: char *string; String, der uenerprueft werden soll              */
/*            char *pattern; Pattern mit dem der Striong verglichen wird     */
/* Rueckgabe: 0 String passt nicht zu dem uebergebenen Pattern               */
/*            1 String passt zu dem ubergebenen Pattern                      */
/*****************************************************************************/
int match(sstring,pattern)
char *sstring,*pattern;
{
     char *st,*pa;
     int lst=0,lpa=0,ist=1,ipa=1;

     st=sstring; while (*st++) lst++; st=sstring; /* Laenge berechnen */
     pa=pattern;while (*pa++) lpa++; pa=pattern;/* Laenge berechnen */
     if (!(lst*lpa)) return(0);     /* Ein String war leer */

     while(1)
	  {
	  if (*pa == '?')
	       {
	       if (ist>lst) return(0);
	       ++ist; ++st; ++ipa; ++pa;
	       if ((ist>lst) && (ipa>lpa)) return(1);
	       if (ipa>lpa) return(0);
	       continue;
	       }
	  if (*pa == '*')
	       {
	       if (ipa == lpa) return(1);
	       ++ipa; ++pa;
	       if (ist > lst) continue;
	       do
		    {
		    if (match(st,pa)) return(1);
		    ++ist; ++st;
		    } while (ist <= lst);
	       return(0);
	       }
	  if ((ist > lst) || (!(*st++ == *pa++))) return(0);
	  ++ipa;
	  if ((++ist > lst) && (ipa > lpa)) return(1);
	  } /* von while */
} /* von match */

/*****************************************************************************/
/* Funktion erstellt aus allen passenden Eintraegen im Directory eine Liste, */
/* die an das Listwidget uebergeben werden kann.                             */
/*                                                                           */
/* Aufruf: directory_erstellen(anzahl);                                      */
/*                                                                           */
/* Parameter: short anzahl; anzahl der Eintraege, die in die Liste eingefuegt*/
/*                          werden, um Speicher zu allocieren.               */
/* Rueckgabe: String *; Pointer auf den Listenkopf                           */
/*****************************************************************************/
String *directory_erstellen(short anzahl)
 {
   static char *offset;            /* Naechste freie Speicherstelle */
   static DIR *dirp2;              /* offenes Directory */
   struct direct *datei;           /* Struktur um Dateinamen zu ermitteln */
   short i=0;                      /* Zaehler */                     
   char f_name[LAENGE];            /* Filename in passender Laenge */
   char *eintrag;                  /* Rueckgabe des geprueften Eintrages */
   String *Liste2;                 /* Liste der bearbeiteten Strings */
   char *Inhalt2;                  /* Listeninhalt */ 
   short directory_typ;            /* Eintrag ist Directory */
   char *stelle;                   /* temp Pointer */

   /* neuen Speicher suchen */
   Liste2 = (String *)malloc((anzahl+2)*sizeof(Liste));
   Inhalt2 = offset = (char *)malloc((anzahl+1)*(LAENGE+1)*sizeof(char));

   /* aktuelles Verzeichnis oeffnen */
   dirp2 = opendir(".");

   directory_typ = 0;
    
   /* Directoryeintraege in Liste uebernehmen */
   i = 0;
   while((datei = readdir(dirp2)) != NULL)
     /* Eintrag ueberpruefen mit match-Funktion und ueberpruefen ob Direct. */
     if((directory_typ = Is_direct(datei->d_name)) ||
	   (match(datei->d_name,patt_global)))
         {
	 sprintf(f_name,"%-20.20s",datei->d_name);

	 /* falls Namen zu lang letzte Stelle mit Stern ausgeben */
	 if((stelle=index(f_name,' ')) == NULL)  
	   {
	   f_name[LAENGE] = '\0';
	   f_name[LAENGE-1] = '*';
	   }
	 if(directory_typ)  /* Directorys wird zur Kennung ein / angehangen */
	   {
	     /* nachfolgende Blanks abschneiden */
	     if((stelle=index(f_name,' ')) != NULL)  
	       *stelle = '/';
	     else 
	       {
	       f_name[LAENGE-1] = '/';
	       f_name[LAENGE-2] = '*';
	       }
	   }
	 strcpy(offset,f_name);              /* Stringinhalt uebernehmen */
	 Liste2[i] = (char *)offset;         /* String in Liste anfuegen */
	 offset = (char *)(offset + LAENGE);  /* freie Stelle */
	 i++;
	 }
   
   /* Liste alphabetisch sortieren */
   qsort(Liste2[2],i-2,LAENGE,strcmp);
   
   /* Liste mit NULL Eintrag beenden */
   i++;
   Liste2[i] = NULL;

   /* Directory Stream schliessen */
   closedir(dirp2);

   /* alten Speicher wieder freigeben */
   if(Liste != NULL)
     free(Liste);
   if(Inhalt != NULL)
     free(Inhalt);

   Liste = Liste2;
   Inhalt = Inhalt2;

   return((String *)Liste); /* Pointer auf Listenkopf wird zureuckgegeben */
}

/*****************************************************************************/
/* Funktion steuert bei einer Neuerstellung der Liste im Listwidget den      */
/* Ablauf und veranlasst die sich daraus ergebenden Folgen.                  */
/*                                                                           */
/* Aufruf: direct_to_list();                                                 */
/*                                                                           */
/* Parameter: keine                                                          */
/* Rueckgabe: keine                                                          */
/*****************************************************************************/
void direct_to_list()
{
   Arg args[1];
   short anzahl;              /* anzahl Directoryeintraege */

   anzahl = count_eintraege();

   /* Datei bei einem Patternwechsel nicht mehr vorhanden */
   /* Dateinamen in Labelfeld loeschen */
   /* ohne direkt in Pointer zu schreiben wird Wert nicht angezeigt */
   XtSetArg(args[0],XtNstring," ");
   XtSetValues(((DialogWidget)text)->dialog.valueW,args,1);

   /* neue Liste erstellen und Listwidget uebergeben */
   XtUnmanageChild(list_direct);
   XawListChange(list_direct,directory_erstellen(anzahl),anzahl,0,True);
   XtManageChild(list_direct);

   /* Rollbalken wieder am oeberen Ende positionieren */ 


}        

/*****************************************************************************/
/* Callbackfunktion fuer den Ok-Button. (Rueckgabe Dateiname, Fileselectbox  */
/* schliessen.                                                               */
/*                                                                           */
/* Aufruf: Ok_gelickt(w,client_data,call_data);                              */
/*                                                                           */
/* Funktion wird nur von X-Windows aufgerufen.                               */
/*****************************************************************************/
void Ok_geklickt(Widget w ,caddr_t client_data,caddr_t call_data)
{
  char *stelle;                 /* Pointer auf erstes Blank im String */


  if(XawDialogGetValueString(text)[0]  == ' ')
    /* falls Dateiname leer ist wird NULL zurueck gegeben vgl. CANCEL-Button */
    filename = NULL;
  else 
    {
    /* Dateinamenfeld war mit Dateinamen gefuellt */
    filename = (char *)malloc(MAXPATH*sizeof(char));
    getcwd(filename,LAENGE2);
    strcat(filename,"/");
    strcat(filename,XawDialogGetValueString(text));
    /* nachfolgende Blanks abschneiden */
    if((stelle=index(filename,' ')) != NULL)  
	*stelle = '\0';
    }

  /* Ueberpruefen, ob Dateiname jetzt tatsaechlich passt */
  free(Liste);
  free(Inhalt);
  XtPopdown(file_s);             /* Ruecksprung */
}
 
/*****************************************************************************/
/* Callbackfunktion fuer den Return im Labelfeld Dateinamen aufgerufen       */
/* Setzt die Parmeter fuer Ok_geklickt (s.o.) um.                            */
/*                                                                           */
/* Aufruf: Ok2_gelickt(widget,event,params,n_params);                        */
/*                                                                           */
/* Funktion wird nur von X-Windows aufgerufen.                               */
/*****************************************************************************/
void Ok2_geklickt(Widget widget,XEvent *event,String *params,Cardinal *n_params)
{
  /* Prozedur wird nach <Return> in Labelfeld aufgerufen */
  /* setzt nur Parameter fuer Ok_geklickt um */
  Ok_geklickt(XtParent(widget),NULL,NULL);
}


/*****************************************************************************/
/* Callbackfunktion fuer den Return im Labelfeld Pfadnamen aufgerufen        */
/* Wechselt in neuen Pfad und erstellt Eintraege in der Liste neu.           */
/*                                                                           */
/* Aufruf: Path_changed(widget,event,params,n_params);                       */
/*                                                                           */
/* Funktion wird nur von X-Windows aufgerufen.                               */
/*****************************************************************************/
void Path_changed(Widget widget,XEvent *event,String *params,Cardinal *n_params)
{
  char *home,               /* Homedirectory aus dem Environment */
       *stelle;             /* temporaerer Pointer */
  char p_name[LAENGE2];     /* Pfad in korrigierter Laenge */
char p_name2[LAENGE2];
  char neuer_pfad[LAENGE2]; /* neuer eingegebene Pfad */
Arg args[1];
  
  /* Prozedur wird nach <Return> in Dialogfeld fuer Path aufgerufen */
  /* uebernimmt ggf. neues Pattern und aendert Eintrage im Fenster    */
  sprintf(neuer_pfad,"%-50.50s",XawDialogGetValueString(XtParent(widget)));
  /* nachfolgende Blanks abschneiden */

  if((stelle=index(neuer_pfad,' ')) != NULL)  
    *stelle = '\0';
  else                       /* Namen sind zu lang */ 
    {
    neuer_pfad[LAENGE2] = '\0';
    neuer_pfad[LAENGE2-1] = '*';
    }

  if(chdir(neuer_pfad) == -1)
    /* Fehler beim Wechsel in angegebenen Pfadnamen */
    {
    home = getenv("HOME");
    if(home != NULL)
       chdir(home);    /* bei Fehler ins Homedirectory wechseln */ 
    else               /* kein Eintrag fuer Homedirectory gefunden */
       chdir("/");

    /* Dialogfeld zur Ausgabe des aktuellen Verzeichnisnamen  aendern  */
    getcwd(p_name,LAENGE2);
    /* ohne direkt in Pointer zu schreiben wird Wert nicht angezeigt */
    XtSetArg(args[0],XtNstring,p_name);
    XtSetValues(((DialogWidget)path)->dialog.valueW,args,1);
    }

  /* evtl. Wechsel in neues Directory erfolgt, daher Liste neu erstellen */
  direct_to_list();
}

/*****************************************************************************/
/* Callbackfunktion fuer ein Verlassen des Labelfeldes fuer Pfadeingabe      */
/* wenn die Eingabe des Pfades nichtr mit Return abgeschlossen wurde, so     */
/* muss der Pfad wieder korrekt angezeigt werden.                            */
/*                                                                           */
/* Aufruf: Path_leave(widget,event,params,n_params);                         */
/*                                                                           */
/* Funktion wird nur von X-Windows aufgerufen.                               */
/*****************************************************************************/
void Path_leave(Widget widget,XEvent *event,String *params,Cardinal *n_params)
{
  char p_name[LAENGE2];     /* Pfad in korrigierter Laenge */
char p_name2[LAENGE2];
Arg args[1];

  /* Dialogfeld zur Ausgabe des aktuellen Verzeichnisnamen  aendern  */
  getcwd(p_name,LAENGE2);
  /* ohne direkt in Pointer zu schreiben wird Wert nicht angezeigt */
  sprintf(p_name2,"%-50.50s",p_name);
  XtSetArg(args[0],XtNstring,p_name2);
  XtSetValues(((DialogWidget)path)->dialog.valueW,args,1);
}

/*****************************************************************************/
/* Callbackfunktion fuer den Return im Labelfeld Pattern aufgerufen          */
/* Wechselt globales Pattern aus und erstellt Eintrage in der Liste neu.     */
/*                                                                           */
/* Aufruf: Patt_changed(widget,event,params,n_params);                       */
/*                                                                           */
/* Funktion wird nur von X-Windows aufgerufen.                               */
/*****************************************************************************/
void Patt_change(Widget widget,XEvent *event,String *params,Cardinal *n_params)
{
  char neues_patt[LAENGE];   /* neues Patternmuster */

  /* Prozedur wird nach <Return> in Labelfeld fuer Pattern aufgerufen */
  /* uebernimmt ggf. neues Pattern und aendert Eintrage im Fenster    */
  strcpy(neues_patt,(char *)XawDialogGetValueString(XtParent(widget)));

  if(neues_patt != patt_global)       /* nur aendern falls Pattern anders */
    {
    strcpy(patt_global,neues_patt);   /* neues Pattern setzen */
    /* Eintrage im Fenster neu erstellen */ 
    direct_to_list();
    }
}

/*****************************************************************************/
/* Callbackfunktion fuer den Cancel-Button.(Rueckgabe NULL, Fileselectbox    */
/* schliessen.                                                               */
/*                                                                           */
/* Aufruf: Cancel_gelickt(w,client_data,call_data);                          */
/*                                                                           */
/* Funktion wird nur von X-Windows aufgerufen.                               */
/*****************************************************************************/
void Cancel_geklickt(Widget w,caddr_t client_data,caddr_t call_data)
{
  filename = NULL;                  /* gibt immer NULL zurueck */
  free(Liste);
  free(Inhalt);
  XtPopdown(file_s);
}

/*****************************************************************************/
/* Callbackfunktion fuer das Waehlen eines Eintrages in der Liste des List-  */
/* widget. Prueft, ob Name eine Datei (Uebernahme in Dialogewidget) oder ein */
/* Directory ist. (Wechsel in neues Directory,Liste neu erstellen)           */
/*                                                                           */
/* Aufruf: File_gewaehlt(w,client_data,call_data);                           */
/*                                                                           */
/* Funktion wird nur von X-Windows aufgerufen.                               */
/*****************************************************************************/
void File_gewaehlt(Widget w,caddr_t client_data,caddr_t call_data)
{
  char name[LAENGE+2],          /* gekuerzter Eintragsnamen (ohne Blanks) */
       p_name[LAENGE2],         /* Pathname mit 50 Stellen */
       p_name2[LAENGE2];
char name2[21];
  Arg args[1];                  /* Argumentvektor */
  char *stelle;                 /* Pointer auf erstes Blank im String */
  short i;                      /* Zaehler */
  XawListReturnStruct *feld;     /* Rueckgabe gewaehltes Feld(Listwidget) */

  
  /* geklickter Dateinamen ermitteln */
  feld = XawListShowCurrent(w);  

  /* Zeichenkette kopieren, damit Button nicht veraendert wird */
  strcpy(name,feld->string); 
  name[LAENGE+2] = '\0';

  /* nachfolgende Blanks abschneiden */
  if((stelle=index(name,' ')) != NULL)  
    *stelle = '\0';

  if (!(Is_direct(name)) && (name[0] != ' ')) /* Name nicht leer */
     /* Eintrag war Dateieintrag */
     {
     /* Eintrag wird in Labelfeld uebernommen */
     /* ohne direkt in Pointer zu schreiben wird der Wert nicht angezeigt */
     sprintf(name2,"%-20s",name);
     XtSetArg(args[0],XtNstring,name2);
     XtSetValues(((DialogWidget)text)->dialog.valueW,args,1);
     }
  else                                          
     {
     /* Eintrag war Directory */
     chdir(name);

     /* Dialogfeld zur Ausgabe des aktuellen Verzeichnisnamen  aendern  */
     getcwd(p_name,LAENGE2);
     /* ohne direkt in Pointer zu schreiben wird Wert nicht angezeigt */
     sprintf(p_name2,"%-50.50s",p_name);
     XtSetArg(args[0],XtNstring,p_name2);
     XtSetValues(((DialogWidget)path)->dialog.valueW,args,1);

     /* neue Liste erstellen und anzeigen */
     direct_to_list();

     }

} 


/*****************************************************************************/
/* Funktion setzt einen String die Mitte eines Strings, der aus einer ueber- */
/* gebenen Anzahl von Leerzeichen besteht.                                   */
/*                                                                           */
/* Aufruf: center(zeile,laenge);                                             */
/*                                                                           */
/* Parameter: char *zeile; String der positioniert werden soll.              */
/*            short laenge; Laenge des neu erstellten Strings.               */
/* Rueckgabe: char *; Pointer auf den neu erstellten String                  */
/*                                                                           */
/* !Vorsicht: der Speicher fuer den neuen String wird mit malloc belegt und! */
/* !sollte daher vom spaeteren Benutzer wieder freigegeben werden          ! */
/*****************************************************************************/
char *center(char *zeile,short laenge)
{
   char *neue_zeile;            /* neu erstellter String */
   short blanks,                /* Anzahl fuehrende Blanks */
	 zeilen_laenge,         /* Laenge des uebergebenen Strings */
	 i,s;

   zeilen_laenge = strlen(zeile);
   neue_zeile = (char *)malloc((laenge+1) *sizeof(char));

   /* am Anfang Blanks einfuegen */
   blanks = (int)((laenge - zeilen_laenge)/2);

   /* gesamten String loeschen */
   for(i=0;i<=laenge;i++)
      neue_zeile[i] = ' ';

   /* String uebernehmen */
   for(i=blanks;i<=blanks+zeilen_laenge-1;i++)
      neue_zeile[i] = zeile[i-blanks];
	
   neue_zeile[laenge] = '\0';
		    
   return(neue_zeile);
}
 
/*****************************************************************************/
/* Callbackfunktion fuer allgemeine Events die unterdreuckt werden sollen    */
/* Die Funktion wird aufgerufen, raeumt den Stack auf und kehrt zureuck      */
/*                                                                           */
/* Aufruf: Dummy(widget,event,params,n_params);                              */
/*                                                                           */
/* Funktion wird nur von X-Windows aufgerufen.                               */
/*****************************************************************************/
/* Prozedur dient dazu unerwuenscht Events abzufangen */
void Dummy(Widget widget,XEvent *event,String *params,Cardinal *n_params)
{
}

/*****************************************************************************/
/* Funktion initialisiert Fileselectbox.(erstellt Widgets usw.)              */
/* Diese Funktion wird i.A. nur einmal waehrend eines Programmes aufgerufen  */
/*                                                                           */
/* Aufruf: init_file_select(w);                                              */
/*                                                                           */
/* Parameter: Widget w; Widget im Baum, an das Fileselectbox gehangen wird   */
/* Rueckgabe: PopupShell Widget, dass Fileselectbox Popup enthaelt           */
/*****************************************************************************/
Widget init_file_select(Widget w)     
{
   Arg args[8];               /* Argumentvektor */
   Widget ok,                 /* Button fuer Ok */
	  box,                /* Rahmen um ganze Fileselectbox */
	  fenster,            /* ViewportWidget um Dir-Eintraege */
	  cancel;             /* Button fuer Cancel */
   short anzahl;              /* Anzahl temporaere Variablen */
   XtTranslations trans;      /* Aktionsbeschreibung */
   /* hinzugefuegte Events bei den Dialogboxen */
   static XtActionsRec Return_null[]={{"Ok2_geklickt",Ok2_geklickt},};
   static XtActionsRec Patt_return[]={{"Patt_change",Patt_change},};
   static XtActionsRec Dummy_call[]={{"Dummy",Dummy},};
   static XtActionsRec Path_return[]={{"Path_changed",Path_changed},};
   static XtActionsRec Path_verlas[]={{"Path_leave",Path_leave},};
   
   Dimension breite;

   /* Abfrage, so dass FileSelectbox nur einmal initialisiert wird */
   if(init_called)  /* bereits aufgerufen */
     return(file_s);

   /* Funktion zum ersten mal aufgerufen Flag setzen */ 
   init_called = 1;                   

   /* Pattern initialisieren */
   strcpy(patt_global,"*");

   /* Voreinstellung fuer Dateiname ist Leerstrings */
   sprintf(_default,"%-21s"," ");
   sprintf(_default2,"%-51s"," ");

   /* File_selectbox ist Popupshell */
   XtSetArg( args[0],XtNx, (XtArgVal) DEFAULT_X);
   XtSetArg( args[1],XtNy, (XtArgVal) DEFAULT_Y);
   file_s = XtCreatePopupShell("F1",transientShellWidgetClass,w,args,2);
   
   /* passender Rahmen um das Ganze */
   box = XtCreateManagedWidget("F2",formWidgetClass,file_s,NULL,0);

   /* Labelfeld zur Ausgabe der Ueberschrift */           
   XtSetArg( args[0],XtNlabel, (XtArgVal) _default2);
   XtSetArg( args[1],XtNborderWidth, (XtArgVal) 4);
   XtSetArg( args[2],XtNvertDistance, (XtArgVal) ABSTAND);
   XtSetArg( args[3],XtNhorizDistance, (XtArgVal) ABSTAND);
   titel_zeile = XtCreateManagedWidget("F10",labelWidgetClass,box,args,4);
   
   /* Dialogfeld zur Ausgabe des aktuellen Verzeichnisnamen */
   XtSetArg( args[0],XtNvalue, (XtArgVal) _default2);
   XtSetArg( args[1],XtNvertDistance, (XtArgVal) ABSTAND);
   XtSetArg( args[2],XtNhorizDistance, (XtArgVal) ABSTAND);
   XtSetArg( args[3],XtNfromVert, (XtArgVal) titel_zeile);
   XtSetArg( args[4],XtNlabel,(XtArgVal) _default2);
   XtSetArg( args[5],XtNborderWidth, (XtArgVal) 0);       
   path = (DialogWidget)
	XtCreateManagedWidget("F9",dialogWidgetClass,box,args,6); 
   /* Labelfeld bei der Dialogbox nicht auf den Bildschirm */
   XtSetArg( args[0],XtNfromHoriz,(XtArgVal) NULL);
   XtSetArg( args[1],XtNfromVert, (XtArgVal) NULL);
   XtSetValues( path->dialog.valueW,args,2);
   XtUnmanageChild(path->dialog.labelW);
   XtSetArg(args[0],XtNwidth,&breite);
   XtGetValues(path->dialog.labelW,args,1);
   XtSetArg(args[0],XtNresize, XawtextResizeNever);
   XtSetArg(args[1],XtNwidth,breite);
   XtSetValues(path->dialog.valueW,args,2);
   /* Return innerhalb des Textfeldes abfangen */
   XtAppAddActions(XtWidgetToApplicationContext(path->dialog.valueW),
	  Path_return,1);
   XtSetArg(args[0],XtNresize, XawtextResizeNever);
   XtSetValues(((DialogWidget)path)->dialog.valueW,args,1);
   trans=XtParseTranslationTable(":<Key>Return:Path_changed()");
   XtOverrideTranslations(path->dialog.valueW,trans);
   /* Eingabe von Leerzeichen im Filenamen ist verboten */
   XtAppAddActions(XtWidgetToApplicationContext(path->dialog.valueW),
	  Dummy_call,1);
   trans=XtParseTranslationTable(":<Key>space:Dummy()");
   XtOverrideTranslations(path->dialog.valueW,trans);
   /* Wenn das Dialogfeld ohne Return verlassen wird, so muss der */
   /* Pfadname wieder korrekt angezeigt werden */
   XtAppAddActions(XtWidgetToApplicationContext(path->dialog.valueW),
	  Path_verlas,1);
   trans=XtParseTranslationTable(":<LeaveWindow>:Path_leave()");
   XtAugmentTranslations(path->dialog.valueW,trans);

   /* Viewport um automatischen Rollbalken zu erzeugen */
   XtSetArg( args[0],XtNallowVert, (XtArgVal) True);
   XtSetArg( args[1],XtNheight, (XtArgVal) HOEHE);
   XtSetArg( args[2],XtNwidth, (XtArgVal) WEITE);
   XtSetArg( args[3],XtNforceBars, (XtArgVal) True);
   XtSetArg( args[4],XtNfromVert, (XtArgVal) path);
   XtSetArg( args[5],XtNvertDistance, (XtArgVal) ABSTAND);
   XtSetArg( args[6],XtNhorizDistance, (XtArgVal) ABSTAND);
   fenster =XtCreateManagedWidget("F3",viewportWidgetClass,box,args,7);
  
   /* Directoryeintraege in ListWidget uebernehmen */
   anzahl = count_eintraege();
   XtSetArg( args[0],XtNverticalList, (XtArgVal) True);
   XtSetArg( args[1],XtNlist, (XtArgVal) directory_erstellen(anzahl));
   XtSetArg( args[2],XtNnumberStrings, (XtArgVal) anzahl);
   XtSetArg( args[3],XtNlongest, (XtArgVal) WEITE);
   XtSetArg( args[4],XtNwidth, (XtArgVal) WEITE);
   XtSetArg( args[5],XtNvertDistance, (XtArgVal) ABSTAND);
   list_direct = XtCreateManagedWidget("F5",listWidgetClass,fenster,args,6);
   XtAddCallback(list_direct,XtNcallback,File_gewaehlt,NULL);

   /* Eingabefeld fuer Dateinamen */
   XtSetArg( args[0],XtNlabel, (XtArgVal) "    FILENAME <cr>   ");
   XtSetArg( args[1],XtNvalue, (XtArgVal) _default);
   XtSetArg( args[2],XtNvertDistance, (XtArgVal) (3*ABSTAND));
   XtSetArg( args[3],XtNfromVert, (XtArgVal) path);
   XtSetArg( args[4],XtNhorizDistance, (XtArgVal) (2*ABSTAND));
   XtSetArg( args[5],XtNfromHoriz, (XtArgVal) fenster);
   text =(DialogWidget)
	 XtCreateManagedWidget("F6",dialogWidgetClass,box,args,6);
   XtSetArg(args[0],XtNwidth,&breite);
   XtGetValues(text->dialog.labelW,args,1);
   XtSetArg(args[0],XtNresize, XawtextResizeNever);
   XtSetArg(args[1],XtNwidth,breite);
   XtSetValues(text->dialog.valueW,args,2);
   XtSetArg(args[0],XtNresize, XawtextResizeNever);
   XtSetValues(((DialogWidget)text)->dialog.valueW,args,1);

   /* Return abfangen */
   XtAppAddActions(XtWidgetToApplicationContext(text->dialog.valueW),
	  Return_null,1);
   trans=XtParseTranslationTable(":<Key>Return:Ok2_geklickt()");
   XtOverrideTranslations(text->dialog.valueW,trans);
   /* Eingabe von Leerzeichen im Filenamen ist verboten */
   XtAppAddActions(XtWidgetToApplicationContext(text->dialog.valueW),
	  Dummy_call,1);
   trans=XtParseTranslationTable(":<Key>space:Dummy()");
   XtOverrideTranslations(text->dialog.valueW,trans);

   /* Eingabefeld fuer Pattern */
   XtSetArg( args[0],XtNlabel, (XtArgVal) "    FILETYPE <cr>   ");
   XtSetArg( args[1],XtNvalue, (XtArgVal) _default);
   XtSetArg( args[2],XtNvertDistance, (XtArgVal) ABSTAND);
   XtSetArg( args[3],XtNfromVert, (XtArgVal) text);
   XtSetArg( args[4],XtNhorizDistance, (XtArgVal) (2*ABSTAND));
   XtSetArg( args[5],XtNfromHoriz, (XtArgVal) fenster);
   patt_t=(DialogWidget)    
	 XtCreateManagedWidget("F13",dialogWidgetClass,box,args,6);
   XtSetArg(args[0],XtNwidth,&breite);
   XtGetValues(patt_t->dialog.labelW,args,1);
   XtSetArg(args[0],XtNresize, XawtextResizeNever);
   XtSetArg(args[1],XtNwidth,breite);
   XtSetValues(patt_t->dialog.valueW,args,2);
   XtSetArg(args[0],XtNresize, XawtextResizeNever);
   XtSetValues(((DialogWidget)patt_t)->dialog.valueW,args,1);
   /* Return abfangen */
   XtAppAddActions(XtWidgetToApplicationContext(patt_t->dialog.valueW),
	  Patt_return,1);
   trans=XtParseTranslationTable(":<Key>Return:Patt_change()");
   XtOverrideTranslations(patt_t->dialog.valueW,trans);
   /* Eingabe von Leerzeichen im Pattern ist verboten */
   XtAppAddActions(XtWidgetToApplicationContext(patt_t->dialog.valueW),
	  Dummy_call,1);
   trans=XtParseTranslationTable(":<Key>space:Dummy()");
   XtOverrideTranslations(patt_t->dialog.valueW,trans);

   /* Cancel Button */
   XtSetArg( args[0],XtNlabel, (XtArgVal) "        Cancel         ");
   XtSetArg( args[1],XtNvertDistance, (XtArgVal) (16*ABSTAND));
   XtSetArg( args[2],XtNfromVert, (XtArgVal) patt_t);
   XtSetArg( args[3],XtNhorizDistance, (XtArgVal) (2* ABSTAND));
   XtSetArg( args[4],XtNfromHoriz, (XtArgVal) fenster);
   cancel = XtCreateManagedWidget("F7",commandWidgetClass,box,args,5);
   XtAddCallback(cancel,XtNcallback,Cancel_geklickt,NULL);

   /* OK Button */
   XtSetArg( args[0],XtNlabel,(XtArgVal) "        Accept         ");
   XtSetArg( args[1],XtNvertDistance, (XtArgVal) ABSTAND);
   XtSetArg( args[2],XtNfromVert, (XtArgVal) cancel);
   XtSetArg( args[3],XtNhorizDistance, (XtArgVal) (2*ABSTAND));
   XtSetArg( args[4],XtNfromHoriz, (XtArgVal) fenster);
   ok = XtCreateManagedWidget("F8",commandWidgetClass,box,args,5);
   XtAddCallback(ok,XtNcallback,Ok_geklickt,NULL);

   return(file_s);
}


/*****************************************************************************/
/* Funktion zum Aufruf der Fileselectbox.   (s.o)                            */
/*                                                                           */
/* Aufruf: File_select(x,y,patt,titel);                                      */
/*****************************************************************************/
char *file_select(char *patt,char *titel)
{
   XtAppContext app_context;           /* Applikationskontext */
   XEvent event;                       /* Event */
   Arg args[2];                        /* Argumentvektor */
   char p_name[LAENGE2],               /* Path ion korrigierter Laenge */
	t_name[LAENGE2];               /* Titel in korrigierter Laenge */
   char *temp;                         /* Pointer zur Speicherfreigabe */

   if( strlen(patt) > LAENGE || 
      strlen(titel) == 0 || strlen(titel) > LAENGE2 )
      {

      printf("Die Argumente sind nicht korrekt !!! \n");
      return(NULL);
      }
   else 
      {

      Liste = (String *)NULL;
      Inhalt = (char *)NULL;

      /* uebergebenes Pattern in globale Variable uebernehmen */
      if(strlen(patt)!=0)
          strcpy(patt_global,patt);
      
      /* Titelzeile in Labelfeld uebernehmen */
      temp = center(titel,LAENGE2);  /* Ueberschrift zentrieren */
      strcpy(t_name,temp);
      free(temp);
      XtSetArg( args[0],XtNlabel,(XtArgVal) t_name);
      XtSetValues(titel_zeile,args,1);

      /* aktuellen Pfadnamen im Dialogwidget anzeigen */
      temp = malloc(LAENGE2+1);
      getcwd(temp,LAENGE2);
      sprintf(p_name,"%-51s",temp);                        
      free(temp);
      /* Dialogfeld zur Ausgabe des aktuellen Verzeichnisnamen  aendern  */
      /* ohne direkt in Pointer zu schreiben wird Wert nicht angezeigt */
      XtSetArg(args[0],XtNstring,p_name);
      XtSetValues(((DialogWidget)path)->dialog.valueW,args,1);

      /* Pattern in DialogWidget uebernehmen */
      /* ohne direkt in Pointer zu schreiben wird Wert nicht angezeigt */
      XtSetArg(args[0],XtNstring,patt_global);
      XtSetValues(((DialogWidget)patt_t)->dialog.valueW,args,1);
       
      /* aktuelles Directory eintragen */
      direct_to_list(); 

      /* Fileselectbox auf dem Bildschirm anzeigen */
      XtPopup(file_s,XtGrabExclusive);
       
      /* Events im Popup selbst verwalten */
      app_context = XtWidgetToApplicationContext(file_s);
      while(((ShellWidget)file_s)->shell.popped_up)
      {
	 XtAppNextEvent(app_context,&event);
	 XtDispatchEvent(&event);
      }

      } 

   /* String bereits in beim OK-Button kontrolliert */
   return(filename);
} 


/*******************************************************************
 * Center a popup in the middle of another widget if possible,     *
 * otherwise make shure that the popup is visible on the screen    *
 *******************************************************************/
void centerpopup(Widget centerin,Widget tocenter)
{
Display *CurDpy;
Position xin,yin,x,y;
Dimension win,hin,wto,hto;
Arg args[4];

CurDpy = XtDisplay(centerin);
XtRealizeWidget(tocenter);
XtSetArg(args[0],XtNwidth,&wto);
XtSetArg(args[1],XtNheight,&hto);
XtGetValues(tocenter,args,2);

XtSetArg(args[0],XtNwidth,&win);
XtSetArg(args[1],XtNheight,&hin);
XtGetValues(centerin,args,2);

XtTranslateCoords(centerin,0,0,&xin,&yin);

x = xin + win/2 - wto/2;
y = yin + hin/2 - hto/2;
if(x < 0)
    x = 0;
if(y < 0)
    y = 0;
if((x+wto) > DisplayWidth(CurDpy, DefaultScreen(CurDpy)))
    x = DisplayWidth(CurDpy, DefaultScreen(CurDpy)) - wto;
if((y+hto) > DisplayHeight(CurDpy, DefaultScreen(CurDpy)))
    y = DisplayHeight(CurDpy, DefaultScreen(CurDpy)) - hto;

XtSetArg(args[0],XtNx,x);
XtSetArg(args[1],XtNy,y);
XtSetValues(tocenter,args,2);
XWarpPointer(CurDpy,None,DefaultRootWindow(CurDpy),0,0,0,0,x+wto/2,y+hto/2);
}

