/////////////////////////////////////////////
// NovaWM - Nova Window Manager for X11    //
/////////////////////////////////////////////
// By: Tim Walters                         //
/////////////////////////////////////////////
// Copyright (C) 2001-2002 Tim Walters     //
/////////////////////////////////////////////

////////////////////////////////////////////////////////////////
//This code is released under the terms of the GNU GPL. Refer //
//to the license file included with this source code.         //
////////////////////////////////////////////////////////////////


#include "novawm.h"

WinMgr::WinMgr ()
{
	focusWindow = 0;
	cDesktop = 1;
}

WinMgr::~WinMgr ()
{
}

Novawm_Window::Novawm_Window ()
{
	window = 0;
	titlebar = 0;
	kill = 0;
	stretch = 0;
	hide = 0;
//	tChild = 0;
//      title = "Unnamed";

	ignoreTransient = false;

	nTChildren = 0;

	desktop = winmgr.cDesktop;

	hasTitlebar = true;
	isTransient = false;

	size_hints = 0;

	isSticky = false;

#ifdef _WIN_GNOME_SUPPORT
	layer = WIN_LAYER_NORMAL;
#else
	layer = 0;
#endif

	isShaded = false;

}

Novawm_Window::~Novawm_Window ()
{
}

void
WinMgr::NewWindow (Window x11_window)
{
#ifdef DEBUG
	printf ("DEBUG: NewWindow()\n");
#endif

	XWindowAttributes win_attrib;
	XSetWindowAttributes set_attrib;
	long dummy;
	char *name;		// = (char *) malloc(1027);
	unsigned long udummy;
	Atom adummy;
	int idummy;

	MotifHints *motif_hints = NULL;

	Window tranWin = None;

	XGetWindowAttributes (display, x11_window, &win_attrib);

	XGrabServer (display);

	if (win_attrib.override_redirect == true)
	{
#ifdef DEBUG
		printf ("DEBUG: override_redirect == true\n");
#endif
		XUnmapWindow (display, x11_window);
		AddUnmapIgnore (x11_window);	//unmapignore++;
		XUngrabServer (display);
		return;
	}

	Novawm_Window *win = new Novawm_Window;

/*	XTextProperty *tprop;
	
	if(!XGetWMName(display,x11_window,tprop))
	{
#ifdef DEBUG
		printf("DEBUG: XGetWMName returned bad status\n");
#endif
		win->title = "Unknown";
	}
	
	if(!tprop->value||tprop->nitems <= 0)
		win->title = "Unknown";

	if(tprop->value)
		win->title = (char *)tprop->value;
*/
	XFetchName (display, x11_window, &name);
printf("New Window Name: %s\n", name);
	if (!name)
		win->title = "Unknown";
	else
		win->title = name;

	win->hasTitlebar = true;

	win->x = win_attrib.x;
	win->y = win_attrib.y;
	win->width = win_attrib.width;
	win->height = win_attrib.height;

	win->colorMap = win_attrib.colormap;

	win->size_hints = XAllocSizeHints ();

	XGetWMNormalHints (display, x11_window, win->size_hints, &dummy);

	if(win->size_hints->flags & PPosition)
	{
		win->x = win->size_hints->x;
		win->y = win->size_hints->y;
	}

	if ((win->y < 20) || (win->y < NOVABAR_HEIGHT))
		win->y = NOVABAR_HEIGHT + 20;

	if (win_attrib.border_width > 0)
	{
		win->width += win_attrib.border_width * 2;
		win->height += win_attrib.border_width * 2;
	}

	win->orig_x = win->x;	//win_attrib.x;
	win->orig_y = win->y;	//win_attrib.y;
	win->orig_width = win->width;	//win_attrib.width;
	win->orig_height = win->height;	//win_attrib.height;

	win->bWidth = win_attrib.border_width;

	win->nTChildren = 0;

	win->window = x11_window;

	if (win->width > XDisplayWidth (display, screen))
		win->width = XDisplayWidth (display, screen);
	if (win->height > XDisplayHeight (display, screen))
		win->height = XDisplayHeight (display, screen);

	if (!(win->size_hints->flags & PMaxSize))
	{
#ifdef DEBUG
		printf ("DEBUG: Bad SizeHints: MIN %dx%d | MAX %dx%d\n",
			win->size_hints->min_width,
			win->size_hints->min_height,
			win->size_hints->max_width,
			win->size_hints->max_height);
#endif
		//So set the maximum to the display geometry
		win->size_hints->max_width =
			XDisplayWidth (display, screen) + 100;
		win->size_hints->max_height =
			XDisplayHeight (display, screen) + 100;
#ifdef DEBUG
		printf ("DEBUG: New SizeHints: MIN %dx%d | MAX %dx%d\n",
			win->size_hints->min_width,
			win->size_hints->min_height,
			win->size_hints->max_width,
			win->size_hints->max_height);
#endif
	}

	if (!(win->size_hints->flags & PMinSize))
	{
#ifdef DEBUG
		printf ("DEBUG: Bad (MIN)SizeHints(%s): MIN %dx%d | MAX %dx%d\n", win->title, win->size_hints->min_width, win->size_hints->min_height, win->size_hints->max_width, win->size_hints->max_height);
#endif
		win->size_hints->min_width = 10;
		win->size_hints->min_height = 10;
#ifdef DEBUG
		printf ("DEBUG: New SizeHints: MIN %dx%d | MAX %dx%d\n",
			win->size_hints->min_width,
			win->size_hints->min_height,
			win->size_hints->max_width,
			win->size_hints->max_height);
#endif
	}

	XGetTransientForHint (display, win->window, &tranWin);

	if (tranWin)
		win->isTransient = true;
	else
		win->isTransient = false;

	Novawm_Window *parent = winmgr.WindowSearch (tranWin);

	if (parent)
	{
		parent->nTChildren++;
	//	if (parent->nTChildren == 1)
	//		parent->tChild = new Window;

		parent->tChild.push_back(x11_window);
		//parent->tChild[parent->nTChildren - 1] = x11_window;
	}

	XGetWindowProperty (display, win->window, motifAtom, 0L, 20L, false,
			    motifAtom, &adummy, &idummy, &udummy, &udummy,
			    (unsigned char **) &motif_hints);

	if (motif_hints)
	{
		if ((motif_hints->flags & (1l << 1)) &&
		    (!(motif_hints->decorations & (1l << 0))))
		{

			if ((motif_hints->decorations & (1l << 3)) == 0)
				win->hasTitlebar = false;
			else
				win->hasTitlebar = true;
		}
	}

	XFree (motif_hints);

	set_attrib.do_not_propagate_mask =
		ButtonPressMask | ButtonReleaseMask | ButtonMotionMask;

	set_attrib.event_mask =
		ExposureMask | ButtonPressMask | ButtonReleaseMask |
		PropertyChangeMask | SubstructureRedirectMask |
		FocusChangeMask | SubstructureNotifyMask | PointerMotionMask |
		EnterWindowMask | LeaveWindowMask;

	set_attrib.background_pixel = mainPixel;

	set_attrib.override_redirect = false;	//true;


	if (win->hasTitlebar == true)
	{
		win->titlebar =
			XCreateWindow (display, root, win->x, win->y - 20,
				       win->width, win->height + 20, 0,
				       DefaultDepth (display, screen),
				       CopyFromParent, DefaultVisual (display,
								      screen),
				       CWBackPixel | CWEventMask
				       | CWOverrideRedirect | CWDontPropagate,
				       &set_attrib);

		//Create the Kill/Close Button Window
		win->kill =
			XCreateWindow (display, win->titlebar,
				       win->width - 19, 3, 16, 16, 0,
				       DefaultDepth (display, screen),
				       CopyFromParent, DefaultVisual (display,
								      screen),
				       CWEventMask | CWDontPropagate,
				       &set_attrib);

		//Create the Stretch/Maximize Button Window
		win->stretch =
			XCreateWindow (display, win->titlebar,
				       win->width - 37, 3, 16, 16, 0,
				       DefaultDepth (display, screen),
				       CopyFromParent, DefaultVisual (display,
								      screen),
				       CWBackPixel | CWEventMask |
				       CWDontPropagate, &set_attrib);

		//Create the Hide/Minimize Button Window
		win->hide =
			XCreateWindow (display, win->titlebar,
				       win->width - 56, 3, 16, 16, 0,
				       DefaultDepth (display, screen),
				       CopyFromParent, DefaultVisual (display,
								      screen),
				       CWBackPixel | CWEventMask |
				       CWDontPropagate, &set_attrib);

	}


	XChangeWindowAttributes (display, win->window,
				 CWDontPropagate, &set_attrib);


	XSelectInput (display, win->window,
		      PropertyChangeMask | FocusChangeMask);

	XAddToSaveSet (display, win->window);

	if (win->hasTitlebar == true)
		XReparentWindow (display, win->window, win->titlebar, 0, 20);

	if (focusType == 1)
	{
		if (win->hasTitlebar == true)
			XGrabButton (display, Button1, AnyModifier,
				     win->titlebar, 1, ButtonPressMask,
				     GrabModeSync, GrabModeAsync, None, None);

	}

	novawm_window_List.push_back (win);

	if (win->hasTitlebar == true)
		XMapRaised (display, win->titlebar);
	XMapWindow (display, win->window);

	if (win->hasTitlebar == true)
	{
		XSetWindowBackgroundPixmap (display, win->kill, killPixmap);
		XClearWindow (display, win->kill);
		XSetWindowBackgroundPixmap (display, win->stretch,
					    stretchPixmap);
		XClearWindow (display, win->stretch);
		XSetWindowBackgroundPixmap (display, win->hide, hidePixmap);
		XClearWindow (display, win->hide);

		//Map the button windows
		XMapWindow (display, win->kill);
		XMapWindow (display, win->stretch);
		XMapWindow (display, win->hide);
	}


	SetFocus (win);

	if (win->hasTitlebar == true)
		XRaiseWindow (display, novawm.NovaBar);

	Redraw (win);

	win->Get_Net_States ();

	nClients++;

#ifdef _WIN_GNOME_SUPPORT
	_WIN_CLIENT_LIST_UpdateList ();
#endif

	XSync (display, true);	//false);

	XUngrabServer (display);

#ifdef DEBUG
	printf ("DEBUG: NewWindow() -- ORIG_GEOM %dx%dx%dx%d | GEOM %dx%dx%dx%d\n", win->orig_x, win->orig_y, win->orig_width, win->orig_height, win->x, win->y, win->width, win->height);
#endif

	SendToDesktop (win, winmgr.cDesktop);

#ifdef _WIN_GNOME_SUPPORT
//Get Layer
	unsigned char *cLayer = 0;

	XGetWindowProperty (display, win->window, winProtocols_Layer, 0L, 20L,
			    false, XA_CARDINAL, &adummy, &idummy, &udummy,
			    &udummy, (unsigned char **) &cLayer);

	if (!cLayer)
	{
		win->layer = WIN_LAYER_NORMAL;
	}
	else
	{
		win->layer = atoi ((const char *) cLayer);
	}
#endif

if(win->x < 0) //TEMPORARY: FORCE WINDOWS TO BE MAPPED FOR THE FIRST TIME ON THE SCREEN
	win->x = win->orig_x = 0;
if(win->y < 0)
	win->y = win->orig_y = 0;

}

