#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <glib.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include "eggtrayicon.h"
//intl stuff
#include<libintl.h>
#include<locale.h>
#define _(String) gettext (String)
#define gettext_noop(String) String
#define N_(String) gettext_noop (String)

//better error handling
#define manager_error(String) g_critical("%s: %s", String, g_strerror(errno))

/* enums for the Beryl options */
typedef enum
{
	AutoBinding,
	StrictBinding,
	XGLBinding
} BindingMode;

typedef enum
{
	AutoCOW,
	UseCOW,
	NoCOW
} COWMode;

typedef enum
{
	AutoRendering,
	IndirectRendering,
	XGLRendering
} RenderingMode;

typedef enum
{
	AutoPlatform,
	NvidiaPlatform,
	AIGLXPlatform,
	XGLPlatform
} PlatformMode;

typedef enum
{
	AutoRenderPath,
	TFPRenderPath,
	CopyRenderPath
} RenderPathMode;

Atom wmAtom;
Atom PopupRunning;
GMutex *mutx;
EggTrayIcon *mainIcon;
GtkWidget *menu;
GtkTooltips *tips;

/* options for Beryl command line */
RenderPathMode renderPath = AutoRenderPath;
PlatformMode platformMode = AutoPlatform;
RenderingMode renderingMode = AutoRendering;
COWMode cowMode = AutoCOW;
BindingMode bindingMode = AutoBinding;

gboolean noGLYield = FALSE;

gboolean hasMouse = FALSE;
gboolean berylLaunched = FALSE;
gboolean decoratorLaunched = FALSE;
gboolean reloadingBeryl = FALSE;
gboolean reloadingDecorator = FALSE;
gboolean XGL = FALSE;
gboolean NV9XXX = FALSE;
gboolean useFB = TRUE;
gint WM = 0;
gint fallBackWM = 0;
gint DM = 0;
gint iconsize = 24;
gchar *displayname;
typedef struct _DMInfo
{
	gchar *Name;
	gchar *Prog;
	GtkWidget *Item;
} DMInfo;
typedef struct _WMInfo
{
	gchar *Name;
	gchar *Prog;
	gchar *Opts;
	gchar *Grep;
	gint xXGL;					// if nonzero, can't use on XGL
	gint Kill;					// if nonzero, means has to be killall'd by its grep-name, and should NOT be xkill'd
	GtkWidget *Item;
	GtkWidget *FBItem;
} WMInfo;
typedef struct _XLSItem
{
	gchar *Command;
	Window w;
} XLSItem;
DMInfo DMs[] = {
	{N_("Standard Beryl Decorator (Emerald)"), "emerald", 0},
	{N_("Aquamarine (KDE Decorator)"), "aquamarine", 0},
	{N_("Heliodor (GNOME/Metacity Decorator)"), "heliodor", 0},
	{N_("Light Themable Decorator (yawd)"), "yawd", 0},
	{N_("GTK Window Decorator"), "gtk-window-decorator", 0},
	{N_("KDE Window Decorator"), "kde-window-decorator", 0},
};

#define numDM (gint)(sizeof(DMs)/sizeof(DMInfo))
WMInfo WMs[] = {
	{N_("Beryl"), 0, 0, 0, 0, 0, 0, 0},
	{N_("Compiz"), "compiz", "--replace gconf", "compiz", 0, 0, 0, 0},
	{N_("Metacity (Gnome Window Manager)"), "metacity", "--replace",
	 "metacity", 0, 0, 0, 0},
	{N_("KWin (KDE Window Manager)"), "kwin", "--replace", "kwin", 0, 0, 0,
	 0},
	{N_("xfwm4 (XFCE Window Manager)"), "xfwm4", "", "xfwm4", 0, 1, 0, 0},
	{N_("WindowMaker"), "wmaker", "", "WindowMaker", 0, 0, 0, 0},
	{N_("FluxBox"), "fluxbox", "", "fluxbox", 1, 1, 0, 0},
	{N_("BlackBox"), "blackbox", "", "blackbox", 0, 1, 0, 0},
	{N_("OpenBox"), "openbox", "", "openbox", 0, 0, 0, 0},
	{N_("IceWM"), "icewm", "", "icewm", 0, 0, 0, 0},
	{N_("Enlightenment"), "enlightenment", "", "enlightenment", 0, 1, 0, 0},
};

#define numWM (gint)(sizeof(WMs)/sizeof(WMInfo))
#define FALLBACKWM_OFFSET 2

GtkWidget *useFBItem;
GtkWidget *FBSubItem;
GtkWidget *DMSubItem;
GtkWidget *reloadDecoratorItem;

void launchWM();
void startWM();
void init_widgets();
void startBeryl();
void showMenu(guint, guint32);
static Window Window_With_Name(Display * dpy, Window top, char *name);


static void usage(const char *programName)
{
	printf(_("Usage: %s "
			 "[-d] [--no-force-window-manager] [--no-force-decorator] "
			 "[--help] [--version]" "\n"), programName);
}

void startApp(GtkWidget * w, gchar * command)
{
	g_spawn_command_line_async(command, NULL);
}

static void signalHandler(int sig)
{
	static int suspending = 0;

	switch (sig)
	{
	case SIGUSR1:
		//FIXME, here we should temporarily disable/hide the last "Quit" entry,
		//Could be missleading to the average user...
		showMenu(0, gtk_get_current_event_time());
		break;
	case SIGUSR2:
		if (!suspending)
		{
			if (!WM)
			{
				WM = fallBackWM + FALLBACKWM_OFFSET;
				startWM();
				suspending = 1;
			}
		}
		else
		{
			WM = 0;
			reloadingBeryl = TRUE;
			startBeryl();
			suspending = 0;
		}
		break;
	default:
		break;
	}
}

gchar *display_part(const gchar * p)
{
	gchar *name = g_strdup(p);
	gchar *tmp;

	if ((tmp = g_strrstr(name, ":")))
	{
		*tmp++ = 0;
		tmp = g_strdup(tmp);
		g_free(name);
		name = tmp;
	}

	if ((tmp = g_strrstr(name, ".")))
	{
		*tmp = 0;
	}

	return name;
}


void beryl_manager_log_handler(const gchar * log_domain,
							   GLogLevelFlags log_level,
							   const gchar * message, gpointer user_data)
{
	g_log_default_handler(log_domain, log_level, message, user_data);

	if (log_level <= G_LOG_LEVEL_WARNING)
		return;

	if (isatty(0))
		g_on_error_query(NULL);
	else
		abort();
}


