// fluxbox.cc for Fluxbox Window Manager
// Copyright (c) 2001 - 2002 Henrik Kinnunen (fluxgen@linuxmail.org)
//
// blackbox.cc for blackbox - an X11 Window manager
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.	IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// $Id: fluxbox.cc,v 1.81 2002/11/15 12:19:17 fluxgen Exp $


#include "fluxbox.hh"

#include "i18n.hh"
#include "Basemenu.hh"
#include "Clientmenu.hh"
#include "Rootmenu.hh"
#include "Screen.hh"
#include "Toolbar.hh"
#include "Window.hh"
#include "Workspace.hh"
#include "Workspacemenu.hh"
#include "StringUtil.hh"
#include "Resource.hh"
#include "XrmDatabaseHelper.hh"
#include "AtomHandler.hh"


//Use GNU extensions
#ifndef	 _GNU_SOURCE
#define	 _GNU_SOURCE
#endif // _GNU_SOURCE

#ifdef		HAVE_CONFIG_H
#include "../config.h"
#endif // HAVE_CONFIG_H

#ifdef SLIT
#include "Slit.hh"
#endif // SLIT
#ifdef USE_GNOME
#include "Gnome.hh"
#endif // USE_GNOME
#ifdef USE_NEWWMSPEC
#include "Ewmh.hh"
#endif //USE_NEWWMSPEC

// X headers
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#ifdef SHAPE
#include <X11/extensions/shape.h>
#endif // SHAPE

#include <cstdio>
#include <cstdlib>
#include <cstring>

#ifdef HAVE_UNISTD_H
#include <sys/types.h>
#include <unistd.h>
#endif // HAVE_UNISTD_H

#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif // HAVE_SYS_PARAM_H

#ifndef	 MAXPATHLEN
#define	 MAXPATHLEN 255
#endif // MAXPATHLEN

#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif // HAVE_SYS_SELECT_H

#ifdef		HAVE_SYS_STAT_H
#include <sys/types.h>
#include <sys/stat.h>
#endif // HAVE_SYS_STAT_H

#ifdef		TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else // !TIME_WITH_SYS_TIME
#ifdef		HAVE_SYS_TIME_H
#include <sys/time.h>
#else // !HAVE_SYS_TIME_H
#include <time.h>
#endif // HAVE_SYS_TIME_H
#endif // TIME_WITH_SYS_TIME

#ifdef		HAVE_LIBGEN_H
#	include <libgen.h>
#endif // HAVE_LIBGEN_H

#include <sys/wait.h>

#include <iostream>
#include <string>
#include <memory>
#include <algorithm>
#include <typeinfo>

using namespace std;
using namespace FbTk;

#ifndef	 HAVE_BASENAME
namespace {

char *basename (char *s) {
	char *save = s;

	while (*s) {
		if (*s++ == '/')
			save = s;
	}

	return save;
}

}; // end anonymous namespace

#endif // HAVE_BASENAME

#define RC_PATH "fluxbox"
#define RC_INIT_FILE "init"


// X event scanner for enter/leave notifies - adapted from twm
typedef struct scanargs {
	Window w;
	Bool leave, inferior, enter;
} scanargs;

static Bool queueScanner(Display *, XEvent *e, char *args) {
	if ((e->type == LeaveNotify) &&
			(e->xcrossing.window == ((scanargs *) args)->w) &&
			(e->xcrossing.mode == NotifyNormal)) {
		((scanargs *) args)->leave = True;
		((scanargs *) args)->inferior = (e->xcrossing.detail == NotifyInferior);
	} else if ((e->type == EnterNotify) &&
			(e->xcrossing.mode == NotifyUngrab))
		((scanargs *) args)->enter = True;

	return False;
}
//-----------------------------------------------------------------
//---- accessors for int, bool, and some enums with Resource ------
//-----------------------------------------------------------------
template<>
void Resource<int>::
setFromString(const char* strval) {
	int val;
	if (sscanf(strval, "%d", &val)==1)
		*this = val;
}

template<>
void Resource<std::string>::
setFromString(const char *strval) {
	*this = strval;
}

template<>
void Resource<bool>::
setFromString(char const *strval) {
	if (strcasecmp(strval, "true")==0)
		*this = true;
	else
		*this = false;
}

template<>
void Resource<Fluxbox::TitlebarList>::
setFromString(char const *strval) {
	vector<std::string> val;
	StringUtil::stringtok(val, strval);
	int size=val.size();
	//clear old values
	m_value.clear();
		
	for (int i=0; i<size; i++) {
		if (strcasecmp(val[i].c_str(), "Maximize")==0)
			m_value.push_back(Fluxbox::MAXIMIZE);
		else if (strcasecmp(val[i].c_str(), "Minimize")==0)
			m_value.push_back(Fluxbox::MINIMIZE);
		else if (strcasecmp(val[i].c_str(), "Shade")==0)
			m_value.push_back(Fluxbox::SHADE);
		else if (strcasecmp(val[i].c_str(), "Stick")==0)
			m_value.push_back(Fluxbox::STICK);
		else if (strcasecmp(val[i].c_str(), "Menu")==0)
			m_value.push_back(Fluxbox::MENU);
		else if (strcasecmp(val[i].c_str(), "Close")==0)
			m_value.push_back(Fluxbox::CLOSE);
	}
}

template<>
void Resource<unsigned int>::
setFromString(const char *strval) {	
	if (sscanf(strval, "%ul", &m_value) != 1)
		setDefaultValue();
}

//-----------------------------------------------------------------
//---- manipulators for int, bool, and some enums with Resource ---
//-----------------------------------------------------------------
template<>
std::string Resource<bool>::
getString() {				
	return std::string(**this == true ? "true" : "false");
}

template<>
std::string Resource<int>::
getString() {
	char strval[256];
	sprintf(strval, "%d", **this);
	return std::string(strval);
}

template<>
std::string Resource<std::string>::
getString() { return **this; }

template<>
std::string Resource<Fluxbox::TitlebarList>::
getString() {
	string retval;
	int size=m_value.size();
	for (int i=0; i<size; i++) {
		switch (m_value[i]) {
			case Fluxbox::SHADE:
				retval.append("Shade");
				break;
			case Fluxbox::MINIMIZE:
				retval.append("Minimize");
				break;
			case Fluxbox::MAXIMIZE:
				retval.append("Maximize");
				break;
			case Fluxbox::CLOSE:
				retval.append("Close");
				break;
			case Fluxbox::STICK:
				retval.append("Stick");
				break;
			case Fluxbox::MENU:
				retval.append("Menu");
				break;
			default:
				break;
		}
		retval.append(" ");
	}

	return retval;
}

template<>
string Resource<unsigned int>::
getString() {
	char tmpstr[128];
	sprintf(tmpstr, "%ul", m_value);
	return string(tmpstr);
}

//static singleton var
Fluxbox *Fluxbox::singleton=0;

//default values for titlebar left and right
//don't forget to change last value in m_rc_titlebar_* if you add more to these
Fluxbox::Titlebar Fluxbox::m_titlebar_left[] = {STICK};
Fluxbox::Titlebar Fluxbox::m_titlebar_right[] = {MINIMIZE, MAXIMIZE, CLOSE};