//Should be a member of WinMgr but I'm in a hurry and I like this way better
void
Novawm_Window::Shade ()
{
//FIXME: Could be cleaner?
	if (isShaded == true)
	{
		winmgr.SetSize (this, width, height);
		//XResizeWindow(display,titlebar,width,height+20);
		isShaded = false;
	}
	else
	{
		XResizeWindow (display, titlebar, width, 20);
		isShaded = true;
	}
}

Novawm_Window *
WinMgr::WindowSearch (Window x11_window)
{
#ifdef DEBUG
	//printf ("DEBUG: WindowSearch(%x)\n", x11_window);
#endif

	if (!x11_window || x11_window == root
	    || x11_window == rootMenu.menuWindow ()
	    || x11_window == windowMenu.menuWindow ())
		return 0;

	for (list < Novawm_Window * >::const_iterator i =
	     novawm_window_List.begin (); i != novawm_window_List.end (); ++i)
	{
		if (((*i)->window == x11_window)
		    || ((*i)->titlebar == x11_window)
		    || ((*i)->kill == x11_window)
		    || ((*i)->stretch == x11_window)
		    || ((*i)->hide == x11_window))
			return *i;
	}

	return 0;
}

void
WinMgr::Redraw (Novawm_Window * novawm_window)
{
	if (!novawm_window)
		return;

	if (novawm_window->title == NULL)
	{
		printf ("BAD TITLE!\n");
		novawm_window->title = "Unknown";
	}

	//XClearWindow (display, novawm_window->titlebar);

	XDrawString (display, novawm_window->titlebar, novawm_gc, 4, 14,
		     novawm_window->title, strlen (novawm_window->title));

	//Draw Raised Border for the titlebar and buttons
	//Titlebar (White lines)
	XDrawLine (display, novawm_window->titlebar, novawm_gc, 0, 0, 0, 20);
	XDrawLine (display, novawm_window->titlebar, novawm_gc, 0, 0,
		   novawm_window->width, 0);

	if (events.downWindow != novawm_window->kill)
	{
		//Kill Button (White lines)
		XDrawLine (display, novawm_window->kill, novawm_gc, 0, 0, 0,
			   16);
		XDrawLine (display, novawm_window->kill, novawm_gc, 0, 0, 16,
			   0);
	}
	if (events.downWindow != novawm_window->stretch)
	{
		//Stretch Button (White lines)
		XDrawLine (display, novawm_window->stretch, novawm_gc, 0, 0,
			   0, 16);
		XDrawLine (display, novawm_window->stretch, novawm_gc, 0, 0,
			   16, 0);
	}
	if (events.downWindow != novawm_window->hide)
	{
		//Hide Button (White lines)
		XDrawLine (display, novawm_window->hide, novawm_gc, 0, 0, 0,
			   16);
		XDrawLine (display, novawm_window->hide, novawm_gc, 0, 0, 16,
			   0);
	}

	XSetForeground (display, novawm_gc, BlackPixel (display, screen));

	if (focusWindow == novawm_window)
		XDrawString (display, novawm_window->titlebar, novawm_gc, 3,
			     13, novawm_window->title,
			     strlen (novawm_window->title));

	//Titlebar (black lines)
	XDrawLine (display, novawm_window->titlebar, novawm_gc, 1, 19,
		   novawm_window->width, 19);
	XDrawLine (display, novawm_window->titlebar, novawm_gc,
		   novawm_window->width - 1, 1, novawm_window->width - 1, 20);

	if (events.downWindow != novawm_window->kill)
	{
		//Kill Button (Black lines)
		XDrawLine (display, novawm_window->kill, novawm_gc, 15, 1, 15,
			   16);
		XDrawLine (display, novawm_window->kill, novawm_gc, 0, 15, 16,
			   15);
	}
	if (events.downWindow != novawm_window->stretch)
	{
		//Stretch Button (Black lines) 
		XDrawLine (display, novawm_window->stretch, novawm_gc, 15, 1,
			   15, 16);
		XDrawLine (display, novawm_window->stretch, novawm_gc, 0, 15,
			   16, 15);
	}
	if (events.downWindow != novawm_window->hide)
	{
		//Hide Button (Black lines)
		XDrawLine (display, novawm_window->hide, novawm_gc, 15, 1, 15,
			   16);
		XDrawLine (display, novawm_window->hide, novawm_gc, 0, 15, 16,
			   15);
	}


	XSetForeground (display, novawm_gc, WhitePixel (display, screen));
}