GSList *parse_xlsclients(gchar * output)
{
	GSList *ret = NULL;
	gchar *curpos;

	for (curpos = output; curpos && curpos[0];
		 curpos = strstr(curpos, "\nWindow"))
	{
		XLSItem *i;
		gchar *p;
		gchar *q;

		curpos += 8;
		i = malloc(sizeof(XLSItem));
		i->w = strtol(curpos, NULL, 16);
		p = strstr(curpos, "Command:  ");
		if (!p)
		{
			g_warning(_("Malformed xlsclients, no command?"));
			free(i);
			continue;
		}
		q = strchr(p, '\n');
		if (!q)
		{
			g_warning(_("Malformed xlsclients, no command?"));
			free(i);
			continue;
		}
		q[0] = '\0';
		p = g_strdup(p + 10);
		q[0] = '\n';
		//trim p down to its basename
		q = strchr(p, ' ');
		if (q)
			q[0] = '\0';
		q = strrchr(p, '/');
		if (!q)
			q = p;
		else
			q++;
		i->Command = g_strdup(q);
		g_free(p);
		ret = g_slist_prepend(ret, i);
	}
	return ret;
}

void load_settings()
{
	gchar *path = g_strconcat(g_get_home_dir(), "/.beryl-managerrc", NULL);
	GKeyFile *f = g_key_file_new();

	if (g_key_file_load_from_file(f, path, 0, NULL))
	{
		GError *e = NULL;
		gint i;
		gboolean b;

		i = g_key_file_get_integer(f, "wm-settings", "active_wm", &e);
		if (!e)
			WM = i;
		e = NULL;
		i = g_key_file_get_integer(f, "wm-settings", "fallback_wm", &e);
		if (!e)
			fallBackWM = i;
		e = NULL;
		i = g_key_file_get_integer(f, "wm-settings", "active_dm", &e);
		if (!e)
			DM = i;
		e = NULL;
		b = g_key_file_get_boolean(f, "wm-settings", "use_fallback_wm", &e);
		if (!e)
			useFB = b;
		e = NULL;
		i = g_key_file_get_integer(f, "wm-settings", "iconsize", &e);
		if (!e && (i >= 12 && i <= 128))
			iconsize = i;
		e = NULL;

		i = g_key_file_get_integer(f, "beryl-settings", "render_path", &e);
		if (!e)
			renderPath = (RenderPathMode) i;
		e = NULL;

		i = g_key_file_get_integer(f, "beryl-settings", "cow_mode", &e);
		if (!e)
			cowMode = (COWMode) i;
		e = NULL;

		i = g_key_file_get_integer(f, "beryl-settings", "rendering_mode", &e);
		if (!e)
			renderingMode = (RenderingMode) i;
		e = NULL;

		i = g_key_file_get_integer(f, "beryl-settings", "platform", &e);
		if (!e)
			platformMode = (PlatformMode) i;
		e = NULL;

		i = g_key_file_get_integer(f, "beryl-settings", "binding", &e);
		if (!e)
			bindingMode = (BindingMode) i;
		e = NULL;

		if (!XGL && NV9XXX)
		{
			b = g_key_file_get_boolean(f, "beryl-settings",
									   "no_gl_yield", &e);
			if (!e)
				noGLYield = b;
			e = NULL;
		}
		else
			noGLYield = FALSE;
	}
	g_key_file_free(f);
	g_free(path);
}

void save_settings()
{
	gchar *path = g_strconcat(g_get_home_dir(), "/.beryl-managerrc", NULL);
	gchar *data;
	GKeyFile *f = g_key_file_new();

	g_key_file_set_integer(f, "wm-settings", "active_wm", WM);
	g_key_file_set_integer(f, "wm-settings", "fallback_wm", fallBackWM);
	g_key_file_set_integer(f, "wm-settings", "active_dm", DM);
	g_key_file_set_integer(f, "wm-settings", "iconsize", iconsize);
	g_key_file_set_boolean(f, "wm-settings", "use_fallback_wm", useFB);
	g_key_file_set_integer(f, "beryl-settings", "render_path", renderPath);
	g_key_file_set_integer(f, "beryl-settings", "cow_mode", cowMode);
	g_key_file_set_integer(f, "beryl-settings", "rendering_mode",
						   renderingMode);
	g_key_file_set_integer(f, "beryl-settings", "platform", platformMode);
	g_key_file_set_integer(f, "beryl-settings", "binding", bindingMode);
	if (!XGL && NV9XXX)
		g_key_file_set_boolean(f, "beryl-settings", "no_gl_yield", noGLYield);
	data = g_key_file_to_data(f, NULL, NULL);
	g_file_set_contents(path, data, -1, NULL);
	g_key_file_free(f);
	g_free(path);
	g_free(data);
}
gboolean is_running(const gchar * command)
{
	gchar *cmd = g_strconcat("pidof ", command, NULL);
	gchar *pret;
	gint i;

	if (g_spawn_command_line_sync(cmd, &pret, NULL, NULL, NULL))
	{
		g_strchomp(pret);
		if (pret && *pret)
		{
			gchar **pidlist = g_strsplit(pret, " ", 0);

			i = 0;
			while (pidlist[i])
			{
				if (atoi(pidlist[i]))
				{
					gchar *buffer;
					gsize len;
					gchar *file =
							g_strconcat("/proc/", pidlist[i], "/environ",
										NULL);
					if (g_file_get_contents(file, &buffer, &len, NULL))
					{
						gchar *cp;

						for (cp = buffer; cp < (buffer + len);
							 cp += strlen(cp) + 1)
						{
							if (strncmp(cp, "DISPLAY=", 8) == 0)
							{
								gchar *part = display_part(cp + 8);

								if (strcmp(part, displayname) == 0)
								{
									g_strfreev(pidlist);
									g_free(pret);
									g_free(file);
									g_free(buffer);
									g_free(cmd);
									g_free(part);
									return TRUE;
								}
								g_free(part);
							}
						}
					}
					g_free(buffer);
					g_free(file);
				}
				i++;
			}
			g_strfreev(pidlist);
		}
		g_free(pret);
	}
	g_free(cmd);
	return FALSE;
}

gboolean is_decor_running()
{
	if (DM >= numDM || DM < 0)
		DM = 0;
	return (is_running(DMs[DM].Prog));
}