Fluxbox::Fluxbox(int m_argc, char **m_argv, const char *dpy_name, const char *rc)
: BaseDisplay(m_argv[0], dpy_name), FbAtoms(getXDisplay()),
m_resourcemanager(), m_screen_rm(),
m_rc_tabs(m_resourcemanager, true, "session.tabs", "Session.Tabs"),
m_rc_iconbar(m_resourcemanager, true, "session.iconbar", "Session.Iconbar"),
m_rc_colors_per_channel(m_resourcemanager, 4, "session.colorsPerChannel", "Session.ColorsPerChannel"),
m_rc_stylefile(m_resourcemanager, "", "session.styleFile", "Session.StyleFile"),
m_rc_menufile(m_resourcemanager, DEFAULTMENU, "session.menuFile", "Session.MenuFile"),
m_rc_keyfile(m_resourcemanager, DEFAULTKEYSFILE, "session.keyFile", "Session.KeyFile"),
m_rc_slitlistfile(m_resourcemanager, "", "session.slitlistFile", "Session.SlitlistFile"),
m_rc_groupfile(m_resourcemanager, "", "session.groupFile", "Session.GroupFile"),
m_rc_titlebar_left(m_resourcemanager, TitlebarList(&m_titlebar_left[0], &m_titlebar_left[1]), "session.titlebar.left", "Session.Titlebar.Left"),
m_rc_titlebar_right(m_resourcemanager, TitlebarList(&m_titlebar_right[0], &m_titlebar_right[3]), "session.titlebar.right", "Session.Titlebar.Right"),
m_rc_cache_life(m_resourcemanager, 5, "session.cacheLife", "Session.CacheLife"),
m_rc_cache_max(m_resourcemanager, 200, "session.cacheMax", "Session.CacheMax"),
focused_window(0), masked_window(0),
timer(this),
no_focus(false),
rc_file(rc ? rc : ""),
argv(m_argv), argc(m_argc), 
key(0)
{

	if (singleton != 0) {
		cerr<<"Fatal! There can only one instance of fluxbox class."<<endl;
		abort();
	}
	
	//catch system signals
	SignalHandler *sigh = SignalHandler::instance();
	
	sigh->registerHandler(SIGSEGV, this);
	sigh->registerHandler(SIGFPE, this);
	sigh->registerHandler(SIGTERM, this);
	sigh->registerHandler(SIGINT, this);
	sigh->registerHandler(SIGCHLD, this);
	sigh->registerHandler(SIGHUP, this);
	sigh->registerHandler(SIGUSR1, this);	
	sigh->registerHandler(SIGUSR2, this);

	//setup cursor bitmaps
	cursor.session = XCreateFontCursor(getXDisplay(), XC_left_ptr);
	cursor.move = XCreateFontCursor(getXDisplay(), XC_fleur);
	cursor.ll_angle = XCreateFontCursor(getXDisplay(), XC_ll_angle);
	cursor.lr_angle = XCreateFontCursor(getXDisplay(), XC_lr_angle);

	//singleton pointer
	singleton = this;

	// setup atom handlers
#ifdef USE_GNOME
	m_atomhandler.push_back(new Gnome()); // for gnome 1 atom support
#endif //USE_GNOME
#ifdef USE_NEWWMSPEC
	m_atomhandler.push_back(new Ewmh()); // for Extended window manager atom support
#endif // USE_NEWWMSPEC

	grab();
	
	setupConfigFiles();
	
	if (! XSupportsLocale())
		cerr<<"Warning: X server does not support locale"<<endl;

	if (XSetLocaleModifiers("") == 0)
		cerr<<"Warning: cannot set locale modifiers"<<endl;

// Set default values to member variables

	resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0;
	
	masked = None;
	
#ifdef SLIT
#ifdef KDE
	//For KDE dock applets
	kwm1_dockwindow = XInternAtom(getXDisplay(), "KWM_DOCKWINDOW", False); //KDE v1.x
	kwm2_dockwindow = XInternAtom(getXDisplay(), "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False); //KDE v2.x
#endif //KDE

#endif // SLIT

#ifdef HAVE_GETPID
	fluxbox_pid = XInternAtom(getXDisplay(), "_BLACKBOX_PID", False);
#endif // HAVE_GETPID

	int i;
	load_rc();
	//allocate screens
	for (i = 0; i < getNumberOfScreens(); i++) {
		char scrname[128], altscrname[128];
		sprintf(scrname, "session.screen%d", i);
		sprintf(altscrname, "session.Screen%d", i);
		BScreen *screen = new BScreen(m_screen_rm, scrname, altscrname, i);
		if (! screen->isScreenManaged()) {
			delete screen;			
			continue;
		}
		screenList.push_back(screen);
		
		// attach screen signals to this
		screen->currentWorkspaceSig().attach(this);
		screen->workspaceCountSig().attach(this);
		screen->workspaceNamesSig().attach(this);
		screen->clientListSig().attach(this);
		
		// initiate atomhandler for screen specific stuff
		for (size_t atomh=0; atomh<m_atomhandler.size(); ++atomh) {
			m_atomhandler[atomh]->initForScreen(*screen);
		}

		
	}

	I18n *i18n = I18n::instance();
	if (screenList.size() == 0) {
		fprintf(stderr,
			i18n->
				getMessage(
				FBNLS::blackboxSet, FBNLS::blackboxNoManagableScreens,
				"Fluxbox::Fluxbox: no managable screens found, aborting.\n"));

		throw static_cast<int>(3);
	}
	
	XSynchronize(getXDisplay(), False);
	XSync(getXDisplay(), False);

	reconfigure_wait = reread_menu_wait = false;
	
	timer.setTimeout(0);
	timer.fireOnce(True);

	//create keybindings handler and load keys file	
	auto_ptr<Keys> tmp(new Keys(getXDisplay(), StringUtil::expandFilename(*m_rc_keyfile).c_str()));
	key = tmp;

	ungrab();
}


Fluxbox::~Fluxbox() {
	// destroy atomhandlers
	while (!m_atomhandler.empty()) {
		delete m_atomhandler.back();
		m_atomhandler.pop_back();
	}
	
	std::list<MenuTimestamp *>::iterator it = menuTimestamps.begin();
	std::list<MenuTimestamp *>::iterator it_end = menuTimestamps.end();
	for (; it != it_end; ++it) {
		MenuTimestamp *ts = *it;

		if (ts->filename)
			delete [] ts->filename;

		delete ts;
	}
	
}

//---------- setupConfigFiles -----------
// setup the configutation files in 
// home directory
//---------------------------------------
void Fluxbox::setupConfigFiles() {

	bool createInit, createKeys, createMenu;
	createInit = createKeys = createMenu = false;

	string dirname = getenv("HOME")+string("/.")+string(RC_PATH) + "/";
	string initFile, keysFile, menuFile, slitlistFile;
	initFile = dirname+RC_INIT_FILE;
	keysFile = dirname+"keys";
	menuFile = dirname+"menu";

	struct stat buf;

	// is file/dir already there?
	if (! stat(dirname.c_str(), &buf)) {
		/*TODO: this
		if (! (buf.st_mode & S_IFDIR)) {
			cerr << dirname.c_str() << "!" << endl;
			return 1;
		}
		*/
		
		// check if anything with those name exists, if not create new
		if (stat(initFile.c_str(), &buf))
			createInit = true;
		if (stat(keysFile.c_str(), &buf))
			createKeys = true;
		if (stat(menuFile.c_str(), &buf))
			createMenu = true;

	} else {
#ifdef DEBUG
		cerr <<__FILE__<<"("<<__LINE__<<"): Creating dir: " << dirname.c_str() << endl;
#endif // DEBUG

		// create directory with perm 700
		if (mkdir(dirname.c_str(), 0700)) {
			cerr << "Can't create " << dirname << " directory!" << endl;
			return;	
		}
		
		//mark creation of files
		createInit = createKeys = createMenu = true;
	}


	// should we copy key configuraion?
	if (createKeys) {
		ifstream from(DEFAULTKEYSFILE);
		ofstream to(keysFile.c_str());

		if (! to.good()) {
			cerr << "Can't write file" << endl;			
		} else if (from.good()) {
			#ifdef DEBUG
			cerr << "Copying file: " << DEFAULTKEYSFILE << endl;
			#endif // DEBUG
			to<<from.rdbuf(); //copy file
			
		} else {
			cerr<<"Can't copy default keys file."<<endl;
		}		
	}

	// should we copy menu configuraion?
	if (createMenu) {
		ifstream from(DEFAULTMENU);
		ofstream to(menuFile.c_str());

		if (! to.good()) {
			cerr << "Can't open " << menuFile.c_str() << "for writing" << endl;
		} else if (from.good()) {
			#ifdef DEBUG
			cerr << "Copying file: " << DEFAULTMENU << endl;
			#endif // DEBUG
			to<<from.rdbuf(); //copy file

		} else {
			cerr<<"Can't copy default menu file."<<endl;
		}		
	}	

	// should we copy default init file?
	if (createInit) {
		ifstream from(DEFAULT_INITFILE);
		ofstream to(initFile.c_str());

		if (! to.good()) {
			cerr << "Can't open " << initFile.c_str() << "for writing" << endl;
		} else if (from.good()) {
			#ifdef DEBUG
			cerr << "Copying file: " << DEFAULT_INITFILE << endl;
			#endif // DEBUG
			to<<from.rdbuf(); //copy file
		} else {
			cerr<<"Can't copy default init file."<<endl;	
		}
	}
}

void Fluxbox::handleEvent(XEvent * const e) {

	if ((masked == e->xany.window) && masked_window &&
			(e->type == MotionNotify)) {
		last_time = e->xmotion.time;
		masked_window->motionNotifyEvent(&e->xmotion);

		return;
	}
	
	switch (e->type) {
	case ButtonRelease:
	case ButtonPress:
		handleButtonEvent(e->xbutton);
	break;	
	case ConfigureRequest:
	{
		FluxboxWindow *win = (FluxboxWindow *) 0;

#ifdef SLIT
		Slit *slit = (Slit *) 0;
#endif // SLIT
		
		if ((win = searchWindow(e->xconfigurerequest.window))) {
			win->configureRequestEvent(&e->xconfigurerequest);

#ifdef SLIT
		} else if ((slit = searchSlit(e->xconfigurerequest.window))) {
			slit->configureRequestEvent(&e->xconfigurerequest);
#endif // SLIT

		} else {
			grab();

			if (validateWindow(e->xconfigurerequest.window)) {
				XWindowChanges xwc;

				xwc.x = e->xconfigurerequest.x;
				xwc.y = e->xconfigurerequest.y;
				xwc.width = e->xconfigurerequest.width;
				xwc.height = e->xconfigurerequest.height;
				xwc.border_width = e->xconfigurerequest.border_width;
				xwc.sibling = e->xconfigurerequest.above;
				xwc.stack_mode = e->xconfigurerequest.detail;

				XConfigureWindow(getXDisplay(), e->xconfigurerequest.window,
							e->xconfigurerequest.value_mask, &xwc);
			}

			ungrab();
		}

	}
	break;
	case MapRequest:
	{
#ifdef DEBUG
		fprintf(stderr,
			I18n::instance()->
				getMessage(
				FBNLS::blackboxSet, FBNLS::blackboxMapRequest,
				 "Fluxbox::process_event(): MapRequest for 0x%lx\n"),
					e->xmaprequest.window);
#endif // DEBUG
		
#ifdef SLIT
#ifdef KDE
		//Check and see if client is KDE dock applet.
		//If so add to Slit
		bool iskdedockapp = false;
		Atom ajunk;
		int ijunk;
		unsigned long *data = (unsigned long *) 0, uljunk;

		// Check if KDE v2.x dock applet
		if (XGetWindowProperty(getXDisplay(), e->xmaprequest.window,
				getKWM2DockwindowAtom(), 0l, 1l, False,
				XA_WINDOW, &ajunk, &ijunk, &uljunk,
				&uljunk, (unsigned char **) &data) == Success) {
					
			if (data)
				iskdedockapp = True;
			XFree((char *) data);
	
		}

		// Check if KDE v1.x dock applet
		if (!iskdedockapp) {
			if (XGetWindowProperty(getXDisplay(), e->xmaprequest.window,
					getKWM1DockwindowAtom(), 0l, 1l, False,
					getKWM1DockwindowAtom(), &ajunk, &ijunk, &uljunk,
					&uljunk, (unsigned char **) &data) == Success) {
				iskdedockapp = (data && data[0] != 0);
				XFree((char *) data);
			}
		}

		if (iskdedockapp) {
			XSelectInput(getXDisplay(), e->xmaprequest.window, StructureNotifyMask);
			ScreenList::iterator it = screenList.begin();			
			for (; (*it) == screenList.back(); ++it) {
				(*it)->getSlit()->addClient(e->xmaprequest.window);
			}
			return;
		}
#endif //KDE
#endif // SLIT
			
		FluxboxWindow *win = searchWindow(e->xmaprequest.window);

		if (! win) {
			win = new FluxboxWindow(e->xmaprequest.window);
			if (!win->isManaged()) {
				delete win;
				win = 0;				
			} else {
				// attach signals
				attachSignals(*win);
			}
		}

		if ((win = searchWindow(e->xmaprequest.window)))
			win->mapRequestEvent(&e->xmaprequest);

	}
	break;
	case MapNotify:
	{
		FluxboxWindow *win = searchWindow(e->xmap.window);
		if (win != 0)
			win->mapNotifyEvent(&e->xmap);

	}
	break;
	

	case UnmapNotify:
		handleUnmapNotify(e->xunmap);
	break;	
	case CreateNotify:
	break;
	case DestroyNotify: {
			FluxboxWindow *win = (FluxboxWindow *) 0;

#ifdef SLIT
			Slit *slit = 0;
#endif // SLIT

			if ((win = searchWindow(e->xdestroywindow.window))) {
				if (win->destroyNotifyEvent(&e->xdestroywindow)) {
					delete win;
					win = 0;
				}

			} 
#ifdef SLIT
			else if ((slit = searchSlit(e->xdestroywindow.window))) {
				slit->removeClient(e->xdestroywindow.window, false);

			}
#endif // SLIT

		}
	break;
	case MotionNotify: {
			last_time = e->xmotion.time;

			FluxboxWindow *win = 0;
			Basemenu *menu = 0;
			Tab *tab = 0;
			
			if ((win = searchWindow(e->xmotion.window)) !=0)
				win->motionNotifyEvent(&e->xmotion);
			else if ((menu = searchMenu(e->xmotion.window)) !=0)
				menu->motionNotifyEvent(&e->xmotion);
			else if ((tab = searchTab(e->xmotion.window)) !=0)
				tab->motionNotifyEvent(&e->xmotion);
				
			
		}
	break;
	case PropertyNotify: {
			
		last_time = e->xproperty.time;

		if (e->xproperty.state != PropertyDelete) {
			FluxboxWindow *win = searchWindow(e->xproperty.window);

			if (win)
				win->propertyNotifyEvent(e->xproperty.atom);
		}
			
	}
	break;
	case EnterNotify: {
			last_time = e->xcrossing.time;

			BScreen *screen = (BScreen *) 0;
			FluxboxWindow *win = (FluxboxWindow *) 0;
			Basemenu *menu = (Basemenu *) 0;
			Toolbar *tbar = (Toolbar *) 0;
			Tab *tab = (Tab *) 0;
			#ifdef		SLIT
			Slit *slit = (Slit *) 0;
			#endif // SLIT

			if (e->xcrossing.mode == NotifyGrab)
				break;

			XEvent dummy;
			scanargs sa;
			sa.w = e->xcrossing.window;
			sa.enter = sa.leave = False;
			XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa);

			if ((e->xcrossing.window == e->xcrossing.root) &&
					(screen = searchScreen(e->xcrossing.window))) {
				screen->getImageControl()->installRootColormap();
			} else if ((win = searchWindow(e->xcrossing.window))) {
				if ((win->getScreen()->isSloppyFocus() ||
						win->getScreen()->isSemiSloppyFocus()) &&
						(! win->isFocused()) && (! no_focus)) {

					grab();

					if (((! sa.leave) || sa.inferior) && win->isVisible() &&
							win->setInputFocus())
						win->installColormap(True);

					ungrab();
				}
			} else if ((menu = searchMenu(e->xcrossing.window)))
				menu->enterNotifyEvent(&e->xcrossing);
			else if ((tbar = searchToolbar(e->xcrossing.window)))
				tbar->enterNotifyEvent(&e->xcrossing);
			else if ((tab = searchTab(e->xcrossing.window))) {
				win = tab->getWindow();
				if (win->getScreen()->isSloppyFocus() && (! win->isFocused()) &&
						(! no_focus)) {
					win->getScreen()->getWorkspace(win->getWorkspaceNumber())->raiseWindow(win);
					
					grab();

					if (((! sa.leave) || sa.inferior) && win->isVisible() &&
							win->setInputFocus())
						win->installColormap(True);

					ungrab();
				}
			}
				
#ifdef SLIT
			else if ((slit = searchSlit(e->xcrossing.window)))
				slit->enterNotifyEvent(&e->xcrossing);
#endif // SLIT

			
		}
	break;
	case LeaveNotify:
		{
			last_time = e->xcrossing.time;

			FluxboxWindow *win = (FluxboxWindow *) 0;
			Basemenu *menu = (Basemenu *) 0;
			Toolbar *tbar = (Toolbar *) 0;
			
			#ifdef SLIT
			Slit *slit = (Slit *) 0;
			#endif // SLIT

			if ((menu = searchMenu(e->xcrossing.window)))
				menu->leaveNotifyEvent(&e->xcrossing);
			else if ((win = searchWindow(e->xcrossing.window)))
				win->installColormap(False);
			else if ((tbar = searchToolbar(e->xcrossing.window)))
				tbar->leaveNotifyEvent(&e->xcrossing);
			#ifdef SLIT
			else if ((slit = searchSlit(e->xcrossing.window)))
				slit->leaveNotifyEvent(&e->xcrossing);
			#endif // SLIT
			
			
		}
	break;
	case Expose:
		{
			FluxboxWindow *win = (FluxboxWindow *) 0;
			Basemenu *menu = (Basemenu *) 0;
			Toolbar *tbar = (Toolbar *) 0;
			Tab *tab = 0;
			
			if ((win = searchWindow(e->xexpose.window)))
				win->exposeEvent(&e->xexpose);
			else if ((menu = searchMenu(e->xexpose.window)))
				menu->exposeEvent(&e->xexpose);
			else if ((tbar = searchToolbar(e->xexpose.window)))
				tbar->exposeEvent(&e->xexpose);
			else if ((tab = searchTab(e->xexpose.window)))
				tab->exposeEvent(&e->xexpose);
			
		}
	break;
	case KeyPress:
		handleKeyEvent(e->xkey);
	break;
	case ColormapNotify: {
		BScreen *screen = searchScreen(e->xcolormap.window);

		if (screen != 0) {
			screen->setRootColormapInstalled((e->xcolormap.state ==
				ColormapInstalled) ? True : False);
		}
	}
	break;
	case FocusIn: {
		if (e->xfocus.mode == NotifyUngrab ||
				e->xfocus.detail == NotifyPointer)
			break;

		FluxboxWindow *win = searchWindow(e->xfocus.window);
		if (win && ! win->isFocused())
			setFocusedWindow(win);
	
	} break;
	case FocusOut:
	break;
	case ClientMessage:
		handleClientMessage(e->xclient);
	break;
	default: {

		#ifdef SHAPE
		if (e->type == getShapeEventBase()) {
			XShapeEvent *shape_event = (XShapeEvent *) e;
			FluxboxWindow *win = (FluxboxWindow *) 0;

			if ((win = searchWindow(e->xany.window)) ||
					(shape_event->kind != ShapeBounding))
				win->shapeEvent(shape_event);
			}
		#endif // SHAPE

		}
	}
}

