/*************************************************************************
 * File: $Source: /usr/usrs/xsource/xmfm/RCS/main.c,v $
 * Author: Jan Newmarch
 * Last modified: $Date: 1992/11/17 00:35:49 $
 * Version: $Revision: 1.7 $
 * Purpose: This file contains the main routine. It sets up the geometry
 *          and calls the Xt main loop.
 *
 * Revision history:
 *	16 Oct 92	caddr_t changed to XtPointer
 *       3 Nov 92       lint-ed
 *	21 Nov 92	added icon pixmap
 ************************************************************************/ 

#include "copyright.h"

/*************************************************************************
 * System includes
 ************************************************************************/ 
#include <stdio.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h>
#include <X11/Xproto.h>
#include <Xm/MainW.h> 
#include <Xm/MessageB.h> 

/*************************************************************************
 * Local includes
 ************************************************************************/ 
#include "const.h"
#include "types.h"
#include "xmfm_icon.h"

#ifdef RDD
#include "rdd.h"
#endif /* RDD */

#ifdef vax11c
#include "vms_cmd_services.h"
#endif /* vax11c */

/*************************************************************************
 * Functions exported
 ************************************************************************/ 
extern int main (
#ifdef UseFunctionPrototypes
	unsigned int argc, char **argv
#endif
);
extern void ErrorDialog (
#ifdef UseFunctionPrototypes
	char *str
#endif
);
extern int fatal (
#ifdef UseFunctionPrototypes
	char *s
#endif
);

/*************************************************************************
 * Variables exported
 ************************************************************************/ 
GC gc, gc_reversed;
file_action *actions;
XtAppContext app_context;
#ifdef RDD
XtTranslations trans_table;
#endif /* RDD */

/*************************************************************************
 * Extern variables
 ************************************************************************/ 
extern XmString empty_string;

/*************************************************************************
 * Extern functions
 ************************************************************************/ 
extern Widget	CreateMenu(
#ifdef UseFunctionPrototypes
	Widget parent, XtPointer user_data
#endif
);
extern Widget	CreateApplication (
#ifdef UseFunctionPrototypes
	Widget parent
#endif
);
extern file_action *LoadFileActions (
#ifdef UseFunctionPrototypes
	dir_pane_info *dpi
#endif
);
extern void SetFiltersInLabels (
#ifdef UseFunctionPrototypes
	dir_pane_info *dpi
#endif
);
extern void ResetFilesInPanes (
#ifdef UseFunctionPrototypes
	dir_pane_info *dpi
#endif
);
extern void child_died (
#ifdef UseFunctionPrototypes
	void
#endif
);

#ifdef MOTIF_DD
extern void InitMotifDD (
#ifdef UseFunctionPrototypes
	Widget app_shell, XtAppContext app_context
#endif
);
#endif

/*************************************************************************
 * Forward functions
 ************************************************************************/ 
int main (
#ifdef UseFunctionPrototypes
	unsigned int argc, char **argv
#endif
);			/*  main logic for application	*/ 

/*************************************************************************
 * Local variables
 ************************************************************************/ 
 
#define Class_name "XmFm" 
 
Widget	app_shell;	/*  ApplicationShell	*/ 

static XrmOptionDescRec myoptions[] =
	{
		{"-configFile", "configFile", XrmoptionSepArg, NULL}
	};

/*************************************************************************
 * Function: XErrorReporter()
 * Purpose: X Event Error handler
 * In parameters : Display *, XErrorEvent *
 * Out parameters:
 * Precondition: X Event error, that can be recovered
 * Postcondition: Application continues
 ************************************************************************/
int XErrorReporter
#ifdef UseFunctionPrototypes
	(Display *dpy, XErrorEvent *)
#else
	(dpy, event)
	Display *dpy;
	XErrorEvent *event;