void showMenu(guint button, guint32 time)
{
	gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, time);
}

gboolean popupClient(GtkWidget * w, GdkEventClient * e, gpointer d)
{
	static GdkAtom my_atom = GDK_NONE;

	if (my_atom == GDK_NONE)
		my_atom = gdk_atom_intern("beryl-manager-Popup", 1);
	if (e->message_type == my_atom)
	{
		showMenu(0, gtk_get_current_event_time());
		return TRUE;
	}
	return FALSE;
}

gboolean buttonUp(GtkWidget * w, GdkEventButton * e, gpointer d)
{
	 if (hasMouse && e->button == 3)  
		showMenu(e->button, e->time);
	return TRUE;
}

gboolean buttonDown(GtkWidget * w, GdkEventButton * e, gpointer d) 
{ 
	if (hasMouse && e->button == 1 && e->type == 5) 
		startApp(w,"beryl-settings"); 
	return TRUE; 
} 

gboolean enterNotify(GtkWidget * w, GdkEventCrossing * e, gpointer d)
{
	hasMouse = TRUE;
	return TRUE;
}

gboolean leaveNotify(GtkWidget * w, GdkEventCrossing * e, gpointer d)
{
	hasMouse = FALSE;
	return TRUE;
}

gboolean destroyNotify(GtkWidget * w, GdkEventClient * e, gpointer d)
{
	init_widgets();
	return TRUE;
}

gboolean decoratorSignalled(gint signal)
{
	g_warning(_("Decorator caught deadly signal %d"), signal);
	return FALSE;				// terminate for now
}

gboolean berylSignalled(gint signal)
{
	g_warning(_("Beryl caught deadly signal %d"), signal);
	return FALSE;				// terminate for now
}

gpointer decorThread(gpointer d)
{
	gint ex = 0;
	gchar *s = NULL;

	if (decoratorLaunched && !reloadingDecorator)
		return NULL;

	decoratorLaunched = FALSE;
	s = g_strconcat(DMs[DM].Prog, " --replace", NULL);
	do
	{
		if (g_spawn_command_line_sync(s, NULL, NULL, &ex, NULL))
		{
			decoratorLaunched = TRUE;
			if (reloadingDecorator)
				reloadingDecorator = FALSE;
		}
		else
		{
			g_warning(_("Couldn't launch selected decorator:%s"),
					  DMs[DM].Name);
			if (WIFEXITED(ex))	// returned something
			{
				g_warning(_("decorator %s returned unsuccessfully"),
						  DMs[DM].Name);
				if (WEXITSTATUS(ex))	// returned something other than 0
				{
					g_warning(_("decorator %s returned with non-zero status"),
							  DMs[DM].Name);
				}
			}
			else if (WIFSIGNALED(ex))
			{
				g_warning(_("decorator %s was killed by a signal"),
						  DMs[DM].Name);
				if (!decoratorSignalled(WTERMSIG(ex)))
				{
				}
			}
		}
	}
	while (!decoratorLaunched);

	g_free(s);
	return NULL;
}

void killIfWM(XLSItem * i, Display * d)
{
	gint j;

	for (j = 1; j < numWM; j++)
	{
		if (!WMs[j].Kill)
		{
			if (strcmp(i->Command, WMs[j].Grep) == 0)
			{
				g_message(_("Killing window %x for client %s."),
						  (unsigned int)i->w, WMs[j].Name);
				XKillClient(d, i->w);
			}
		}
	}
}
void freeXLS(XLSItem * i, gpointer p)
{
	g_free(i->Command);
	free(i);
}

void killWM()
{
	gint killed = 0;

	if (!g_mutex_trylock(mutx))
		return;
	{
		Display *d = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());

		XLockDisplay(d);
		{
			gint i;

			for (i = 1; i < numWM; i++)
			{
				if (WMs[i].Kill)
				{
					gchar *pret;
					gchar *cm = g_strconcat("pidof ", WMs[i].Grep, NULL);

					if (!g_spawn_command_line_sync
						(cm, &pret, NULL, NULL, NULL))
						g_warning(_("No pidof, this may not work right."));
					else
					{
						g_strchomp(pret);
						if (pret)
						{
							gchar *cret;

							if (strlen(pret))
							{
								if (pret[strlen(pret) - 1] == '\n')
									pret[strlen(pret) - 1] = '\0';
								for (cret = pret - 1; cret;
									 cret = strchr(cret, ' '))
								{
									gchar *p;
									gchar *e;
									gchar *f;
									pid_t pid;
									gsize l;

									cret++;
									p = strchr(cret, ' ');
									if (p)
										p[0] = '\0';
									f = g_strdup_printf("/proc/%s/environ",
														cret);
									pid = strtol(cret, NULL, 10);
									if (p)
										p[0] = ' ';
									if (g_file_get_contents(f, &e, &l, NULL))
									{
										gchar *cp;

										for (cp = e; (cp - e) < l;
											 cp += strlen(cp) + 1)
										{
											if (strncmp(cp, "DISPLAY=", 8) ==
												0)
											{
												//might be killable
												gchar *md =
														display_part(cp + 8);
												if (strcmp(md, displayname) ==
													0)
												{
													//on same display, go ahead kill
													if (kill(pid, SIGTERM) !=
														-1)
														killed++;
												}
												g_free(md);
											}
										}
										g_free(e);
									}
									else
									{
										g_warning("Couldn't open %s", f);
									}
									g_free(f);
								}
							}
							g_free(pret);
						}
					}
					g_free(cm);
				}
			}
			Window w = wmAtom ? XGetSelectionOwner(d, wmAtom) : None;

			if (w != None)
				XKillClient(d, w);
			else if (killed)
			{
				gchar *cli;
				GSList *xls;

				g_warning(_
						  ("Couldn't find a Selection Owner, perhaps no WM running?\nOtherwise, manually kill your wm, and report the bug to the developers, it doesn't follow the standards.\nFalling back to looking for a defined WM in xlsclients."));
				if (!g_spawn_command_line_sync
					("xlsclients -l", &cli, NULL, NULL, NULL))
				{
					g_warning(_("No xlsclients, this may not work right."));
				}
				else
				{
					if (!cli)
						manager_error(_
									  ("No output from xlsclients, bailing."));
					xls = parse_xlsclients(cli);
					g_free(cli);
					g_slist_foreach(xls, (GFunc) killIfWM, d);
					g_slist_foreach(xls, (GFunc) freeXLS, NULL);
					g_slist_free(xls);
				}
			}
			XSync(d, FALSE);
		}
		XUnlockDisplay(d);
	}
	g_mutex_unlock(mutx);
}