void Fluxbox::handleButtonEvent(XButtonEvent &be) {
	switch (be.type) {
	case ButtonPress:
	{
		last_time = be.time;

		FluxboxWindow *win = (FluxboxWindow *) 0;
		Basemenu *menu = (Basemenu *) 0;

#ifdef		SLIT
		Slit *slit = (Slit *) 0;
#endif // SLIT

		Toolbar *tbar = (Toolbar *) 0;			
		Tab *tab = 0;

		if ((win = searchWindow(be.window))) {

			win->buttonPressEvent(&be);
				
			if (be.button == 1)
				win->installColormap(True);
					
		} else if ((menu = searchMenu(be.window))) {
			menu->buttonPressEvent(&be);

#ifdef	SLIT
		} else if ((slit = searchSlit(be.window))) {
			slit->buttonPressEvent(&be);
#endif // SLIT

		} else if ((tbar = searchToolbar(be.window))) {
			tbar->buttonPressEvent(&be);
		} else if ((tab = searchTab(be.window))) {
			tab->buttonPressEvent(&be);
		} else {
			ScreenList::iterator it = screenList.begin();
			ScreenList::iterator it_end = screenList.end();

			for (; it != it_end; ++it) {

				BScreen *screen = *it;
				if (be.window != screen->getRootWindow())
					continue;
				
				
				if (be.button == 1) {
					if (! screen->isRootColormapInstalled())
						screen->getImageControl()->installRootColormap();

					if (screen->getWorkspacemenu()->isVisible())
						screen->getWorkspacemenu()->hide();
					if (screen->getRootmenu()->isVisible())
						screen->getRootmenu()->hide();
						
				} else if (be.button == 2) {
					int mx = be.x_root -
						(screen->getWorkspacemenu()->width() / 2);
					int my = be.y_root -
						(screen->getWorkspacemenu()->titleHeight() / 2);
	
					if (mx < 0) mx = 0;
					if (my < 0) my = 0;

					if (mx + screen->getWorkspacemenu()->width() >
						screen->getWidth()) {
						mx = screen->getWidth() -
							screen->getWorkspacemenu()->width() -						
							screen->getBorderWidth();
					}

					if (my + screen->getWorkspacemenu()->height() >
							screen->getHeight()) {
						my = screen->getHeight() -
							screen->getWorkspacemenu()->height() -
							screen->getBorderWidth();
					}
					screen->getWorkspacemenu()->move(mx, my);

					if (! screen->getWorkspacemenu()->isVisible()) {
						screen->getWorkspacemenu()->removeParent();
						screen->getWorkspacemenu()->show();
					}
				} else if (be.button == 3) { 
				//calculate placement of workspace menu
				//and show/hide it				
					int mx = be.x_root -
						(screen->getRootmenu()->width() / 2);
					int my = be.y_root -
						(screen->getRootmenu()->titleHeight() / 2);

					if (mx < 0) mx = 0;
					if (my < 0) my = 0;

					if (mx + screen->getRootmenu()->width() > screen->getWidth()) {
						mx = screen->getWidth() -
							screen->getRootmenu()->width() -
							screen->getBorderWidth();
					}

					if (my + screen->getRootmenu()->height() >
							screen->getHeight()) {
						my = screen->getHeight() -
							screen->getRootmenu()->height() -
							screen->getBorderWidth();
					}
					screen->getRootmenu()->move(mx, my);

					if (! screen->getRootmenu()->isVisible()) {
						checkMenu();
						screen->getRootmenu()->show();
					}
				} else if (screen->isDesktopWheeling() && be.button == 4) {
					screen->nextWorkspace(1);
				} else if (screen->isDesktopWheeling() && be.button == 5) {
					screen->prevWorkspace(1);
				}
			}
		}
	}

	break;
	case ButtonRelease:
	{
		last_time = be.time;
		FluxboxWindow *win = (FluxboxWindow *) 0;
		Basemenu *menu = (Basemenu *) 0;
		Toolbar *tbar = (Toolbar *) 0;
		Tab *tab = 0;
		
		if ((win = searchWindow(be.window)))
			win->buttonReleaseEvent(&be);
		else if ((menu = searchMenu(be.window)))
			menu->buttonReleaseEvent(&be);
		else if ((tbar = searchToolbar(be.window)))
			tbar->buttonReleaseEvent(&be);
		else if ((tab = searchTab(be.window)))
			tab->buttonReleaseEvent(&be);
	}
	break;	
	default:
	break;
	}
}

void Fluxbox::handleUnmapNotify(XUnmapEvent &ue) {

		
	FluxboxWindow *win = 0;
	
#ifdef SLIT
	Slit *slit = (Slit *) 0;
#endif // SLIT
	BScreen *screen = searchScreen(ue.event);
	
	if ( (ue.event != ue.window) && (screen != 0 || !ue.send_event))
	 	return;
	
	if ((win = searchWindow(ue.window)) != 0) {

		if (win->unmapNotifyEvent(&ue)) {
			delete win;
			if (focused_window == win) // some extra checking
				focused_window = 0;
			win = 0;
		}
  
	}
#ifdef SLIT
	else if ((slit = searchSlit(ue.window))!=0) {
		slit->removeClient(ue.window);
	}
#endif // SLIT

}