void
WinMgr::Move (Novawm_Window * novawm_window)
{
#ifdef DEBUG
	printf ("DEBUG: Move()\n");
#endif

	XEvent event;
	XConfigureEvent configEvent;
	Window wdummy;
	int x, y, winx, winy;
	unsigned int mdummy;
	int idummy;

	//XGrabPointer (display, novawm_window->titlebar, false,
	//            ButtonReleaseMask | PointerMotionMask, GrabModeAsync,
	//            GrabModeAsync, None, MoveCursor, CurrentTime);

	//XGrabServer (display);

	XDefineCursor (display, novawm_window->titlebar, MoveCursor);

	XQueryPointer (display, novawm_window->titlebar, &wdummy, &wdummy, &x,
		       &y, &winx, &winy, &mdummy);

	configEvent.type = ConfigureNotify;
	configEvent.event = novawm_window->window;
	configEvent.window = novawm_window->window;
	configEvent.width = novawm_window->width;
	configEvent.height = novawm_window->height;	// - novawm_window->bWidth;
	configEvent.border_width = novawm_window->bWidth;
	configEvent.above = Below;
	configEvent.override_redirect = false;

	while (1)
	{
		XMaskEvent (display,
			    ButtonPressMask | ButtonReleaseMask |
			    PointerMotionMask | ExposureMask, &event);
		switch (event.type)
		{
		case Expose:
			Redraw (WindowSearch (event.xexpose.window));

			if ((event.xexpose.window == novawm.NovaBar) ||
			    (event.xexpose.window == novawm.nbClock)
			    || (event.xexpose.window == novawm.nbCurWin)
			    || (event.xexpose.window == novawm.nbListButton)
			    || (event.xexpose.window == novawm.nbWinList)
			    || (event.xexpose.window == novawm.nbWLstScrllBar)
			    || (event.xexpose.window == novawm.nbWLstItemWin)
			    || (event.xexpose.window == novawm.nbWLstScrllUp)
			    || (event.xexpose.window == novawm.nbWLstScrllDwn)
			    || (event.xexpose.window == novawm.nbButton))
				novawm.DrawBar ();

			break;

		case MotionNotify:
			XQueryPointer (display, novawm_window->titlebar,
				       &wdummy, &wdummy, &x, &y, &idummy,
				       &idummy, &mdummy);


			XMoveWindow (display, novawm_window->titlebar,	//x - winx, y - winy);
				     event.xmotion.x_root - winx,	//event.xmotion.x,
				     event.xmotion.y_root - winy);	//event.xmotion.y);

			novawm_window->x = event.xmotion.x_root - winx;
			//event.xmotion.x;
			novawm_window->y = event.xmotion.y_root - winy + 20;
			//event.xmotion.y+20;
			break;

		case ButtonRelease:
//                      novawm_window->x = x;
//                      novawm_window->y = y;
			//XUngrabServer (display);
//                      XUngrabPointer (display, CurrentTime);

			XDefineCursor (display, novawm_window->titlebar,
				       Arrow);

			//Add 20 for the titlebar
			//(Incase the window needs its EXACT position)
			configEvent.x = novawm_window->x;
			configEvent.y = novawm_window->y;	//+20;

			XSendEvent (display, novawm_window->window, false,
				    StructureNotifyMask,
				    (XEvent *) & configEvent);

			//Update the Window
			Redraw (novawm_window);


			return;
			break;

		}

	}

}