void startWM()
{
	gchar *wm_command = g_strjoin(" ", WMs[WM].Prog, WMs[WM].Opts, NULL);

	berylLaunched = FALSE;
	killWM();
	g_spawn_command_line_async(wm_command, NULL);
	g_free(wm_command);
}

#define BERYL_COMMAND_LINE_SIZE 150

gpointer berylThread(gpointer d)
{
	gint ex = 0;
	gchar beryl_command[BERYL_COMMAND_LINE_SIZE];

	if (XGL)
		g_strlcpy(beryl_command, "beryl-xgl", BERYL_COMMAND_LINE_SIZE);
	else
		g_strlcpy(beryl_command, "beryl", BERYL_COMMAND_LINE_SIZE);

	switch (renderPath)
	{
	case TFPRenderPath:
		g_strlcat(beryl_command, " --use-tfp", BERYL_COMMAND_LINE_SIZE);
		break;
	case CopyRenderPath:
		g_strlcat(beryl_command, " --use-copy", BERYL_COMMAND_LINE_SIZE);
		break;
	default:
		break;
	}

	switch (renderingMode)
	{
	case IndirectRendering:
		g_strlcat(beryl_command, " --indirect-rendering",
				  BERYL_COMMAND_LINE_SIZE);
		break;
	case XGLRendering:
		g_strlcat(beryl_command, " --xgl-rendering", BERYL_COMMAND_LINE_SIZE);
		break;
	default:
		break;
	}

	switch (cowMode)
	{
	case UseCOW:
		g_strlcat(beryl_command, " --use-cow", BERYL_COMMAND_LINE_SIZE);
		break;
	case NoCOW:
		g_strlcat(beryl_command, " --no-cow", BERYL_COMMAND_LINE_SIZE);
		break;
	default:
		break;
	}

	switch (platformMode)
	{
	case AIGLXPlatform:
		g_strlcat(beryl_command, " --force-aiglx", BERYL_COMMAND_LINE_SIZE);
		break;
	case NvidiaPlatform:
		g_strlcat(beryl_command, " --force-nvidia", BERYL_COMMAND_LINE_SIZE);
		break;
	case XGLPlatform:
		g_strlcat(beryl_command, " --force-xgl", BERYL_COMMAND_LINE_SIZE);
		break;
	default:
		break;
	}

	switch (bindingMode)
	{
	case StrictBinding:
		g_strlcat(beryl_command, " --strict-binding",
				  BERYL_COMMAND_LINE_SIZE);
		break;
	case XGLBinding:
		g_strlcat(beryl_command, " --xgl-binding", BERYL_COMMAND_LINE_SIZE);
		break;
	default:
		break;
	}

	if (noGLYield)
		g_strlcat(beryl_command, " --skip-gl-yield", BERYL_COMMAND_LINE_SIZE);

	berylLaunched = TRUE;
	while (berylLaunched)
	{
		killWM();
		if (!g_spawn_command_line_sync(beryl_command, NULL, NULL, &ex, NULL))
		{
			if (XGL)
				manager_error(_("can't execute beryl-xgl"));
			else
				manager_error(_("can't execute beryl"));
		}
		if (reloadingBeryl)
		{
			reloadingBeryl = FALSE;
			return NULL;
		}
		else if (WIFEXITED(ex))	// returned something
		{
			if (WEXITSTATUS(ex))	// returned something other than 0
			{
				berylLaunched = FALSE;
			}
		}
		else if (WIFSIGNALED(ex))	// killed by a signal
		{
			if (!berylSignalled(WTERMSIG(ex)))
			{
				berylLaunched = FALSE;
			}
		}
	}
	//if this thread exits, and WM is still beryl, fall back into the fall back WM
	if (WM == 0 && useFB)
	{
		WM = fallBackWM + FALLBACKWM_OFFSET;
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(WMs[WM].Item),
									   TRUE);
		//gtk_widget_set_sensitive(useFBItem,FALSE);
		gtk_widget_set_sensitive(DMSubItem, FALSE);
		gtk_widget_set_sensitive(reloadDecoratorItem, FALSE);
		//gtk_widget_set_sensitive(FBSubItem,FALSE);
		//for(ex=1;ex<numWM;ex++)
		//{
		//    gtk_widget_set_sensitive(WMs[ex].FBItem,FALSE);
		//}
		for (ex = 0; ex < numDM; ex++)
		{
			gtk_widget_set_sensitive(DMs[ex].Item, FALSE);
		}
		launchWM();
	}
	return NULL;
}

void reloadBeryl()
{
	if (berylLaunched)
		reloadingBeryl = TRUE;
	g_thread_create(berylThread, NULL, FALSE, NULL);	// launch beryl
	if (!decoratorLaunched && !is_decor_running())
		g_thread_create(decorThread, NULL, FALSE, NULL);	// launch decorator
}

void startBeryl()
{
	if (!berylLaunched)
		g_thread_create(berylThread, NULL, FALSE, NULL);	// launch beryl
	if (!decoratorLaunched && !is_decor_running())
		g_thread_create(decorThread, NULL, FALSE, NULL);	// launch decorator
}

void reloadDecorator(GtkWidget * w, gpointer p)
{
	if (decoratorLaunched)
		reloadingDecorator = TRUE;
	g_thread_create(decorThread, NULL, FALSE, NULL);	// launch decorator
}

void launchWM()
{
	save_settings();
	if (WM == 0)
		startBeryl();
	else
		startWM();
}

void reloadWM(GtkWidget * w, gpointer p)
{
	if (WM == 0)
		reloadBeryl();
	else
		startWM();
}

void setWM(GtkWidget * w, gpointer p)
{
	gint i = GPOINTER_TO_INT(p);

	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
	{
		gint j;

		if (i != WM)
		{
			WM = i;
			launchWM();
		}
		//gtk_widget_set_sensitive(useFBItem,i==0);
		gtk_widget_set_sensitive(reloadDecoratorItem, i < 3);
		//gtk_widget_set_sensitive(FBSubItem,i==0 && useFB);
		gtk_widget_set_sensitive(DMSubItem, i < 3);
		for (j = 0; j < numDM; j++)
		{
			gtk_widget_set_sensitive(DMs[j].Item, i < 3);
		}
		//for (j=1;j<numWM;j++)
		//{
		//    gtk_widget_set_sensitive(WMs[j].FBItem,i==0 && useFB);
		//}
		save_settings();
	}
}
void setFallbackWM(GtkWidget * w, gpointer p)
{
	gint i = GPOINTER_TO_INT(p);

	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
	{
		fallBackWM = i;
		save_settings();
	}
}