//------------ handleClientMessage --------
// Handles XClientMessageEvent
//-----------------------------------------
void Fluxbox::handleClientMessage(XClientMessageEvent &ce) {
#ifdef DEBUG
	cerr<<__FILE__<<"("<<__LINE__<<"): ClientMessage. data.l[0]=0x"<<hex<<ce.data.l[0]<<
	"  message_type=0x"<<ce.message_type<<dec<<endl;
	
#endif // DEBUG

	if (ce.format != 32)
		return;
	
	if (ce.message_type == getWMChangeStateAtom()) {
		FluxboxWindow *win = searchWindow(ce.window);
		if (! win || ! win->validateClient())
			return;

		if (ce.data.l[0] == IconicState)
			win->iconify();
		if (ce.data.l[0] == NormalState)
			win->deiconify();
	} else if (ce.message_type == getFluxboxChangeWorkspaceAtom()) {
		BScreen *screen = searchScreen(ce.window);

		if (screen && ce.data.l[0] >= 0 &&
				ce.data.l[0] < (signed)screen->getCount())
			screen->changeWorkspaceID(ce.data.l[0]);
				
	} else if (ce.message_type == getFluxboxChangeWindowFocusAtom()) {
		FluxboxWindow *win = searchWindow(ce.window);
		if (win && win->isVisible() && win->setInputFocus())
			win->installColormap(True);
	} else if (ce.message_type == getFluxboxCycleWindowFocusAtom()) {
		BScreen *screen = searchScreen(ce.window);

		if (screen) {
			if (! ce.data.l[0])
				screen->prevFocus();
			else
				screen->nextFocus();
		}		
	} else if (ce.message_type == getFluxboxChangeAttributesAtom()) {
		
		FluxboxWindow *win = searchWindow(ce.window);

		if (win && win->validateClient()) {
			BlackboxHints net;
			net.flags = ce.data.l[0];
			net.attrib = ce.data.l[1];
			net.workspace = ce.data.l[2];
			net.stack = ce.data.l[3];
			net.decoration = static_cast<int>(ce.data.l[4]);
			win->changeBlackboxHints(&net);
		}
	} else {
		FluxboxWindow *win = searchWindow(ce.window);
		BScreen *screen = searchScreen(ce.window);
		
		for (size_t i=0; i<m_atomhandler.size(); ++i) {
			m_atomhandler[i]->checkClientMessage(ce, screen, win);
		}
	}
}
//----------- handleKeyEvent ---------------
// Handles KeyRelease and KeyPress events
//------------------------------------------
void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
	switch (ke.type) {
	case KeyPress:
	{
		Toolbar *tbar = searchToolbar(ke.window);
		BScreen *screen = searchScreen(ke.window);
			
		if (tbar && tbar->isEditing())
			tbar->keyPressEvent(&ke);
		else if (screen)	{
			#ifdef DEBUG
			cerr<<"KeyEvent"<<endl;
			#endif
			//find action
			Keys::KeyAction action = key->getAction(&ke);
			#ifdef DEBUG
			const char *actionstr = key->getActionStr(action);
			if (actionstr)
				cerr<<"KeyAction("<<actionstr<<")"<<endl;				
			#endif
			if (action==Keys::LASTKEYGRAB) //if action not found end case
				break;

			// what to allow if moving
			if (focused_window && focused_window->isMoving()) {
				int allowed = false;
				switch (action) {
				case Keys::WORKSPACE:
				case Keys::SENDTOWORKSPACE:
				case Keys::WORKSPACE1:
				case Keys::WORKSPACE2:
				case Keys::WORKSPACE3:
				case Keys::WORKSPACE4:
				case Keys::WORKSPACE5:
				case Keys::WORKSPACE6:
				case Keys::WORKSPACE7:
				case Keys::WORKSPACE8:
				case Keys::WORKSPACE9:
				case Keys::WORKSPACE10:
				case Keys::WORKSPACE11:
				case Keys::WORKSPACE12:
				case Keys::NEXTWORKSPACE:
				case Keys::PREVWORKSPACE:
				case Keys::LEFTWORKSPACE:
				case Keys::RIGHTWORKSPACE:
					allowed = true;
					break;
				default:
					allowed = false;
				}
				if (!allowed) break;
			}

			switch (action) {					
			case Keys::WORKSPACE:
				// Workspace1 has id 0, hence -1
				screen->changeWorkspaceID(key->getParam()-1);
			break;
			case Keys::SENDTOWORKSPACE:
				// Workspace1 has id 0, hence -1
				screen->sendToWorkspace(key->getParam()-1);
			break;
			// NOTE!!! The WORKSPACEn commands are not needed anymore
			case Keys::WORKSPACE1:
				screen->changeWorkspaceID(0);
			break;
			case Keys::WORKSPACE2:
				screen->changeWorkspaceID(1);
			break;
			case Keys::WORKSPACE3:
				screen->changeWorkspaceID(2);
			break;
			case Keys::WORKSPACE4:
				screen->changeWorkspaceID(3);
			break;
			case Keys::WORKSPACE5:
				screen->changeWorkspaceID(4);
			break;
			case Keys::WORKSPACE6:
				screen->changeWorkspaceID(5);
			break;
			case Keys::WORKSPACE7:
				screen->changeWorkspaceID(6);
			break;
			case Keys::WORKSPACE8:
				screen->changeWorkspaceID(7);
			break;
			case Keys::WORKSPACE9:
				screen->changeWorkspaceID(8);
			break;
			case Keys::WORKSPACE10:
				screen->changeWorkspaceID(9);
			break;
			case Keys::WORKSPACE11:
				screen->changeWorkspaceID(10);
			break;
			case Keys::WORKSPACE12:
				screen->changeWorkspaceID(11);
			break;
			case Keys::NEXTWORKSPACE:
				screen->nextWorkspace(key->getParam());
			break;
			case Keys::PREVWORKSPACE:
				screen->prevWorkspace(key->getParam());
			break;
			case Keys::LEFTWORKSPACE:
				screen->leftWorkspace(key->getParam());
			break;
			case Keys::RIGHTWORKSPACE:
				screen->rightWorkspace(key->getParam());
			break;
			case Keys::KILLWINDOW: //kill the current window
				if (focused_window) {
					XKillClient(screen->getBaseDisplay()->getXDisplay(),
						focused_window->getClientWindow());
				}
			break;
			case Keys::NEXTWINDOW:	//activate next window
				screen->nextFocus(key->getParam());
				if (focused_window && focused_window->getTab())
					focused_window->getTab()->raise();
			break;
			case Keys::PREVWINDOW:	//activate prev window
				screen->prevFocus(key->getParam());
				if (focused_window && focused_window->getTab())
					focused_window->getTab()->raise();
			break;
			case Keys::NEXTTAB: 
				if (focused_window && focused_window->getTab()) {
					Tab *tab = focused_window->getTab();
					if (tab->next()) {
						screen->getCurrentWorkspace()->raiseWindow(
							tab->next()->getWindow());
						tab->next()->getWindow()->setInputFocus();
					} else {
						screen->getCurrentWorkspace()->raiseWindow(
							tab->first()->getWindow());
						tab->first()->getWindow()->setInputFocus();
					}	
				}
			break;						
			case Keys::PREVTAB: 
				if (focused_window && focused_window->getTab()) {
					Tab *tab = focused_window->getTab();
					if (tab->prev()) {
						screen->getCurrentWorkspace()->raiseWindow(
							tab->prev()->getWindow());
						tab->prev()->getWindow()->setInputFocus();
					} else {
						screen->getCurrentWorkspace()->raiseWindow(
							tab->last()->getWindow());
						tab->last()->getWindow()->setInputFocus();
					}
				}
			break;
			case Keys::FIRSTTAB:
				if (focused_window && focused_window->getTab()) {
					Tab *tab = focused_window->getTab();
					screen->getCurrentWorkspace()->raiseWindow(
						tab->first()->getWindow());
					tab->first()->getWindow()->setInputFocus();
				}
			break;
			case Keys::LASTTAB:
				if (focused_window && focused_window->getTab()) {
					Tab *tab = focused_window->getTab();
					screen->getCurrentWorkspace()->raiseWindow(
						tab->last()->getWindow());
					tab->last()->getWindow()->setInputFocus();
				}
			break;
			case Keys::MOVETABPREV:
				if (focused_window && focused_window->getTab()) {
					focused_window->getTab()->movePrev();
				}
			break;
			case Keys::MOVETABNEXT:
				if (focused_window && focused_window->getTab()) {
					focused_window->getTab()->moveNext();
				}
			break;
			case Keys::EXECUTE: //execute command on keypress
			{
				#ifndef		__EMX__
				char displaystring[MAXPATHLEN];
				sprintf(displaystring, "DISPLAY=%s",
					DisplayString(getXDisplay()));
				sprintf(displaystring + strlen(displaystring) - 1, "%d",
					screen->getScreenNumber());		
#ifdef DEBUG
				cerr<<__FILE__<<"("<<__LINE__<<"): Executing:"<<key->getExecCommand().c_str()<<endl;
#endif // DEBUG
						
				bexec(key->getExecCommand().c_str(), displaystring);
				#else
				spawnlp(P_NOWAIT, "cmd.exe", "cmd.exe", "/c", item->exec(), NULL);
				#endif // !__EMX__
						
			
			}
			break;
			case Keys::ROOTMENU: //show root menu
			{
				ScreenList::iterator it = screenList.begin();
				ScreenList::iterator it_end = screenList.end();

				for (; it != it_end; ++it) {

					BScreen *screen = (*it);
					if (ke.window != screen->getRootWindow())
						continue;
						
					//calculate placement of workspace menu
					//and show/hide it				
					int mx = ke.x_root -
						(screen->getRootmenu()->width() / 2);
					int my = ke.y_root -
						(screen->getRootmenu()->titleHeight() / 2);

					if (mx < 0) mx = 0;
					if (my < 0) my = 0;

					if (mx + screen->getRootmenu()->width() > screen->getWidth()) {
						mx = screen->getWidth() -
							screen->getRootmenu()->width() -
							screen->getBorderWidth();
					}

					if (my + screen->getRootmenu()->height() >
							screen->getHeight()) {
						my = screen->getHeight() -
							screen->getRootmenu()->height() -
							screen->getBorderWidth();
					}
					screen->getRootmenu()->move(mx, my);

					if (! screen->getRootmenu()->isVisible()) {
						checkMenu();
						screen->getRootmenu()->show();
					}
				}
			}
			break;
			default: //try to see if its a window action
				doWindowAction(action, key->getParam());
			}
		}
	break;
	}
	
	default:
	break;
	}
	
	
}
void Fluxbox::doWindowAction(Keys::KeyAction action, const int param) {
	if (!focused_window)
		return;

	unsigned int t_placement = focused_window->getScreen()->getTabPlacement();
	unsigned int t_alignment = focused_window->getScreen()->getTabAlignment();
	
	switch (action) {
		case Keys::ICONIFY:
			focused_window->iconify();
		break;
		case Keys::RAISE:
			if (focused_window->hasTab())
				focused_window->getTab()->raise(); //raise the tabs if we have any
			focused_window->getScreen()->getWorkspace(focused_window->getWorkspaceNumber())->raiseWindow(focused_window);
		break;
		case Keys::LOWER:
 	   	focused_window->getScreen()->getWorkspace(focused_window->getWorkspaceNumber())->lowerWindow(focused_window);
			if (focused_window->hasTab())
				focused_window->getTab()->lower(); //lower the tabs AND it's windows

		break;
		case Keys::CLOSE:
			focused_window->close();
		break;
		case Keys::SHADE:		
			focused_window->shade(); // this has to be done in THIS order
			if (focused_window->hasTab())
				focused_window->getTab()->shade();
		break;
		case Keys::MAXIMIZE:
			focused_window->maximize(0);
		break;
		case Keys::STICK:
			focused_window->stick();
		break;								
		case Keys::VERTMAX:
			if (focused_window->isResizable())
				focused_window->maximize(2); // maximize vertically, done with mouse2
		break;
		case Keys::HORIZMAX:
			if (focused_window->isResizable())
				focused_window->maximize(3); // maximize horisontally, done with mouse3
		break;
		case Keys::NUDGERIGHT:	
			focused_window->configure(
				focused_window->getXFrame()+param, focused_window->getYFrame(),
				focused_window->getWidth(), focused_window->getHeight());
		break;
		case Keys::NUDGELEFT:			
			focused_window->configure(
				focused_window->getXFrame()-param, focused_window->getYFrame(),
				focused_window->getWidth(), focused_window->getHeight());
		break;
		case Keys::NUDGEUP:
			focused_window->configure(
				focused_window->getXFrame(), focused_window->getYFrame()-param,
				focused_window->getWidth(), focused_window->getHeight());
		break;
		case Keys::NUDGEDOWN:
			focused_window->configure(
				focused_window->getXFrame(), focused_window->getYFrame()+param,
				focused_window->getWidth(), focused_window->getHeight());
		break;
		// NOTE !!! BIGNUDGExxxx is not needed, just use 10 as a parameter
		case Keys::BIGNUDGERIGHT:		
			focused_window->configure(
				focused_window->getXFrame()+10, focused_window->getYFrame(),
				focused_window->getWidth(), focused_window->getHeight());
		break;
		case Keys::BIGNUDGELEFT:						
			focused_window->configure(
				focused_window->getXFrame()-10, focused_window->getYFrame(),
				focused_window->getWidth(), focused_window->getHeight());
		break;
		case Keys::BIGNUDGEUP:								
			focused_window->configure(
				focused_window->getXFrame(), focused_window->getYFrame()-10,
				focused_window->getWidth(), focused_window->getHeight());
		break;								
		case Keys::BIGNUDGEDOWN:					
			focused_window->configure(
				focused_window->getXFrame(), focused_window->getYFrame()+10,
				focused_window->getWidth(), focused_window->getHeight());								
		break;												
		case Keys::HORIZINC:
			if (focused_window->isResizable())
				focused_window->configure(
					focused_window->getXFrame(), focused_window->getYFrame(),
					focused_window->getWidth()+10, focused_window->getHeight());

				if (focused_window->hasTab() &&
						(t_placement == Tab::PTOP || t_placement == Tab::PBOTTOM)) {
					if (t_alignment == Tab::ARELATIVE)
						focused_window->getTab()->calcIncrease();
					if (t_alignment != Tab::PLEFT)
						focused_window->getTab()->setPosition();
				}
		break;								
		case Keys::VERTINC:
			if (focused_window->isResizable())
				focused_window->configure(
					focused_window->getXFrame(), focused_window->getYFrame(),
					focused_window->getWidth(), focused_window->getHeight()+10);

				if (focused_window->hasTab() &&
						(t_placement == Tab::PLEFT || t_placement == Tab::PRIGHT)) {
					if (t_alignment == Tab::ARELATIVE)
						focused_window->getTab()->calcIncrease();
					if (t_alignment != Tab::PRIGHT)
						focused_window->getTab()->setPosition();
				}
		break;
		case Keys::HORIZDEC:				
			if (focused_window->isResizable())
				focused_window->configure(
					focused_window->getXFrame(), focused_window->getYFrame(),
					focused_window->getWidth()-10, focused_window->getHeight());

				if (focused_window->hasTab() &&
						(t_placement == Tab::PTOP || t_placement == Tab::PBOTTOM)) {
					if (t_alignment == Tab::ARELATIVE)
						focused_window->getTab()->calcIncrease();
					if (t_alignment != Tab::PLEFT)
						focused_window->getTab()->setPosition();
				}
		break;								
		case Keys::VERTDEC:
			if (focused_window->isResizable())
				focused_window->configure(
					focused_window->getXFrame(), focused_window->getYFrame(),
					focused_window->getWidth(), focused_window->getHeight()-10);

				if (focused_window->hasTab() &&
						(t_placement == Tab::PLEFT || t_placement == Tab::PRIGHT)) {
					if (t_alignment == Tab::ARELATIVE)
						focused_window->getTab()->calcIncrease();
					if (t_alignment != Tab::PRIGHT)
						focused_window->getTab()->setPosition();
				}
		break;
		case Keys::TOGGLEDECOR:
			focused_window->toggleDecoration();
		break;
		case Keys::TOGGLETAB:
			focused_window->setTab(!focused_window->hasTab());
		break;
		default: //do nothing
		break;							
	}

}