//Added to always check size hints before resizing
void
WinMgr::SetSize (Novawm_Window * novawm_window, int wWidth, int wHeight)
{
	XConfigureEvent configEvent;
	XWindowAttributes win_attr;

	if (wWidth > novawm_window->size_hints->max_width)
		wWidth = novawm_window->size_hints->max_width;
	if (wWidth < novawm_window->size_hints->min_width)
		wWidth = novawm_window->size_hints->max_width;
	if (wHeight > novawm_window->size_hints->max_height)
		wHeight = novawm_window->size_hints->max_height;
	if (wHeight < novawm_window->size_hints->min_height)
		wHeight = novawm_window->size_hints->max_height;

	XGetWindowAttributes (display, novawm_window->window, &win_attr);
	configEvent.border_width = win_attr.border_width;

	novawm_window->width = wWidth;
	novawm_window->height = wHeight;

	configEvent.type = ConfigureNotify;
	configEvent.event = novawm_window->window;
	configEvent.window = novawm_window->window;
	configEvent.x = novawm_window->x;
	configEvent.y = novawm_window->y;
	configEvent.width = novawm_window->width;
	configEvent.height = novawm_window->height;
	configEvent.above = Below;
	configEvent.override_redirect = false;

	XResizeWindow (display, novawm_window->titlebar, wWidth,
		       wHeight + 20);
	XResizeWindow (display, novawm_window->window,
		       wWidth - (win_attr.border_width * 2),
		       wHeight - (win_attr.border_width * 2));

	//Move the titlebar buttons
	XMoveWindow (display, novawm_window->kill, novawm_window->width - 19,
		     3);
	XMoveWindow (display, novawm_window->stretch,
		     novawm_window->width - 37, 3);
	XMoveWindow (display, novawm_window->hide, novawm_window->width - 56,
		     3);

	XSendEvent (display, novawm_window->window, false,
		    StructureNotifyMask, (XEvent *) & configEvent);

}