#endif
{
	/*
	 *	Check to see if this is a CopyArea/ClearArea call.  For
	 *	now, lets just ignore them.
	 */
	if ((event->request_code == X_CopyArea ||
	     event->request_code == X_ClearArea) && 
	     event->error_code == BadValue) {
		return 1;	/* ignore */
	} else {
		char buffer[1024];

		XGetErrorText(dpy, event->error_code, buffer, 1024);
		fprintf(stderr, "%%XMFM-W-XERROR, %s\n", buffer);
		fprintf(stderr, "-XMFM-W-XERROR, Display: 0x%x, Serial: %d, ResourceID: 0x%x\n", 
				event->display, event->serial, event->resourceid);
	}
	return 1;
}

/*************************************************************************
 * Function: fatal()
 * Purpose: report a fatal error and giveup
 * In parameters: s
 * Out parameters:
 * Precondition; error of some kind occurred that cant be fixed
 * Postcondition: application stopped after message printed to stderr
 ************************************************************************/ 
int fatal
#ifdef UseFunctionPrototypes
	(char *s)
#else
	(s)
	char *s;

#endif
{
	fprintf (stderr, s);
	exit(1);
}

/*************************************************************************
 * Function: SetActionsInDirsToolbar ()
 * Purpose: Place the actions in the dirs toolbar, from .xmfmrc
 * In parameters: dpi
 * Out parameters:
 * Side effects: 
 * Precondition;
 * Postcondition: xmfm actions attached to each button in dirs toolbar
 *************************************************************************/
void
SetActionsInDirsToolbar 
#ifdef UseFunctionPrototypes
	(dir_pane_info *dpi)
#else
	(dpi)
	dir_pane_info *dpi;

#endif
{	file_action *pfa;
	action_pair *pap;
	int button;
	Widget tool_button;
	XmString xmstr;
	tool_button_info *tbi;

	/* find file pattern matching this name */
	pfa = actions;
	while (pfa != NULL)
		if (pfa -> file_type == PANE_TYPE &&
			RegExpMatch ("*", pfa -> fsm_ptr))
			break;
		else	pfa = pfa -> next;

	button = 0;
	/* set actions in toolbar */
	if (pfa != NULL)
	{
		pap = pfa -> actions;
		while (button < DIRS_TOOLBAR_SIZE && pap != NULL)
		{
			tool_button = (dpi -> dirs_toolbar) [button];

			/* set the action label in the button */
			xmstr = XmStringCreateLtoR (pap -> action_label,
                                          XmSTRING_DEFAULT_CHARSET);
			XtVaSetValues (tool_button,
					XmNlabelString, (XtArgVal) xmstr,
					NULL);
			XmStringFree (xmstr);

			/* set the action in the buttons user data */
			XtVaGetValues (tool_button,
					XmNuserData, (XtArgVal) &tbi,
					NULL);
			tbi -> action = pap -> action;
			tbi -> run_in_xterm = pap -> run_in_xterm;
			tbi -> pause_after_exec = pap -> pause_after_exec;
			tbi -> prompt = pap -> prompt;
			tbi -> has_prompt = pap -> has_prompt;

			XtSetSensitive (tool_button, True);
			button++;
			pap = pap -> next;
		}
	}
	/* empty out the remaining buttons */
	for ( ; button < DIRS_TOOLBAR_SIZE; button++)
	{
		tool_button = (dpi -> dirs_toolbar) [button];
		/* break out as soon as we hit an already insensitive button */
/*
		if (XtIsSensitive (tool_button) == False)
			break;
*/
		XtVaSetValues (tool_button,
				XmNlabelString, (XtArgVal) empty_string,
				NULL);
		XtSetSensitive (tool_button, False);
	}
}

/*************************************************************************
 * Function: create_gcs ()
 * Purpose: set up global gcs with opposite fg/bg
 * In parameters: w
 * Out parameters:
 * Side effects: alters global gc and gc_reversed
 * Precondition;
 * Postcondition:
 ************************************************************************/ 
static void
create_gcs 
#ifdef UseFunctionPrototypes
	(Widget w)