// handle system signals here
void Fluxbox::handleEvent(SignalEvent * const sig) {
	I18n *i18n = I18n::instance();
	static int re_enter = 0;

	switch (sig->signum) {
		case SIGCHLD: // we don't want the child process to kill us
			waitpid(-1, 0, WNOHANG | WUNTRACED);
		break;
		case SIGHUP:
			load_rc();
		break;
		case SIGUSR1:
			reload_rc();
		break;
		case SIGUSR2:
			rereadMenu();
		break;
		case SIGSEGV:
			abort();
		break;
		case SIGFPE:
		case SIGINT:
		case SIGTERM:
			shutdown();
		break;
		default:
			fprintf(stderr,
			i18n->getMessage(
				 FBNLS::BaseDisplaySet, FBNLS::BaseDisplaySignalCaught,
				 "%s:	signal %d caught\n"),
				getApplicationName(), sig);

			if (! isStartup() && ! re_enter) {
				re_enter = 1;
				fprintf(stderr,
					i18n->getMessage(
						FBNLS::BaseDisplaySet, FBNLS::BaseDisplayShuttingDown,
						"shutting down\n"));
				shutdown();
			}

			
			fprintf(stderr,
			i18n->getMessage(
				 FBNLS::BaseDisplaySet, FBNLS::BaseDisplayAborting,
				 "aborting... dumping core\n"));
			abort();
		break;
	}
}


void Fluxbox::update(FbTk::Subject *changedsub) {
//TODO: fix signaling, this does not look good
	if (typeid(*changedsub) == typeid(FluxboxWindow)) {
		FluxboxWindow::WinSubject *winsub = dynamic_cast<FluxboxWindow::WinSubject *>(changedsub);
		FluxboxWindow &win = winsub->win();
		if ((&(win.hintSig())) == changedsub) { // hint signal
#ifdef DEBUG
			cerr<<__FILE__<<"("<<__LINE__<<") WINDOW hint signal from "<<&win<<endl;
#endif // DEBUG
			for (size_t i=0; i<m_atomhandler.size(); ++i) {
				if (m_atomhandler[i]->update())
					m_atomhandler[i]->updateHints(win);
			}
		} else if ((&(win.stateSig())) == changedsub) { // state signal
#ifdef DEBUG
			cerr<<__FILE__<<"("<<__LINE__<<") WINDOW state signal from "<<&win<<endl;
#endif // DEBUG
			for (size_t i=0; i<m_atomhandler.size(); ++i) {
				if (m_atomhandler[i]->update())
					m_atomhandler[i]->updateState(win);
			}
		} else if ((&(win.workspaceSig())) == changedsub) {  // workspace signal
#ifdef DEBUG
			cerr<<__FILE__<<"("<<__LINE__<<") WINDOW workspace signal from "<<&win<<endl;
#endif // DEBUG
			for (size_t i=0; i<m_atomhandler.size(); ++i) {
				if (m_atomhandler[i]->update())
					m_atomhandler[i]->updateWorkspace(win);
			}
		} else {
#ifdef DEBUG
			cerr<<__FILE__<<"("<<__LINE__<<"): WINDOW uncought signal from "<<&win<<endl;
#endif // DEBUG
		}
		
	} else if (typeid(*changedsub) == typeid(BScreen::ScreenSubject)) {
		BScreen::ScreenSubject *subj = dynamic_cast<BScreen::ScreenSubject *>(changedsub);
		BScreen &screen = subj->screen();
		if ((&(screen.workspaceCountSig())) == changedsub) {
#ifdef DEBUG	
			cerr<<__FILE__<<"("<<__LINE__<<"): SCREEN workspace count signal"<<endl;
#endif // DEBUG
			for (size_t i=0; i<m_atomhandler.size(); ++i) {
				if (m_atomhandler[i]->update())
					m_atomhandler[i]->updateWorkspaceCount(screen);
			}
		} else if ((&(screen.workspaceNamesSig())) == changedsub) {
#ifdef DEBUG
			cerr<<__FILE__<<"("<<__LINE__<<"): SCREEN workspace names signal"<<endl;
#endif // DEBUG
			for (size_t i=0; i<m_atomhandler.size(); ++i) {
				if (m_atomhandler[i]->update())
					m_atomhandler[i]->updateWorkspaceNames(screen);
			}
		} else if ((&(screen.currentWorkspaceSig())) == changedsub) {
#ifdef DEBUG
			cerr<<__FILE__<<"("<<__LINE__<<"): SCREEN current workspace signal"<<endl;
#endif // DEBUG	
			for (size_t i=0; i<m_atomhandler.size(); ++i) {
				if (m_atomhandler[i]->update())
					m_atomhandler[i]->updateCurrentWorkspace(screen);
			}
		} else if ((&(screen.clientListSig())) == changedsub) {
#ifdef DEBUG
			cerr<<__FILE__<<"("<<__LINE__<<"): SCREEN client list signal"<<endl;
#endif // DEBUG
			for (size_t i=0; i<m_atomhandler.size(); ++i) {
				if (m_atomhandler[i]->update())
					m_atomhandler[i]->updateClientList(screen);
			}
		}
	}
}

