/****************************************************************************
 * File: refresh.c
 * Author: Jan Newmarch
 * Last modified: $Date: 1992/11/17 00:35:55 $
 * Version: $Revision: 1.2 $
 * Purpose: this file contains routines that look out for a child dying.
 *	This presumably is a function called by executing an action on
 *	a file, and this may have modified the directory contents. The
 *	stuff here catches SIGCHLD events.
 * Revision history:
 ***************************************************************************/

#include "copyright.h"

/***************************************************************************
 * System includes
 ***************************************************************************/
#ifdef vax11c
#include <processes.h>
#else
#include <sys/wait.h>
#endif /* vax11c */
#include <sys/types.h>
#include <signal.h>
#include <sys/stat.h>
#include <stdio.h>

/***************************************************************************
 * Local includes
 ***************************************************************************/
#include "types.h"
#include "DirMgr.h"

/***************************************************************************
 * Extern variables
 ***************************************************************************/

/***************************************************************************
 * Extern functions 
 ***************************************************************************/
extern void ResetPanesAndSelectFile (
#ifdef UseFunctionPrototypes
	dir_pane_info *dpi, char *file_name
#endif
);

/***************************************************************************
 * Functions exported 
 ***************************************************************************/
void child_died (
#ifdef UseFunctionPrototypes
	void
#endif
);
void add_pid (
#ifdef UseFunctionPrototypes
	pid_t pid, dir_pane_info *dpi
#endif
);

/***************************************************************************
 * Variables exported 
 ***************************************************************************/

/***************************************************************************
 * Forward functions
 ***************************************************************************/
#ifdef vax11c
void refresh_dir (
#ifdef UseFunctionPrototypes
	XtPointer client_data, XtIntervalId *id
#endif
);
#else
static void refresh_dir (
#ifdef UseFunctionPrototypes
	XtPointer client_data, XtIntervalId *id
#endif
);
#endif /* vax11c */

/***************************************************************************
 * Local variables 
 ***************************************************************************/
typedef struct pid_list_elmt
{
	pid_t pid;
	dir_pane_info *dpi;
	struct pid_list_elmt *next;
}
	pid_pair, *pid_list_t;

static pid_list_t pid_list = NULL;

/***************************************************************************
 * Function: child_died
 * Purpose: catch a SIGCHLD signal, and set a work-proc if needed
 * In parameters:
 * Out parameters:
 * Precondition:
 * Postcondition: work proc set if directory contents have changed
 ***************************************************************************/
void
child_died 
#ifdef UseFunctionPrototypes
	(void)
#else
	()

#endif
{	int status;
	pid_t pid;
	pid_list_t p = pid_list,
		   trail = pid_list;
	DirectoryMgr *dm;
	DirEntry *de;
	time_t prev_modified, last_modified;
	struct stat stat_buf;

#ifdef DEBUG_SIGNAL
	fprintf (stderr, "SIGCHLD caught\n");
#endif
	if ((pid = wait (&status)) == -1)
		return;
/*
 *	Comment out during the compile.  This code path
 *	will never be taken under OpenVMS.
 */
#ifndef vax11c
	signal (SIGCHLD, SIG_IGN);
#endif /* vax11c */
	while (p != NULL)
	{
		if (p -> pid == pid)
		{	/* does the dir need updating?
			   first find the info in dpi
			 */
			dm = p -> dpi -> directory_manager;
			DirectoryMgrGotoNamedItem (dm, ".");
			de = DirectoryMgrCurrentEntry (dm);
			prev_modified = DirEntryLastModify (de);

			/* now find current info */
			if (stat (DirectoryPath (DirectoryMgrDir (dm)),
						&stat_buf) == -1)
				return;	/* error - e.g. dir has vanished */
			last_modified = stat_buf.st_mtime;
#ifdef DEBUG_SIGNAL
			fprintf (stderr, "directory previously modified %ld\n\
last modified %ld\n", 
					prev_modified, last_modified);
#endif

			/* add timeout to update if dir has changed */
			if (last_modified > prev_modified)
				XtAddTimeOut (0, refresh_dir, p -> dpi);
			else
/*
 *	Comment out during the compile.  This code path
 *	will never be taken under OpenVMS.
 */
#ifndef vax11c
				signal (SIGCHLD, child_died);
#endif /* !vax11c */

			/* remove this element anyway */
			if (trail == p)		/* start of list */
				pid_list = p -> next;
			else			/* later in list */
				trail -> next = p -> next;
			XtFree ((char *) p);

			return;
		}
		trail = p;
		p = p -> next;

	}
/*
 *	The following compile conditionals are to allow this module
 *	to be compiled under OpenVMS.  This routine will never get
 *	called since we will never fork to launch applications.
 */
#ifndef vax11c
	signal (SIGCHLD, child_died );
#endif /* !vax11c */
}


/***************************************************************************
 * Function: add_pid
 * Purpose: add a pid/dpi pair to the pid list
 * In parameters: pid,dpi
 * Out parameters:
 * Precondition:
 * Postcondition: pid added to list of undead children
 ***************************************************************************/
void
add_pid 
#ifdef UseFunctionPrototypes
	(pid_t pid, dir_pane_info *dpi)
#else
	(pid, dpi)
	pid_t pid;
	dir_pane_info *dpi;

#endif
{
	pid_list_t p;

	p = (pid_list_t) XtMalloc (sizeof (struct pid_list_elmt));
	p -> pid = pid;
	p -> dpi = dpi;
	p -> next = pid_list;
	pid_list = p;
}


/***************************************************************************
 * Function: refresh_dir
 * Purpose: refresh directory contents
 * In parameters: dpi
 * Out parameters:
 * Precondition:
 * Postcondition: new directory contents showing, focus on slected file
 ***************************************************************************/
/* ARGSUSED */
#ifdef vax11c
void
#else
static void
#endif /* vax11c */
refresh_dir 
#ifdef UseFunctionPrototypes
	(XtPointer client_data, XtIntervalId *id)
#else
	(client_data, id)
	XtPointer client_data;
	XtIntervalId *id;

#endif
{
	dir_pane_info *dpi = (dir_pane_info *) client_data;

#ifdef DEBUG_SIGNAL
	fprintf (stderr, "Timeout called, refreshing dir\n");
#endif
	ResetPanesAndSelectFile (dpi, dpi -> file_selected);
#ifndef vax11c
	signal (SIGCHLD, child_died);
#endif /* !vax11c */
}