#else
	(w)
	Widget w;

#endif
{
	/* uses black and white.
	   should pick up fg and bg from button resources? */
	gc = XCreateGC (XtDisplay (w),
			XtWindow (w),
			(unsigned long) 0, NULL);
	XSetBackground (XtDisplay (w),
			gc,
			WhitePixelOfScreen (XtScreen (w)));
	XSetForeground (XtDisplay (w),
			gc,
			BlackPixelOfScreen (XtScreen (w)));

	gc_reversed = XCreateGC (XtDisplay (w),
			XtWindow (w),
			(unsigned long) 0, NULL);
	XSetBackground (XtDisplay (w),
			gc_reversed,
			BlackPixelOfScreen (XtScreen (w)));
	XSetForeground (XtDisplay (w),
			gc_reversed,
			WhitePixelOfScreen (XtScreen (w)));
}

#ifdef RDD
/*************************************************************************
 * Function: myDropAction ()
 * Purpose: what to do when a drop takes place
 * In parameters: w, event, args, nargs
 * Out parameters:
 * Precondition: 
 * Postcondition: drop data (file name) placed in RDD cut buffer
 ************************************************************************/ 
/* ARGSUSED */
void myDropAction 
#ifdef UseFunctionPrototypes
	(Widget w, XEvent *event, String *args, Cardinal *nargs)
#else
	(w, event, args, nargs)
	Widget w;
	XEvent *event;
	String *args;
	Cardinal *nargs;

#endif
{	pane_button_info *pbi;
	char full_file_name[MAXPATHLEN];

	XtVaGetValues (w,
			XmNuserData, &pbi, NULL);
	strcpy (full_file_name,
		DirectoryPath (DirectoryMgrDir (pbi -> dpi -> directory_manager)));
	strcat (full_file_name, pbi -> name);

	rddSetDropData (full_file_name,
			strlen(full_file_name) + 1);	/* copy data to rdd,
							  including null byte */
	rddDropAction (w, (XButtonEvent *) event, args, nargs);		/* then use default action */
}
#endif /* RDD */


/*************************************************************************
 * Function: main.c
 * Purpose: run the application
 * In parameters: argc, argv
 * Out parameters:
 * Precondition: true
 * Postcondition: application has completed
 ************************************************************************/ 
int
main 
#ifdef UseFunctionPrototypes
	(unsigned int argc, char **argv)
#else
	(argc,argv)  
	unsigned int	argc; 
	char 		**argv; 