void Fluxbox::attachSignals(FluxboxWindow &win) {
	win.hintSig().attach(this);
	win.stateSig().attach(this);
	win.workspaceSig().attach(this);
	for (size_t i=0; i<m_atomhandler.size(); ++i) {
		m_atomhandler[i]->setupWindow(win);
	}
}

BScreen *Fluxbox::searchScreen(Window window) {
	BScreen *screen = (BScreen *) 0;
	ScreenList::iterator it = screenList.begin();
	ScreenList::iterator it_end = screenList.end();

	for (; it != it_end; ++it) {
		if (*it) {
			if ((*it)->getRootWindow() == window) {
				screen = (*it);
				return screen;
			}
		}
	}

	return (BScreen *) 0;
}


FluxboxWindow *Fluxbox::searchWindow(Window window) {
	std::map<Window, FluxboxWindow *>::iterator it = windowSearch.find(window);
	return it == windowSearch.end() ? 0 : it->second;
}


FluxboxWindow *Fluxbox::searchGroup(Window window, FluxboxWindow *win) {
	std::map<Window, FluxboxWindow *>::iterator it = groupSearch.find(window);
	return it == groupSearch.end() ? 0 : it->second;
}


Basemenu *Fluxbox::searchMenu(Window window) {
	std::map<Window, Basemenu *>::iterator it = menuSearch.find(window);
	return it == menuSearch.end() ? 0 : it->second;
}


Toolbar *Fluxbox::searchToolbar(Window window) {
	std::map<Window, Toolbar *>::iterator it = toolbarSearch.find(window);
	return it == toolbarSearch.end() ? 0 : it->second;
}

Tab *Fluxbox::searchTab(Window window) {
	std::map<Window, Tab *>::iterator it = tabSearch.find(window);
	return it == tabSearch.end() ? 0 : it->second;
}


#ifdef		SLIT
Slit *Fluxbox::searchSlit(Window window) {
	std::map<Window, Slit *>::iterator it = slitSearch.find(window);
	return it == slitSearch.end() ? 0 : it->second;
}
#endif // SLIT


void Fluxbox::saveWindowSearch(Window window, FluxboxWindow *data) {
	windowSearch[window] = data;
}


void Fluxbox::saveGroupSearch(Window window, FluxboxWindow *data) {
	groupSearch[window] = data;
}


void Fluxbox::saveMenuSearch(Window window, Basemenu *data) {
	menuSearch[window] = data;
}


void Fluxbox::saveToolbarSearch(Window window, Toolbar *data) {
	toolbarSearch[window] = data;
}


void Fluxbox::saveTabSearch(Window window, Tab *data) {
	tabSearch[window] = data;
}

#ifdef SLIT
void Fluxbox::saveSlitSearch(Window window, Slit *data) {
	slitSearch[window] = data;
}
#endif // SLIT


void Fluxbox::removeWindowSearch(Window window) {
	windowSearch.erase(window);
}


void Fluxbox::removeGroupSearch(Window window) {
	groupSearch.erase(window);
}

void Fluxbox::removeMenuSearch(Window window) {
	menuSearch.erase(window);
}

void Fluxbox::removeToolbarSearch(Window window) {
	toolbarSearch.erase(window);
}


void Fluxbox::removeTabSearch(Window window) {
	tabSearch.erase(window);
}

#ifdef		SLIT
void Fluxbox::removeSlitSearch(Window window) {
	slitSearch.erase(window);
}
#endif // SLIT


void Fluxbox::restart(const char *prog) {
	shutdown();

	if (prog) {
		execlp(prog, prog, NULL);
		perror(prog);
	}

	// fall back in case the above execlp doesn't work
	execvp(argv[0], argv);
	execvp(basename(argv[0]), argv);
}


void Fluxbox::shutdown() {
	BaseDisplay::shutdown();

	XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime);

	//send shutdown to all screens
	ScreenList::iterator it = screenList.begin();
	ScreenList::iterator it_end = screenList.end();
	for (; it != it_end; ++it) {
		if(*it)
			(*it)->shutdown();
	}

	XSync(getXDisplay(), False);

}

//------ save_rc --------
//saves resources
//----------------------
void Fluxbox::save_rc() {

	XrmDatabase new_blackboxrc = 0;
	
	char rc_string[1024];

	string dbfile(getRcFilename());
	
	if (dbfile.size() != 0) {
		m_resourcemanager.save(dbfile.c_str(), dbfile.c_str());
		m_screen_rm.save(dbfile.c_str(), dbfile.c_str());
	} else
		cerr<<"database filename is invalid!"<<endl;
	

	sprintf(rc_string, "session.doubleClickInterval:	%lu",
					resource.double_click_interval);
	XrmPutLineResource(&new_blackboxrc, rc_string);

	sprintf(rc_string, "session.autoRaiseDelay:	%lu",
					((resource.auto_raise_delay.tv_sec * 1000) +
					(resource.auto_raise_delay.tv_usec / 1000)));
	XrmPutLineResource(&new_blackboxrc, rc_string);

	ScreenList::iterator it = screenList.begin();
	ScreenList::iterator it_end = screenList.end();

	//Save screen resources

	for (; it != it_end; ++it) {
		BScreen *screen = *it;
		int screen_number = screen->getScreenNumber();

		#ifdef SLIT
		string slit_placement;

		switch (screen->getSlitPlacement()) {
		case Slit::TOPLEFT: slit_placement = "TopLeft"; break;
		case Slit::CENTERLEFT: slit_placement = "CenterLeft"; break;
		case Slit::BOTTOMLEFT: slit_placement = "BottomLeft"; break;
		case Slit::TOPCENTER: slit_placement = "TopCenter"; break;
		case Slit::BOTTOMCENTER: slit_placement = "BottomCenter"; break;
		case Slit::TOPRIGHT: slit_placement = "TopRight"; break;
		case Slit::BOTTOMRIGHT: slit_placement = "BottomRight"; break;
		case Slit::CENTERRIGHT: default: slit_placement = "CenterRight"; break;
		}

		sprintf(rc_string, "session.screen%d.slit.placement: %s", screen_number,
			slit_placement.c_str());
		XrmPutLineResource(&new_blackboxrc, rc_string);

		sprintf(rc_string, "session.screen%d.slit.direction: %s", screen_number,
			((screen->getSlitDirection() == Slit::HORIZONTAL) ? "Horizontal" :
			"Vertical"));
		XrmPutLineResource(&new_blackboxrc, rc_string);

		sprintf(rc_string, "session.screen%d.slit.onTop: %s", screen_number,
			((screen->getSlit()->isOnTop()) ? "True" : "False"));
		XrmPutLineResource(&new_blackboxrc, rc_string);

		sprintf(rc_string, "session.screen%d.slit.autoHide: %s", screen_number,
			((screen->getSlit()->doAutoHide()) ? "True" : "False"));
		XrmPutLineResource(&new_blackboxrc, rc_string);

		#ifdef XINERAMA
		sprintf(rc_string, "session.screen%d.slit.onHead: %d", screen_number,
			screen->getSlitOnHead());
		XrmPutLineResource(&new_blackboxrc, rc_string);
		#endif // XINERAMA

		#endif // SLIT

		sprintf(rc_string, "session.screen%d.rowPlacementDirection: %s", screen_number,
			((screen->getRowPlacementDirection() == BScreen::LEFTRIGHT) ?
				"LeftToRight" : "RightToLeft"));
		XrmPutLineResource(&new_blackboxrc, rc_string);

		sprintf(rc_string, "session.screen%d.colPlacementDirection: %s", screen_number,
			((screen->getColPlacementDirection() == BScreen::TOPBOTTOM) ?
			"TopToBottom" : "BottomToTop"));
		XrmPutLineResource(&new_blackboxrc, rc_string);

		string placement;
		
		switch (screen->getPlacementPolicy()) {
		case BScreen::CASCADEPLACEMENT:
			placement = "CascadePlacement";
			break;

		case BScreen::COLSMARTPLACEMENT:
			placement = "ColSmartPlacement";
			break;

		default:
		case BScreen::ROWSMARTPLACEMENT:
			placement = "RowSmartPlacement";
			break;
		}
		
		sprintf(rc_string, "session.screen%d.windowPlacement: %s", screen_number,
			placement.c_str());
		XrmPutLineResource(&new_blackboxrc, rc_string);

		std::string focus_mode;
		if (screen->isSloppyFocus() && screen->doAutoRaise())
			focus_mode = "AutoRaiseSloppyFocus";
		else if (screen->isSloppyFocus())
			focus_mode = "SloppyFocus";
		else if (screen->isSemiSloppyFocus() && screen->doAutoRaise())
			focus_mode = "AutoRaiseSemiSloppyFocus";
		else if (screen->isSemiSloppyFocus())
			focus_mode = "SemiSloppyFocus";	
		else
			focus_mode = "ClickToFocus";

		sprintf(rc_string, "session.screen%d.focusModel: %s", screen_number,
			focus_mode.c_str());
		XrmPutLineResource(&new_blackboxrc, rc_string);

//		load_rc(screen);
		// these are static, but may not be saved in the users resource file,
		// writing these resources will allow the user to edit them at a later
		// time... but loading the defaults before saving allows us to rewrite the
		// users changes...

#ifdef		HAVE_STRFTIME
		sprintf(rc_string, "session.screen%d.strftimeFormat: %s", screen_number,
			screen->getStrftimeFormat());
		XrmPutLineResource(&new_blackboxrc, rc_string);
#else // !HAVE_STRFTIME
		sprintf(rc_string, "session.screen%d.dateFormat:	%s", screen_number,
			((screen->getDateFormat() == B_EuropeanDate) ?
				"European" : "American"));
		XrmPutLineResource(&new_blackboxrc, rc_string);

		sprintf(rc_string, "session.screen%d.clockFormat:	%d", screen_number,
			((screen->isClock24Hour()) ? 24 : 12));
		XrmPutLineResource(&new_blackboxrc, rc_string);
#endif // HAVE_STRFTIME

		// write out the users workspace names
		sprintf(rc_string, "session.screen%d.workspaceNames: ", screen_number);
		string workspaces_string(rc_string);

		for (unsigned int workspace=0; workspace < screen->getCount(); workspace++) {
			if (screen->getWorkspace(workspace)->name().size()!=0)
				workspaces_string.append(screen->getWorkspace(workspace)->name());
			else
				workspaces_string.append("Null");
			workspaces_string.append(",");
		}

		XrmPutLineResource(&new_blackboxrc, workspaces_string.c_str());
	
	}

	XrmDatabase old_blackboxrc = XrmGetFileDatabase(dbfile.c_str());

	XrmMergeDatabases(new_blackboxrc, &old_blackboxrc); //merge database together
	XrmPutFileDatabase(old_blackboxrc, dbfile.c_str());
	XrmDestroyDatabase(old_blackboxrc);
#ifdef DEBUG
	cerr<<__FILE__<<"("<<__LINE__<<"): ------------ SAVING DONE"<<endl;	
#endif // DEBUG
}