void
WinMgr::Stretch (Novawm_Window * novawm_window)
{
#ifdef DEBUG
	printf ("DEBUG: Stretch()\n");
#endif


	//Check if it is already stretched
	if ((novawm_window->width != novawm_window->orig_width) &&
	    (novawm_window->height != novawm_window->orig_height))
	{

		if (novawm_window->hasTitlebar != true)	//Has no titlebar
		{
			novawm_window->width = novawm_window->orig_width;
			novawm_window->height = novawm_window->orig_height;

			XMoveWindow (display, novawm_window->window,
				     novawm_window->orig_x,
				     novawm_window->orig_y);

			SetSize (novawm_window, novawm_window->orig_width,
				 novawm_window->orig_height);

			return;
		}

		else		//Has a titlebar
		{

			if ((novawm_window->width >
			     novawm_window->size_hints->max_width)
			    || (novawm_window->height >
				novawm_window->size_hints->max_height))
			{

				novawm_window->width =
					novawm_window->size_hints->max_width;
				novawm_window->height =
					novawm_window->size_hints->max_height;
			}

			novawm_window->x = novawm_window->orig_x;
			novawm_window->y = novawm_window->orig_y;
			novawm_window->width = novawm_window->orig_width;
			novawm_window->height = novawm_window->orig_height;

			SetSize (novawm_window, novawm_window->orig_width,
				 novawm_window->orig_height);

			XMoveWindow (display, novawm_window->titlebar,
				     novawm_window->x, novawm_window->y);
			return;

		}

	}

	//Stretch to fullscreen
	else
	{
		if (novawm_window->hasTitlebar != true)	//Has no titlebar
		{
			//This probably wouldn't be possible in this version
			return;
		}

		else
		{
			novawm_window->orig_x = novawm_window->x;
			novawm_window->orig_y = novawm_window->y;
			novawm_window->x = 0;
			novawm_window->y = NOVABAR_HEIGHT;
			novawm_window->width =
				XDisplayWidth (display, screen);
			novawm_window->height =
				XDisplayHeight (display,
						screen) - NOVABAR_HEIGHT;

			if ((novawm_window->width >
			     novawm_window->size_hints->max_width)
			    || (novawm_window->height >
				novawm_window->size_hints->max_height))
			{
#ifdef DEBUG
				printf ("DEBUG: Going fullscreen\n");
#endif

				novawm_window->width =
					novawm_window->size_hints->max_width;
				novawm_window->height =
					novawm_window->size_hints->max_height;
			}

			XMoveWindow (display, novawm_window->titlebar, 0,
				     NOVABAR_HEIGHT);

			SetSize (novawm_window, XDisplayWidth (display, screen), XDisplayHeight (display, screen) - NOVABAR_HEIGHT - 20);	//Leave room for the NovaBar and titlebar
			return;

		}
	}
}

void
WinMgr::Raise (Novawm_Window * novawm_window)
{
#ifdef DEBUG
	printf ("DEBUG: Raise()\n");
#endif

	if (!novawm_window)
	{
		#ifdef DEBUG
		printf("DEBUG: Can't raise bad window.\n");
		#endif
		return;
	}

	//Check the desktop
#ifdef _WIN_GNOME_SUPPORT
	if (novawm_window->layer == WIN_LAYER_NORMAL)
	{
#endif
		if (novawm_window->desktop != cDesktop)
			SetDesktop (novawm_window->desktop);	//Goto that desktop
#ifdef _WIN_GNOME_SUPPORT
	}
#endif

	novawm_window->SetState (NormalState);

	if (novawm_window->hasTitlebar != true)
	{
		XMapRaised (display, novawm_window->window);
		#ifdef DEBUG
		printf("DEBUG: Raising window without titlebar(%s)\n", novawm_window->title);
		#endif
	}
	else
	{
		XMapRaised (display, novawm_window->titlebar);
		XMapRaised (display, novawm_window->window);
	}

	if (novawm_window->ignoreTransient != true)
	{
		if (novawm_window->nTChildren > 0)
		{
			for (int i = 0; i < novawm_window->nTChildren; i++)
			{
				//Raise any windows transient to this one
				Raise (WindowSearch
				       (novawm_window->tChild[i]));
			}
		}
	}

}

void
WinMgr::SetFocus (Novawm_Window * novawm_window)
{
#ifdef DEBUG
	printf ("DEBUG: SetFocus()\n");
#endif

	Raise (novawm_window);

	focusWindow = novawm_window;

//Redraw all titlebars
	for (list < Novawm_Window * >::const_iterator i =
	     winmgr.novawm_window_List.begin ();
	     i != winmgr.novawm_window_List.end (); ++i)
	{
		XClearWindow (display, (*i)->titlebar);
		Redraw ((*i));

	}

	if (!novawm_window)
		return;

	XSetInputFocus (display, novawm_window->window, RevertToNone,
			CurrentTime);

	novawm.DrawBar ();

}

void
WinMgr::Hide (Novawm_Window * novawm_window)
{
#ifdef DEBUG
	printf ("DEBUG: Hide()\n");
#endif

	if (!novawm_window)
		return;

	if (novawm_window->hasTitlebar != true)
		XUnmapWindow (display, novawm_window->window);
	else
		XUnmapWindow (display, novawm_window->titlebar);

	novawm_window->SetState (WithdrawnState);

	if (novawm_window->nTChildren > 0)
	{
		for (int i = 0; i < novawm_window->nTChildren; i++)
		{
			//Hide any windows transient to this one
			Hide (WindowSearch (novawm_window->tChild[i]));
		}
	}

	//if(focusWindow == novawm_window && novawm_window->prev)
	//SetFocus(novawm_window->prev);
	SetFocus (0);

	if (novawm_window->hasTitlebar == true)
		AddUnmapIgnore (novawm_window->titlebar);	//unmapignore++;
	else
		AddUnmapIgnore (novawm_window->window);

}