#endif
{ 	
	Widget		applic_widget;
	dir_pane_info *dpi;
	Pixmap		icon_pixmap; 
#ifdef vax11c
	int		status;
#endif /* vax11c */

#ifdef RDD
/*
 * RDD
 * The normal translations for a button, plus those needed to do a 
 * drag-n-drop procedure.
 */
	String myTranslations =
		"#override\n\
		<Btn1Down>:	Arm() rddStartAction()\n\
		<Btn1Up>:	Activate() Disarm() myDropAction()\n\
		<Btn1Motion>:	rddDragAction()\n";
#endif /* RDD */



 
	/*	Initialize toolkit and open the display. 
		Use XtInitialize and XtWidgetToAppContext cos
		I can't get XtAppCreateShell to work
		in builtin_opendir()
	*/ 
	 app_shell = XtInitialize(
			 NULL, 		/* application name */	
	 	 	 Class_name, 	/* class name */	
	 	 	 myoptions, 		/* options */	
	 	 	 XtNumber (myoptions),	/* number of options */	
	 	 	 &argc, argv);
	app_context = XtWidgetToApplicationContext (app_shell);

	/* set the icon pixmap */
	icon_pixmap = XCreateBitmapFromData(XtDisplay(app_shell),
			RootWindowOfScreen(XtScreen(app_shell)),
			xmfm_bits, xmfm_width, xmfm_height);
	XtVaSetValues(app_shell, XmNiconPixmap, icon_pixmap, NULL);
	  
#	ifdef DEBUG_MAIN
		fprintf(stderr, "Initialised toolkit\n");
#	endif
 
#ifdef RDD
	/* RDD add action myAction */
	{
		XtActionsRec actions;
		actions.string	= "myDropAction";
		actions.proc	= myDropAction;
		XtAppAddActions (app_context, &actions, 1);
	}

	/* RDD  initialize the rdd package */
	rddInit (app_shell, app_context);

	/* RDD parse translations table */
	trans_table = XtParseTranslationTable (myTranslations);
#endif /* RDD */

#ifdef MOTIF_DD
        InitMotifDD (app_shell, app_context);
#endif /* MOTIF_DD */

	applic_widget = CreateApplication (app_shell);
	XtManageChild (applic_widget);

#	ifdef DEBUG_MAIN
		fprintf(stderr, "Created application\n");
#	endif

	/*	Create and realize main application window. 
	*/ 
	XtRealizeWidget (app_shell); 

#	ifdef DEBUG_MAIN
		fprintf(stderr, "Realised windows\n");
#	endif

	create_gcs (app_shell);


	/* set files in panes */
	XtVaGetValues (applic_widget,
			XmNuserData, (XtArgVal) &dpi,
			NULL);

	actions = LoadFileActions (dpi);

	ResetFilesInPanes (dpi);

	SetActionsInDirsToolbar (dpi);

        SetFiltersInLabels (dpi);

#ifdef vax11c
	/*
	 *	establish the proper context to run commands
	 */
	if (!((status = initRun("XMFM"))&1)) lib$stop(status);
#else
	/* set up a signal handler for children dying
	   typically actions performed on files that may
	   change directories
	*/
	signal (SIGCHLD, child_died);
#endif /* vax11c */

	/*	Get and dispatch events. 
	*/ 
#	ifdef DEBUG_MAIN
		fprintf(stderr, "Main looping...\n");
#	endif

	XSetErrorHandler(XErrorReporter);

#ifdef RDD
	rddAppMainLoop (app_context);
#else
	XtAppMainLoop (app_context); 
#endif /* RDD */
} 
 

/*************************************************************************
 * Function: DestroyDialogCB ()
 * Purpose: destroy a dialog
 * In parameters: w, c1, c2
 * Out parameters:
 * Precondition: w is a child of a popup shell
 * Postcondition: parent on down all destroyed
 ************************************************************************/ 
/* ARGSUSED */
void
DestroyDialogCB
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer c1, XtPointer c2)
#else
	(w, c1, c2)
	Widget w;
	XtPointer c1, c2;

#endif
{
	XtUnmanageChild(w);
	XtDestroyWidget(XtParent(w));
}

/*-------------------------------------------------------------
**	Show Error Message Dialog when a system error has occurred
*/

/*************************************************************************
 * Function: ErrorDialog ()
 * Purpose: show an error dialog
 * In parameters: str
 * Out parameters:
 * Precondition: an error of some kind has occurred
 * Postcondition: user has registered error
 ************************************************************************/ 
void ErrorDialog
#ifdef UseFunctionPrototypes
	(char *str)
#else
	(str)
char * str;

#endif
{	int n;
	Arg	args[MAX_ARGS];
	Widget cancel, help, dialog;
	XmString xmstr;

	n = 0;
	xmstr = XmStringCreateSimple (str);
	XtSetArg (args[n], XmNmessageString, xmstr); n++;
	dialog = XmCreateErrorDialog(app_shell, "", args, n);
	XmStringFree(xmstr);
	XtAddCallback(dialog, XmNokCallback, DestroyDialogCB, NULL);

	help = XmMessageBoxGetChild(dialog, 
			XmDIALOG_HELP_BUTTON);
	XtUnmanageChild(help);

	cancel = XmMessageBoxGetChild(dialog, 
			XmDIALOG_CANCEL_BUTTON);
	XtUnmanageChild(cancel);

	XtManageChild(dialog);
}