void toggleRenderingPath(GtkWidget * w, gpointer p)
{
	RenderPathMode rPath = GPOINTER_TO_INT(p);

	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
	{
		renderPath = rPath;
		save_settings();
		reloadWM(w, p);
	}
}

void toggleCOW(GtkWidget * w, gpointer p)
{
	COWMode cow = GPOINTER_TO_INT(p);

	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
	{
		cowMode = cow;
		save_settings();
		reloadWM(w, p);
	}
}

void togglePlatform(GtkWidget * w, gpointer p)
{
	PlatformMode platform = GPOINTER_TO_INT(p);

	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
	{
		platformMode = platform;
		save_settings();
		reloadWM(w, p);
	}
}

void toggleBinding(GtkWidget * w, gpointer p)
{
	BindingMode binding = GPOINTER_TO_INT(p);

	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
	{
		bindingMode = binding;
		save_settings();
		reloadWM(w, p);
	}
}

void toggleRendering(GtkWidget * w, gpointer p)
{
	RenderingMode rendering = GPOINTER_TO_INT(p);

	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
	{
		renderingMode = rendering;
		save_settings();
		reloadWM(w, p);
	}
}

void toggleFB(GtkWidget * w, gpointer p)
{
	gint i;

	useFB = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	gtk_widget_set_sensitive(FBSubItem, useFB);
	for (i = 1; i < numWM; i++)
		gtk_widget_set_sensitive(WMs[i].FBItem, useFB);
	save_settings();
}

void setDM(GtkWidget * w, gpointer p)
{
	gint i = GPOINTER_TO_INT(p);

	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
	{
		DM = i;
		save_settings();
		reloadDecorator(w, p);
	}
}
GtkWidget *make_image(gchar * path)
{
	GdkPixbuf *p;
	gint w, h;

	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &w, &h);
	p = gdk_pixbuf_new_from_file_at_size(path, w, h, NULL);
	if (!p)
		return gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE,
										GTK_ICON_SIZE_MENU);
	else
		return gtk_image_new_from_pixbuf(p);
}

void quitMe(GtkWidget * w, gpointer p)
{
	gtk_main_quit();
}

gboolean is_wm_running(gint wm)
{
	const gchar *nam;

	if (wm > 0)
	{
		nam = WMs[wm].Grep;
		return is_running(nam);
	}
	else
	{
		return is_running("beryl") || is_running("beryl-xgl") ||
				is_running("compiz");
	}
}
gboolean detect_app(const gchar * app)
{
	gint ex;
	gchar *f = g_strdup_printf("sh -c 'which %s > /dev/null 2>&1'", app);

	if (!g_spawn_command_line_sync(f, NULL, NULL, &ex, NULL))
		manager_error(_("can't use this app, no which"));
	g_free(f);
	if (WIFEXITED(ex))
	{
		if (WEXITSTATUS(ex) == 0)
			return TRUE;
	}
	else
		manager_error(_("something went wrong with which"));
	return FALSE;
}

gboolean detect_wm(gint wm)
{
	if (!XGL || !WMs[wm].xXGL)
	{
		if (detect_app(WMs[wm].Prog))
			return TRUE;
	}
	if (wm == WM)
		WM = -1;
	if (wm == fallBackWM + FALLBACKWM_OFFSET)
		fallBackWM = -1;
	return FALSE;
}

gboolean detect_dm(gint dm)
{
	if (detect_app(DMs[dm].Prog))
		return TRUE;
	if (dm == DM)
		DM = -1;
	return FALSE;
}

void setGLYield(GtkWidget * w, gpointer p)
{
	noGLYield = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	save_settings();
	if (WM == 0)
		reloadBeryl();
}

GtkWidget *add_menu_group_item(GtkWidget * menu, GSList ** group,
							   const gchar * name, gboolean show,
							   gboolean check, GCallback callback,
							   gpointer data)
{
	GtkWidget *mitem;

	mitem = gtk_radio_menu_item_new_with_label(*group, name);
	*group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mitem));
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);

	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), check);

	if (show)
		gtk_widget_show(mitem);
	else
		gtk_widget_hide(mitem);

	g_signal_connect(mitem, "toggled", callback, data);

	return mitem;
}

