/*
 *   xmcd - Motif(tm) CD Audio Player
 *
 *   Copyright (C) 1993-2001  Ti Kan
 *   E-mail: xmcd@amb.org
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program 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 General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */
#ifndef LINT
static char *_main_c_ident_ = "@(#)main.c	7.8 01/06/10";
#endif

#include "common_d/appenv.h"
#include "common_d/util.h"
#include "xmcd_d/xmcd.h"
#include "xmcd_d/resource.h"
#include "xmcd_d/widget.h"
#include "xmcd_d/callback.h"
#include "xmcd_d/cdfunc.h"
#include "xmcd_d/command.h"
#include "libdi_d/libdi.h"


#define STARTUP_CMD_DELAY	1500	/* Delay interval before running
					 * startup command
					 */

/* Global data */
char			*progname,	/* The path name we are invoked with */
			*cdisplay;	/* Command-line specified display */
appdata_t		app_data;	/* Options data */
widgets_t		widgets;	/* Holder of all widgets */
pixmaps_t		pixmaps;	/* Holder of all pixmaps */
FILE			*errfp;		/* Error message stream */

/* Data global to this module only */
STATIC curstat_t	status;		/* Current CD player status */
STATIC XtAppContext	app_context;	/* Application context */
STATIC Colormap		localcmap;	/* local colormap */
STATIC char		*cmd;		/* Command string */


/***********************
 *   public routines   *
 ***********************/

/*
 * curstat_addr
 *	Return the address of the curstat_t structure.
 *
 * Args:
 *	Nothing.
 *
 * Return:
 *	Nothing.
 */
curstat_t *
curstat_addr(void)
{
	return (&status);
}


/*
 * event_loop
 *	Used to handle X events while waiting on I/O.
 *
 * Args:
 *	flag - Currently unused
 *
 * Return:
 *	Nothing.
 */
/* ARGSUSED */
void
event_loop(int flag)
{
	while (XtAppPending(app_context))
		XtAppProcessEvent(app_context, XtIMAll);
}


/*
 * shutdown_gui
 *	Perform window system shutdown cleanup.
 *
 * Args:
 *	None.
 *
 * Return:
 *	Nothing.
 */
void
shutdown_gui(void)
{
	if (app_data.instcmap)
		XFreeColormap(XtDisplay(widgets.toplevel), localcmap);
}


/***********************
 *  internal routines  *
 ***********************/


/*
 * usage
 *	Display command line usage syntax
 *
 * Args:
 *	arg - The command line arg string that is invalid
 *
 * Return:
 *	Nothing.
 */
STATIC void
usage(char *arg)
{
	if (strcmp(arg, "-help") != 0) {
		(void) fprintf(errfp, "%s: %s\n\n",
			app_data.str_badopts, arg);
	}

	(void) fprintf(errfp, "Usage: %s %s %s %s\n            %s %s %s",
		PROGNAME,
		"[-dev device]",
		"[-instcmap]",
		"[-remote]",
		"[-rmthost hostname]",
		"[-debug level#]",
		"[-help]");

#if defined(SVR4) && defined(sun)
	/* Solaris 2 volume manager auto-start support */
	(void) fprintf(errfp, "\n            [-c device] [-X] [-o]");
#endif

 	(void) fprintf(errfp, "\n            [command [arg ...]]\n\n");

	/* Display command usage */
	cmd_usage();

 	(void) fprintf(errfp,
	    "\nStandard Xt Intrinsics toolkit options are also supported.\n");
}


/*
 * main
 *	The main function
 */