void
WinMgr::Resize (Novawm_Window * novawm_window)
{
#ifdef DEBUG
	printf ("DEBUG: Resize()\n");
#endif

	if (!novawm_window)
		return;

	XEvent event;
	Window wdummy;
	XWindowAttributes win_attrib;
	int x, y, winx, winy;
	unsigned int mdummy;
	int idummy;
	XGrabPointer (display, novawm_window->titlebar, false,
		      ButtonReleaseMask | PointerMotionMask,
		      GrabModeAsync, GrabModeAsync, None, ResizeCursor,
		      CurrentTime);
//      XGrabServer (display);
	XQueryPointer (display, novawm_window->titlebar, &wdummy,
		       &wdummy, &x, &y, &winx, &winy, &mdummy);
	/*configEvent.type = ConfigureNotify;
	 * configEvent.event = novawm_window->window;
	 * configEvent.window = novawm_window->window;
	 * configEvent.width = novawm_window->width;
	 * configEvent.height = novawm_window->height;
	 * configEvent.border_width = 0;
	 * configEvent.above = Below;
	 * configEvent.override_redirect = false; */

	XGetWindowAttributes (display, novawm_window->window, &win_attrib);

	//I added this because of problems with the wrong values
	//Update size values
	/*novawm_window->width = win_attrib.width;
	 * novawm_window->height = win_attrib.height;
	 * novawm_window->orig_width = win_attrib.width;
	 * novawm_window->orig_height = win_attrib.height; */

	XWarpPointer (display, None, root, 0, 0, 0, 0,
		      novawm_window->x + novawm_window->width + 2,
		      novawm_window->y + novawm_window->height + 2);

	while (1)
	{
		XMaskEvent (display,
			    ButtonPressMask | ButtonReleaseMask |
			    PointerMotionMask | ExposureMask, &event);
		switch (event.type)
		{
		case Expose:
			Redraw (WindowSearch (event.xexpose.window));
			break;

		case MotionNotify:
			XQueryPointer (display, root, &wdummy, &wdummy,
				       &idummy, &idummy, &x, &y, &mdummy);

			//Can't make it smaller than the titlebar (Doing so will also cause some apps to quit)
			if (y - novawm_window->y - 2 <=
			    21 + win_attrib.border_width)
				break;

			if ((x - novawm_window->x - 2 >
			     novawm_window->size_hints->max_width)
			    || (x - novawm_window->x - 2 <
				novawm_window->size_hints->min_width)
			    || (y - novawm_window->y - 2 >
				novawm_window->size_hints->max_height)
			    || (y - novawm_window->y - 2 <
				novawm_window->size_hints->min_height))
			{
#ifdef DEBUG
/*				printf ("DEBUG: Resize to %dx%d, Max GEOM is %dx%d Min GEOM is % dx % d \ n ", x - novawm_window->x - 2, y - novawm_window->y - 2, novawm_window->size_hints->max_width, novawm_window->size_hints->max_height, novawm_window->size_hints->max_width, novawm_window->size_hints->min_height);
*/#endif
				break;
			}

			SetSize (novawm_window, x - novawm_window->x - 2,
				 y - novawm_window->y - 2);

			novawm_window->orig_width = novawm_window->width;	//x - novawm_window->x - 2;
			novawm_window->orig_height = novawm_window->height;
			break;
		case ButtonRelease:

			XUngrabPointer (display, CurrentTime);
			XSync (display, true);	//false);

			Redraw (novawm_window);


			return;
			break;
		}

	}


}

void
WinMgr::Kill (Novawm_Window * novawm_window)
{
#ifdef DEBUG
	printf ("DEBUG: Kill()\n");
#endif

	Atom *pCheck = 0;
	XEvent deleteEvent;
	int nProtocols;
	if (!novawm_window)
		return;
	deleteEvent.type = ClientMessage;
	deleteEvent.xclient.window = novawm_window->window;
	deleteEvent.xclient.message_type = protocolAtom;
	deleteEvent.xclient.format = 32;
	deleteEvent.xclient.data.l[0] = deleteAtom;
	deleteEvent.xclient.data.l[1] = CurrentTime;
	int deleted = 0;

	//Hide (novawm_window);

	if (!novawm_window->window)
	{
		XDestroyWindow (display, novawm_window->titlebar);
		novawm_window->Destroy ();
	}


	XGetWMProtocols (display, novawm_window->window, &pCheck,
			 &nProtocols);

	if (pCheck)
	{

		for (int i = 0; i < nProtocols; i++)
		{
			if (pCheck[i] == deleteAtom)
			{
				deleted = 1;
				XSendEvent (display, novawm_window->window,
					    false, NoEventMask, &deleteEvent);
				//AddUnmapIgnore(novawm_window->window); //unmapignore++;
				break;
			}
		}

		if (pCheck)
			XFree (pCheck);
	}

	if (deleted != 1)	//The Window doesn't support the Delete Protocol
	{
		XKillClient (display, novawm_window->window);	//Safe?
		//unmapignore++;
	}
}