void init_menu()
{
	GtkWidget *submenu;
	GtkWidget *mitem;
	GtkWidget *smshell;
	GSList *renderPathGroup = NULL;
	GSList *cowGroup = NULL;
	GSList *platformGroup = NULL;
	GSList *bindingGroup = NULL;
	GSList *renderingGroup = NULL;
	GSList *wms = NULL;
	GSList *fbk = NULL;
	GSList *dms = NULL;
	gint i;

	menu = gtk_menu_new();
	g_object_ref(menu);

	if (detect_app("beryl-settings"))
	{
		mitem = gtk_image_menu_item_new_with_label(_("Beryl Settings Manager"));
		gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem),
			 make_image(DATADIR "/icons/hicolor/scalable/apps/beryl-settings.svg"));
		gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
		gtk_widget_show(mitem);
		g_signal_connect(mitem, "activate", G_CALLBACK(startApp),
						 "beryl-settings");
	}

	if (detect_app("emerald-theme-manager"))
	{
		mitem = gtk_image_menu_item_new_with_label(_("Emerald Theme Manager"));
		gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem),
			make_image(PIXMAPS_DIR "/emerald-theme-manager-icon.png"));
		gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
		gtk_widget_show(mitem);
		g_signal_connect(mitem, "activate", G_CALLBACK(startApp),
						 "emerald-theme-manager");
	}

	if (detect_app("emerald-theme-manager") || detect_app("beryl-settings"))
	{
		mitem = gtk_separator_menu_item_new();
		gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
		gtk_widget_show(mitem);
	}

	mitem = gtk_image_menu_item_new_with_label(_("Reload Window Manager"));
	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem),
		gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU));
	g_signal_connect(mitem, "activate", G_CALLBACK(reloadWM), NULL);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);

	mitem = gtk_image_menu_item_new_with_label(_("Select Window Manager"));
	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem),
		make_image(PIXMAPS_DIR "/wm-select.png"));
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);

	smshell = gtk_menu_new();
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell);

	for (i = 0; i < numWM; i++)
	{
		mitem = add_menu_group_item(smshell, &wms, gettext(WMs[i].Name),
									((i == 0) ||
									 detect_wm(i)), (i == WM),
									G_CALLBACK(setWM), GINT_TO_POINTER(i));
		WMs[i].Item = mitem;
	}

	mitem = gtk_image_menu_item_new_with_label(_("Advanced Beryl options"));
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);

	submenu = gtk_menu_new();
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), submenu);

	mitem = gtk_image_menu_item_new_with_label(_("Rendering path"));
	gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
	gtk_widget_show(mitem);

	smshell = gtk_menu_new();
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell);

	add_menu_group_item(smshell, &renderPathGroup, _("Automatic"), TRUE,
						(renderPath == AutoRenderPath),
						G_CALLBACK(toggleRenderingPath),
						GINT_TO_POINTER(AutoRenderPath));
	add_menu_group_item(smshell, &renderPathGroup, _("Texture From Pixmap"),
						TRUE, (renderPath == TFPRenderPath),
						G_CALLBACK(toggleRenderingPath),
						GINT_TO_POINTER(TFPRenderPath));
	add_menu_group_item(smshell, &renderPathGroup, _("Copy"), TRUE,
						(renderPath == CopyRenderPath),
						G_CALLBACK(toggleRenderingPath),
						GINT_TO_POINTER(CopyRenderPath));

	mitem = gtk_image_menu_item_new_with_label(_("Composite Overlay Window"));
	gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
	gtk_widget_show(mitem);

	smshell = gtk_menu_new();
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell);

	add_menu_group_item(smshell, &cowGroup, _("Automatic"), TRUE,
						(cowMode == AutoCOW), G_CALLBACK(toggleCOW),
						GINT_TO_POINTER(AutoCOW));
	add_menu_group_item(smshell, &cowGroup, _("Use COW"), TRUE,
						(cowMode == UseCOW), G_CALLBACK(toggleCOW),
						GINT_TO_POINTER(UseCOW));
	add_menu_group_item(smshell, &cowGroup, _("Don't use COW"), TRUE,
						(cowMode == NoCOW), G_CALLBACK(toggleCOW),
						GINT_TO_POINTER(NoCOW));

	mitem = gtk_image_menu_item_new_with_label(_("Rendering platform"));
	gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
	gtk_widget_show(mitem);

	smshell = gtk_menu_new();
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell);

	add_menu_group_item(smshell, &platformGroup, _("Automatic"), TRUE,
						(platformMode == AutoPlatform),
						G_CALLBACK(togglePlatform),
						GINT_TO_POINTER(AutoPlatform));
	add_menu_group_item(smshell, &platformGroup, _("Force Nvidia"), TRUE,
						(platformMode == NvidiaPlatform),
						G_CALLBACK(togglePlatform),
						GINT_TO_POINTER(NvidiaPlatform));
	add_menu_group_item(smshell, &platformGroup, _("Force AIGLX"), TRUE,
						(platformMode == AIGLXPlatform),
						G_CALLBACK(togglePlatform),
						GINT_TO_POINTER(AIGLXPlatform));
	add_menu_group_item(smshell, &platformGroup, _("Force XGL"), TRUE,
						(platformMode == XGLPlatform),
						G_CALLBACK(togglePlatform),
						GINT_TO_POINTER(XGLPlatform));

	mitem = gtk_image_menu_item_new_with_label(_("Binding"));
	gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
	gtk_widget_show(mitem);

	smshell = gtk_menu_new();
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell);

	add_menu_group_item(smshell, &bindingGroup, _("Automatic"), TRUE,
						(bindingMode == AutoBinding),
						G_CALLBACK(toggleBinding),
						GINT_TO_POINTER(AutoBinding));
	add_menu_group_item(smshell, &bindingGroup, _("Strict Binding"), TRUE,
						(bindingMode == StrictBinding),
						G_CALLBACK(toggleBinding),
						GINT_TO_POINTER(StrictBinding));
	add_menu_group_item(smshell, &bindingGroup, _("XGL Binding"), TRUE,
						(bindingMode == XGLBinding),
						G_CALLBACK(toggleBinding),
						GINT_TO_POINTER(XGLBinding));

	mitem = gtk_image_menu_item_new_with_label(_("Rendering"));
	gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
	gtk_widget_show(mitem);

	smshell = gtk_menu_new();
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell);

	add_menu_group_item(smshell, &renderingGroup, _("Automatic"), TRUE,
						(renderingMode == AutoRendering),
						G_CALLBACK(toggleRendering),
						GINT_TO_POINTER(AutoRendering));
	add_menu_group_item(smshell, &renderingGroup, _("Indirect Rendering"),
						TRUE, (renderingMode == IndirectRendering),
						G_CALLBACK(toggleRendering),
						GINT_TO_POINTER(IndirectRendering));
	add_menu_group_item(smshell, &renderingGroup, _("XGL Rendering"), TRUE,
						(renderingMode == XGLRendering),
						G_CALLBACK(toggleRendering),
						GINT_TO_POINTER(XGLRendering));

	if (!XGL && NV9XXX)
	{
		mitem = gtk_check_menu_item_new_with_label(_
												   ("Disable GL Yield setting\n"
													"Use this to fix some redraw bugs"));
		gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), noGLYield);
		gtk_widget_show(mitem);
		g_signal_connect(mitem, "toggled", G_CALLBACK(setGLYield), NULL);
	}

	mitem = gtk_separator_menu_item_new();
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);

	mitem = gtk_image_menu_item_new_with_label(_("Reload Window Decorator"));
	reloadDecoratorItem = mitem;
	gtk_widget_set_sensitive(reloadDecoratorItem, WM < 3);
	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem),
								  gtk_image_new_from_stock(GTK_STOCK_REFRESH,
														   GTK_ICON_SIZE_MENU));
	g_signal_connect(mitem, "activate", G_CALLBACK(reloadDecorator), NULL);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);

	mitem = gtk_image_menu_item_new_with_label(_("Select Window Decorator"));
	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem),
								  make_image(PIXMAPS_DIR "/wd-select.png"));
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);

	smshell = gtk_menu_new();
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell);
	DMSubItem = mitem;
	gtk_widget_set_sensitive(GTK_WIDGET(DMSubItem), WM < 3);

	for (i = 0; i < numDM; i++)
	{
		mitem = gtk_radio_menu_item_new_with_label(dms, gettext(DMs[i].Name));
		dms = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mitem));
		if (i == DM)
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), TRUE);
		gtk_menu_shell_append(GTK_MENU_SHELL(smshell), mitem);
		if (detect_dm(i))
			gtk_widget_show(mitem);
		else
			gtk_widget_hide(mitem);
		g_signal_connect(mitem, "toggled", G_CALLBACK(setDM),
						 GINT_TO_POINTER(i));
		DMs[i].Item = mitem;
	}

	mitem = gtk_separator_menu_item_new();
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);

	mitem = gtk_check_menu_item_new_with_label(_
											   ("Launch Fall-back Window\nManager if beryl crashes"));
	useFBItem = mitem;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), useFB);
	g_signal_connect(mitem, "toggled", G_CALLBACK(toggleFB), NULL);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);

	mitem = gtk_image_menu_item_new_with_label(_
											   ("Select Fall-back Window Manager"));
	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem),
								  make_image(PIXMAPS_DIR
											 "/fall-back-wm-select.png"));
	FBSubItem = mitem;
	gtk_widget_set_sensitive(FBSubItem, useFB);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);

	smshell = gtk_menu_new();
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell);

	for (i = FALLBACKWM_OFFSET; i < numWM; i++)
	{
		mitem = gtk_radio_menu_item_new_with_label(fbk, gettext(WMs[i].Name));
		fbk = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mitem));
		if ((i - FALLBACKWM_OFFSET) == fallBackWM)
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), TRUE);
		gtk_widget_set_sensitive(mitem, useFB);
		gtk_menu_shell_append(GTK_MENU_SHELL(smshell), mitem);
		if (detect_wm(i))
			gtk_widget_show(mitem);
		else
			gtk_widget_hide(mitem);
		WMs[i].FBItem = mitem;
		g_signal_connect(mitem, "toggled", G_CALLBACK(setFallbackWM),
						 GINT_TO_POINTER(i - FALLBACKWM_OFFSET));
	}

	mitem = gtk_separator_menu_item_new();
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);

	mitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
	g_signal_connect(mitem, "activate", G_CALLBACK(quitMe), NULL);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show(mitem);
}