//-------- getRcFilename -------------
// Returns filename of resource file
//------------------------------------
string Fluxbox::getRcFilename() {
 
	if (rc_file.size() == 0) { // set default filename
		string defaultfile(getenv("HOME")+string("/.")+RC_PATH+string("/")+RC_INIT_FILE);
		return defaultfile;
	}

	return rc_file;
}

//-------- getDefaultDataFilename -------------
// Provides default filename of data file
//---------------------------------------------
void Fluxbox::getDefaultDataFilename(char *name, string &filename) {
	filename = string(getenv("HOME")+string("/.")+RC_PATH+string("/")+name);
}

void Fluxbox::load_rc() {
	XrmDatabaseHelper database;
	
	//get resource filename
	string dbfile(getRcFilename());

	if (dbfile.size() != 0) {
		if (!m_resourcemanager.load(dbfile.c_str())) {
			cerr<<"Faild to load database:"<<dbfile<<endl;
			cerr<<"Trying with: "<<DEFAULT_INITFILE<<endl;
			if (!m_resourcemanager.load(DEFAULT_INITFILE))
				cerr<<"Faild to load database: "<<DEFAULT_INITFILE<<endl;
		}
	} else {
		if (!m_resourcemanager.load(DEFAULT_INITFILE))
			cerr<<"Faild to load database: "<<DEFAULT_INITFILE<<endl;
	}
	
	XrmValue value;
	char *value_type;

	if (m_rc_menufile->size()) {
		*m_rc_menufile = StringUtil::expandFilename(*m_rc_menufile);
		if (!m_rc_menufile->size())
			m_rc_menufile.setDefaultValue();
	} else
		m_rc_menufile.setDefaultValue();
 
 	if (m_rc_slitlistfile->size() != 0) {
 		*m_rc_slitlistfile = StringUtil::expandFilename(*m_rc_slitlistfile);
 	} else {
 		string filename;
 		getDefaultDataFilename("slitlist", filename);
 		m_rc_slitlistfile.setFromString(filename.c_str());
 	}

	if (*m_rc_colors_per_channel < 2)
		*m_rc_colors_per_channel = 2;
	else if (*m_rc_colors_per_channel > 6)
		*m_rc_colors_per_channel = 6;

	if (m_rc_stylefile->size() == 0)
		*m_rc_stylefile = DEFAULTSTYLE;
	else // expand tilde
		*m_rc_stylefile = StringUtil::expandFilename(*m_rc_stylefile);

	//load file
	database = XrmGetFileDatabase(dbfile.c_str());
	if (database==0) {
		cerr<<"Fluxbox: Cant open "<<dbfile<<" !"<<endl;
		cerr<<"Using: "<<DEFAULT_INITFILE<<endl;
		database = XrmGetFileDatabase(DEFAULT_INITFILE);
	}

	if (XrmGetResource(*database, "session.doubleClickInterval",
				"Session.DoubleClickInterval", &value_type, &value)) {
		if (sscanf(value.addr, "%lu", &resource.double_click_interval) != 1)
			resource.double_click_interval = 250;
	} else
		resource.double_click_interval = 250;

	if (XrmGetResource(*database, "session.autoRaiseDelay", "Session.AutoRaiseDelay", 
			&value_type, &value)) {
		if (sscanf(value.addr, "%lu", &resource.auto_raise_delay.tv_usec) != 1)
			resource.auto_raise_delay.tv_usec = 250;
	} else
		resource.auto_raise_delay.tv_usec = 250;

	resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000;
	resource.auto_raise_delay.tv_usec -=
		(resource.auto_raise_delay.tv_sec * 1000);
	resource.auto_raise_delay.tv_usec *= 1000;

	// expand tilde
	*m_rc_groupfile = StringUtil::expandFilename(*m_rc_groupfile);

#ifdef DEBUG
	cerr<<__FILE__<<": Loading groups ("<<*m_rc_groupfile<<")"<<endl;
#endif // DEBUG
	if (!Workspace::loadGroups(*m_rc_groupfile)) {
		cerr<<"Faild to load groupfile: "<<*m_rc_groupfile<<endl;
	}
}

void Fluxbox::load_rc(BScreen *screen) {
	//get resource filename
	string dbfile(getRcFilename());
	if (dbfile.size() != 0) {
		if (!m_screen_rm.load(dbfile.c_str())) {
			cerr<<"Faild to load database:"<<dbfile<<endl;
			cerr<<"Trying with: "<<DEFAULT_INITFILE<<endl;
			if (!m_screen_rm.load(DEFAULT_INITFILE))
				cerr<<"Faild to load database: "<<DEFAULT_INITFILE<<endl;
		}
	} else {
		if (!m_screen_rm.load(DEFAULT_INITFILE))
			cerr<<"Faild to load database: "<<DEFAULT_INITFILE<<endl;
	}
	
	XrmDatabaseHelper database;

	database = XrmGetFileDatabase(dbfile.c_str());
	if (database==0)
		database = XrmGetFileDatabase(DEFAULT_INITFILE);
		
	XrmValue value;
	char *value_type, name_lookup[1024], class_lookup[1024];
	int screen_number = screen->getScreenNumber();

	sprintf(name_lookup, "session.screen%d.rowPlacementDirection", screen_number);
	sprintf(class_lookup, "Session.Screen%d.RowPlacementDirection", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		if (! strncasecmp(value.addr, "righttoleft", value.size))
			screen->saveRowPlacementDirection(BScreen::RIGHTLEFT);
		else	
			screen->saveRowPlacementDirection(BScreen::LEFTRIGHT);
	} else
		screen->saveRowPlacementDirection(BScreen::LEFTRIGHT);

	sprintf(name_lookup, "session.screen%d.colPlacementDirection", screen_number);
	sprintf(class_lookup, "Session.Screen%d.ColPlacementDirection", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		if (! strncasecmp(value.addr, "bottomtotop", value.size))
			screen->saveColPlacementDirection(BScreen::BOTTOMTOP);
		else
			screen->saveColPlacementDirection(BScreen::TOPBOTTOM);
	} else
		screen->saveColPlacementDirection(BScreen::TOPBOTTOM);

	screen->removeWorkspaceNames();

	sprintf(name_lookup, "session.screen%d.workspaceNames", screen_number);
	sprintf(class_lookup, "Session.Screen%d.WorkspaceNames", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
#ifdef DEBUG
		cerr<<__FILE__<<"("<<__LINE__<<"): Workspaces="<<screen->getNumberOfWorkspaces()<<endl;
#endif // DEBUG
		char *search = StringUtil::strdup(value.addr);

		int i;
		for (i = 0; i < screen->getNumberOfWorkspaces(); i++) {
			char *nn;

			if (! i) nn = strtok(search, ",");
			else nn = strtok(0, ",");

			if (nn)
				screen->addWorkspaceName(nn);	
			else break;
			
		}

		delete [] search;
	}

	sprintf(name_lookup, "session.screen%d.focusModel", screen_number);
	sprintf(class_lookup, "Session.Screen%d.FocusModel", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		if (! strncasecmp(value.addr, "clicktofocus", value.size)) {
			screen->saveAutoRaise(false);
			screen->saveSloppyFocus(false);
			screen->saveSemiSloppyFocus(false);

		} else if (! strncasecmp(value.addr, "autoraisesloppyfocus", value.size)) {
			screen->saveSemiSloppyFocus(false);
			screen->saveSloppyFocus(true);
			screen->saveAutoRaise(true);
		} else if (! strncasecmp(value.addr, "autoraisesemisloppyfocus", value.size)) {
			screen->saveSloppyFocus(false);
			screen->saveSemiSloppyFocus(true);
			screen->saveAutoRaise(true);

		} else if (! strncasecmp(value.addr, "semisloppyfocus", value.size)) {
			screen->saveSloppyFocus(false);
			screen->saveSemiSloppyFocus(true);
			screen->saveAutoRaise(false);

		} else {

			screen->saveSemiSloppyFocus(false);	
			screen->saveSloppyFocus(true);
			screen->saveAutoRaise(false);
		}
	} else {
		screen->saveSemiSloppyFocus(false);
		screen->saveSloppyFocus(true); 
		screen->saveAutoRaise(false);
	}

	sprintf(name_lookup, "session.screen%d.windowPlacement", screen_number);
	sprintf(class_lookup, "Session.Screen%d.WindowPlacement", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		if (! strncasecmp(value.addr, "RowSmartPlacement", value.size))
			screen->savePlacementPolicy(BScreen::ROWSMARTPLACEMENT);
		else if (! strncasecmp(value.addr, "ColSmartPlacement", value.size))
			screen->savePlacementPolicy(BScreen::COLSMARTPLACEMENT);
		else
			screen->savePlacementPolicy(BScreen::CASCADEPLACEMENT);
	} else
		screen->savePlacementPolicy(BScreen::ROWSMARTPLACEMENT);

#ifdef SLIT
	sprintf(name_lookup, "session.screen%d.slit.placement", screen_number);
	sprintf(class_lookup, "Session.Screen%d.Slit.Placement", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		if (! strncasecmp(value.addr, "TopLeft", value.size))
			screen->saveSlitPlacement(Slit::TOPLEFT);
		else if (! strncasecmp(value.addr, "CenterLeft", value.size))
			screen->saveSlitPlacement(Slit::CENTERLEFT);
		else if (! strncasecmp(value.addr, "BottomLeft", value.size))
			screen->saveSlitPlacement(Slit::BOTTOMLEFT);
		else if (! strncasecmp(value.addr, "TopCenter", value.size))
			screen->saveSlitPlacement(Slit::TOPCENTER);
		else if (! strncasecmp(value.addr, "BottomCenter", value.size))
			screen->saveSlitPlacement(Slit::BOTTOMCENTER);
		else if (! strncasecmp(value.addr, "TopRight", value.size))
			screen->saveSlitPlacement(Slit::TOPRIGHT);
		else if (! strncasecmp(value.addr, "BottomRight", value.size))
			screen->saveSlitPlacement(Slit::BOTTOMRIGHT);
		else
			screen->saveSlitPlacement(Slit::CENTERRIGHT);
	} else
		screen->saveSlitPlacement(Slit::CENTERRIGHT);

	sprintf(name_lookup, "session.screen%d.slit.direction", screen_number);
	sprintf(class_lookup, "Session.Screen%d.Slit.Direction", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		if (! strncasecmp(value.addr, "Horizontal", value.size))
			screen->saveSlitDirection(Slit::HORIZONTAL);
		else
			screen->saveSlitDirection(Slit::VERTICAL);
	} else
		screen->saveSlitDirection(Slit::VERTICAL);

	sprintf(name_lookup, "session.screen%d.slit.onTop", screen_number);
	sprintf(class_lookup, "Session.Screen%d.Slit.OnTop", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		if (! strncasecmp(value.addr, "True", value.size))
			screen->saveSlitOnTop(True);
		else
			screen->saveSlitOnTop(False);
	} else
		screen->saveSlitOnTop(False);

	sprintf(name_lookup, "session.screen%d.slit.autoHide", screen_number);
	sprintf(class_lookup, "Session.Screen%d.Slit.AutoHide", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		if (! strncasecmp(value.addr, "True", value.size))
			screen->saveSlitAutoHide(True);
		else
			screen->saveSlitAutoHide(False);
	} else
		screen->saveSlitAutoHide(False);

	#ifdef XINERAMA
	int tmp_head;
	sprintf(name_lookup, "session.screen%d.slit.onHead", screen_number);
	sprintf(class_lookup, "Session.Screen%d.Slit.OnHead", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		if (sscanf(value.addr, "%d", &tmp_head) != 1)
			tmp_head = 0;
	} else
		tmp_head = 0;
	screen->saveSlitOnHead(tmp_head);
	#endif // XINERAMA

#endif // SLIT

#ifdef HAVE_STRFTIME
	sprintf(name_lookup, "session.screen%d.strftimeFormat", screen_number);
	sprintf(class_lookup, "Session.Screen%d.StrftimeFormat", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value))
		screen->saveStrftimeFormat(value.addr);
	else
		screen->saveStrftimeFormat("%I:%M %p");