void
WinMgr::Create_ListMenu (int menu_x, int menu_y)
{
	listMenu.Clear ();	//Clear the menu
	if (novawm_window_List.size () == 0)	//There are no windows to manage
	{
		listMenu.AddItem ("No windows to manage!");
		return;
	}

	nListWindow = 0;

	for (list < Novawm_Window * >::const_iterator i =
	     winmgr.novawm_window_List.begin ();
	     i != winmgr.novawm_window_List.end (); ++i)
	{
		if ((*i)->isTransient != true)
		{
			listMenu.AddItem ((*i)->title);
			nListWindow++;
		}
	}

	listMenu.Create (menu_x, menu_y);
}

void
WinMgr::listMenu_Click (int item)
{
	if (item > nListWindow && item < 0)
		return;
	int n = 0;
//      for (Novawm_Window * cWindow = topWindow;
//           cWindow || i >= nListWindow; cWindow = cWindow->next)
	for (list < Novawm_Window * >::const_iterator i =
	     winmgr.novawm_window_List.begin ();
	     i != winmgr.novawm_window_List.end (); ++i)
	{
		if ((*i)->isTransient != true)
		{
			if (n == item)
			{
				SetFocus ((*i));
				break;
			}

			n++;
		}
	}

	//Clear list
	nListWindow = 0;
}

void
Novawm_Window::Destroy ()
{
#ifdef DEBUG
	printf ("DEBUG: Novawm_Window::Destroy()\n");
#endif

	XGrabServer (display);

	if (focusType == 1)
		XUngrabButton (display, AnyButton, AnyModifier, titlebar);

	XReparentWindow (display, window, root, x, y);

	XRemoveFromSaveSet (display, window);

	if (hasTitlebar == true)
		XDestroyWindow (display, titlebar);

	XSync (display, false);

	XUngrabServer (display);

	winmgr.novawm_window_List.remove (this);

	winmgr.SetFocus (0);
	delete this;

#ifdef _WIN_GNOME_SUPPORT
	winmgr._WIN_CLIENT_LIST_UpdateList ();
#endif

}

int
Novawm_Window::GetState ()
{
#ifdef DEBUG
	printf ("DEBUG: GetState()\n");
#endif

	Atom gState;
	int format;
	unsigned long dummy;
	long *data;
	int get_state = WithdrawnState;

	XGetWindowProperty (display, window, stateAtom, 0L, 2L,
			    false, stateAtom, &gState, &format,
			    &dummy, &dummy, (unsigned char **) &data);
	if (data)
		get_state = *data;

	XFree (data);
	return get_state;
}

void
Novawm_Window::SetState (int set_state)
{
#ifdef DEBUG
	printf ("DEBUG: SetState(%d)\n", set_state);
#endif

	CARD32 data[2];
	state = set_state;
	data[0] = set_state;
	data[1] = None;
	XChangeProperty (display, window, stateAtom, stateAtom,
			 32, PropModeReplace, (unsigned char *) data, 2);

}

void
Novawm_Window::Get_Net_States ()
{
	unsigned char StateList[10];
	if (!StateList)
	{
		printf ("NovaWM ERROR: Failed to allocate memory for retrieving _NET_WM_STATEs\n");
		return;
	}

	Atom dAtom;
	unsigned long nStates = 0;
	int format;
	unsigned long dummy;

	XGetWindowProperty (display, window,
			    netStateAtom, XA_CARDINAL, 32, false,
			    netStateAtom, &dAtom, &format, &nStates, &dummy,
			    (unsigned char **) &StateList);

	for (int i = 0; i < nStates; i++)
	{
		if ((Atom) StateList[i] == netStateStickyAtom)
		{
			isSticky = true;
		}
		if ((Atom) StateList[i] == netStateSkipBarAtom)
			skipBar = true;
	}
}

void
WinMgr::SetDesktop (int desktop)
{
#ifdef DEBUG
	printf ("DEBUG: SetDesktop(%d)\n", desktop);
#endif

	if ((desktop > maxDesktops) || (desktop < 0))
	{
#ifdef DEBUG
		printf ("DEBUG: Attempt to goto desktop outside of allowed desktops.\n");
#endif
		return;		//Bad Desktop
	}

	if (desktop + 1 > nDesktops)
		AddDesktop ();

	cDesktop = desktop;

//      for (Novawm_Window * window = topWindow;
	//     (window) ; window = window->next)
	for (list < Novawm_Window * >::const_iterator i =
	     winmgr.novawm_window_List.begin ();
	     i != winmgr.novawm_window_List.end (); ++i)
	{
		if (((*i)->desktop != cDesktop)
		    && ((*i)->state == NormalState))
		{
			//Don't Hide() the window or it won't show up when we return to its desktop
#ifdef _WIN_GNOME_SUPPORT
			if ((*i)->layer == WIN_LAYER_NORMAL)
			{
#endif
				if ((*i)->isSticky == false)
				{
					if ((*i)->hasTitlebar == true)
						XUnmapWindow (display,
							      (*i)->titlebar);
					else
						XUnmapWindow (display,
							      (*i)->window);
				}
#ifdef _WIN_GNOME_SUPPORT
			}
#endif

			//Don't let the window change its state! (fixes desktop bugs!! :) )
			if ((*i)->hasTitlebar == true)
				AddUnmapIgnore ((*i)->titlebar);	//unmapignore++;
			else
				AddUnmapIgnore ((*i)->window);

		}

		if (((*i)->desktop == cDesktop)
		    && ((*i)->state == NormalState))
		{
			//Don't Raise() the window because if it's already hidden it shouldn't be mapped
			Raise ((*i));
		}
	}

	//Make sure the NovaBar is on top (For apps like Nautilus)
	XRaiseWindow (display, novawm.NovaBar);

#ifdef _WIN_GNOME_SUPPORT
	//Set the current desktop
	CARD32 currentWorkspace = (CARD32) winmgr.cDesktop;
	XChangeProperty (display, root, winProtocols_Workspace,
			 XA_CARDINAL, 32, PropModeReplace,
			 (unsigned char *) &currentWorkspace, 1);
#endif

}