void init_widgets()
{
	GtkWidget *icon;
	GtkWidget *evbox;
	GdkPixbuf *pbuf;

	tips = gtk_tooltips_new();
	mainIcon = egg_tray_icon_new(_("Beryl Manager"));
	evbox = gtk_event_box_new();
	gtk_event_box_set_visible_window(GTK_EVENT_BOX(evbox), FALSE);
	gtk_tooltips_set_tip(tips, evbox, _("Beryl Manager"),
						 _("Manage various things related to Beryl"));
	pbuf = gdk_pixbuf_new_from_file_at_size(DATADIR
											"/icons/hicolor/scalable/apps/beryl-manager.svg",
											iconsize, iconsize, NULL);
	if (!pbuf)
		pbuf = gdk_pixbuf_new_from_file(DATADIR
										"/icons/hicolor/24x24/apps/beryl-manager.png",
										NULL);
	if (!pbuf)
		pbuf = gdk_pixbuf_new_from_file(PIXMAPS_DIR "/beryl-manager.png",
										NULL);
	if (!pbuf)
		icon = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE,
										GTK_ICON_SIZE_SMALL_TOOLBAR);
	else
	{
		g_object_ref(G_OBJECT(pbuf));
		icon = gtk_image_new_from_pixbuf(pbuf);
	}
	gtk_container_add(GTK_CONTAINER(mainIcon), evbox);
	gtk_container_add(GTK_CONTAINER(evbox), icon);
	g_signal_connect(evbox, "button-release-event", G_CALLBACK(buttonUp),
					NULL);
	g_signal_connect(evbox, "button-press-event", G_CALLBACK(buttonDown), 
					NULL); 
	g_signal_connect(evbox, "enter-notify-event", G_CALLBACK(enterNotify),
					 NULL);
	g_signal_connect(evbox, "leave-notify-event", G_CALLBACK(leaveNotify),
					 NULL);
	g_signal_connect(evbox, "destroy", G_CALLBACK(destroyNotify), NULL);
	g_signal_connect(mainIcon, "client-event", G_CALLBACK(popupClient), NULL);
	gtk_widget_show_all(GTK_WIDGET(mainIcon));
}

void detect_nvidia()
{
	//find out if we have XGL
	gint ex = 0;

	if (!g_spawn_command_line_sync
		("sh -c 'glxinfo | grep -i NVIDIA > /dev/null'", NULL, NULL, &ex,
		 NULL))
		manager_error(_("can't use this app, no glxinfo or no grep"));
	if (WIFEXITED(ex))
	{
		if (WEXITSTATUS(ex) == 0)
			NV9XXX = TRUE;
		else
			NV9XXX = FALSE;
	}
	else
		manager_error(_("something went wrong with glxinfo or grep"));

}