int
main(int argc, char **argv)
{
	int	i;
	Display	*display;
#ifdef HAS_SETEUID
	uid_t	euid,
		ruid;
	gid_t	egid,
		rgid;
#endif

	/* Error message stream */
	errfp = stderr;

	/* Initialize variables */
	progname = argv[0];

	/* Handle some signals */
	if (signal(SIGINT, onsig) == SIG_IGN)
		(void) signal(SIGINT, SIG_IGN);
	if (signal(SIGHUP, onsig) == SIG_IGN)
		(void) signal(SIGHUP, SIG_IGN);
	if (signal(SIGTERM, onsig) == SIG_IGN)
		(void) signal(SIGTERM, SIG_IGN);
	if (signal(SIGQUIT, onsig) == SIG_IGN)
		(void) signal(SIGQUIT, SIG_IGN);

	/* Set SIGCHLD handler to default */
#ifndef __VMS_VER
	(void) signal(SIGCHLD, SIG_DFL);
#else
#if (__VMS_VER >= 70000000) && (__DECC_VER > 50230003)
	/* OpenVMS v7.0 and DECCV5.2 have these defined */
	(void) signal(SIGCHLD, SIG_DFL);
#endif
#endif

	/* Ignore SIGALRMs until we need them */
	(void) signal(SIGALRM, SIG_IGN);

	/* Hack: Aside from stdin, stdout, stderr, there shouldn't
	 * be any other files open, so force-close them.  This is
	 * necessary in case xmcd was inheriting any open file
	 * descriptors from a parent process which is for the
	 * CD-ROM device, and violating exclusive-open requirements
	 * on some platforms.
	 */
	for (i = 3; i < 10; i++)
		(void) close(i);

#if (XtSpecificationRelease >= 5)
	/* Set locale */
	XtSetLanguageProc(NULL, NULL, NULL);
#endif

	/* Snoop command line for -display before XtVaAppInitialize
	 * consumes it  Also, handle -help here before we attempt
	 * to open the X display.
	 */
	for (i = 0; i < argc; i++) {
		if (strcmp(argv[i], "-display") == 0)
			cdisplay = argv[++i];
		else if (strcmp(argv[i], "-help") == 0) {
			usage(argv[i]);
			exit(1);
		}
	}

#ifdef HAS_SETEUID
	/* Get real IDs */
	ruid = getuid();
	rgid = getgid();

	/* Save effective IDs */
	euid = geteuid();
	egid = getegid();

	/* Give up root until we have a connection to the X server, so
	 * that X authentication will work correctly.
	 */
	(void) seteuid(ruid);
	(void) setegid(rgid);
#endif

	/* Initialize X toolkit */
	widgets.toplevel = XtVaAppInitialize(
		&app_context,
		"XMcd",
		options, XtNumber(options),
		&argc, argv,
		NULL,
		XmNmappedWhenManaged, False,
		NULL
	);

	/* Get application options */
	XtVaGetApplicationResources(
		widgets.toplevel,
		(XtPointer) &app_data,
		resources,
		XtNumber(resources),
		NULL
	);
		
	/* Build command */
	if (argc > 1) {
		for (i = 1;  i < argc; i++) {
			if (argv[i][0] == '-') {
				usage(argv[i]);
				exit(1);
			}

			if (i == 1) {
				cmd = (char *) MEM_ALLOC(
					"cmd",
					strlen(argv[i]) + 1
				);
				if (cmd == NULL) {
					CD_FATAL(app_data.str_nomemory);
					exit(1);
				}
				cmd[0] = '\0';
			}
			else {
				cmd = (char *) MEM_REALLOC(
					"cmd",
					cmd,
					strlen(cmd) + strlen(argv[i]) + 2
				);
				if (cmd == NULL) {
					CD_FATAL(app_data.str_nomemory);
					exit(1);
				}
				(void) strcat(cmd, " ");
			}
			(void) strcat(cmd, argv[i]);
		}
	}

	display = XtDisplay(widgets.toplevel);

	/* Initialize libutil */
	util_init();

	if (app_data.remotemode) {
		/* Remote control specified */
		cmd_init(&status, display, TRUE);
		exit(cmd_sendrmt(display, cmd));
	}

	/* Install colormap if specified */
	if (app_data.instcmap) {
		localcmap = XCopyColormapAndFree(
			display,
			DefaultColormap(display, DefaultScreen(display))
		);
		XtVaSetValues(widgets.toplevel, XmNcolormap, localcmap, NULL);
	}

	/* Create all widgets */
	create_widgets(&widgets);

	/* Configure resources before realizing widgets */
	pre_realize_config(&widgets);

	/* Display widgets */
	XtRealizeWidget(widgets.toplevel);

	/* Configure resources after realizing widgets */
	post_realize_config(&widgets, &pixmaps);

	/* Register callback routines */
	register_callbacks(&widgets, &status);

#ifdef HAS_SETEUID
	/* Ok, back to root */
	(void) seteuid(euid);
	(void) setegid(egid);
#endif

	XtMapWidget(widgets.toplevel);

	/* Initialize various subsystems */
	cd_init(&status);

	/* Start various subsystems */
	cd_start(&status);

	/* Start remote control */
	cmd_init(&status, display, FALSE);

	if (cmd != NULL) {
		/* Change to watch cursor */
		cd_busycurs(TRUE, CURS_ALL);

		/* Schedule to perform start-up command */
		(void) cd_timeout( 
			STARTUP_CMD_DELAY,
			cmd_startup,
			(byte_t *) cmd
		);
	}

	/* Main event processing loop */
	XtAppMainLoop(app_context);

	shutdown_gui();
	exit(0);

	/*NOTREACHED*/
}

