/*-
 * Copyright (c) 2001 Jordan DeLong
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include "wm.h"

/* general globals */
Display		*display;		/* our display connection */
Cursor		cursor_default;		/* default cursor (for root window) */
Cursor		cursor_move;		/* cursor used when moving windows */
Cursor		cursor_place;		/* cursor for interactive placement */
XContext	client_context;		/* window context with client_t * */
XContext	root_context;		/* context for root windows storing screen_t * */
XContext	decor_context;		/* context with a decor_t * for decor windows */
XContext	plugin_context;		/* used for override_redirect windows created by plugins */
int		shape_base;		/* event base for shape extension (0 == no shape ext) */

char		*binary_name;		/* the bin golem was launched as (for restarts, etc) */
char		*homedir_path;		/* path to the user's home directory */

volatile int	restart_flag = 0;	/* flag when set means golem needs to restart */
volatile char	*restart_bin = NULL;	/* what to restart when golem_restart = 1, or null */

/* X atoms and their names */
Atom atoms[NUM_ATOMS];
char *atom_names[NUM_ATOMS] = {
	"WM_PROTOCOLS",
	"WM_DELETE_WINDOW",
	"WM_CHANGE_STATE",
	"WM_STATE"
};

/*
 * crash recovery; for segmentation violations we dump a
 * core and restart.
 */
static RETSIGTYPE handle_sigsegv(int no) {
	warnx("segmentation fault; dumping a corefile and restarting");
	if (!fork())
		abort();
	execlp(binary_name, binary_name, NULL);
	exit(EXIT_FAILURE);
}

/* handle exiting children */
static RETSIGTYPE handle_sigchld(int no) {
	pid_t pid;
	int status;

	/* wait on all the pids that need to exit */
	while (((pid = waitpid(-1, &status, WNOHANG)) > 0)
		|| (pid < 0 && errno == EINTR));
}

/* allow SIGUSR1 to restart the windowmanager */
static RETSIGTYPE handle_sigusr1(int no) {
	restart_flag = 1;
	restart_bin = binary_name;
}

/* setup signals, open display, parse the rcfile, and then go to our loop */
int main(int argc, char **argv) {

	/* if -v we just print version and exit */
	if (argc > 1 && strcmp(argv[1], "-v") == 0) {
		printf("golem-" VERSION "\n"
			BUILD_INFO "\n"
			"Copyright (c) 2001 Jordan DeLong\n");
		exit(0);
	}

#ifdef I18N
	setlocale(LC_CTYPE,"");
#endif
	binary_name = argv[0];
	homedir_path = getenv("HOME");

	signal(SIGCHLD, handle_sigchld);
	signal(SIGUSR1, handle_sigusr1);

	/* try to get a connection to the X server */
	display = XOpenDisplay(NULL);
	if (display == NULL)
		errx(1, "unable to open display");

	/* call startup routines */
	warnx("initializing");
	options_init();
	plugin_init();
	rcfile_parse();
	screen_init();
	image_init();
	xinerama_init();
	plugin_start();
	screen_manage_existing();
	options_clean();

	/*
	 * don't reg this 'till now, so we won't get in an infinite loop
	 * during startup.
	 */
	signal(SIGSEGV, handle_sigsegv);

	/*
	 * call the main event loop; the loop runs processing on incoming
	 * X events until something sets restart_flag.  whatever set
	 * restart_flag may also set restart_bin, which we handle after
	 * calling shutdown routines.
	 */
	event_loop();

	/* call shutdown routines */
	warnx("shutting down");
	desktop_shutdown();
	plugin_shutdown();
	client_shutdown();
	keys_shutdown();
	decor_shutdown();
	dgroup_shutdown();
	pixmap_shutdown();
	screen_shutdown();
	xinerama_shutdown();
	warnx("finished");

	/*
	 * if restart_bin isn't set, we simply exit.  otherwise we need to
	 * execve the appropriate binary in our place.
	 */
	if (restart_bin == binary_name)
		execlp(binary_name, binary_name, NULL);
	else if (restart_bin != NULL)
		execl(_PATH_BSHELL, "sh", "-c", restart_bin, NULL);

	return 0;
}