void detect_xgl()
{
	//find out if we have XGL
	gint ex = 0;

	if (!g_spawn_command_line_sync("sh -c 'xvinfo | grep -i Xgl > /dev/null'",
								   NULL, NULL, &ex, NULL))
		manager_error(_("can't use this app, no xvinfo or no grep"));
	if (WIFEXITED(ex))
	{
		if (WEXITSTATUS(ex) == 0)
			XGL = TRUE;
		else
			XGL = FALSE;
	}
	else
		manager_error(_("something went wrong with xvinfo or grep"));
}
int main(int argc, char **argv)
{
	gint i, found;
	gchar *buffer;
	gboolean daemon_mode = TRUE;
	Display *d;
	gboolean force_window_manager = TRUE;
	gboolean force_decorator = TRUE;
	Window running_window;

	//Intialise error handler
	g_log_set_handler(G_LOG_DOMAIN,
					  G_LOG_LEVEL_WARNING |
					  G_LOG_LEVEL_ERROR |
					  G_LOG_LEVEL_CRITICAL, beryl_manager_log_handler, NULL);

	//set the locale stuff 
	setlocale(LC_ALL, "");
	bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
	bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
	textdomain(GETTEXT_PACKAGE);

	//parse command line arguments
	for (i = 1; i < argc; i++)
	{
		if (strcmp(argv[i], "--help") == 0)
		{
			usage(argv[0]);
			return 0;
		}
		else if (strcmp(argv[i], "--version") == 0)
		{
			printf(PACKAGE_STRING "\n");
			return 0;
		}
		else if (strcmp(argv[i], "-d") == 0)
		{
			daemon_mode = FALSE;
		}
		else if (strcmp(argv[i], "--no-force-window-manager") == 0)
		{
			force_window_manager = FALSE;
		}
		else if (strcmp(argv[i], "--no-force-decorator") == 0)
		{
			force_decorator = FALSE;
		}
		else
		{
			usage(argv[0]);
			return 1;
		}
	}

	//detach from console or not
	if (daemon_mode)
	{
		daemon(1, 1);
		close(0);
	}

	if (!XInitThreads())
	{
		g_warning(_("Can't init XLib thread support"));
		return 3;
	}

	d = XOpenDisplay(NULL);
	if ((running_window = Window_With_Name(d, DefaultRootWindow(d),
										   //                 GDK_WINDOW_XID(
										   // gdk_get_default_root_window()
										   // ),
										   "Beryl Manager")))
		// "Event Tester")))
	{
		XEvent clientEvent;
		gboolean missed = FALSE;

		PopupRunning = XInternAtom(d, "beryl-manager-Popup", 0);

		clientEvent.xclient.type = ClientMessage;
		clientEvent.xclient.window = running_window;
		clientEvent.xclient.message_type = PopupRunning;
		clientEvent.xclient.format = 32;
		clientEvent.xclient.display = d;
		clientEvent.xclient.data.l[0] = 0;
		clientEvent.xclient.data.l[1] = 0;
		clientEvent.xclient.data.l[2] = 0;
		clientEvent.xclient.data.l[3] = 0;
		clientEvent.xclient.data.l[4] = 0;
		//  gdk_error_trap_push ();
		missed = XSendEvent(d, running_window,
							False, NoEventMask, &clientEvent);
		XSync(d, False);
		// gdk_error_trap_pop ();
		return 0;
	}
	XCloseDisplay(d);

	// Some warning about changed behaviour for the unaware user
	/*
	   if (!force_window_manager && !force_decorator) {
	   if (!strcmp (PACKAGE_VERSION, "0.1.1")) {
	   fprintf(stderr, "beryl-manager doesn't autostart window-manager/decorator\n"
	   "any more. Please consult: man beryl-manager\n\n");
	   }
	   } 
	 */
	//taken out because starting beryl is -the- reason for beryl-manager's existence.

	gtk_init(&argc, &argv);
	d = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());

	buffer = g_strdup(DisplayString
					  (gdk_x11_display_get_xdisplay
					   (gdk_display_get_default())));
	if (buffer)
	{
		displayname = display_part(buffer);
		g_free(buffer);
	}

	if (!g_thread_supported())
		g_thread_init(NULL);
	gdk_threads_init();
	gdk_threads_enter();
	mutx = g_mutex_new();


	// Check for the windows manager
	buffer = g_strconcat("WM_S", displayname, NULL);
	wmAtom = XInternAtom(d, buffer, 0);
	g_free(buffer);

	detect_xgl();
	if (!XGL)
		detect_nvidia();

	load_settings();
	init_widgets();
	init_menu();
	if (WM < 0 || WM >= (numWM))
		WM = -1;
	if (WM == -1)
	{
		//set WM to beryl for now
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(WMs[0].Item),
									   TRUE);
	}
	if (fallBackWM < 0 || fallBackWM > (numWM - 1))
		fallBackWM = -1;
	if (fallBackWM == -1)
	{
		//we have to find a fall back WM that exists
		gint i;

		for (i = 1; i < numWM; i++)
		{
			if (detect_wm(i))
			{
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM
											   (WMs[i].FBItem), TRUE);
				fallBackWM = i - FALLBACKWM_OFFSET;
				break;
			}
		}
	}
	if (fallBackWM == -1)
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(useFBItem), FALSE);
	if (DM < 0 || DM >= numDM)
		DM = -1;
	if (DM == -1)
	{
		//we have to find a DM that exists
		gint i;

		for (i = 0; i < numDM; i++)
		{
			if (detect_dm(i))
			{
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM
											   (DMs[i].Item), TRUE);
				DM = i;
				break;
			}
		}
	}
	if (DM == -1)
		manager_error("No Display Manager Found!");
	save_settings();

	found = False;
	for (i = 0; i < numDM && !found; i++)
	{
		if (is_running(DMs[i].Prog))
			found = True;
	}
	if (!found || (force_decorator && !is_decor_running()))
	{
		g_thread_create(decorThread, NULL, FALSE, NULL);	// launch decorator
	}

	if (!force_window_manager)
	{
		found = False;
		for (i = 0; i < numWM && !found; i++)
			if (is_wm_running(i))
				found = True;
		if (!found)
			launchWM();
	}
	else if (!is_wm_running(WM))
	{
		launchWM();
	}
	signal(SIGUSR1, signalHandler);
	signal(SIGUSR2, signalHandler);

	gtk_main();
	gdk_threads_leave();

	g_free(displayname);

	return 0;
}



/*      -       -       -       -       -       -       -       -       -

* [These functions are from the file "dsimple.c" used with xwininfo.]
*
* Written by Mark Lillibridge.   Last updated 7/1/87
*
*
* Window_With_Name: routine to locate a window with a given name on a display.
*                   If no window with the given name is found, 0 is returned.
*                   If more than one window has the given name, the first
*                   one found will be returned.  Only top and its subwindows
*                   are looked at.  Normally, top should be the Root Window.
*/
static Window Window_With_Name(Display * dpy, Window top, char *name)
{
	Window *children, dummy;
	unsigned int nchildren;
	unsigned i;
	Window w = 0;
	char *window_name;

	if (XFetchName(dpy, top, &window_name) && !strcmp(window_name, name))
	{
		XFree(window_name);
		return (top);
	}

	XFree(window_name);
	if (!XQueryTree(dpy, top, &dummy, &dummy, &children, &nchildren))
		return (0);

	for (i = 0; i < nchildren; i++)
	{
		w = Window_With_Name(dpy, children[i], name);
		if (w)
			break;
	}
	if (children)
		XFree((char *)children);
	return (w);
}


syntax highlighted by Code2HTML, v. 0.9.1