//There may be a more code in AddDesktop() in some other version
int
WinMgr::AddDesktop ()
{
#ifdef DEBUG
	printf ("DEBUG: AddDesktop()\n");
#endif

	nDesktops++;

#ifdef _WIN_GNOME_SUPPORT
	//Set the number of desktops
	CARD32 desktopNum = (CARD32) winmgr.nDesktops;
	XChangeProperty (display, root, winProtocols_WorkspaceCount,
			 XA_CARDINAL, 32, PropModeReplace,
			 (unsigned char *) &desktopNum, 1);
#endif

	return 1;
}

void
WinMgr::RemoveDesktop ()
{
#ifdef DEBUG
	printf ("DEBUG: RemoveDesktop()\n");
#endif

	nDesktops--;
}

void
WinMgr::SendToDesktop (Novawm_Window * window, int desktop)
{
#ifdef DEBUG
	printf ("DEBUG: SendToDesktop(%d)\n", desktop);
#endif

	if ((desktop > maxDesktops) || (desktop < 0))
	{
#ifdef DEBUG
		printf ("DEBUG: Attempt to send a window to a illegal desktop\n");
#endif
		return;
	}

	if (desktop + 1 > nDesktops)
		AddDesktop ();

	window->desktop = desktop;

	if ((cDesktop != desktop) && (window->state == NormalState))
	{
		if (window->hasTitlebar == true)
			XUnmapWindow (display, window->titlebar);
		else
			XUnmapWindow (display, window->window);

		//Don't let the window change its state!
		AddUnmapIgnore (window->titlebar);	//window);

	}

	CARD32 desktopNum = (CARD32) desktop;

	XChangeProperty (display, window->window, netDesktopAtom,
			 XA_CARDINAL, 32, PropModeReplace,
			 (unsigned char *) &desktopNum, 1);

#ifdef _WIN_GNOME_SUPPORT
	XChangeProperty (display, window->window, winProtocols_WorkspaceCount,
			 XA_CARDINAL, 32, PropModeReplace,
			 (unsigned char *) &desktopNum, 1);
#endif

}

#ifdef _WIN_GNOME_SUPPORT
void
WinMgr::_WIN_CLIENT_LIST_UpdateList ()
{
#ifdef DEBUG
	printf ("DEBUG: Updating _WIN_CLIENT_LIST\n");
#endif

	Window *wIDList = (Window *) malloc (sizeof (Window) * nClients);
	if (!wIDList)
	{
		printf ("NovaWM ERROR: Failed to allocate memory for the _WIN_CLIENT_LIST for some reason.\n");
		return;
	}

	int n = 0;
	int listClients = 0;
//      for (Novawm_Window * currentWindow = topWindow; currentWindow;
//           currentWindow = currentWindow->next)
	for (list < Novawm_Window * >::const_iterator i =
	     winmgr.novawm_window_List.begin ();
	     i != winmgr.novawm_window_List.end (); ++i)
	{

		if ((*i)->layer == WIN_LAYER_NORMAL)
		{
			wIDList[n] = (*i)->window;
			listClients++;
		}

		n++;
	}

	XChangeProperty (display, root,
			 winProtocols_ClientList,
			 XA_CARDINAL, 32, PropModeReplace,
			 (unsigned char *) wIDList, nClients);

	if (wIDList)
		free (wIDList);
}
#endif

void
WinMgr::AddUnmapIgnore (Window ignoreWindow)
{
#ifdef DEBUG
	printf ("DEBUG: AddUnmapIgnore(%x)\n", ignoreWindow);
#endif

	ignoreUnmapList.push_back (ignoreWindow);

}

void
WinMgr::RemoveUnmapIgnore (Window ignoreWindow)
{
#ifdef DEBUG
	printf ("DEBUG: RemoveUnmapIgnore(%x)\n", ignoreWindow);
#endif

	ignoreUnmapList.remove (ignoreWindow);
}

int
WinMgr::Find_UnmapIgnore (Window ignoreWindow)
{
#ifdef DEBUG
	printf ("DEBUG: Find_UnmapIgnore(%x)\n", ignoreWindow);
#endif

	for (list < Window >::const_iterator i = ignoreUnmapList.begin ();
	     i != ignoreUnmapList.end (); ++i)
	{
		if ((*i) == ignoreWindow)
		{
#ifdef DEBUG
			printf ("DEBUG: Found %x\n", i);
#endif
			return 1;
		}
	}

	return -1;
}


syntax highlighted by Code2HTML, v. 0.9.1