#else //	HAVE_STRFTIME

	sprintf(name_lookup, "session.screen%d.dateFormat", screen_number);
	sprintf(class_lookup, "Session.Screen%d.DateFormat", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		if (strncasecmp(value.addr, "european", value.size))
			screen->saveDateFormat(B_AmericanDate);
		else
			screen->saveDateFormat(B_EuropeanDate);
	} else
		screen->saveDateFormat(B_AmericanDate);

	sprintf(name_lookup, "session.screen%d.clockFormat", screen_number);
	sprintf(class_lookup, "Session.Screen%d.ClockFormat", screen_number);
	if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
			&value)) {
		int clock;
		if (sscanf(value.addr, "%d", &clock) != 1)
			screen->saveClock24Hour(False);
		else if (clock == 24) 
			screen->saveClock24Hour(True);
		else 
			screen->saveClock24Hour(False);
	} else
		screen->saveClock24Hour(False);
#endif // HAVE_STRFTIME

	//check size on toolbarwidth percent	
	if (screen->getToolbarWidthPercent() <= 0 || 
			screen->getToolbarWidthPercent() > 100)
		screen->saveToolbarWidthPercent(66);

	if (screen->getTabWidth()>512)
		screen->saveTabWidth(512);
	else if (screen->getTabWidth()<0)
		screen->saveTabWidth(64);
	
	if (screen->getTabHeight()>512)
		screen->saveTabHeight(512);
	else if (screen->getTabHeight()<0)
		screen->saveTabHeight(5);
}

void Fluxbox::loadRootCommand(BScreen *screen)	{
	XrmDatabase database = (XrmDatabase) 0;
 
	string dbfile(getRcFilename());

	database = XrmGetFileDatabase(dbfile.c_str());
	if (!database) 
		database = XrmGetFileDatabase(DEFAULT_INITFILE);

	XrmValue value;
	char *value_type, name_lookup[1024], class_lookup[1024];
	sprintf(name_lookup, "session.screen%d.rootCommand", screen->getScreenNumber());
	sprintf(class_lookup, "Session.Screen%d.RootCommand", screen->getScreenNumber());
	if (XrmGetResource(database, name_lookup, class_lookup, &value_type,
			&value)) {										 
		screen->saveRootCommand(value.addr==0 ? "": value.addr);
	} else
		screen->saveRootCommand("");		
	
}

void Fluxbox::reload_rc() {
	load_rc();
	reconfigure();
}


void Fluxbox::reconfigure() {
	reconfigure_wait = true;

	if (! timer.isTiming()) 
		timer.start();
}


void Fluxbox::real_reconfigure() {

	XrmDatabase new_blackboxrc = (XrmDatabase) 0;

	string dbfile(getRcFilename());
	XrmDatabase old_blackboxrc = XrmGetFileDatabase(dbfile.c_str());

	XrmMergeDatabases(new_blackboxrc, &old_blackboxrc);
	XrmPutFileDatabase(old_blackboxrc, dbfile.c_str());
	
	if (old_blackboxrc)
		XrmDestroyDatabase(old_blackboxrc);

	std::list<MenuTimestamp *>::iterator it = menuTimestamps.begin();
	std::list<MenuTimestamp *>::iterator it_end = menuTimestamps.end();
	for (; it != it_end; ++it) {
		MenuTimestamp *ts = *it;

		if (ts) {
			if (ts->filename)
				delete [] ts->filename;

			delete ts;
		}
	}
	menuTimestamps.erase(menuTimestamps.begin(), menuTimestamps.end());

	ScreenList::iterator sit = screenList.begin();
	ScreenList::iterator sit_end = screenList.end();
	for (; sit != sit_end; ++sit)
		(*sit)->reconfigure();
	
	//reconfigure keys
	key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str());

	//reconfigure tabs
	reconfigureTabs();

}

//------------- reconfigureTabs ----------
// Reconfigure all tabs size and increase steps
// ---------------------------------------
void Fluxbox::reconfigureTabs() {
	//tab reconfiguring
	TabList::iterator it = tabSearch.begin();
	TabList::iterator it_end = tabSearch.end();
	//setting all to unconfigured
	for (; it != it_end; ++it) {
		it->second->setConfigured(false);
	}
	it = tabSearch.begin(); // resetting list and start configure tabs
	//reconfiguring
	for (; it != it_end; ++it) {
		Tab *tab = it->second;
		if (!tab->configured()) {
			tab->setConfigured(true);
			tab->resizeGroup(); 
			tab->calcIncrease();
			tab->setPosition();
		}
	}
}

void Fluxbox::checkMenu() {
	Bool reread = False;
	std::list<MenuTimestamp *>::iterator it = menuTimestamps.begin();
	std::list<MenuTimestamp *>::iterator it_end = menuTimestamps.end();
	for (; it != it_end && (! reread); ++it) {
		struct stat buf;

		if (! stat((*it)->filename, &buf)) {
			if ((*it)->timestamp != buf.st_ctime)
				reread = True;
		} else
			reread = True;
	}

	if (reread) rereadMenu();
}


void Fluxbox::rereadMenu() {
	reread_menu_wait = True;

	if (! timer.isTiming()) timer.start();
}


void Fluxbox::real_rereadMenu() {
	std::list<MenuTimestamp *>::iterator it = menuTimestamps.begin();
	std::list<MenuTimestamp *>::iterator it_end = menuTimestamps.end();
	for (; it != it_end; ++it) {
		MenuTimestamp *ts = *it;

		if (ts) {
			if (ts->filename)
				delete [] ts->filename;

			delete ts;
		}
	}
	menuTimestamps.erase(menuTimestamps.begin(), menuTimestamps.end());

	ScreenList::iterator sit = screenList.begin();
	ScreenList::iterator sit_end = screenList.end();
	for (; sit != sit_end; ++sit) {
		(*sit)->rereadMenu();
	}
}

void Fluxbox::saveMenuFilename(const char *filename) {
	Bool found = False;

	std::list<MenuTimestamp *>::iterator it = menuTimestamps.begin();
	std::list<MenuTimestamp *>::iterator it_end = menuTimestamps.end();
	for (; it != it_end; ++it) {
		if (! strcmp((*it)->filename, filename)) found = True;
	}

	if (! found) {
		struct stat buf;

		if (! stat(filename, &buf)) {
			MenuTimestamp *ts = new MenuTimestamp;

			ts->filename = StringUtil::strdup(filename);
			ts->timestamp = buf.st_ctime;

			menuTimestamps.push_back(ts);
		}
	}
}


void Fluxbox::timeout() {
	if (reconfigure_wait)
		real_reconfigure();

	if (reread_menu_wait)
		real_rereadMenu();

	reconfigure_wait = reread_menu_wait = false;
}

// set focused window
void Fluxbox::setFocusedWindow(FluxboxWindow *win) {
	BScreen *old_screen = 0, *screen = 0;
	FluxboxWindow *old_win = 0;
	Toolbar *old_tbar = 0, *tbar = 0;
	Workspace *old_wkspc = 0, *wkspc = 0;

	if (focused_window != 0) {
		old_win = focused_window;
		old_screen = old_win->getScreen();
		
		old_tbar = old_screen->getToolbar();
		old_wkspc = old_screen->getWorkspace(old_win->getWorkspaceNumber());

		old_win->setFocusFlag(False);
		old_wkspc->menu().setItemSelected(old_win->getWindowNumber(), false);
		
	}

	if (win && ! win->isIconic()) {
		// make sure we have a valid win pointer with a valid screen
		ScreenList::iterator winscreen = 
			std::find(screenList.begin(), screenList.end(),
				win->getScreen());
		if (winscreen == screenList.end()) {
			focused_window = 0; // the window pointer wasn't valid, mark no window focused
		} else {
			screen = *winscreen;
			tbar = screen->getToolbar();
			wkspc = screen->getWorkspace(win->getWorkspaceNumber());		
			focused_window = win;     // update focused window
			win->setFocusFlag(True); // set focus flag
			// select this window in workspace menu
			wkspc->menu().setItemSelected(win->getWindowNumber(), true);
		}
	} else
		focused_window = 0;

	if (tbar != 0)
		tbar->redrawWindowLabel(True);
	if (screen != 0)
		screen->updateNetizenWindowFocus();

	if (old_tbar && old_tbar != tbar)
		old_tbar->redrawWindowLabel(True);
	if (old_screen && old_screen != screen)
		old_screen->updateNetizenWindowFocus();

}