/*****************************************************************************/
/**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
/**                          Salt Lake City, Utah                           **/
/**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
/**                        Cambridge, Massachusetts                         **/
/**                                                                         **/
/**                           All Rights Reserved                           **/
/**                                                                         **/
/**    Permission to use, copy, modify, and distribute this software and    **/
/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
/**    granted, provided that the above copyright notice appear  in  all    **/
/**    copies and that both  that  copyright  notice  and  this  permis-    **/
/**    sion  notice appear in supporting  documentation,  and  that  the    **/
/**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
/**    in publicity pertaining to distribution of the  software  without    **/
/**    specific, written prior permission.                                  **/
/**                                                                         **/
/**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
/**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
/**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
/**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
/**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
/*****************************************************************************/
/* 
 *  [ ctwm ]
 *
 *  Copyright 1992 Claude Lecommandeur.
 *            
 * Permission to use, copy, modify  and distribute this software  [ctwm] and
 * its documentation for any purpose is hereby granted without fee, provided
 * that the above  copyright notice appear  in all copies and that both that
 * copyright notice and this permission notice appear in supporting documen-
 * tation, and that the name of  Claude Lecommandeur not be used in adverti-
 * sing or  publicity  pertaining to  distribution of  the software  without
 * specific, written prior permission. Claude Lecommandeur make no represen-
 * tations  about the suitability  of this software  for any purpose.  It is
 * provided "as is" without express or implied warranty.
 *
 * Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL  IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS.  IN NO
 * EVENT SHALL  Claude Lecommandeur  BE LIABLE FOR ANY SPECIAL,  INDIRECT OR
 * CONSEQUENTIAL  DAMAGES OR ANY  DAMAGES WHATSOEVER  RESULTING FROM LOSS OF
 * USE, DATA  OR PROFITS,  WHETHER IN AN ACTION  OF CONTRACT,  NEGLIGENCE OR
 * OTHER  TORTIOUS ACTION,  ARISING OUT OF OR IN  CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author:  Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ]
 */


/***********************************************************************
 *
 * $XConsortium: events.c,v 1.182 91/07/17 13:59:14 dave Exp $
 *
 * twm event handling
 *
 * 17-Nov-87 Thomas E. LaStrange		File created
 *
 * Do the necessary modification to be integrated in ctwm.
 * Can no longer be used for the standard twm.
 *
 * 22-April-92 Claude Lecommandeur.
 *
 *
 ***********************************************************************/

#include <stdio.h>
#include <errno.h>
#ifndef VMS
#include <sys/time.h>
#endif
#if defined(AIXV3) || defined(_SYSTYPE_SVR4) || defined(ibm) || defined __QNX__
#include <sys/select.h>
#endif
#include <ctype.h>

#include "twm.h"
#ifdef VMS
#include <decw$include/Xatom.h>
#else
#include <X11/Xatom.h>
#endif
#include "add_window.h"
#include "clicktofocus.h"
#include "menus.h"
#include "events.h"
#include "resize.h"
#include "parse.h"
#include "util.h"
#include "screen.h"
#include "icons.h"
#include "iconmgr.h"
#include "version.h"

#ifdef VMS
#include <starlet.h>
#include <ssdef.h>
#include <lib$routines.h>
#define USE_SIGNALS
#else
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)<(y)?(x):(y))
#endif
#define ABS(x) ((x)<0?-(x):(x))

extern int iconifybox_width, iconifybox_height;
extern unsigned int mods_used;
extern int menuFromFrameOrWindowOrTitlebar;
extern char *CurrentSelectedWorkspace;
extern int RaiseDelay;

#ifdef USE_SIGNALS
extern Bool AnimationPending;
#else /* USE_SIGNALS */
extern struct timeval AnimateTimeout;
#endif /* USE_SIGNALS */
extern int  AnimationSpeed;
extern Bool AnimationActive;
extern Bool MaybeAnimate;

extern int  AlternateKeymap;
extern Bool AlternateContext;

static void CtwmNextEvent (Display *display, XEvent  *event);
static void RedoIcon(void);
static void do_key_menu (MenuRoot *menu,	/* menu to pop up */
			 Window w);		/* invoking window or None */
void RedoIconName(void);
extern void twmrc_error_prefix(void);

#ifdef SOUNDS
extern void play_sound(int snd);
#endif
FILE *tracefile = NULL;

#define MAX_X_EVENT 256
event_proc EventHandler[MAX_X_EVENT]; /* event handler jump table */
char *Action;
int Context = C_NO_CONTEXT;	/* current button press context */
TwmWindow *ButtonWindow;	/* button press window structure */
XEvent ButtonEvent;		/* button press event */
XEvent Event;			/* the current event */
TwmWindow *Tmp_win;		/* the current twm window */

extern Window captiveroot;
Window DragWindow;		/* variables used in moving windows */
int origDragX;
int origDragY;
int DragX;
int DragY;
unsigned int DragWidth;
unsigned int DragHeight;
unsigned int DragBW;
int CurrentDragX;
int CurrentDragY;

/* Vars to tell if the resize has moved. */
extern int ResizeOrigX;
extern int ResizeOrigY;

static int enter_flag;
static int leave_flag;
static int ColortableThrashing;
static TwmWindow *enter_win, *raise_win, *leave_win, *lower_win;

int ButtonPressed = -1;
int Cancel = FALSE;

void HandleCreateNotify(void);
void HandleShapeNotify (void);
void HandleFocusChange (void);
extern int ShapeEventBase, ShapeErrorBase;

extern Window lowerontop;

#ifdef GNOME
#  include "gnomewindefs.h"
  extern Atom _XA_WIN_WORKSPACE;
  extern Atom _XA_WIN_STATE;
#endif /* GNOME */

extern Atom _XA_WM_OCCUPATION;
extern Atom _XA_WM_CURRENTWORKSPACE;

int GnomeProxyButtonPress = -1;

/*#define TRACE_FOCUS*/
/*#define TRACE*/

static void dumpevent (XEvent *e);

#if defined(__hpux) && !defined(_XPG4_EXTENDED)
#   define FDSET int*
#else
#   define FDSET fd_set*
#endif

static unsigned int set_mask_ignore (unsigned int modifier)
{
    int i;
    unsigned int ModifierMask[8] = { ShiftMask, ControlMask, LockMask,
				     Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask,
				     Mod5Mask };

    if (Scr->IgnoreLockModifier) modifier &= ~LockMask;
    for (i = 0 ; i < 8 ; i++) {
	if (Scr->IgnoreModifier & ModifierMask [i]) modifier &= ~ModifierMask [i];
    }
    return modifier;
}

void AutoRaiseWindow (TwmWindow *tmp)
{
    RaiseWindow (tmp);

    if (ActiveMenu && ActiveMenu->w) XRaiseWindow (dpy, ActiveMenu->w);
    XSync (dpy, 0);
    enter_win = NULL;
    enter_flag = TRUE;
    raise_win = tmp;
    WMapRaise (tmp);
}

void SetRaiseWindow (TwmWindow *tmp)
{
    enter_flag = TRUE;
    enter_win = NULL;
    raise_win = tmp;
    leave_win = NULL;
    leave_flag = FALSE;
    lower_win = NULL;
    XSync (dpy, 0);
}

void AutoLowerWindow (TwmWindow *tmp)
{
    LowerWindow (tmp);

    if (ActiveMenu && ActiveMenu->w) XRaiseWindow (dpy, ActiveMenu->w);
    XSync (dpy, 0);
    enter_win = NULL;
    enter_flag = FALSE;
    raise_win = NULL;
    leave_win = NULL;
    leave_flag = TRUE;
    lower_win = tmp;
    WMapLower (tmp);
}



/***********************************************************************
 *
 *  Procedure:
 *	InitEvents - initialize the event jump table
 *
 ***********************************************************************
 */

void InitEvents(void)
{
    int i;


    ResizeWindow = (Window) 0;
    DragWindow = (Window) 0;
    enter_flag = FALSE;
    enter_win = raise_win = NULL;
    leave_flag = FALSE;
    leave_win = lower_win = NULL;

    for (i = 0; i < MAX_X_EVENT; i++)
	EventHandler[i] = HandleUnknown;

    EventHandler[Expose] = HandleExpose;
    EventHandler[CreateNotify] = HandleCreateNotify;
    EventHandler[DestroyNotify] = HandleDestroyNotify;
    EventHandler[MapRequest] = HandleMapRequest;
    EventHandler[MapNotify] = HandleMapNotify;
    EventHandler[UnmapNotify] = HandleUnmapNotify;
    EventHandler[MotionNotify] = HandleMotionNotify;
    EventHandler[ButtonRelease] = HandleButtonRelease;
    EventHandler[ButtonPress] = HandleButtonPress;
    EventHandler[EnterNotify] = HandleEnterNotify;
    EventHandler[LeaveNotify] = HandleLeaveNotify;
    EventHandler[ConfigureRequest] = HandleConfigureRequest;
    EventHandler[ClientMessage] = HandleClientMessage;
    EventHandler[PropertyNotify] = HandlePropertyNotify;
    EventHandler[KeyPress] = HandleKeyPress;
    EventHandler[KeyRelease] = HandleKeyRelease;
    EventHandler[ColormapNotify] = HandleColormapNotify;
    EventHandler[VisibilityNotify] = HandleVisibilityNotify;
    EventHandler[FocusIn] = HandleFocusChange;
    EventHandler[FocusOut] = HandleFocusChange;
    if (HasShape)
	EventHandler[ShapeEventBase+ShapeNotify] = HandleShapeNotify;
}




Time lastTimestamp = CurrentTime;	/* until Xlib does this for us */

Bool StashEventTime (register XEvent *ev)
{
    switch (ev->type) {
      case KeyPress:
      case KeyRelease:
	lastTimestamp = ev->xkey.time;
	return True;
      case ButtonPress:
      case ButtonRelease:
	lastTimestamp = ev->xbutton.time;
	return True;
      case MotionNotify:
	lastTimestamp = ev->xmotion.time;
	return True;
      case EnterNotify:
      case LeaveNotify:
	lastTimestamp = ev->xcrossing.time;
	return True;
      case PropertyNotify:
	lastTimestamp = ev->xproperty.time;
	return True;
      case SelectionClear:
	lastTimestamp = ev->xselectionclear.time;
	return True;
      case SelectionRequest:
	lastTimestamp = ev->xselectionrequest.time;
	return True;
      case SelectionNotify:
	lastTimestamp = ev->xselection.time;
	return True;
    }
    return False;
}



/*
 * WindowOfEvent - return the window about which this event is concerned; this
 * window may not be the same as XEvent.xany.window (the first window listed
 * in the structure).
 */
Window WindowOfEvent (XEvent *e)
{
    /*
     * Each window subfield is marked with whether or not it is the same as
     * XEvent.xany.window or is different (which is the case for some of the
     * notify events).
     */
    switch (e->type) {
      case KeyPress:
      case KeyRelease:  return e->xkey.window;			     /* same */
      case ButtonPress:
      case ButtonRelease:  return e->xbutton.window;		     /* same */
      case MotionNotify:  return e->xmotion.window;		     /* same */
      case EnterNotify:
      case LeaveNotify:  return e->xcrossing.window;		     /* same */
      case FocusIn:
      case FocusOut:  return e->xfocus.window;			     /* same */
      case KeymapNotify:  return e->xkeymap.window;		     /* same */
      case Expose:  return e->xexpose.window;			     /* same */
      case GraphicsExpose:  return e->xgraphicsexpose.drawable;	     /* same */
      case NoExpose:  return e->xnoexpose.drawable;		     /* same */
      case VisibilityNotify:  return e->xvisibility.window;	     /* same */
      case CreateNotify:  return e->xcreatewindow.window;	     /* DIFF */
      case DestroyNotify:  return e->xdestroywindow.window;	     /* DIFF */
      case UnmapNotify:  return e->xunmap.window;		     /* DIFF */
      case MapNotify:  return e->xmap.window;			     /* DIFF */
      case MapRequest:  return e->xmaprequest.window;		     /* DIFF */
      case ReparentNotify:  return e->xreparent.window;		     /* DIFF */
      case ConfigureNotify:  return e->xconfigure.window;	     /* DIFF */
      case ConfigureRequest:  return e->xconfigurerequest.window;    /* DIFF */
      case GravityNotify:  return e->xgravity.window;		     /* DIFF */
      case ResizeRequest:  return e->xresizerequest.window;	     /* same */
      case CirculateNotify:  return e->xcirculate.window;	     /* DIFF */
      case CirculateRequest:  return e->xcirculaterequest.window;    /* DIFF */
      case PropertyNotify:  return e->xproperty.window;		     /* same */
      case SelectionClear:  return e->xselectionclear.window;	     /* same */
      case SelectionRequest: return e->xselectionrequest.requestor;  /* DIFF */
      case SelectionNotify:  return e->xselection.requestor;	     /* same */
      case ColormapNotify:  return e->xcolormap.window;		     /* same */
      case ClientMessage:  return e->xclient.window;		     /* same */
      case MappingNotify:  return None;
    }
    return None;
}

void FixRootEvent (XEvent *e)
{
    if (Scr->Root == Scr->RealRoot)
	return;

    switch (e->type) {
      case KeyPress:
      case KeyRelease:
	  e->xkey.x_root -= Scr->rootx;
	  e->xkey.y_root -= Scr->rooty;
	  e->xkey.root    = Scr->Root;
	  break;
      case ButtonPress:
      case ButtonRelease:
	  e->xbutton.x_root -= Scr->rootx;
	  e->xbutton.y_root -= Scr->rooty;
	  e->xbutton.root    = Scr->Root;
	  break;
      case MotionNotify:
	  e->xmotion.x_root -= Scr->rootx;
	  e->xmotion.y_root -= Scr->rooty;
	  e->xmotion.root    = Scr->Root;
	  break;
      case EnterNotify:
      case LeaveNotify:
	  e->xcrossing.x_root -= Scr->rootx;
	  e->xcrossing.y_root -= Scr->rooty;
	  e->xcrossing.root    = Scr->Root;
	  break;
      default:
	  break;
    }
}



/* Move this next to GetTwmWindow()? */
static ScreenInfo *GetTwmScreen(XEvent *event)
{
    ScreenInfo *scr;

    if (XFindContext(dpy, event->xany.window, ScreenContext,
					(XPointer *)&scr) == XCNOENT) {
	scr = FindScreenInfo(WindowOfEvent(event));
    }

    return scr;
}

/***********************************************************************
 *
 *  Procedure:
 *	DispatchEvent2 -
 *      handle a single X event stored in global var Event
 *      this routine for is for a call during an f.move
 *
 ***********************************************************************
 */
Bool DispatchEvent2 (void)
{
    Window w = Event.xany.window;
    ScreenInfo *lastScr = Scr;   /* XXX_MIKE - assume Scr OK on entry... */
    StashEventTime (&Event);

    Tmp_win = GetTwmWindow(w);
    Scr = GetTwmScreen(&Event);

    dumpevent(&Event);

    if (!Scr) {
	Scr = lastScr;	    /* XXX_MIKE - try not to leave Scr NULL */
	return False;
    }
    FixRootEvent (&Event);

#ifdef SOUNDS
    play_sound(Event.type);
#endif

    if (menuFromFrameOrWindowOrTitlebar) {
	if (Event.type == Expose)
	    HandleExpose();
    } else {
	if (Event.type>= 0 && Event.type < MAX_X_EVENT)
	    (*EventHandler[Event.type])();
    }

    return True;
}

/***********************************************************************
 *
 *  Procedure:
 *	DispatchEvent - handle a single X event stored in global var Event
 *
 ***********************************************************************
 */
Bool DispatchEvent (void)
{
    Window w = Event.xany.window;
    ScreenInfo *lastScr = Scr;   /* XXX_MIKE - assume Scr OK on entry... */
    StashEventTime (&Event);

    Tmp_win = GetTwmWindow(w);
    Scr = GetTwmScreen(&Event);

    dumpevent(&Event);

    if (!Scr) {
	Scr = lastScr;	    /* XXX_MIKE - try not to leave Scr NULL */
	return False;
    }

    if (captive) {
      if ((Event.type == ConfigureNotify) && (Event.xconfigure.window == Scr->CaptiveRoot)) {
	ConfigureRootWindow (&Event);
	return (False);
      }
    }
    FixRootEvent (&Event);
    if (Event.type>= 0 && Event.type < MAX_X_EVENT) {
#ifdef SOUNDS
        play_sound(Event.type);
#endif
	(*EventHandler[Event.type])();
    }
    return True;
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleEvents - handle X events
 *
 ***********************************************************************
 */

void HandleEvents(void)
{
    while (TRUE)
    {
	if (enter_flag && !QLength(dpy)) {
	    if (enter_win && enter_win != raise_win) {
		AutoRaiseWindow (enter_win);  /* sets enter_flag T */
	    } else {
		enter_flag = FALSE;
	    }
	}
	if ( leave_flag && !QLength(dpy) ) {
	    if (leave_win && leave_win != lower_win) {
		AutoLowerWindow (leave_win); /* sets leave_flag T */
	    } else {
		leave_flag = FALSE;
	    }
	}
	if (ColortableThrashing && !QLength(dpy) && Scr) {
	    InstallColormaps(ColormapNotify, NULL);
	}
	WindowMoved = FALSE;

	CtwmNextEvent (dpy, &Event);

	if (Event.type < 0 || Event.type >= MAX_X_EVENT)
	    XtDispatchEvent (&Event);
	else

	(void) DispatchEvent ();
    }
}

#define nextEvent(event) XtAppNextEvent(appContext, event);

#ifdef VMS
extern unsigned long timefe;
#endif

static void CtwmNextEvent (Display *display, XEvent  *event)
{
    int animate = (AnimationActive && MaybeAnimate);

#ifdef VMS
    if (QLength (display) != 0) {
	nextEvent (event);
	return;
    }
    if (animate && AnimationPending) Animate ();
    while (1) {
       sys$waitfr(timefe);
       sys$clref(timefe);

       if (animate && AnimationPending) Animate ();
       if (QLength (display) != 0) {
	  nextEvent (event);
	  return;
       }
    }
#else /* VMS */
    int		found;
    fd_set	mask;
    int		fd;
    struct timeval timeout, *tout = NULL;

    if (RestartFlag)
	DoRestart(CurrentTime);
    if (XEventsQueued (display, QueuedAfterFlush) != 0) {
	nextEvent (event);
	return;
    }
    fd = ConnectionNumber (display);

#ifdef USE_SIGNALS
    if (animate && AnimationPending) Animate ();
    while (1) {
	FD_ZERO (&mask);
	FD_SET  (fd, &mask);
	found = select (fd + 1, (FDSET)&mask, (FDSET) 0, (FDSET) 0, 0);
	if (RestartFlag)
	    DoRestart(CurrentTime);
	if (found < 0) {
	    if (errno == EINTR) {
		if (animate)
		    Animate ();
	    }
	    else perror ("select");
	    continue;
	}
	if (FD_ISSET (fd, &mask)) {
	    nextEvent (event);
	    return;
	}
    }
#else /* USE_SIGNALS */
    if (animate) TryToAnimate ();
    if (RestartFlag)
	DoRestart(CurrentTime);
    if (! MaybeAnimate) {
	nextEvent (event);
	return;
    }
    if (animate) tout = (AnimationSpeed > 0) ? &timeout : NULL;
    while (1) {
	FD_ZERO (&mask);
	FD_SET  (fd, &mask);
	if (animate) {
	    timeout = AnimateTimeout;
	}
	found = select (fd + 1, (FDSET)&mask, (FDSET) 0, (FDSET) 0, tout);
	if (RestartFlag)
	    DoRestart(CurrentTime);
	if (found < 0) {
	    if (errno != EINTR) perror ("select");
	    continue;
	}
	if (FD_ISSET (fd, &mask)) {
	    nextEvent (event);
	    return;
	}
	if (found == 0) {
	    if (animate) TryToAnimate ();
	    if (RestartFlag)
		DoRestart(CurrentTime);
	    if (! MaybeAnimate) {
		nextEvent (event);
		return;
	    }
	    continue;
	}
    }
#endif /* USE_SIGNALS */
#endif /* VMS */
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleColormapNotify - colormap notify event handler
 *
 * This procedure handles both a client changing its own colormap, and
 * a client explicitly installing its colormap itself (only the window
 * manager should do that, so we must set it correctly).
 *
 ***********************************************************************
 */

void HandleColormapNotify(void)
{
    XColormapEvent *cevent = (XColormapEvent *) &Event;
    ColormapWindow *cwin, **cwins;
    TwmColormap *cmap;
    int lost, won, n, number_cwins;

/*    if (! Tmp_win) return; */
    if (XFindContext(dpy, cevent->window, ColormapContext, (XPointer *)&cwin) == XCNOENT)
	return;
    cmap = cwin->colormap;

    if (cevent->new)
    {
	if (XFindContext(dpy, cevent->colormap, ColormapContext,
			 (XPointer *)&cwin->colormap) == XCNOENT)
	    cwin->colormap = CreateTwmColormap(cevent->colormap);
	else
	    cwin->colormap->refcnt++;

	cmap->refcnt--;

	if (cevent->state == ColormapUninstalled)
	    cmap->state &= ~CM_INSTALLED;
	else
	    cmap->state |= CM_INSTALLED;

	if (cmap->state & CM_INSTALLABLE) {
	    InstallColormaps(ColormapNotify, NULL);
	}

	if (cmap->refcnt == 0)
	{
	    XDeleteContext(dpy, cmap->c, ColormapContext);
	    free((char *) cmap);
	}

	return;
    }

    if (cevent->state == ColormapUninstalled &&
	(cmap->state & CM_INSTALLABLE))
    {
	if (!(cmap->state & CM_INSTALLED))
	    return;
	cmap->state &= ~CM_INSTALLED;

	if (!ColortableThrashing)
	{
	    ColortableThrashing = TRUE;
	    XSync(dpy, 0);
	}

	if (cevent->serial >= Scr->cmapInfo.first_req)
	{
	    number_cwins = Scr->cmapInfo.cmaps->number_cwins;

	    /*
	     * Find out which colortables collided.
	     */

	    cwins = Scr->cmapInfo.cmaps->cwins;
	    for (lost = won = -1, n = 0;
		 (lost == -1 || won == -1) && n < number_cwins;
		 n++)
	    {
		if (lost == -1 && cwins[n] == cwin)
		{
		    lost = n;	/* This is the window which lost its colormap */
		    continue;
		}

		if (won == -1 &&
		    cwins[n]->colormap->install_req == cevent->serial)
		{
		    won = n;	/* This is the window whose colormap caused */
		    continue;	/* the de-install of the previous colormap */
		}
	    }

	    /*
	    ** Cases are:
	    ** Both the request and the window were found:
	    **		One of the installs made honoring the WM_COLORMAP
	    **		property caused another of the colormaps to be
	    **		de-installed, just mark the scoreboard.
	    **
	    ** Only the request was found:
	    **		One of the installs made honoring the WM_COLORMAP
	    **		property caused a window not in the WM_COLORMAP
	    **		list to lose its map.  This happens when the map
	    **		it is losing is one which is trying to be installed,
	    **		but is getting getting de-installed by another map
	    **		in this case, we'll get a scoreable event later,
	    **		this one is meaningless.
	    **
	    ** Neither the request nor the window was found:
	    **		Somebody called installcolormap, but it doesn't
	    **		affect the WM_COLORMAP windows.  This case will
	    **		probably never occur.
	    **
	    ** Only the window was found:
	    **		One of the WM_COLORMAP windows lost its colormap
	    **		but it wasn't one of the requests known.  This is
	    **		probably because someone did an "InstallColormap".
	    **		The colormap policy is "enforced" by re-installing
	    **		the colormaps which are believed to be correct.
	    */

	    if (won != -1) {
		if (lost != -1)
		{
		    /* lower diagonal index calculation */
		    if (lost > won)
			n = lost*(lost-1)/2 + won;
		    else
			n = won*(won-1)/2 + lost;
		    Scr->cmapInfo.cmaps->scoreboard[n] = 1;
		} else
		{
		    /*
		    ** One of the cwin installs caused one of the cwin
		    ** colormaps to be de-installed, so I'm sure to get an
		    ** UninstallNotify for the cwin I know about later.
		    ** I haven't got it yet, or the test of CM_INSTALLED
		    ** above would have failed.  Turning the CM_INSTALLED
		    ** bit back on makes sure we get back here to score
		    ** the collision.
		    */
		    cmap->state |= CM_INSTALLED;
		}
	    } else if (lost != -1) {
		InstallColormaps(ColormapNotify, NULL);
	    } else {
		ColortableThrashing = FALSE; /* Gross Hack for HP WABI. CL. */
	    }
	}
    }

    else if (cevent->state == ColormapUninstalled)
	cmap->state &= ~CM_INSTALLED;

    else if (cevent->state == ColormapInstalled)
	cmap->state |= CM_INSTALLED;
}



/*
 * LastFocusEvent -- skip over focus in/out events for this
 *		window.
 */

static XEvent *LastFocusEvent(Window w, XEvent *first)
{
	static XEvent current;
	XEvent *last, new;

	new= *first;
	last=NULL;
	
	do {
		if ( (new.type == FocusIn || new.type == FocusOut) 
		    && new.xfocus.mode == NotifyNormal 
		    && (new.xfocus.detail == NotifyNonlinear 
			|| new.xfocus.detail == NotifyPointer
			|| new.xfocus.detail == NotifyAncestor
			|| (new.xfocus.detail == NotifyNonlinearVirtual)
			))
		{
			current=new;
			last= &current;
#ifdef TRACE_FOCUS
			printf("! %s 0x%x mode=%d, detail=%d\n", 
			       new.xfocus.type == FocusIn?"in":"out",
			       Tmp_win,new.xfocus.mode, new.xfocus.detail);
#endif       
		}
		else
		{
#ifdef TRACE_FOCUS
			printf("~ %s 0x%x mode=%d, detail=%d\n", 
			       new.xfocus.type == FocusIn?"in":"out",
			       Tmp_win,new.xfocus.mode, new.xfocus.detail);
#endif
		}
	} while (XCheckWindowEvent(dpy, w, FocusChangeMask, &new));
	return last;
}

/*
 * HandleFocusIn -- deal with the focus moving under us.
 */

void HandleFocusIn(XFocusInEvent *event)
{

#ifdef TRACE_FOCUS
	printf("HandleFocusIn : +0x%x (0x%x, 0x%x), mode=%d, detail=%d\n", 
	       Tmp_win, Tmp_win->w, event->window, event->mode, event->detail);
#endif

    if (Tmp_win->iconmgr) return;
    if (Tmp_win->wmhints && ! Tmp_win->wmhints->input) return;
    if (Scr->Focus == Tmp_win) return;
    if (Tmp_win->AutoSqueeze && Tmp_win->squeezed) AutoSqueeze (Tmp_win);
    SetFocusVisualAttributes (Tmp_win, True);
    Scr->Focus = Tmp_win;
}

void HandleFocusOut(XFocusOutEvent *event)
{
#ifdef TRACE_FOCUS
	printf("HandleFocusOut : -0x%x (0x%x, 0x%x), mode=%d, detail=%d\n", 
	       Tmp_win, Tmp_win->w, event->window, event->mode, event->detail);
#endif

    if (Tmp_win->iconmgr) return;
    if (Scr->Focus != Tmp_win) return;
    if (Scr->SloppyFocus) return;
    if (Tmp_win->AutoSqueeze && !Tmp_win->squeezed) AutoSqueeze (Tmp_win);
    SetFocusVisualAttributes (Tmp_win, False);
    Scr->Focus= NULL;
}

void HandleFocusChange(void)
{
	XEvent *event;
	
	if (Tmp_win)
	{
		event = LastFocusEvent(Event.xany.window,&Event);
		
		if ( event != NULL)
		{
			if (event->type == FocusIn)
			  HandleFocusIn(&event->xfocus);
			else
			  HandleFocusOut(&event->xfocus);
		}
	}
}

void SynthesiseFocusOut(Window w)
{
	XEvent event;

#ifdef TRACE_FOCUS
	printf ("Synthesizing FocusOut on %x\n", w);
#endif

	event.type=FocusOut;
	event.xfocus.window=w;
	event.xfocus.mode=NotifyNormal;
	event.xfocus.detail=NotifyPointer;
	
	XPutBackEvent(dpy, &event);
}


void SynthesiseFocusIn(Window w)
{
	XEvent event;

#ifdef TRACE_FOCUS
	printf ("Synthesizing FocusIn on %x\n", w);
#endif

	event.type=FocusIn;
	event.xfocus.window=w;
	event.xfocus.mode=NotifyNormal;
	event.xfocus.detail=NotifyPointer;
	
	XPutBackEvent(dpy, &event);

}


/***********************************************************************
 *
 *  Procedure:
 *	HandleVisibilityNotify - visibility notify event handler
 *
 * This routine keeps track of visibility events so that colormap
 * installation can keep the maximum number of useful colormaps
 * installed at one time.
 *
 ***********************************************************************
 */

void HandleVisibilityNotify(void)
{
    XVisibilityEvent *vevent = (XVisibilityEvent *) &Event;
    ColormapWindow *cwin;
    TwmColormap *cmap;

    if (XFindContext(dpy, vevent->window, ColormapContext, (XPointer *)&cwin) == XCNOENT)
	return;
    
    /*
     * when Saber complains about retreiving an <int> from an <unsigned int>
     * just type "touch vevent->state" and "cont"
     */
    cmap = cwin->colormap;
    if ((cmap->state & CM_INSTALLABLE) &&
	vevent->state != cwin->visibility &&
	(vevent->state == VisibilityFullyObscured ||
	 cwin->visibility == VisibilityFullyObscured) &&
	cmap->w == cwin->w) {
	cwin->visibility = vevent->state;
	InstallWindowColormaps(VisibilityNotify, (TwmWindow *) NULL);
    } else
	cwin->visibility = vevent->state;
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleKeyRelease - key release event handler
 *
 ***********************************************************************
 */

void HandleKeyRelease(void)
{
  if (Tmp_win == Scr->currentvs->wsw->twm_win)
    WMgrHandleKeyReleaseEvent (Scr->currentvs, &Event);
}
/***********************************************************************
 *
 *  Procedure:
 *	HandleKeyPress - key press event handler
 *
 ***********************************************************************
 */

void HandleKeyPress(void)
{
    FuncKey *key;
    int len;
    unsigned int modifier;
    Window w;

    if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);

    if (ActiveMenu != NULL) {
	MenuItem *item;
	int	 offset;
	char *keynam;
	KeySym keysym;
	int xx, yy, wx, wy;
	Window junkW;

	item = (MenuItem*) 0;

	keysym = XLookupKeysym  ((XKeyEvent*) &Event, 0);
	if (! keysym) return;
	keynam = XKeysymToString (keysym);
	if (! keynam) return;

	if (!strcmp (keynam, "Down") || !strcmp (keynam, "space")) {
	    xx = Event.xkey.x;
	    yy = Event.xkey.y + Scr->EntryHeight;
	    XTranslateCoordinates (dpy, Scr->Root, ActiveMenu->w, xx, yy, &wx, &wy, &junkW);
	    if ((wy < 0) || (wy > ActiveMenu->height))
		yy -= (wy - (Scr->EntryHeight / 2) - 2);
	    if ((wx < 0) || (wx > ActiveMenu->width))
		xx -= (wx - (ActiveMenu->width / 2));
	    XWarpPointer (dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
			ActiveMenu->width, ActiveMenu->height, xx, yy);
	    return;
	}
	else
	if (!strcmp (keynam, "Up")) {
	    xx = Event.xkey.x;
	    yy = Event.xkey.y - Scr->EntryHeight;
	    XTranslateCoordinates (dpy, Scr->Root, ActiveMenu->w, xx, yy, &wx, &wy, &junkW);
	    if ((wy < 0) || (wy > ActiveMenu->height))
		yy -= (wy - ActiveMenu->height + (Scr->EntryHeight / 2) + 2);
	    if ((wx < 0) || (wx > ActiveMenu->width))
		xx -= (wx - (ActiveMenu->width / 2));
	    XWarpPointer (dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
			ActiveMenu->width, ActiveMenu->height, xx, yy);
	    return;
	}
	else
	if (!strcmp (keynam, "Right") || !strcmp (keynam, "Return")) {
	    item = ActiveItem;
	}
	else
	if (!strcmp (keynam, "Left") || !strcmp(keynam, "Escape")) {
	    MenuRoot *menu;

	    if (ActiveMenu->pinned) return;
	    if (!ActiveMenu->prev || MenuDepth == 1) {
		PopDownMenu ();
		XUngrabPointer  (dpy, CurrentTime);
		return;
	    }
	    xx = Event.xkey.x;
	    yy = Event.xkey.y;
	    menu = ActiveMenu->prev;
	    XTranslateCoordinates (dpy, Scr->Root, menu->w, xx, yy, &wx, &wy, &junkW);
	    xx -= (wx - (menu->width / 2));
	    if (menu->lastactive)
		yy -= (wy - menu->lastactive->item_num * Scr->EntryHeight -
			(Scr->EntryHeight / 2) - 2);
	    else
		yy -= (wy - (Scr->EntryHeight / 2) - 2);
	    XUnmapWindow (dpy, ActiveMenu->w);
	    if (Scr->Shadow) XUnmapWindow (dpy, ActiveMenu->shadow);
	    XWarpPointer (dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
			menu->width, menu->height, xx, yy);
	    return;
	}
	else
	if (strlen (keynam) == 1) {
	    MenuItem *startitem;
	    xx = Event.xkey.x;
	    yy = Event.xkey.y;

	    startitem = ActiveItem ? ActiveItem : ActiveMenu->first;
	    item = startitem->next;
	    if (item == (MenuItem*) 0) item = ActiveMenu->first;
	    modifier = (Event.xkey.state & mods_used);
	    modifier = set_mask_ignore (modifier);

	    while (item != startitem) {
		Boolean	 matched = False;
		offset = 0;
		switch (item->item [0]) {
		    case '^' :
			if ((modifier & ControlMask) &&
			    (keynam [0] == Tolower (item->item [1])))
			    matched = True;
			break;
		    case '~' :
			if ((modifier & Mod1Mask) &&
			    (keynam [0] == Tolower (item->item [1])))
			    matched = True;
			break;
		    case ' ' :
			offset = 1;
			/*FALLTHROUGH*/
		    default :
			if (((Scr->IgnoreCaseInMenuSelection) &&
			    (keynam [0] == Tolower (item->item [offset]))) ||

			     ((modifier & ShiftMask) && Isupper (item->item [offset]) &&
			     (keynam [0] == Tolower (item->item [offset]))) ||

			    (!(modifier & ShiftMask) && Islower (item->item [offset]) &&
			     (keynam [0] == item->item [offset]))) matched = True;
			break;
		}
		if (matched) break;
		item = item->next;
		if (item == (MenuItem*) 0) item = ActiveMenu->first;
	    }
	    if (item == startitem) return;
	    wx = ActiveMenu->width / 2;
	    wy = (item->item_num * Scr->EntryHeight) + (Scr->EntryHeight / 2) + 2;
	    XTranslateCoordinates (dpy, ActiveMenu->w, Scr->Root, wx, wy, &xx, &yy, &junkW);
	    XWarpPointer (dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
			ActiveMenu->width, ActiveMenu->height, xx, yy);
	    return;
	}
	else return;
	if (item) {
	    switch (item->func) {
		case 0 :
		case F_TITLE :
		    break;

		case F_MENU :
		    if (!strcmp (keynam, "Return")) {
			if (ActiveMenu == Scr->Workspaces) {
			    PopDownMenu();
			    XUngrabPointer  (dpy, CurrentTime);
			    GotoWorkSpaceByName (Scr->currentvs, item->action + 8);
			}
			else {
			    ExecuteFunction (item->func, item->action,
				ButtonWindow ? ButtonWindow->frame : None,
				ButtonWindow, &Event, Context, FALSE);
			    PopDownMenu();
			}
			return;
		    }
		    xx = Event.xkey.x;
		    yy = Event.xkey.y;
		    XTranslateCoordinates (dpy, Scr->Root, ActiveMenu->w, xx, yy,
				&wx, &wy, &junkW);
		    if (ActiveItem) {
			ActiveItem->state = 0;
			PaintEntry (ActiveMenu, ActiveItem,  False);
			ActiveItem = NULL;
		    }
		    xx -= (wx - ActiveMenu->width);
		    yy -= (wy - item->item_num * Scr->EntryHeight - (Scr->EntryHeight / 2) - 2);
		    Event.xkey.x_root = xx;
		    Event.xkey.y_root = yy;
		    XWarpPointer (dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
				ActiveMenu->width, ActiveMenu->height, xx, yy);
		    if (ActiveMenu == Scr->Workspaces)
			CurrentSelectedWorkspace = item->item;
		    do_key_menu (item->sub, None);
		    CurrentSelectedWorkspace = NULL;
		    break;

		default :
		    if (item->func != F_PIN) PopDownMenu();
		    ExecuteFunction (item->func, item->action,
			ButtonWindow ? ButtonWindow->frame : None,
			ButtonWindow, &Event, Context, FALSE);
	    }
	}
	else {
	    PopDownMenu();
	    XUngrabPointer  (dpy, CurrentTime);
	}
	return;
    }

    Context = C_NO_CONTEXT;
    if (Event.xany.window == Scr->Root) {
	if (AlternateContext) {
	    XUngrabPointer  (dpy, CurrentTime);
	    XUngrabKeyboard (dpy, CurrentTime);
	    AlternateContext = False;
	    Context = C_ALTERNATE;
	}
	else
	if (AlternateKeymap && Event.xkey.subwindow) {
	    w = Event.xkey.subwindow;
	    Tmp_win = GetTwmWindow(w);
	    if (Tmp_win) Event.xany.window = Tmp_win->w;
	}
	else Context = C_ROOT;
    }
    if (Tmp_win)
    {
	if (Event.xany.window == Tmp_win->title_w)
	    Context = C_TITLE;
	if (Event.xany.window == Tmp_win->w)
	    Context = C_WINDOW;
	if (Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w))
	    Context = C_ICON;
	if (Event.xany.window == Tmp_win->frame)
	    Context = C_FRAME;
	if (Tmp_win->iconmanagerlist) {
	    if (Event.xany.window == Tmp_win->iconmanagerlist->w ||
		Event.xany.window == Tmp_win->iconmanagerlist->icon)
		Context = C_ICONMGR;
	}
	if (Tmp_win->wspmgr)
	    Context = C_WORKSPACE;
    }

    modifier = (Event.xkey.state | AlternateKeymap) & mods_used;
    modifier = set_mask_ignore (modifier);
    if (AlternateKeymap) {
	XUngrabPointer  (dpy, CurrentTime);
	XUngrabKeyboard (dpy, CurrentTime);
	AlternateKeymap = 0;
    }
    for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next)
    {
	if (key->keycode == Event.xkey.keycode &&
	    key->mods == modifier &&
	    (key->cont == Context || key->cont == C_NAME))
	{
	    /* weed out the functions that don't make sense to execute
	     * from a key press 
	     * TODO: add keyboard moving/resizing of windows.
	     */
	    if (key->func == F_MOVE || key->func == F_RESIZE)
		return;

	    if (key->cont != C_NAME)
	    {
		if (key->func == F_MENU) {
		    ButtonEvent = Event;
		    ButtonWindow = Tmp_win;
		    do_key_menu (key->menu, (Window) None);
		}
		else {
		    ExecuteFunction(key->func, key->action, Event.xany.window,
			Tmp_win, &Event, Context, FALSE);
		    if (!AlternateKeymap && !AlternateContext)
			XUngrabPointer(dpy, CurrentTime);
		}
		return;
	    }
	    else
	    {
		int matched = FALSE;
		len = strlen(key->win_name);

		/* try and match the name first */
		for (Tmp_win = Scr->FirstWindow; Tmp_win != NULL;
		    Tmp_win = Tmp_win->next)
		{
		    if (!strncmp(key->win_name, Tmp_win->name, len))
		    {
			matched = TRUE;
			ExecuteFunction(key->func, key->action, Tmp_win->frame,
			    Tmp_win, &Event, C_FRAME, FALSE);
			if (!AlternateKeymap && !AlternateContext)
			    XUngrabPointer(dpy, CurrentTime);
		    }
		}

		/* now try the res_name */
		if (!matched)
		    for (Tmp_win = Scr->FirstWindow; Tmp_win != NULL;
			 Tmp_win = Tmp_win->next)
		    {
			if (!strncmp(key->win_name, Tmp_win->class.res_name, len))
			{
			    matched = TRUE;
			    ExecuteFunction(key->func, key->action, Tmp_win->frame,
					    Tmp_win, &Event, C_FRAME, FALSE);
			    if (!AlternateKeymap && !AlternateContext)
				XUngrabPointer(dpy, CurrentTime);
			}
		    }

		/* now try the res_class */
		if (!matched)
		    for (Tmp_win = Scr->FirstWindow; Tmp_win != NULL;
			 Tmp_win = Tmp_win->next)
		    {
			if (!strncmp(key->win_name, Tmp_win->class.res_class, len))
			{
			    matched = TRUE;
			    ExecuteFunction(key->func, key->action, Tmp_win->frame,
					    Tmp_win, &Event, C_FRAME, FALSE);
			    if (!AlternateKeymap && !AlternateContext)
				XUngrabPointer(dpy, CurrentTime);
			}
		    }
		if (matched)
		    return;
	    }
	}
    }

    /* if we get here, no function key was bound to the key.  Send it
     * to the client if it was in a window we know about.
     */
    if (Tmp_win)
    {
        /* if (Tmp_win == Scr->currentvs->wsw->twm_win) */
	if (Tmp_win->wspmgr) {
	  WMgrHandleKeyPressEvent (Scr->currentvs, &Event);
	  return;
        }
        if (Tmp_win->icon && ((Event.xany.window == Tmp_win->icon->w) ||
	    (Event.xany.window == Tmp_win->frame) ||
	    (Event.xany.window == Tmp_win->title_w) ||
	    (Tmp_win->iconmanagerlist &&
	     (Event.xany.window == Tmp_win->iconmanagerlist->w))))
        {
            Event.xkey.window = Tmp_win->w;
            XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event);
        }
    }

}



static void free_window_names (TwmWindow *tmp,
			       Bool nukefull, Bool nukename, Bool nukeicon)
{
/*
 * XXX - are we sure that nobody ever sets these to another constant (check
 * twm windows)?
 */
    if ((tmp->name == tmp->full_name) && (tmp->name == tmp->icon_name)) {
	if (nukefull && nukename && nukeicon)
	    FreeWMPropertyString(tmp->name);
    } else
    if (tmp->name == tmp->full_name) {
	if (nukename && nukefull)
	    FreeWMPropertyString(tmp->name);
	if (nukeicon)
	    FreeWMPropertyString(tmp->icon_name);
    } else
    if (tmp->name == tmp->icon_name) {
	if (nukename && nukeicon)
	    FreeWMPropertyString(tmp->name);
	if (nukefull)
	    FreeWMPropertyString(tmp->full_name);
    } else
    if (tmp->icon_name == tmp->full_name) {
	if (nukeicon && nukefull)
	    FreeWMPropertyString(tmp->icon_name);
	if (nukename)
	    FreeWMPropertyString(tmp->name);
    } else {
	if (nukefull)
	    FreeWMPropertyString(tmp->full_name);
	if (nukename)
	    FreeWMPropertyString(tmp->name);
	if (nukeicon)
	    FreeWMPropertyString(tmp->icon_name);
    }
    return;
}



void free_cwins (TwmWindow *tmp)
{
    int i;
    TwmColormap *cmap;

    if (tmp->cmaps.number_cwins) {
	for (i = 0; i < tmp->cmaps.number_cwins; i++) {
	     if (--tmp->cmaps.cwins[i]->refcnt == 0) {
		cmap = tmp->cmaps.cwins[i]->colormap;
		if (--cmap->refcnt == 0) {
		    XDeleteContext(dpy, cmap->c, ColormapContext);
		    free((char *) cmap);
		}
		XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext);
		free((char *) tmp->cmaps.cwins[i]);
	    }
	}
	free((char *) tmp->cmaps.cwins);
	if (tmp->cmaps.number_cwins > 1) {
	    free(tmp->cmaps.scoreboard);
	    tmp->cmaps.scoreboard = NULL;
	}
	tmp->cmaps.number_cwins = 0;
    }
}



/***********************************************************************
 *
 *  Procedure:
 *	HandlePropertyNotify - property notify event handler
 *
 ***********************************************************************
 */

void HandlePropertyNotify(void)
{
    unsigned char *prop = NULL;
    Atom actual = None;
    int actual_format;
    unsigned long nitems, bytesafter;
    unsigned long valuemask;		/* mask for create windows */
    XSetWindowAttributes attributes;	/* attributes for create windows */
    Pixmap pm;
    int icon_change;
    XRectangle inc_rect;
    XRectangle logical_rect;

    unsigned char *gwkspc;

    /* watch for standard colormap changes */
    if (Event.xproperty.window == Scr->Root) {
	XStandardColormap *maps = NULL;
	int nmaps;

	if (Event.xproperty.atom == _XA_WM_CURRENTWORKSPACE) {
	    switch (Event.xproperty.state) {
		case PropertyNewValue:
		    if (XGetWindowProperty (dpy, Scr->Root, _XA_WM_CURRENTWORKSPACE,
				0L, 200L, False, XA_STRING, &actual, &actual_format,
				&nitems, &bytesafter, &prop) == Success) {
			if (nitems == 0) return;
			GotoWorkSpaceByName (Scr->vScreenList, (char*)prop);
			XFree ((char*) prop);
		    }
		    return;

		default:
		    return;
	    }
	}
	switch (Event.xproperty.state) {
	  case PropertyNewValue:
	    if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, 
				  Event.xproperty.atom)) {
		/* if got one, then replace any existing entry */
		InsertRGBColormap (Event.xproperty.atom, maps, nmaps, True);
	    }
	    return;

	  case PropertyDelete:
	    RemoveRGBColormap (Event.xproperty.atom);
	    return;
	}
    }

    if (!Tmp_win) return;		/* unknown window */

#define MAX_NAME_LEN 200L		/* truncate to this many */
#define MAX_ICON_NAME_LEN 200L		/* ditto */

    switch (Event.xproperty.atom) {
      case XA_WM_NAME:
	prop = GetWMPropertyString(Tmp_win->w, XA_WM_NAME);
	if (prop == NULL) return;
#ifdef CLAUDE
	if (strstr (prop, " - Mozilla")) {
	  char *moz = strstr (prop, " - Mozilla");
	  *moz = '\0';
	}
#endif
	free_window_names (Tmp_win, True, True, False);

	Tmp_win->full_name = (char*) prop;
	Tmp_win->name = (char*) prop;
	Tmp_win->nameChanged = 1;
	XmbTextExtents(Scr->TitleBarFont.font_set,
		       Tmp_win->name, strlen (Tmp_win->name),
		       &inc_rect, &logical_rect);
	Tmp_win->name_width = logical_rect.width;

	SetupWindow (Tmp_win, Tmp_win->frame_x, Tmp_win->frame_y,
		     Tmp_win->frame_width, Tmp_win->frame_height, -1);

	if (Tmp_win->title_w) XClearArea(dpy, Tmp_win->title_w, 0,0,0,0, True);
	if (Scr->AutoOccupy) WmgrRedoOccupation (Tmp_win);

	/* Experimental, not yet working.
	{
	    ColorPair cp;
	    int f, b;

	    f = GetColorFromList (Scr->TitleForegroundL, Tmp_win->full_name,
							&Tmp_win->class, &cp.fore);
	    b = GetColorFromList (Scr->TitleBackgroundL, Tmp_win->full_name,
							&Tmp_win->class, &cp.back);
	    if (f || b) {
		if (Scr->use3Dtitles  && !Scr->BeNiceToColormap) GetShadeColors (&cp);
		Tmp_win->title = cp;
	    }
	    f = GetColorFromList (Scr->BorderColorL, Tmp_win->full_name,
						    &Tmp_win->class, &cp.fore);
	    b = GetColorFromList (Scr->BorderColorL, Tmp_win->full_name,
						    &Tmp_win->class, &cp.back);
	    if (f || b) {
		if (Scr->use3Dborders && !Scr->BeNiceToColormap) GetShadeColors (&cp);
		Tmp_win->borderC = cp;
	    }

	    f = GetColorFromList (Scr->BorderTileForegroundL, Tmp_win->full_name,
							     &Tmp_win->class, &cp.fore);
	    b = GetColorFromList (Scr->BorderTileBackgroundL, Tmp_win->full_name,
							     &Tmp_win->class, &cp.back);
	    if (f || b) {
		if (Scr->use3Dborders && !Scr->BeNiceToColormap) GetShadeColors (&cp);
		Tmp_win->border_tile = cp;
	    }
	}
	*/
	/*
	 * if the icon name is NoName, set the name of the icon to be
	 * the same as the window 
	 */
	if (Tmp_win->icon_name == NoName) {
	    Tmp_win->icon_name = Tmp_win->name;
	    RedoIcon();
	}
	break;

      case XA_WM_ICON_NAME:
	prop = GetWMPropertyString(Tmp_win->w, XA_WM_ICON_NAME);
	if (prop == NULL) return;
#ifdef CLAUDE
	if (strstr (prop, " - Mozilla")) {
	  char *moz = strstr (prop, " - Mozilla");
	  *moz = '\0';
	}
#endif
	icon_change = strcmp (Tmp_win->icon_name, (char*) prop);
	free_window_names (Tmp_win, False, False, True);
	Tmp_win->icon_name = (char*) prop;

	if (icon_change) {
	    RedoIcon();
	}
	break;

      case XA_WM_HINTS:
	if (Tmp_win->wmhints) XFree ((char *) Tmp_win->wmhints);
	Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window);

	if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & WindowGroupHint)) {
	    Tmp_win->group = Tmp_win->wmhints->window_group;
	    if (Tmp_win->group && !GetTwmWindow(Tmp_win->group))
		Tmp_win->group = 0;	/* see comment in AddWindow() */
	}

	if (!Tmp_win->forced && Tmp_win->wmhints &&
	    Tmp_win->wmhints->flags & IconWindowHint) {
	    if (Tmp_win->icon && Tmp_win->icon->w) {
	    	int icon_x, icon_y;

		/*
		 * There's already an icon window.
		 * Try to find out where it is; if we succeed, move the new
		 * window to where the old one is.
		 */
		if (XGetGeometry (dpy, Tmp_win->icon->w, &JunkRoot, &icon_x,
		  &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) {
		    /*
		     * Move the new icon window to where the old one was.
		     */
		    XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x,
		      icon_y);
		}

		/*
		 * If the window is iconic, map the new icon window.
		 */
		if (Tmp_win->isicon)
		    XMapWindow(dpy, Tmp_win->wmhints->icon_window);

		/*
		 * Now, if the old window isn't ours, unmap it, otherwise
		 * just get rid of it completely.
		 */
		if (Tmp_win->icon_not_ours) {
		    if (Tmp_win->icon->w != Tmp_win->wmhints->icon_window)
			XUnmapWindow(dpy, Tmp_win->icon->w);
		} else
		    XDestroyWindow(dpy, Tmp_win->icon->w);

		/*
		 * The new icon window isn't our window, so note that fact
		 * so that we don't treat it as ours.
		 */
		Tmp_win->icon_not_ours = TRUE;

		/*
		 * Now make the new window the icon window for this window,
		 * and set it up to work as such (select for key presses
		 * and button presses/releases, set up the contexts for it,
		 * and define the cursor for it).
		 */
		Tmp_win->icon->w = Tmp_win->wmhints->icon_window;
		XSelectInput (dpy, Tmp_win->icon->w,
		  KeyPressMask | ButtonPressMask | ButtonReleaseMask);
		XSaveContext(dpy, Tmp_win->icon->w, TwmContext, (XPointer)Tmp_win);
		XSaveContext(dpy, Tmp_win->icon->w, ScreenContext, (XPointer)Scr);
		XDefineCursor(dpy, Tmp_win->icon->w, Scr->IconCursor);
	    }
	}

	if (Tmp_win->icon && Tmp_win->icon->w && !Tmp_win->forced && Tmp_win->wmhints &&
	    (Tmp_win->wmhints->flags & IconPixmapHint)) {
	    int x;
	    if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
			       &JunkX, &JunkY, (unsigned int *)&Tmp_win->icon->width, 
			       (unsigned int *)&Tmp_win->icon->height, &JunkBW,
				&JunkDepth)) {
		return;
	    }

	    pm = XCreatePixmap (dpy, Scr->Root, Tmp_win->icon->width,
				Tmp_win->icon->height, Scr->d_depth);

	    FB(Tmp_win->icon->iconc.fore, Tmp_win->icon->iconc.back);

	    if (JunkDepth == Scr->d_depth)
		XCopyArea  (dpy, Tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
			0,0, Tmp_win->icon->width, Tmp_win->icon->height, 0, 0);
	    else
		XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
			0,0, Tmp_win->icon->width, Tmp_win->icon->height, 0, 0, 1 );

	    if (Tmp_win->icon->image) {
		if (Tmp_win->icon->image->pixmap)
		    XFreePixmap (dpy, Tmp_win->icon->image->pixmap);
		Tmp_win->icon->image->pixmap = pm;
		Tmp_win->icon->image->width  = Tmp_win->icon->width;
		Tmp_win->icon->image->height = Tmp_win->icon->height;
		Tmp_win->icon->image->mask   = None;
		Tmp_win->icon->image->next   = None;
	    }

	    valuemask = CWBackPixmap;
	    attributes.background_pixmap = pm;

	    if (Tmp_win->icon->bm_w)
		XDestroyWindow(dpy, Tmp_win->icon->bm_w);

	    x = GetIconOffset (Tmp_win->icon);
	    Tmp_win->icon->bm_w =
	      XCreateWindow (dpy, Tmp_win->icon->w, x, 0,
			     (unsigned int) Tmp_win->icon->width,
			     (unsigned int) Tmp_win->icon->height,
			     (unsigned int) 0, Scr->d_depth,
			     (unsigned int) CopyFromParent, Scr->d_visual,
			     valuemask, &attributes);

	    if (! (Tmp_win->wmhints->flags & IconMaskHint)) {
		XRectangle rect;

		rect.x      = x;
		rect.y      = 0;
		rect.width  = Tmp_win->icon->width;
		rect.height = Tmp_win->icon->height;
		XShapeCombineRectangles (dpy, Tmp_win->icon->w, ShapeBounding, 0,
					0, &rect, 1, ShapeUnion, 0);
	    }
	    XMapSubwindows (dpy, Tmp_win->icon->w);
	    RedoIconName();
	}
	if (Tmp_win->icon && Tmp_win->icon->w && !Tmp_win->forced && Tmp_win->wmhints &&
	    (Tmp_win->wmhints->flags & IconMaskHint)) {
	    int x;
	    Pixmap mask;
	    GC gc;

	    if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_mask, &JunkRoot,
			       &JunkX, &JunkY, &JunkWidth, &JunkHeight, &JunkBW,
			       &JunkDepth)) {
		return;
	    }
	    if (JunkDepth != 1) return;

	    mask = XCreatePixmap (dpy, Scr->Root, JunkWidth, JunkHeight, 1);
	    if (!mask) return;
	    gc = XCreateGC (dpy, mask, 0, NULL);
	    if (!gc) return;
	    XCopyArea (dpy, Tmp_win->wmhints->icon_mask, mask, gc,
		       0, 0, JunkWidth, JunkHeight, 0, 0);
	    XFreeGC (dpy, gc);
	    x = GetIconOffset (Tmp_win->icon);
	    XShapeCombineMask (dpy, Tmp_win->icon->bm_w, ShapeBounding, 0, 0, mask, ShapeSet);
	    XShapeCombineMask (dpy, Tmp_win->icon->w,    ShapeBounding, x, 0, mask, ShapeSet);
	    if (Tmp_win->icon->image) {
		if (Tmp_win->icon->image->mask) XFreePixmap (dpy, Tmp_win->icon->image->mask);
		Tmp_win->icon->image->mask = mask;
		RedoIconName ();
	    }
	}
	break;

      case XA_WM_NORMAL_HINTS:
      {
	GetWindowSizeHints (Tmp_win);
	break;
      }
      default:
	if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS) {
	    FetchWmColormapWindows (Tmp_win);	/* frees old data */
	    break;
	} else if (Event.xproperty.atom == _XA_WM_PROTOCOLS) {
	    FetchWmProtocols (Tmp_win);
	    break;
	} else if (Event.xproperty.atom == _XA_WM_OCCUPATION) {
	  if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L, MAX_NAME_LEN, False,
				  XA_STRING, &actual, &actual_format, &nitems,
				  &bytesafter, &prop) != Success ||
	      actual == None) return;
	  ChangeOccupation (Tmp_win, GetMaskFromProperty (prop, nitems));
	  XFree ((char *)prop);
	}
#ifdef GNOME
	else if (Event.xproperty.atom == _XA_WIN_WORKSPACE){
	  if(XGetWindowProperty(dpy, Tmp_win->w, Event.xproperty.atom, 0L, 32, False,
				XA_CARDINAL, &actual, &actual_format, &nitems, &bytesafter,
				&gwkspc) != Success || actual == None) return;
	  ChangeOccupation (Tmp_win, 1 << (int)(*gwkspc));
	  XFree ((char *)gwkspc);
	}
#endif /* GNOME */
	break;
    }
}



static void RedoIcon(void)
{
    Icon *icon;
    char *pattern;

    if (Tmp_win->icon_not_ours) {
	RedoIconName ();
	return;
    }
    icon = (Icon*) 0;
    if ((pattern = LookPatternInNameList (Scr->IconNames, Tmp_win->icon_name))) {
	icon = (Icon*) LookInNameList (Tmp_win->iconslist, pattern);
    }
    else
    if ((pattern = LookPatternInNameList (Scr->IconNames, Tmp_win->full_name))) {
	icon = (Icon*) LookInNameList (Tmp_win->iconslist, pattern);
    }
    else
    if ((pattern = LookPatternInList (Scr->IconNames, Tmp_win->full_name, &Tmp_win->class))) {
	icon = (Icon*) LookInNameList (Tmp_win->iconslist, pattern);
    }
    if (pattern == NULL) {
	RedoIconName ();
	return;
    }
    if (icon != NULL) {
	if (Tmp_win->icon == icon) {
	    RedoIconName ();
	    return;
	}
	if (Tmp_win->icon_on && visible (Tmp_win)) {
	    IconDown (Tmp_win);
	    if (Tmp_win->icon && Tmp_win->icon->w) XUnmapWindow (dpy, Tmp_win->icon->w);
	    Tmp_win->icon = icon;
	    IconUp (Tmp_win);
	    XMapRaised (dpy, Tmp_win->icon->w);
        }
	else {
	    Tmp_win->icon = icon;
	}
	RedoIconName ();
    }
    else {
	if (Tmp_win->icon_on && visible (Tmp_win)) {
	    IconDown (Tmp_win);
	    if (Tmp_win->icon && Tmp_win->icon->w) XUnmapWindow (dpy, Tmp_win->icon->w);
	    CreateIconWindow (Tmp_win, -100, -100);
	    XMapRaised (dpy, Tmp_win->icon->w);
	}
	else {
	    Tmp_win->icon = (Icon*) 0;
	    WMapUpdateIconName (Tmp_win);
	}
	RedoIconName ();
    }
}

/***********************************************************************
 *
 *  Procedure:
 *	RedoIconName - procedure to re-position the icon window and name
 *
 ***********************************************************************
 */

void RedoIconName(void)
{
    int x;
    XRectangle ink_rect;
    XRectangle logical_rect;

    if (Scr->NoIconTitlebar || 
	LookInNameList (Scr->NoIconTitle, Tmp_win->icon_name) ||
	LookInList (Scr->NoIconTitle, Tmp_win->full_name, &Tmp_win->class)) goto wmapupd;
    if (Tmp_win->iconmanagerlist)
    {
	/* let the expose event cause the repaint */
	XClearArea(dpy, Tmp_win->iconmanagerlist->w, 0,0,0,0, True);

	if (Scr->SortIconMgr)
	    SortIconManager(Tmp_win->iconmanagerlist->iconmgr);
    }

    if (!Tmp_win->icon  || !Tmp_win->icon->w) goto wmapupd;

    if (Tmp_win->icon_not_ours) goto wmapupd;

    XmbTextExtents(Scr->IconFont.font_set,
		   Tmp_win->icon_name, strlen(Tmp_win->icon_name),
		   &ink_rect, &logical_rect);
    Tmp_win->icon->w_width = logical_rect.width;
    Tmp_win->icon->w_width += 2 * Scr->IconManagerShadowDepth + 6;
    if (Tmp_win->icon->w_width > Scr->MaxIconTitleWidth)
	Tmp_win->icon->w_width = Scr->MaxIconTitleWidth;

    if (Tmp_win->icon->w_width < Tmp_win->icon->width)
    {
	Tmp_win->icon->x = (Tmp_win->icon->width - Tmp_win->icon->w_width)/2;
	Tmp_win->icon->x += Scr->IconManagerShadowDepth + 3;
	Tmp_win->icon->w_width = Tmp_win->icon->width;
    }
    else
    {
	Tmp_win->icon->x = Scr->IconManagerShadowDepth + 3;
    }

    x = GetIconOffset (Tmp_win->icon);
    Tmp_win->icon->y = Tmp_win->icon->height + Scr->IconFont.height +
				Scr->IconManagerShadowDepth;
    Tmp_win->icon->w_height = Tmp_win->icon->height + Scr->IconFont.height +
				2 * Scr->IconManagerShadowDepth + 6;

    XResizeWindow(dpy, Tmp_win->icon->w, Tmp_win->icon->w_width, Tmp_win->icon->w_height);
    if (Tmp_win->icon->bm_w)
    {
	XRectangle rect;

	XMoveWindow(dpy, Tmp_win->icon->bm_w, x, 0);
	XMapWindow(dpy, Tmp_win->icon->bm_w);
	if (Tmp_win->icon->image && Tmp_win->icon->image->mask) {
	    XShapeCombineMask(dpy, Tmp_win->icon->bm_w, ShapeBounding, 0, 0,
				Tmp_win->icon->image->mask, ShapeSet);
	    XShapeCombineMask(dpy, Tmp_win->icon->w, ShapeBounding, x, 0,
				Tmp_win->icon->image->mask, ShapeSet);
	} else if (Tmp_win->icon->has_title) {
	    rect.x      = x;
	    rect.y      = 0;
	    rect.width  = Tmp_win->icon->width;
	    rect.height = Tmp_win->icon->height;
	    XShapeCombineRectangles (dpy, Tmp_win->icon->w, ShapeBounding,
			0, 0, &rect, 1, ShapeSet, 0);
	}
	if (Tmp_win->icon->has_title) {
	    if (Scr->ShrinkIconTitles && Tmp_win->icon->title_shrunk) {
		rect.x      = x;
		rect.y      = Tmp_win->icon->height;
		rect.width  = Tmp_win->icon->width;
		rect.height = Tmp_win->icon->w_height - Tmp_win->icon->height;
	    } else {
		rect.x      = 0;
		rect.y      = Tmp_win->icon->height;
		rect.width  = Tmp_win->icon->w_width;
		rect.height = Tmp_win->icon->w_height - Tmp_win->icon->height;
	    }
	    XShapeCombineRectangles (dpy,  Tmp_win->icon->w, ShapeBounding, 0,
				     0, &rect, 1, ShapeUnion, 0);
	}
    }
    if (Scr->ShrinkIconTitles &&
	Tmp_win->icon->title_shrunk &&
	Tmp_win->icon_on && (visible (Tmp_win))) {
	IconDown (Tmp_win);
	IconUp (Tmp_win);
    }
    if (Tmp_win->isicon)
    {
	XClearArea(dpy, Tmp_win->icon->w, 0, 0, 0, 0, True);
    }
wmapupd:
    WMapUpdateIconName (Tmp_win);
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleClientMessage - client message event handler
 *
 ***********************************************************************
 */

void HandleClientMessage(void)
{
    TwmWindow *twm_win;
    int i;

    if (Event.xclient.message_type == _XA_WM_CHANGE_STATE) {
	if (Tmp_win != NULL) {
	    if (Event.xclient.data.l[0] == IconicState && !Tmp_win->isicon) {
		XEvent button;
		XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild,
			       &(button.xmotion.x_root),
			       &(button.xmotion.y_root),
			       &JunkX, &JunkY, &JunkMask);

		ExecuteFunction (F_ICONIFY, NULLSTR, Event.xany.window,
				 Tmp_win, &button, FRAME, FALSE);
		XUngrabPointer (dpy, CurrentTime);
	    }
	}
	return;
    }
#ifdef GNOME
    /* 6/19/1999 nhd for GNOME compliance */
    if (Event.xclient.message_type == _XA_WIN_WORKSPACE) {
      /* XXXXX
	 supposedly works with a single screen, but is less certain with
	 multiple screens */
      GotoWorkSpaceByNumber (Scr->currentvs, Event.xclient.data.l[0]);
      return;
    }
    if (Event.xclient.message_type == _XA_WIN_STATE) {
      unsigned long new_stuff = (unsigned long) Event.xclient.data.l [1];
      unsigned long old_stuff = (unsigned long) Event.xclient.data.l [0];
      Window	      tmp_win = Event.xclient.window;
      for (twm_win = Scr->FirstWindow; twm_win != NULL; twm_win = twm_win->next)
	if (twm_win->w == tmp_win) break;
      if (twm_win == NULL) return;
      for (i = 1; i < (1 << 10); i <<= 1){
	switch (old_stuff & i) {
	  case WIN_STATE_STICKY: /* sticky */
	    if (new_stuff & i) OccupyAll (twm_win);
	    else ChangeOccupation (twm_win, (1<<(Scr->currentvs->wsw->currentwspc->number)));
	    break;
	  case WIN_STATE_MINIMIZED: /* minimized - reserved */
	    break;
	  case WIN_STATE_MAXIMIZED_VERT: /* window in maximized V state */
	    break;
	  case WIN_STATE_MAXIMIZED_HORIZ: /* maximized horizontally */
	    break;
	  case WIN_STATE_HIDDEN: /* hidden - what does this mean?? */
	    break;
	  case WIN_STATE_SHADED: /* shaded (squeezed) */
	    Squeeze (twm_win);
	    break;
	  case WIN_STATE_HID_WORKSPACE: /* not on this workspace */
	    break;
	  case WIN_STATE_HID_TRANSIENT: /* owner of transient hidden ? */
	    break;
	  case WIN_STATE_FIXED_POSITION: /* position fixed, don't move */
	    break;
	  case WIN_STATE_ARRANGE_IGNORE: /* ignore when auto-arranging */
	    break;
	}
      }
    }
#endif /* GNOME */
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleExpose - expose event handler
 *
 ***********************************************************************
 */

static void flush_expose(Window w);

void HandleExpose(void)
{
    MenuRoot *tmp;
    virtualScreen *vs;

    if (XFindContext(dpy, Event.xany.window, MenuContext, (XPointer *)&tmp) == 0)
    {
	PaintMenu(tmp, &Event);
	return;
    }

    if (Event.xexpose.count != 0)
	return;

    if (Event.xany.window == Scr->InfoWindow && InfoLines)
    {
	int i;
	int height;

	Draw3DBorder (Scr->InfoWindow, 0, 0,
		InfoWidth, InfoHeight, 2, Scr->DefaultC, off, True, False);

	FB(Scr->DefaultC.fore, Scr->DefaultC.back);

	height = Scr->DefaultFont.height+2;
	for (i = 0; i < InfoLines; i++)
	{
	    XmbDrawString(dpy, Scr->InfoWindow, Scr->DefaultFont.font_set,
			  Scr->NormalGC, 5,
			  (i*height) + Scr->DefaultFont.y + 5,
			  Info[i], strlen(Info[i]));
	}
	flush_expose (Event.xany.window);
    }
    else if (Tmp_win != NULL)
    {
	if (Scr->use3Dborders && (Event.xany.window == Tmp_win->frame)) {
	    PaintBorders (Tmp_win, ((Tmp_win == Scr->Focus) ? True : False));
	    flush_expose (Event.xany.window);
	    return;
	}
	else
	if (Event.xany.window == Tmp_win->title_w)
	{
	    PaintTitle (Tmp_win);
	    flush_expose (Event.xany.window);
	    return;
	}
	else if (Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w) &&
		! Scr->NoIconTitlebar &&
		! LookInList (Scr->NoIconTitle, Tmp_win->full_name, &Tmp_win->class))
	{
	    PaintIcon (Tmp_win);
	    flush_expose (Event.xany.window);
	    return;
	} else if (Tmp_win->titlebuttons) {
	    int i;
	    TBWindow *tbw;
	    Window w = Event.xany.window;
	    int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;

	    for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
		if (w == tbw->window) {
		    PaintTitleButton (Tmp_win, tbw);
		    flush_expose (tbw->window);
                    return;
                }
            }
	}
	for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
	  if (Tmp_win == vs->wsw->twm_win) {
	    WMgrHandleExposeEvent (vs, &Event);
	    flush_expose (Event.xany.window);
	    return;
	  }
	}
	if (Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) {
	    PaintOccupyWindow ();
	    flush_expose (Event.xany.window);
	    return;
	} else 	if (Tmp_win->iconmanagerlist) {
	    WList *iconmanagerlist = Tmp_win->iconmanagerlist;

	    if (Event.xany.window == iconmanagerlist->w)
	    {
		int offs;

		DrawIconManagerBorder(iconmanagerlist, True);

		FB(iconmanagerlist->cp.fore, iconmanagerlist->cp.back);
		offs = Scr->use3Diconmanagers ? Scr->IconManagerShadowDepth : 2;
		if (Scr->use3Diconmanagers && (Scr->Monochrome != COLOR))
		    XmbDrawImageString(dpy, Event.xany.window,
				       Scr->IconManagerFont.font_set,
				       Scr->NormalGC, 
				       iconmgr_textx,
				       Scr->IconManagerFont.y + offs + 2,
				       Tmp_win->icon_name,
				       strlen(Tmp_win->icon_name));
		else
		    XmbDrawString(dpy, Event.xany.window,
				  Scr->IconManagerFont.font_set, Scr->NormalGC,
				  iconmgr_textx,
				  Scr->IconManagerFont.y + offs + 2,
				  Tmp_win->icon_name,
				  strlen(Tmp_win->icon_name));
		flush_expose (Event.xany.window);
		return;
	    }
	    if (Event.xany.window == iconmanagerlist->icon)
	    {
		if (Scr->use3Diconmanagers && iconmanagerlist->iconifypm) {
		    XCopyArea(dpy, iconmanagerlist->iconifypm,
				iconmanagerlist->icon,
				Scr->NormalGC, 0, 0,
				iconifybox_width, iconifybox_height, 0, 0);
		}
		else {
		    FB(iconmanagerlist->cp.fore, iconmanagerlist->cp.back);
		    XCopyPlane(dpy, Scr->siconifyPm, iconmanagerlist->icon,
			    Scr->NormalGC, 0,0,
			    iconifybox_width, iconifybox_height, 0, 0, 1);
		}
		flush_expose (Event.xany.window);
		return;
	    }
	}
    }
}



static void remove_window_from_ring (TwmWindow *tmp)
{
    TwmWindow *prev = tmp->ring.prev, *next = tmp->ring.next;

    if (enter_win == tmp) {
	enter_flag = FALSE;
	enter_win = NULL;
    }
    if (raise_win == Tmp_win) raise_win = NULL;
    if (leave_win == tmp) {
	leave_flag = FALSE;
	leave_win = NULL;
    }
    if (lower_win == Tmp_win) lower_win = NULL;

    /*
     * 1. Unlink window
     * 2. If window was only thing in ring, null out ring
     * 3. If window was ring leader, set to next (or null)
     */
    if (prev) prev->ring.next = next;
    if (next) next->ring.prev = prev;
    if (Scr->Ring == tmp) 
      Scr->Ring = (next != tmp ? next : (TwmWindow *) NULL);

    if (!Scr->Ring || Scr->RingLeader == tmp) Scr->RingLeader = Scr->Ring;
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleDestroyNotify - DestroyNotify event handler
 *
 ***********************************************************************
 */

void HandleDestroyNotify(void)
{
    /*
     * Warning, this is also called by HandleUnmapNotify; if it ever needs to
     * look at the event, HandleUnmapNotify will have to mash the UnmapNotify
     * into a DestroyNotify.
     */

    if (Tmp_win == NULL)
	return;

    RemoveWindowFromRegion (Tmp_win);
#ifdef GNOME
    GnomeDeleteClientWindow (Tmp_win); /* Fix the gnome client list */
#endif /* GNOME */
    if (Tmp_win == Scr->Focus)
    {
	Scr->Focus = (TwmWindow*) NULL;
	FocusOnRoot();
    }
    if (Scr->SaveWorkspaceFocus) {
	struct WorkSpace *ws;
	for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
	    if (ws->save_focus == Tmp_win)
		ws->save_focus = NULL;
	}
    }
    XDeleteContext(dpy, Tmp_win->w, TwmContext);
    XDeleteContext(dpy, Tmp_win->w, ScreenContext);
    XDeleteContext(dpy, Tmp_win->frame, TwmContext);
    XDeleteContext(dpy, Tmp_win->frame, ScreenContext);
    if (Tmp_win->icon && Tmp_win->icon->w)
    {
	XDeleteContext(dpy, Tmp_win->icon->w, TwmContext);
	XDeleteContext(dpy, Tmp_win->icon->w, ScreenContext);
    }
    if (Tmp_win->title_height) {
	int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;

	XDeleteContext(dpy, Tmp_win->title_w, TwmContext);
	XDeleteContext(dpy, Tmp_win->title_w, ScreenContext);
	if (Tmp_win->hilite_wl) {
	    XDeleteContext(dpy, Tmp_win->hilite_wl, TwmContext);
	    XDeleteContext(dpy, Tmp_win->hilite_wl, ScreenContext);
	}
	if (Tmp_win->hilite_wr) {
	    XDeleteContext(dpy, Tmp_win->hilite_wr, TwmContext);
	    XDeleteContext(dpy, Tmp_win->hilite_wr, ScreenContext);
	}
	if (Tmp_win->lolite_wr) {
	    XDeleteContext(dpy, Tmp_win->lolite_wr, TwmContext);
	    XDeleteContext(dpy, Tmp_win->lolite_wr, ScreenContext);
	}
	if (Tmp_win->lolite_wl) {
	    XDeleteContext(dpy, Tmp_win->lolite_wl, TwmContext);
	    XDeleteContext(dpy, Tmp_win->lolite_wl, ScreenContext);
	}
	if (Tmp_win->titlebuttons) {
	    int i;

	    for (i = 0; i < nb; i++) {
		XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
				TwmContext);
		XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
				ScreenContext);
	    }
        }
	/*
	 * The hilite_wl etc windows don't need to be XDestroyWindow()ed
	 * since that will happen when the parent is destroyed (??)
	 */
    }

    if (Scr->cmapInfo.cmaps == &Tmp_win->cmaps) {
	InstallColormaps(DestroyNotify, &Scr->RootColormaps);
    }

    /*
     * TwmWindows contain the following pointers
     * 
     *     1.  full_name
     *     2.  name
     *     3.  icon_name
     *     4.  wmhints
     *     5.  class.res_name
     *     6.  class.res_class
     *     7.  list
     *     8.  iconmgrp
     *     9.  cwins
     *     10. titlebuttons
     *     11. window ring
     *     12. squeeze_info (delete if squeeze_info_copied)
     *     13. HiliteImage
     *     14. iconslist
     */
    WMapDestroyWindow (Tmp_win);
    if (Tmp_win->gray) XFreePixmap (dpy, Tmp_win->gray);

    /*
     * According to the manual page, the following destroys all child windows
     * of the frame too, which is most of the windows we're concerned with, so
     * anything related to them must be done before here.
     * Icons are not child windows.
     */
    XDestroyWindow(dpy, Tmp_win->frame);
    if (Tmp_win->icon) {
	if (Tmp_win->icon->w && !Tmp_win->icon_not_ours) {
	    XDestroyWindow(dpy, Tmp_win->icon->w);
	    IconDown (Tmp_win);
	}
	free (Tmp_win->icon);
	Tmp_win->icon = NULL;
    }
    Tmp_win->occupation = 0;
    RemoveIconManager(Tmp_win);					/* 7 */
    if (Scr->FirstWindow == Tmp_win)
	Scr->FirstWindow = Tmp_win->next;
    if (Tmp_win->prev != NULL)
	Tmp_win->prev->next = Tmp_win->next;
    if (Tmp_win->next != NULL)
	Tmp_win->next->prev = Tmp_win->prev;
    if (Tmp_win->auto_raise) Scr->NumAutoRaises--;
    if (Tmp_win->auto_lower) Scr->NumAutoLowers--;
    if (Tmp_win->frame == lowerontop) lowerontop = -1;

    free_window_names (Tmp_win, True, True, True);		/* 1, 2, 3 */
    if (Tmp_win->wmhints)					/* 4 */
      XFree ((char *)Tmp_win->wmhints);
    if (Tmp_win->class.res_name && Tmp_win->class.res_name != NoName)  /* 5 */
      XFree ((char *)Tmp_win->class.res_name);
    if (Tmp_win->class.res_class && Tmp_win->class.res_class != NoName) /* 6 */
      XFree ((char *)Tmp_win->class.res_class);
    free_cwins (Tmp_win);					/* 9 */
    if (Tmp_win->titlebuttons) { 				/* 10 */ 
	free(Tmp_win->titlebuttons);
	Tmp_win->titlebuttons = NULL;
    }
    
    remove_window_from_ring (Tmp_win);				/* 11 */
    if (Tmp_win->squeeze_info_copied) { 			/* 12 */
	free(Tmp_win->squeeze_info);
	Tmp_win->squeeze_info = NULL;
    }
    DeleteHighlightWindows(Tmp_win);				/* 13 */
    DeleteIconsList (Tmp_win);					/* 14 */

    free((char *)Tmp_win);
    Tmp_win = NULL;

    if (Scr->ClickToFocus || Scr->SloppyFocus)
	set_last_window (Scr->currentvs->wsw->currentwspc);
}



void HandleCreateNotify(void)
{
#ifdef DEBUG_EVENTS
    fprintf(stderr, "CreateNotify w = 0x%x\n", Event.xcreatewindow.window);
    fflush(stderr);
    XBell(dpy, 0);
    XSync(dpy, 0);
#endif
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleMapRequest - MapRequest event handler
 *
 ***********************************************************************
 */

void HandleMapRequest(void)
{
    int zoom_save;

    Event.xany.window = Event.xmaprequest.window;
    Tmp_win = GetTwmWindow(Event.xany.window);

    /* If the window has never been mapped before ... */
    if (Tmp_win == NULL)
    {
	/* Add decorations. */
	Tmp_win = AddWindow(Event.xany.window, FALSE, (IconMgr *) NULL);
	if (Tmp_win == NULL) return;
#ifdef GNOME
	GnomeAddClientWindow (Tmp_win); /* add the new window to the gnome client list */
#endif /* GNOME */
    }
    else
    {
	/*
	 * If the window has been unmapped by the client, it won't be listed
	 * in the icon manager.  Add it again, if requested.
	 */
	if (Tmp_win->iconmanagerlist == NULL)
	    (void) AddIconManager (Tmp_win);
    }

    if (Tmp_win->iconmgr) return;
    if (Tmp_win->squeezed) return;

    if (Scr->WindowMask) XRaiseWindow (dpy, Scr->WindowMask);

    /* If it's not merely iconified, and we have hints, use them. */
    if (! Tmp_win->isicon)
    {
	int state;
	Window icon;

	state = NormalState;
	/* use WM_STATE if enabled */
	if (!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) &&
	      (state == NormalState || state == IconicState || state == InactiveState))) {
	    if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint))
		state = Tmp_win->wmhints->initial_state;
	}
	switch (state) 
	{
	    case DontCareState:
	    case NormalState:
	    case ZoomState:
		if (Tmp_win->StartSqueezed)
		    Squeeze (Tmp_win);
		else
		    XMapWindow(dpy, Tmp_win->w);
		XMapWindow(dpy, Tmp_win->frame);
		SetMapStateProp(Tmp_win, NormalState);
		SetRaiseWindow (Tmp_win);
		Tmp_win->mapped = TRUE;
		if (Scr->ClickToFocus &&
		    Tmp_win->wmhints  &&
		    Tmp_win->wmhints->input) SetFocus (Tmp_win, CurrentTime);
		    /* kai */
		if (Scr->AutoFocusToTransients &&
		    Tmp_win->transient &&
		    Tmp_win->wmhints   &&
		    Tmp_win->wmhints->input) SetFocus (Tmp_win, CurrentTime);
		break;

	    case InactiveState:
		Tmp_win->mapped = TRUE;
		if (Tmp_win->UnmapByMovingFarAway) {
		    XMoveWindow (dpy, Tmp_win->frame, Scr->rootw + 1, Scr->rooth + 1);
		    XMapWindow  (dpy, Tmp_win->w);
		    XMapWindow  (dpy, Tmp_win->frame);
		}
		if (Tmp_win->StartSqueezed) Squeeze (Tmp_win);
		break;

	    case IconicState:
		zoom_save = Scr->DoZoom;
		Scr->DoZoom = FALSE;
		Iconify(Tmp_win, -100, -100);
		Scr->DoZoom = zoom_save;
		break;
	}
    }
    /* If no hints, or currently an icon, just "deiconify" */
    else
    {
      if (1/*OCCUPY (Tmp_win, Scr->workSpaceMgr.activeWSPC)*/) {
	if (Tmp_win->StartSqueezed) Squeeze (Tmp_win);
	DeIconify(Tmp_win);
	SetRaiseWindow (Tmp_win);
      }
      else {
	Tmp_win->mapped = TRUE;
      }
    }
    if (Tmp_win->mapped) WMapMapWindow (Tmp_win);
    MaybeAnimate = True;
}



void SimulateMapRequest (Window w)
{
    Event.xmaprequest.window = w;
    HandleMapRequest ();
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleMapNotify - MapNotify event handler
 *
 ***********************************************************************
 */

void HandleMapNotify(void)
{
    if (Tmp_win == NULL)
	return;

    /*
     * Need to do the grab to avoid race condition of having server send
     * MapNotify to client before the frame gets mapped; this is bad because
     * the client would think that the window has a chance of being viewable
     * when it really isn't.
     */

    XGrabServer (dpy);
    if (Tmp_win->icon && Tmp_win->icon->w) XUnmapWindow(dpy, Tmp_win->icon->w);
    if (Tmp_win->title_w) XMapSubwindows(dpy, Tmp_win->title_w);
    XMapSubwindows(dpy, Tmp_win->frame);
    if (Scr->Focus != Tmp_win && Tmp_win->hilite_wl) XUnmapWindow(dpy, Tmp_win->hilite_wl);
    if (Scr->Focus != Tmp_win && Tmp_win->hilite_wr) XUnmapWindow(dpy, Tmp_win->hilite_wr);
    if (Scr->Focus == Tmp_win && Tmp_win->lolite_wl) XUnmapWindow(dpy, Tmp_win->lolite_wl);
    if (Scr->Focus == Tmp_win && Tmp_win->lolite_wr) XUnmapWindow(dpy, Tmp_win->lolite_wr);

    XMapWindow(dpy, Tmp_win->frame);
    XUngrabServer (dpy);
    XFlush (dpy);
    Tmp_win->mapped = TRUE;
    Tmp_win->isicon = FALSE;
    Tmp_win->icon_on = FALSE;
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleUnmapNotify - UnmapNotify event handler
 *
 ***********************************************************************
 */

void HandleUnmapNotify(void)
{
    int dstx, dsty;
    Window dumwin;

    /*
     * The July 27, 1988 ICCCM spec states that a client wishing to switch
     * to WithdrawnState should send a synthetic UnmapNotify with the
     * event field set to (pseudo-)root, in case the window is already
     * unmapped (which is the case for twm for IconicState).  Unfortunately,
     * we looked for the TwmContext using that field, so try the window
     * field also.
     */
    if (Tmp_win == NULL)
    {
	Event.xany.window = Event.xunmap.window;
	Tmp_win = GetTwmWindow(Event.xany.window);
    }

    if (Tmp_win == NULL || Event.xunmap.window == Tmp_win->frame ||
	(Tmp_win->icon && Event.xunmap.window == Tmp_win->icon->w) ||
	(!Tmp_win->mapped && !Tmp_win->isicon))
	return;
/*
    if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->isicon))
	return;
*/
    /*
     * The program may have unmapped the client window, from either
     * NormalState or IconicState.  Handle the transition to WithdrawnState.
     *
     * We need to reparent the window back to the root (so that twm exiting 
     * won't cause it to get mapped) and then throw away all state (pretend 
     * that we've received a DestroyNotify).
     */
/* Is it the correct behaviour ???
    XDeleteProperty (dpy, Tmp_win->w, _XA_WM_OCCUPATION);
*/
    XGrabServer (dpy);
    if (XTranslateCoordinates (dpy, Event.xunmap.window, Tmp_win->attr.root,
			       0, 0, &dstx, &dsty, &dumwin)) {
	XEvent ev;
	Bool reparented = XCheckTypedWindowEvent (dpy, Event.xunmap.window, 
						  ReparentNotify, &ev);
	SetMapStateProp (Tmp_win, WithdrawnState);
	if (reparented) {
	    if (Tmp_win->old_bw) XSetWindowBorderWidth (dpy,
							Event.xunmap.window, 
							Tmp_win->old_bw);
	    if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint))
	      XUnmapWindow (dpy, Tmp_win->wmhints->icon_window);
	} else {
	    XReparentWindow (dpy, Event.xunmap.window, Tmp_win->attr.root,
			     dstx, dsty);
	    RestoreWithdrawnLocation (Tmp_win);
	}
	XRemoveFromSaveSet (dpy, Event.xunmap.window);
	XSelectInput (dpy, Event.xunmap.window, NoEventMask);
	HandleDestroyNotify ();		/* do not need to mash event before */
    } /* else window no longer exists and we'll get a destroy notify */
    XUngrabServer (dpy);
    XFlush (dpy);
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleMotionNotify - MotionNotify event handler
 *
 ***********************************************************************
 */

void HandleMotionNotify(void)
{
    if (ResizeWindow != (Window) 0)
    {
	XQueryPointer( dpy, Event.xany.window,
	    &(Event.xmotion.root), &JunkChild,
	    &(Event.xmotion.x_root), &(Event.xmotion.y_root),
	    &(Event.xmotion.x), &(Event.xmotion.y),
	    &JunkMask);

	FixRootEvent (&Event);
	/* Set WindowMoved appropriately so that f.deltastop will
	   work with resize as well as move. */
	if (abs (Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta
	    || abs (Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta)
	  WindowMoved = TRUE;

	Tmp_win = GetTwmWindow(ResizeWindow);
	if (Tmp_win && Tmp_win->winbox) {
	    XTranslateCoordinates (dpy, Scr->Root, Tmp_win->winbox->window,
		Event.xmotion.x_root, Event.xmotion.y_root,
		&(Event.xmotion.x_root), &(Event.xmotion.y_root), &JunkChild);
	}
	DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win);
    }
    else
    if (Scr->BorderCursors && Tmp_win && Event.xany.window == Tmp_win->frame) {
	SetBorderCursor (Tmp_win, Event.xmotion.x, Event.xmotion.y);
    }
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleButtonRelease - ButtonRelease event handler
 *
 ***********************************************************************
 */
void HandleButtonRelease(void)
{
    int xl, yt, w, h;
    unsigned mask;

#ifdef GNOME
    if (GnomeProxyButtonPress == Event.xbutton.button) {
      GnomeProxyButtonPress = -1;
      XSendEvent (dpy, Scr->currentvs->wsw->w, False, SubstructureNotifyMask, &Event);
    }
#endif /* GNOME */
    if (InfoLines) 		/* delete info box on 2nd button release  */
      if (Context == C_IDENTIFY) {
	XUnmapWindow(dpy, Scr->InfoWindow);
	InfoLines = 0;
	Context = C_NO_CONTEXT;
      }

    if (DragWindow != None)
    {
	MoveOutline(Scr->XineramaRoot, 0, 0, 0, 0, 0, 0);

	Tmp_win = GetTwmWindow(DragWindow);
	if (Tmp_win->winbox) {
	    XTranslateCoordinates (dpy, Scr->Root, Tmp_win->winbox->window,
		Event.xbutton.x_root, Event.xbutton.y_root,
		&(Event.xbutton.x_root), &(Event.xbutton.y_root), &JunkChild);
	}
	if (DragWindow == Tmp_win->frame)
	{
	    xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw;
	    yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw;
	    w = DragWidth + 2 * Tmp_win->frame_bw;
	    h = DragHeight + 2 * Tmp_win->frame_bw;
	}
	else
	{
	    xl = Event.xbutton.x_root - DragX - DragBW;
	    yt = Event.xbutton.y_root - DragY - DragBW;
	    w = DragWidth + 2 * DragBW;
	    h = DragHeight + 2 * DragBW;
	}

	if (ConstMove)
	{
	    if (ConstMoveDir == MOVE_HORIZ)
		yt = ConstMoveY;

	    if (ConstMoveDir == MOVE_VERT)
		xl = ConstMoveX;

	    if (ConstMoveDir == MOVE_NONE)
	    {
		yt = ConstMoveY;
		xl = ConstMoveX;
	    }
	}

	if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
	    TryToGrid (Tmp_win, &xl, &yt);
	if (MoveFunction == F_MOVEPUSH &&
	    Scr->OpaqueMove &&
	    DragWindow == Tmp_win->frame) TryToPush (Tmp_win,  xl,  yt, 0);
	if (MoveFunction == F_MOVEPACK ||
	    (MoveFunction == F_MOVEPUSH &&
	     DragWindow == Tmp_win->frame)) TryToPack (Tmp_win, &xl, &yt);
	if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
	{
            ConstrainByBorders (Tmp_win, &xl, w, &yt, h);
	}

	CurrentDragX = xl;
	CurrentDragY = yt;
	/*
	 * sometimes getScreenOf() replies with the wrong window when moving
	 * y to a negative number.  Need to figure out why... [XXX]
	 */
	if(xl < 0 || yt < 0 || xl > Scr->rootw || yt > Scr->rooth) {
		int odestx, odesty;
		int destx, desty;
		Window cr;
		virtualScreen *newvs;

		XTranslateCoordinates(dpy, Tmp_win->vs->window, 
			Scr->XineramaRoot, xl, yt, &odestx, &odesty, &cr);

		newvs = findIfVScreenOf(odestx, odesty);
		if(newvs && newvs->wsw && newvs->wsw->currentwspc) {
			XTranslateCoordinates(dpy, Scr->XineramaRoot, 
				newvs->window, odestx, odesty, 
				&destx, &desty, &cr);
			AddToWorkSpace(newvs->wsw->currentwspc->name, Tmp_win);
			RemoveFromWorkSpace(Tmp_win->vs->wsw->currentwspc->name, Tmp_win);
			xl = destx;
			yt = desty;
		}

	}
	if (DragWindow == Tmp_win->frame)
	    SetupWindow (Tmp_win, xl, yt,
		       Tmp_win->frame_width, Tmp_win->frame_height, -1);
	else
	    XMoveWindow (dpy, DragWindow, xl, yt);

	if (!Scr->NoRaiseMove) /* && !Scr->OpaqueMove)    opaque already did */
	    RaiseFrame(DragWindow);

	if (!Scr->OpaqueMove)
	    UninstallRootColormap();
	else
	    XSync(dpy, 0);

	if (Scr->NumAutoRaises) {
	    enter_flag = TRUE;
	    enter_win = NULL;
	    raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove)
			 ? Tmp_win : NULL);
	}

	/* CCC equivalent code for auto lower not needed? */

#if 0
	if (Scr->NumAutoLowers) {
	    leave_flag = TRUE;
	    leave_win = NULL;
	    lower_win = ((DragWindow == Tmp_win->frame)
			 ? Tmp_win : NULL);
	}
#endif

	DragWindow = (Window) 0;
	ConstMove = FALSE;
    }

    if (ResizeWindow != (Window) 0)
    {
	EndResize();
    }

    if (ActiveMenu != NULL && RootFunction == 0)
    {
	if (ActiveItem)
	{
	    int func = ActiveItem->func;
	    Action = ActiveItem->action;
	    switch (func) {
	      case F_TITLE:
		if (Scr->StayUpMenus) 	{
		    ButtonPressed = -1;
		    if (Scr->WarpToDefaultMenuEntry && ActiveMenu->defaultitem) {
			WarpCursorToDefaultEntry (ActiveMenu);
		    }
		    return;
		}
		break;
	      case F_MOVE:
	      case F_FORCEMOVE:
	      case F_DESTROY:
	      case F_DELETE:
	      case F_DELETEORDESTROY:
		ButtonPressed = -1;
		break;
	      case F_CIRCLEUP:
	      case F_CIRCLEDOWN:
	      case F_REFRESH:
	      case F_WARPTOSCREEN:
		PopDownMenu();
		break;
	      default:
		break;
	    }
	    if (func != F_PIN && func != F_MENU) PopDownMenu();
	    ExecuteFunction(func, Action,
		ButtonWindow ? ButtonWindow->frame : None,
		ButtonWindow, &Event/*&ButtonEvent*/, Context, TRUE);
	    Context = C_NO_CONTEXT;
	    ButtonWindow = NULL;

	    /* if we are not executing a defered command, then take down the
	     * menu
	     */
	    if (ActiveMenu) PopDownMenu();
	}
	else
	if (Scr->StayUpMenus && !ActiveMenu->entered) {
	    ButtonPressed = -1;
	    if (Scr->WarpToDefaultMenuEntry && ActiveMenu->defaultitem) {
		WarpCursorToDefaultEntry (ActiveMenu);
	    }
	    return;
	}
	else
	    PopDownMenu();
    }

    mask = (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
    switch (Event.xbutton.button)
    {
	case Button1: mask &= ~Button1Mask; break;
	case Button2: mask &= ~Button2Mask; break;
	case Button3: mask &= ~Button3Mask; break;
	case Button4: mask &= ~Button4Mask; break;
	case Button5: mask &= ~Button5Mask; break;
    }

    if (RootFunction != 0 ||
	ResizeWindow != None ||
	DragWindow != None)
	ButtonPressed = -1;

    if (AlternateKeymap || AlternateContext) {
	ButtonPressed = -1;
	return;
    }

    if (RootFunction == 0 &&
	(Event.xbutton.state & mask) == 0 &&
	DragWindow == None &&
	ResizeWindow == None)
    {
	XUngrabPointer(dpy, CurrentTime);
	XUngrabServer(dpy);
	XFlush(dpy);
	EventHandler[EnterNotify] = HandleEnterNotify;
	EventHandler[LeaveNotify] = HandleLeaveNotify;
	ButtonPressed = -1;
	if (DownIconManager)
	{
	    DownIconManager->down = FALSE;
	    if (Scr->Highlight) DrawIconManagerBorder(DownIconManager, False);
	    DownIconManager = NULL;
	}
	Cancel = FALSE;
    }
}



static void do_menu (MenuRoot *menu,	/* menu to pop up */
		     Window w)		/* invoking window or None */
{
    int x = Event.xbutton.x_root;
    int y = Event.xbutton.y_root;
    Bool center;

    if (!Scr->NoGrabServer)
	XGrabServer(dpy);
    if (w) {
	int h = Scr->TBInfo.width - Scr->TBInfo.border;
	Window child;

	(void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child);
	center = False;
    } else {
	center = True;
    }
    if (PopUpMenu (menu, x, y, center)) {
	UpdateMenu();
    } else {
	XBell (dpy, 0);
    }
}

static void do_key_menu (MenuRoot *menu,	/* menu to pop up */
			 Window w)		/* invoking window or None */
{
    int x = Event.xkey.x_root;
    int y = Event.xkey.y_root;
    Bool center;

/* I don't think this is necessary.
    if (!Scr->NoGrabServer) XGrabServer(dpy);
*/
    if (w) {
	int h = Scr->TBInfo.width - Scr->TBInfo.border;
	Window child;

	(void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child);
	center = False;
    } else {
	center = True;
    }
    if (PopUpMenu (menu, x, y, center)) {
	UpdateMenu();
    } else {
	XBell (dpy, 0);
    }

}



/***********************************************************************
 *
 *  Procedure:
 *	HandleButtonPress - ButtonPress event handler
 *
 ***********************************************************************
 */
void HandleButtonPress(void)
{
    unsigned int modifier;
    Cursor cur;
    MenuRoot *mr;
    FuncButton *tmp = 0;
    int func = 0;
    Window w;

    GnomeProxyButtonPress = -1;

    /* pop down the menu, if any */

    if (XFindContext (dpy, Event.xbutton.window, MenuContext, (XPointer *) &mr) != XCSUCCESS) {
	mr = (MenuRoot*) 0;
    }
    if (ActiveMenu && (! ActiveMenu->pinned) &&
		(Event.xbutton.subwindow != ActiveMenu->w)) {
	PopDownMenu();
	return;
    }
    if ((ActiveMenu != NULL) && (RootFunction != 0) && (mr != ActiveMenu)) PopDownMenu();

    XSync(dpy, 0);
			/* XXX - remove? */

    if (ButtonPressed != -1 && !InfoLines) /* want menus if we have info box */
    {
	/* we got another butt press in addition to one still held
	 * down, we need to cancel the operation we were doing
	 */
	Cancel = TRUE;
	CurrentDragX = origDragX;
	CurrentDragY = origDragY;
	if (!menuFromFrameOrWindowOrTitlebar) {
	  if (Scr->OpaqueMove && DragWindow != None) {
	    XMoveWindow (dpy, DragWindow, origDragX, origDragY);
	  } else {
	    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
	  }
	}
	XUnmapWindow(dpy, Scr->SizeWindow);
	if (!Scr->OpaqueMove)
	    UninstallRootColormap();
	ResizeWindow = None;
	DragWindow = None;
	cur = LeftButt;
	if (Event.xbutton.button == Button2)
	    cur = MiddleButt;
	else if (Event.xbutton.button >= Button3)
	    cur = RightButt;

	XGrabPointer(dpy, Scr->Root, True,
	    ButtonReleaseMask | ButtonPressMask,
	    GrabModeAsync, GrabModeAsync,
	    Scr->Root, cur, CurrentTime);

	return;
    }
    else
	ButtonPressed = Event.xbutton.button;

    if ((ActiveMenu != NULL) && (ActiveMenu->pinned)) {
	if (Event.xbutton.window == ActiveMenu->w) {
	    modifier = (Event.xbutton.state & mods_used);
	    modifier = set_mask_ignore (modifier);
	    if ((ActiveItem && (ActiveItem->func == F_TITLE)) || (modifier == 8)) {
		MoveMenu (&Event);
		/*ButtonPressed = -1;*/
	    }
	}
	Context = C_ROOT;
	return;
    }

    if (ResizeWindow != None ||
	DragWindow != None  ||
	ActiveMenu != NULL)
	return;

    /* check the title bar buttons */
    if (Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons)
    {
	register int i;
	register TBWindow *tbw;
	register TitleButtonFunc *tbf;
	int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;

	modifier = Event.xbutton.state & mods_used;
	modifier = set_mask_ignore (modifier);

	for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
	    if (Event.xany.window == tbw->window) {
		for (tbf = tbw->info->funs; tbf; tbf = tbf->next) {
		    if (tbf->num == ButtonPressed
			&& tbf->mods == modifier) {
			switch (tbf->func) {
			case F_MENU :
			    Context = C_TITLE;
			    ButtonEvent = Event;
			    ButtonWindow = Tmp_win;
			    do_menu (tbf->menuroot, tbw->window);
			    break;

			default :
			    ExecuteFunction (tbf->func, tbf->action,
					     Event.xany.window, Tmp_win,
					     &Event, C_TITLE, FALSE);
			}
			return;
		    }
		}
	    }
	}
    }

    Context = C_NO_CONTEXT;

    if (Event.xany.window == Scr->InfoWindow)
      Context = C_IDENTIFY;

    if (Event.xany.window == Scr->Root) {
	if (AlternateContext) {
	    XUngrabPointer  (dpy, CurrentTime);
	    XUngrabKeyboard (dpy, CurrentTime);
	    AlternateContext = False;
	    Context = C_ALTERNATE;
	}
	else
	if (AlternateKeymap && Event.xbutton.subwindow) {
	    int dx, dy;
	    Window child;

	    w = Event.xbutton.subwindow;
	    Tmp_win = GetTwmWindow(w);
	    if (Tmp_win) {
		Event.xany.window    = Tmp_win->frame;
		XTranslateCoordinates (dpy, Scr->Root, Tmp_win->frame,
			Event.xbutton.x, Event.xbutton.y, &dx, &dy, &child);
		Event.xbutton.x = dx;
		Event.xbutton.x = dy;
		Event.xbutton.subwindow = child;
	    }
	}
	else
	    Context = C_ROOT;
    }
    if (Tmp_win)
    {
	if (Tmp_win->iconmanagerlist && (RootFunction != 0) &&
		((Event.xany.window == Tmp_win->iconmanagerlist->icon) ||
		 (Event.xany.window == Tmp_win->iconmanagerlist->w))) {
	    Tmp_win = Tmp_win->iconmanagerlist->iconmgr->twm_win;
	    if (Tmp_win) {
		XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
		    Event.xbutton.x, Event.xbutton.y, 
		    &JunkX, &JunkY, &JunkChild);

		Event.xbutton.x = JunkX - Tmp_win->frame_bw3D;
		Event.xbutton.y = JunkY - Tmp_win->title_height - Tmp_win->frame_bw3D;
		Event.xany.window = Tmp_win->w;
		Context = C_WINDOW;
	    }
	}
	else if (Event.xany.window == Tmp_win->title_w) {
	    if (Scr->ClickToFocus &&
		Tmp_win->wmhints &&
		Tmp_win->wmhints->input) SetFocus (Tmp_win, CurrentTime);
	    Context = C_TITLE;
	}
	else if (Event.xany.window == Tmp_win->w) {
	    if (Scr->ClickToFocus || Scr->RaiseOnClick) {
		if (Scr->ClickToFocus &&
		    Tmp_win->wmhints &&
		    Tmp_win->wmhints->input) {
		    SetFocus (Tmp_win, CurrentTime);
		}
		if (Scr->RaiseOnClick) {
		    RaiseWindow (Tmp_win);
		    WMapRaise   (Tmp_win);
		}
		XSync (dpy, 0);
		XAllowEvents (dpy, ReplayPointer, CurrentTime);
		XSync (dpy, 0);
		ButtonPressed = -1;
		return;
	    }
	    else {
		printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n");
		Context = C_WINDOW;
	    }
	}
	else if (Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w))
	{
	    Context = C_ICON;
	}
	else if (Event.xany.window == Tmp_win->frame) 
	{
	    /* since we now place a button grab on the frame instead
             * of the window, (see GrabButtons() in add_window.c), we
             * need to figure out where the pointer exactly is before
             * assigning Context.  If the pointer is on the application
             * window we will change the event structure to look as if
             * it came from the application window.
	     */
	    if (Event.xbutton.subwindow == Tmp_win->w) {
	      XTranslateCoordinates (dpy, Event.xany.window, Tmp_win->w,
			Event.xbutton.x, Event.xbutton.y,
			&Event.xbutton.x, &Event.xbutton.y, &JunkChild);
	      Event.xbutton.window = Tmp_win->w;

	      if (Tmp_win->iswinbox && JunkChild) {
		    XTranslateCoordinates (dpy, Tmp_win->w, JunkChild,
			Event.xbutton.x, Event.xbutton.y,
			&JunkX, &JunkY, &JunkChild);
		    if (JunkChild && (Tmp_win = GetTwmWindow(JunkChild))) {
			Event.xany.window = JunkChild;
			Event.xbutton.x   = JunkX;
			Event.xbutton.y   = JunkY;
		    }
	      }
	      Context = C_WINDOW;
	    }
	    else
	    if (Event.xbutton.subwindow && (Event.xbutton.subwindow == Tmp_win->title_w)) {
		Context = C_TITLE;
	    }
            else {
		Context = C_FRAME;
	    }
	    if (Scr->ClickToFocus &&
		Tmp_win->wmhints &&
		Tmp_win->wmhints->input) SetFocus (Tmp_win, CurrentTime);
	}
	else if (Tmp_win->wspmgr ||
		 (Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
	    Context = C_WINDOW;
	}
	else if (Tmp_win->iconmanagerlist) {
	    if ((Event.xany.window == Tmp_win->iconmanagerlist->icon) ||
		(Event.xany.window == Tmp_win->iconmanagerlist->w)) {
		Tmp_win->iconmanagerlist->down = TRUE;
		if (Scr->Highlight)
		    DrawIconManagerBorder(Tmp_win->iconmanagerlist, False);
		DownIconManager = Tmp_win->iconmanagerlist;
		Context = C_ICONMGR;
	    }
	}
    }

    /* this section of code checks to see if we were in the middle of
     * a command executed from a menu
     */
    if (RootFunction != 0)
    {
	if (Event.xany.window == Scr->Root)
	{
	    Window win;
	    /* if the window was the Root, we don't know for sure it
	     * it was the root.  We must check to see if it happened to be
	     * inside of a client that was getting button press events.
	     */
	    XTranslateCoordinates(dpy, Scr->Root, Scr->Root,
		Event.xbutton.x, 
		Event.xbutton.y, 
		&JunkX, &JunkY, &Event.xany.window);

	    if (Event.xany.window != 0 &&
		(Tmp_win = GetTwmWindow(Event.xany.window))) {
		if (Tmp_win && Tmp_win->iswinbox) {
		    XTranslateCoordinates (dpy, Scr->Root, Event.xany.window,
			JunkX, JunkY,  &JunkX, &JunkY, &win);
		    XTranslateCoordinates (dpy, Event.xany.window, win,
			JunkX, JunkY,  &JunkX, &JunkY, &win);
		    if (win != 0) Event.xany.window = win;
		}
	    }
	    if (Event.xany.window == 0 ||
		!(Tmp_win = GetTwmWindow(Event.xany.window)))
	    {
		RootFunction = 0;
		XBell(dpy, 0);
		return;
	    }
	    XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
		Event.xbutton.x, 
		Event.xbutton.y, 
		&JunkX, &JunkY, &JunkChild);

	    Event.xbutton.x = JunkX;
	    Event.xbutton.y = JunkY;
	    Context = C_WINDOW;
	}
	else
	if (mr != (MenuRoot*) 0) {
	    RootFunction = 0;
	    XBell(dpy, 0);
	    return;
	}

	/* make sure we are not trying to move an identify window */
	if (Event.xany.window != Scr->InfoWindow)
	  ExecuteFunction(RootFunction, Action, Event.xany.window,
			  Tmp_win, &Event, Context, FALSE);

	RootFunction = 0;
	return;
    }

    ButtonEvent = Event;
    ButtonWindow = Tmp_win;

    /* if we get to here, we have to execute a function or pop up a 
     * menu
     */
    modifier = (Event.xbutton.state | AlternateKeymap) & mods_used;
    modifier = set_mask_ignore (modifier);
    if (AlternateKeymap) {
	XUngrabPointer  (dpy, CurrentTime);
	XUngrabKeyboard (dpy, CurrentTime);
	AlternateKeymap = 0;
    }
    if ((Context == C_NO_CONTEXT) || (Context == C_IDENTIFY))
	return;

    RootFunction = 0;

    /* see if there already is a key defined for this context */
    for (tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) {
	if ((tmp->num  == Event.xbutton.button) &&
	    (tmp->cont == Context) && (tmp->mods == modifier))
	    break;
    }
    if (tmp) {
	func = tmp->func;
	switch (func) {
	    case F_MENU :
		do_menu (tmp->menu, (Window) None);
		break;

	    default :
		if (func != 0) {
		    Action = tmp->item ? tmp->item->action : NULL;
		    ExecuteFunction (func,
			Action, Event.xany.window, Tmp_win, &Event, Context, FALSE);
		}
	}
    }
    else {
	if (Tmp_win == Scr->currentvs->wsw->twm_win) {
	  WMgrHandleButtonEvent (Scr->currentvs, &Event);
	  return;
	}
    }
    if (Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)
    {
	OccupyHandleButtonEvent (&Event);
    }
    else if (func == 0 && Scr->DefaultFunction.func != 0)
    {
	if (Scr->DefaultFunction.func == F_MENU)
	{
	    do_menu (Scr->DefaultFunction.menu, (Window) None);
	}
	else
	{
	    Action = Scr->DefaultFunction.item ?
		Scr->DefaultFunction.item->action : NULL;
	    ExecuteFunction(Scr->DefaultFunction.func, Action,
	       Event.xany.window, Tmp_win, &Event, Context, FALSE);
	}
    }
#ifdef GNOME1 /* Makes DeferExecution (in menus.c) fail. TODO. */
    else {
        /* GNOME: Pass on the event to any applications listening for root window clicks */
        GnomeProxyButtonPress = Event.xbutton.button;
	ButtonPressed = -1;
	XUngrabPointer (dpy, CurrentTime);
	XSendEvent (dpy, Scr->currentvs->wsw->twm_win->w, False,
		    SubstructureNotifyMask, &Event);
    }
#endif /* GNOME1 */
}



/***********************************************************************
 *
 *  Procedure:
 *	HENQueueScanner - EnterNotify event q scanner
 *
 *	Looks at the queued events and determines if any matching
 *	LeaveNotify events or EnterEvents deriving from the
 *	termination of a grab are behind this event to allow
 *	skipping of unnecessary processing.
 *
 ***********************************************************************
 */

typedef struct HENScanArgs {
    Window w;		/* Window we are currently entering */
    Bool leaves;	/* Any LeaveNotifies found for this window */
    Bool inferior;	/* Was NotifyInferior the mode for LeaveNotify */
    Bool enters;	/* Any EnterNotify events with NotifyUngrab */
} HENScanArgs;

/* ARGSUSED*/
static Bool HENQueueScanner(Display *display, XEvent *ev, char *_args)
{
    HENScanArgs *args = (void *)_args;

    if (ev->type == LeaveNotify) {
	if (ev->xcrossing.window == args->w &&
	    ev->xcrossing.mode == NotifyNormal) {
	    args->leaves = True;
	    /*
	     * Only the last event found matters for the Inferior field.
	     */
	    args->inferior =
		(ev->xcrossing.detail == NotifyInferior);
	}
    } else if (ev->type == EnterNotify) {
	if (ev->xcrossing.mode == NotifyUngrab)
	    args->enters = True;
    }

    return (False);
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleEnterNotify - EnterNotify event handler
 *
 ***********************************************************************
 */

void HandleEnterNotify(void)
{
    MenuRoot *mr, *tmp;
    XEnterWindowEvent *ewp = &Event.xcrossing;
    HENScanArgs scanArgs;
    XEvent dummy;
    virtualScreen *vs;

    /*
     * if we aren't in the middle of menu processing
     */
    if (!ActiveMenu) {
	/*
	 * We're not interested in pseudo Enter/Leave events generated
	 * from grab initiations.
	 */
	if (ewp->mode == NotifyGrab)
	    return;

	/*
	 * Scan for Leave and Enter Notify events to see if we can avoid some
	 * unnecessary processing.
	 */
	scanArgs.w = ewp->window;
	scanArgs.leaves = scanArgs.enters = False;
	(void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (void *) &scanArgs);

	/*
	 * if entering root window, restore twm default colormap so that 
	 * titlebars are legible
	 */
	if (ewp->window == Scr->Root) {
	    Window forus_ret;
	    int focus_rev;

	    if (!scanArgs.leaves && !scanArgs.enters) {
		InstallColormaps(EnterNotify, &Scr->RootColormaps);
	    }
	    if (! Scr->FocusRoot) return;
	    XGetInputFocus (dpy, &forus_ret, &focus_rev);
	    if ((forus_ret != PointerRoot) && (forus_ret != None)) {
		SetFocus ((TwmWindow *) NULL, Event.xcrossing.time);
	    }
	    return;
	}
	for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
	  if (ewp->window == vs->window) {
	    Scr->Root  = vs->window;
	    Scr->rootx = Scr->crootx + vs->x;
	    Scr->rooty = Scr->crooty + vs->y;
	    Scr->rootw = vs->w;
	    Scr->rooth = vs->h;
	    Scr->currentvs = vs;
	    /*fprintf (stderr, "entering new vs : 0x%x, 0x%x, %d, %d, %d, %d\n",
	      vs, Scr->Root, vs->x, vs->y, vs->w, vs->h);*/
	    return;
	  }
	}

	/* Handle RaiseDelay, if any.....
	 */
	if (RaiseDelay > 0) {
	    if (Tmp_win && Tmp_win->auto_raise &&
		    (!Tmp_win->iconmanagerlist ||
		      Tmp_win->iconmanagerlist->w != ewp->window)) {
		ColormapWindow *cwin;
#ifdef VMS
		float timeout = 0.0125;
#else
		static struct timeval tout, timeout = {0,12500};
#endif

		if (XFindContext(dpy, Tmp_win->w, ColormapContext,
				 (XPointer *)&cwin) == XCNOENT) {
		    cwin = (ColormapWindow *)NULL;
		}

		if ((ewp->detail != NotifyInferior
		     || Tmp_win->frame == ewp->window)
		     && (!cwin || cwin->visibility != VisibilityUnobscured)) {
		    int x, y, px, py, d, i;
		    Window w;

		    XQueryPointer(dpy, Scr->Root, &w, &w, &px, &py,
				  &d, &d, (unsigned int *)&d);

		    /* The granularity of RaiseDelay is about 25 ms.
		     * The timeout variable is set to 12.5 ms since we
		     * pass this way twice each time a twm window is
		     * entered.
		     */
		    for (i = 25; i < RaiseDelay; i += 25) {
#ifdef VMS
			lib$wait(&timeout);
#else
			tout = timeout;
			select(0, 0, 0, 0, &tout);
#endif
			/* Did we leave this window already? */
			scanArgs.w = ewp->window;
			scanArgs.leaves = scanArgs.enters = False;
			(void) XCheckIfEvent(dpy, &dummy, HENQueueScanner,
					     (void *) &scanArgs);
			if (scanArgs.leaves && !scanArgs.inferior) return;

			XQueryPointer(dpy, Scr->Root, &w, &w, &x, &y,
				      &d, &d, (unsigned int *)&d);

			/* Has the pointer moved?  If so reset the loop cnt.
			 * We want the pointer to be still for RaiseDelay
			 * milliseconds before terminating the loop
			 */
			if (x != px || y != py) {
			    i = 0; px = x; py = y;
			}
		    }
		}
	    }

	    /*
	     * Scan for Leave and Enter Notify events to see if we can avoid some
	     * unnecessary processing.
	     */
	    scanArgs.w = ewp->window;
	    scanArgs.leaves = scanArgs.enters = False;
	    (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (void *) &scanArgs);

	    /*
	     * if entering root window, restore twm default colormap so that 
	     * titlebars are legible
	     */
	    if (ewp->window == Scr->Root) {
		if (!scanArgs.leaves && !scanArgs.enters) {
		    InstallColormaps(EnterNotify, &Scr->RootColormaps);
		}
		return;
	    }
	}
	/* End of RaiseDelay modification. */
  
	/*
	 * if we have an event for a specific one of our windows
	 */
	if (Tmp_win) {
	    /*
	     * If currently in PointerRoot mode (indicated by FocusRoot), then
	     * focus on this window
	     */
	    if (Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) {
		Bool accinput;

		if (Scr->ShrinkIconTitles &&
		    Tmp_win->icon &&
		    ewp->window == Tmp_win->icon->w &&
		    ewp->detail != NotifyInferior) {
		    if (Scr->AutoRaiseIcons) XRaiseWindow (dpy, Tmp_win->icon->w);
		    ExpandIconTitle (Tmp_win);
		    return;
		}

		if (Tmp_win->iconmanagerlist)
		    CurrentIconManagerEntry (Tmp_win->iconmanagerlist);

		accinput = Tmp_win->mapped && Tmp_win->wmhints && Tmp_win->wmhints->input;
		if (Tmp_win->iconmanagerlist &&
		    ewp->window == Tmp_win->iconmanagerlist->w &&
		    !accinput &&
		    Tmp_win->iconmanagerlist->iconmgr &&
		    Tmp_win->iconmanagerlist->iconmgr->twm_win) {
			SetFocus(Tmp_win->iconmanagerlist->iconmgr->twm_win,
				 CurrentTime);
			return;
		}

		if (Tmp_win->mapped) {
		    /*
		     * unhighlight old focus window
		     */

		    /*
		     * If entering the frame or the icon manager, then do 
		     * "window activation things":
		     *
		     *     1.  <highlighting is not done here any more>
		     *     2.  install frame colormap
		     *     3.  <frame and highlight border not set here>
		     *     4.  focus on client window to forward typing
		     *     4a. same as 4 but for icon mgr w/with NoTitleFocus
		     *     5.  send WM_TAKE_FOCUS if requested
		     */
		    if (Scr->BorderCursors && ewp->window == Tmp_win->frame) {
			SetBorderCursor (Tmp_win, ewp->x, ewp->y);
		    }
		    if (ewp->window == Tmp_win->frame ||
			(Scr->IconManagerFocus &&
			 Tmp_win->iconmanagerlist &&
			 ewp->window == Tmp_win->iconmanagerlist->w)) {

			if (!scanArgs.leaves && !scanArgs.enters) {
			    InstallColormaps (EnterNotify,	/* 2 */
					      &Scr->RootColormaps);
			}

			/*
			 * Event is in the frame or the icon mgr:
			 *
			 * "4" -- TitleFocus is set: windows should get 
			 *        focus as long as they accept input.
			 *
			 * "4a" - If TitleFocus is not set, windows should get
			 *        the focus if the event was in the icon mgr
			 *        (as long as they accept input).
			 * 
			 */

			/* If the window takes input... */
			if (Tmp_win->wmhints && Tmp_win->wmhints->input) {
				
				/* if 4 or 4a, focus on the window */
				if (Scr->TitleFocus ||  
				    (Tmp_win->iconmanagerlist && 
				     (Tmp_win->iconmanagerlist->w == ewp->window))) {
				  SetFocus (Tmp_win, ewp->time);
				}
			}
			    
			if (Scr->TitleFocus &&
			    (Tmp_win->protocols & DoesWmTakeFocus)){    /* 5 */

				/* for both locally or globally active */
				SendTakeFocusMessage (Tmp_win, ewp->time);
			}
			else if (!Scr->TitleFocus 
				 && Tmp_win->wmhints 
				 && Tmp_win->wmhints->input
				 && Event.xcrossing.focus) {
			    SynthesiseFocusIn(Tmp_win->w);
			}

 		    } else if (ewp->window == Tmp_win->w) {
			/*
			 * If we are entering the application window, install
			 * its colormap(s).
			 */
			if (Scr->BorderCursors) SetBorderCursor (Tmp_win, -1000, -1000);
			if (!scanArgs.leaves || scanArgs.inferior) {
			    InstallWindowColormaps(EnterNotify, Tmp_win);
			}

			if (Event.xcrossing.focus) {
				SynthesiseFocusIn(Tmp_win->w);
			}

			/* must deal with WM_TAKE_FOCUS clients now, if 
			   we're not in TitleFocus mode */

			if (!(Scr->TitleFocus) &&
			    (Tmp_win->protocols & DoesWmTakeFocus)) {

				/* locally active clients need help from WM
				   to get the input focus */
				
				if (Tmp_win->wmhints &&
				    Tmp_win->wmhints->input)
				  SetFocus(Tmp_win, ewp->time);

				/* for both locally & globally active clnts */

				SendTakeFocusMessage(Tmp_win, ewp->time);
			}
		    }
		}			/* end if Tmp_win->mapped */
		if (Tmp_win->wmhints != NULL &&
			ewp->window == Tmp_win->wmhints->icon_window &&
			(!scanArgs.leaves || scanArgs.inferior)) {
			    InstallWindowColormaps(EnterNotify, Tmp_win);
		}
	    }				/* end if FocusRoot */
	    else
	    if (Scr->BorderCursors && (ewp->window == Tmp_win->w)) {
		SetBorderCursor (Tmp_win, -1000, -1000);
	    }
	    /*
	     * If this window is to be autoraised, mark it so
	     */
	    if (Tmp_win->auto_raise) {
		enter_win = Tmp_win;
		if (enter_flag == FALSE) AutoRaiseWindow (Tmp_win);
	    } else if (enter_flag && raise_win == Tmp_win)
	      enter_win = Tmp_win;
	    /*
	     * set ring leader
	     */
	    if (Tmp_win->ring.next && (!enter_flag || raise_win == enter_win))
	      Scr->RingLeader = Tmp_win;
	    XSync (dpy, 0);
	    return;
	}				/* end if Tmp_win */
    }					/* end if !ActiveMenu */

    /*
     * Find the menu that we are dealing with now; punt if unknown
     */
    if (XFindContext (dpy, ewp->window, MenuContext, (XPointer *)&mr) != XCSUCCESS) return;

    if (! ActiveMenu && mr->pinned && (RootFunction == 0)) {
	PopUpMenu (mr, 0, 0, 0);
	Context = C_ROOT;
	UpdateMenu ();
	return;
    }
    mr->entered = TRUE;
    if (RootFunction == 0) {
	for (tmp = ActiveMenu; tmp; tmp = tmp->prev) {
	    if (tmp == mr) break;
	}
	if (! tmp) return;

	for (tmp = ActiveMenu; tmp != mr; tmp = tmp->prev) {
	    if (tmp->pinned) break;
	    HideMenu (tmp);
	    MenuDepth--;
	}
	UninstallRootColormap ();

	if (ActiveItem) {
	    ActiveItem->state = 0;
	    PaintEntry (ActiveMenu, ActiveItem,  False);
	}
	ActiveItem = NULL;
	ActiveMenu = mr;
	if (1/*Scr->StayUpMenus*/) {
	    int i, x, y, x_root, y_root, entry;
	    MenuItem *mi;

	    XQueryPointer (dpy, ActiveMenu->w, &JunkRoot, &JunkChild, &x_root, &y_root,
			&x, &y, &JunkMask);
	    if ((x > 0) && (y > 0) && (x < ActiveMenu->width) && (y < ActiveMenu->height)) {
		entry = y / Scr->EntryHeight;
		for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next) {
		    if (i == entry) break;
		}
		if (mi) {
		    ActiveItem = mi;
		    ActiveItem->state = 1;
		    PaintEntry (ActiveMenu, ActiveItem, False);
		}
	    }
	}
	if (ActiveMenu->pinned) XUngrabPointer(dpy, CurrentTime);
    }
    return;
}



/***********************************************************************
 *
 *  Procedure:
 *	HLNQueueScanner - LeaveNotify event q scanner
 *
 *	Looks at the queued events and determines if any
 *	EnterNotify events are behind this event to allow
 *	skipping of unnecessary processing.
 *
 ***********************************************************************
 */

typedef struct HLNScanArgs {
    Window w;		/* The window getting the LeaveNotify */
    Bool enters;	/* Any EnterNotify event at all */
    Bool matches;	/* Any matching EnterNotify events */
} HLNScanArgs;

/* ARGSUSED*/
static Bool HLNQueueScanner(Display *display, XEvent *ev, char *_args)
{
    HLNScanArgs *args = (void *)_args;

    if (ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) {
	args->enters = True;
	if (ev->xcrossing.window == args->w)
	    args->matches = True;
    }

    return (False);
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleLeaveNotify - LeaveNotify event handler
 *
 ***********************************************************************
 */

void HandleLeaveNotify(void)
{
    HLNScanArgs scanArgs;
    XEvent dummy;

    if (ActiveMenu && ActiveMenu->pinned && (Event.xcrossing.window == ActiveMenu->w)) {
	PopDownMenu ();
    }

    if (Tmp_win != NULL)
    {
	Bool inicon;

	/*
	 * We're not interested in pseudo Enter/Leave events generated
	 * from grab initiations and terminations.
	 */
	if (Event.xcrossing.mode != NotifyNormal)
	    return;

	if (Scr->ShrinkIconTitles &&
	    Tmp_win->icon &&
	    Event.xcrossing.window == Tmp_win->icon->w &&
	    Event.xcrossing.detail != NotifyInferior) {
	    ShrinkIconTitle (Tmp_win);
	    return;
	}

	inicon = (Tmp_win->iconmanagerlist &&
		  Tmp_win->iconmanagerlist->w == Event.xcrossing.window);

	if (Scr->RingLeader && Scr->RingLeader == Tmp_win &&
	    (Event.xcrossing.detail != NotifyInferior &&
	     Event.xcrossing.window != Tmp_win->w)) {
#ifdef DEBUG
	     fprintf(stderr, "HandleLeaveNotify: Event.xcrossing.window %x != Tmp_win->w %x\n", Event.xcrossing.window, Tmp_win->w);
#endif
	    if (!inicon) {
		if (Event.xcrossing.window != Tmp_win->frame /*was: Tmp_win->mapped*/) {
		    Tmp_win->ring.cursor_valid = False;
#ifdef DEBUG
		    fprintf(stderr, "HandleLeaveNotify: cursor_valid = False\n");
#endif
		} else {	/* Event.xcrossing.window == Tmp_win->frame */
		    Tmp_win->ring.cursor_valid = True;
		    Tmp_win->ring.curs_x = (Event.xcrossing.x_root -
					    Tmp_win->frame_x);
		    Tmp_win->ring.curs_y = (Event.xcrossing.y_root -
					    Tmp_win->frame_y);
#ifdef DEBUG
		    fprintf(stderr, "HandleLeaveNotify: cursor_valid = True; x = %d (%d-%d), y = %d (%d-%d)\n", Tmp_win->ring.curs_x, Event.xcrossing.x_root, Tmp_win->frame_x, Tmp_win->ring.curs_y, Event.xcrossing.y_root, Tmp_win->frame_y);
#endif
		}
	    }
	    Scr->RingLeader = (TwmWindow *) NULL;
	}
	if (Scr->FocusRoot) {

	    if (Event.xcrossing.detail != NotifyInferior) {

		/*
		 * Scan for EnterNotify events to see if we can avoid some
		 * unnecessary processing.
		 */
		scanArgs.w = Event.xcrossing.window;
		scanArgs.enters = scanArgs.matches = False;
		(void) XCheckIfEvent(dpy, &dummy, HLNQueueScanner,
				     (char *) &scanArgs);

		if (Event.xcrossing.window == Tmp_win->frame && !scanArgs.matches) {
		    if (Scr->TitleFocus ||
			Tmp_win->protocols & DoesWmTakeFocus)
		      SetFocus ((TwmWindow *) NULL, Event.xcrossing.time);
		    /* pretend there was a focus out as sometimes 
		       * we don't get one. */
		    if ( Event.xcrossing.focus)
                      SynthesiseFocusOut(Tmp_win->w);
		}
		else
		if (Scr->IconManagerFocus && inicon) {
		    if (! Tmp_win->mapped ||
			! Tmp_win->wmhints ||
			! Tmp_win->wmhints->input) {
			return;
		    }
		    if (Scr->TitleFocus || Tmp_win->protocols & DoesWmTakeFocus)
			SetFocus ((TwmWindow *) NULL, Event.xcrossing.time);
			if (Event.xcrossing.focus) SynthesiseFocusOut (Tmp_win->w);
		} else if (Event.xcrossing.window == Tmp_win->w &&
				!scanArgs.enters) {
		    InstallColormaps(LeaveNotify, &Scr->RootColormaps);
		}
	    }
	}
	/* Autolower modification. */
	if (Tmp_win->auto_lower) {
	    leave_win = Tmp_win;
	    if (leave_flag == FALSE) AutoLowerWindow (Tmp_win);
	} else if (leave_flag && lower_win == Tmp_win)
	    leave_win = Tmp_win;

	XSync (dpy, 0);
	return;
    }
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleConfigureRequest - ConfigureRequest event handler
 *
 ***********************************************************************
 */

void HandleConfigureRequest(void)
{
    XWindowChanges xwc;
    unsigned long xwcm;
    int x, y, width, height, bw;
    int gravx, gravy;
    XConfigureRequestEvent *cre = &Event.xconfigurerequest;
    Bool sendEvent;

#ifdef DEBUG_EVENTS
    fprintf(stderr, "ConfigureRequest\n");
    if (cre->value_mask & CWX)
	fprintf(stderr, "  x = %d\n", cre->x);
    if (cre->value_mask & CWY)
	fprintf(stderr, "  y = %d\n", cre->y);
    if (cre->value_mask & CWWidth)
	fprintf(stderr, "  width = %d\n", cre->width);
    if (cre->value_mask & CWHeight)
	fprintf(stderr, "  height = %d\n", cre->height);
    if (cre->value_mask & CWSibling)
	fprintf(stderr, "  above = 0x%x\n", cre->above);
    if (cre->value_mask & CWStackMode)
	fprintf(stderr, "  stack = %d\n", cre->detail);
#endif

    /*
     * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
     * be wrong
     */
    Event.xany.window = cre->window;	/* mash parent field */
    Tmp_win = GetTwmWindow(cre->window);

    /*
     * According to the July 27, 1988 ICCCM draft, we should ignore size and
     * position fields in the WM_NORMAL_HINTS property when we map a window.
     * Instead, we'll read the current geometry.  Therefore, we should respond
     * to configuration requests for windows which have never been mapped.
     */
    if (!Tmp_win || (Tmp_win->icon && (Tmp_win->icon->w == cre->window))) {
	xwcm = cre->value_mask & 
	    (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
	xwc.x = cre->x;
	xwc.y = cre->y;
	xwc.width = cre->width;
	xwc.height = cre->height;
	xwc.border_width = cre->border_width;
	XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
	return;
    }

    sendEvent = False;
    if ((cre->value_mask & CWStackMode) && Tmp_win->stackmode) {
	TwmWindow *otherwin;

	xwc.sibling = (((cre->value_mask & CWSibling) &&
			(otherwin = GetTwmWindow(cre->above)))
		       ? otherwin->frame : cre->above);
	xwc.stack_mode = cre->detail;
	XConfigureWindow (dpy, Tmp_win->frame, 
			  cre->value_mask & (CWSibling | CWStackMode), &xwc);
	sendEvent = True;
    }


    /* Don't modify frame_XXX fields before calling SetupWindow! */
    x = Tmp_win->frame_x;
    y = Tmp_win->frame_y;
    width = Tmp_win->frame_width;
    height = Tmp_win->frame_height;
    bw = Tmp_win->frame_bw;

    /*
     * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the
     * configure request are for the upper-left outer corner of the window.
     * This means that we need to adjust for the additional title height as
     * well as for any border width changes that we decide to allow.  The
     * current window gravity is to be used in computing the adjustments, just
     * as when initially locating the window.  Note that if we do decide to 
     * allow border width changes, we will need to send the synthetic 
     * ConfigureNotify event.
     */
    GetGravityOffsets (Tmp_win, &gravx, &gravy);

    if (cre->value_mask & CWBorderWidth) {
	int bwdelta = cre->border_width - Tmp_win->old_bw;  /* posit growth */
	if (bwdelta && Scr->ClientBorderWidth) {  /* if change allowed */
	    x += gravx * bwdelta;	/* change default values only */
	    y += gravy * bwdelta;	/* ditto */
	    bw = cre->border_width;
	    if (Tmp_win->title_height) height += bwdelta;
	    x += (gravx < 0) ? bwdelta : -bwdelta;
	    y += (gravy < 0) ? bwdelta : -bwdelta;
	}
	Tmp_win->old_bw = cre->border_width;  /* for restoring */
    }

    if (cre->value_mask & CWX) {	/* override even if border change */
	x = cre->x - bw;
	x -= ((gravx < 0) ? 0 : Tmp_win->frame_bw3D);
    }
    if (cre->value_mask & CWY) {
	y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw;
	y -= ((gravy < 0) ? 0 : Tmp_win->frame_bw3D);
    }

    if (cre->value_mask & CWWidth) {
	width = cre->width + 2 * Tmp_win->frame_bw3D;
    }
    if (cre->value_mask & CWHeight) {
	height = cre->height + Tmp_win->title_height + 2 * Tmp_win->frame_bw3D;
    }

    if (width != Tmp_win->frame_width || height != Tmp_win->frame_height)
	Tmp_win->zoomed = ZOOM_NONE;

    /* Workaround for Java 1.4 bug that freezes the application whenever
     * a new window is displayed. (When UsePPosition is on and either
     * UseThreeDBorders or BorderWidth 0 is set.)
     */
    if (!bw)
        sendEvent = True; 

    /*
     * SetupWindow (x,y) are the location of the upper-left outer corner and
     * are passed directly to XMoveResizeWindow (frame).  The (width,height)
     * are the inner size of the frame.  The inner width is the same as the 
     * requested client window width; the inner height is the same as the
     * requested client window height plus any title bar slop.
     */
    SetupFrame (Tmp_win, x, y, width, height, bw, sendEvent);
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleShapeNotify - shape notification event handler
 *
 ***********************************************************************
 */
void HandleShapeNotify (void)
{
    XShapeEvent	    *sev = (XShapeEvent *) &Event;

    if (Tmp_win == NULL)
	return;
    if (sev->kind != ShapeBounding)
	return;
    if (!Tmp_win->wShaped && sev->shaped) {
	XShapeCombineMask (dpy, Tmp_win->frame, ShapeClip, 0, 0, None,
			   ShapeSet);
    }
    Tmp_win->wShaped = sev->shaped;
    SetFrameShape (Tmp_win);
}



/***********************************************************************
 *
 *  Procedure:
 *	HandleUnknown - unknown event handler
 *
 ***********************************************************************
 */

void HandleUnknown(void)
{
#ifdef DEBUG_EVENTS
    fprintf(stderr, "type = %d\n", Event.type);
#endif
}



/***********************************************************************
 *
 *  Procedure:
 *	Transient - checks to see if the window is a transient
 *
 *  Returned Value:
 *	TRUE	- window is a transient
 *	FALSE	- window is not a transient
 *
 *  Inputs:
 *	w	- the window to check
 *
 ***********************************************************************
 */

int Transient(Window w, Window *propw)
{
    return (XGetTransientForHint(dpy, w, propw));
}



/***********************************************************************
 *
 *  Procedure:
 *	FindScreenInfo - get ScreenInfo struct associated with a given window
 *
 *  Returned Value:
 *	ScreenInfo struct
 *
 *  Inputs:
 *	w	- the window
 *
 ***********************************************************************
 */

ScreenInfo *FindScreenInfo(Window w)
{
    XWindowAttributes attr;
    int scrnum;

    attr.screen = NULL;
    if (XGetWindowAttributes(dpy, w, &attr)) {
	for (scrnum = 0; scrnum < NumScreens; scrnum++) {
	    if (ScreenList[scrnum] != NULL &&
		(ScreenOfDisplay(dpy, ScreenList[scrnum]->screen) ==
		 attr.screen))
	      return ScreenList[scrnum];
	}
    }

    return NULL;
}



static void flush_expose (Window w)
{
    XEvent dummy;

				/* SUPPRESS 530 */
    while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy)) ;
}



/***********************************************************************
 *
 *  Procedure:
 *	InstallWindowColormaps - install the colormaps for one twm window
 *
 *  Inputs:
 *	type	- type of event that caused the installation
 *	tmp	- for a subset of event types, the address of the
 *		  window structure, whose colormaps are to be installed.
 *
 ***********************************************************************
 */

int InstallWindowColormaps (int type, TwmWindow *tmp)
{
    if (tmp) {
	return InstallColormaps (type, &tmp->cmaps);
    } else {
	return InstallColormaps (type, NULL);
    }
}

int InstallColormaps (int type, Colormaps *cmaps)
{
    int i, j, n, number_cwins, state;
    ColormapWindow **cwins, *cwin, **maxcwin = NULL;
    TwmColormap *cmap;
    char *row, *scoreboard;

    switch (type) {
    case EnterNotify:
    case LeaveNotify:
    case DestroyNotify:
    default:
	/* Save the colormap to be loaded for when force loading of
	 * root colormap(s) ends.
	 */
	Scr->cmapInfo.pushed_cmaps = cmaps;
	/* Don't load any new colormap if root colormap(s) has been
	 * force loaded.
	 */
	if (Scr->cmapInfo.root_pushes)
	    return (0);
	/* Don't reload the current window colormap list.
	if (Scr->cmapInfo.cmaps == cmaps)
	    return (0);
	 */
	if (Scr->cmapInfo.cmaps) {
	    for (i = Scr->cmapInfo.cmaps->number_cwins,
		 cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++) {
		(*cwins)->colormap->state &= ~CM_INSTALLABLE;
	    }
	}
	Scr->cmapInfo.cmaps = cmaps;
	break;
    
    case PropertyNotify:
    case VisibilityNotify:
    case ColormapNotify:
	break;
    }

    number_cwins = Scr->cmapInfo.cmaps->number_cwins;
    cwins = Scr->cmapInfo.cmaps->cwins;
    scoreboard = Scr->cmapInfo.cmaps->scoreboard;

    ColortableThrashing = FALSE; /* in case installation aborted */

    state = CM_INSTALLED;

      for (i = n = 0; i < number_cwins; i++) {
	cwins[i]->colormap->state &= ~CM_INSTALL;
      }
      for (i = n = 0; i < number_cwins && n < Scr->cmapInfo.maxCmaps; i++) {
	cwin = cwins[i];
	cmap = cwin->colormap;
	if (cmap->state & CM_INSTALL) continue;
	cmap->state |= CM_INSTALLABLE;
	cmap->w = cwin->w;
	if (cwin->visibility != VisibilityFullyObscured) {
	    row = scoreboard + (i*(i-1)/2);
	    for (j = 0; j < i; j++)
		if (row[j] && (cwins[j]->colormap->state & CM_INSTALL))
		    break;
	    if (j != i) continue;
	    n++;
	    maxcwin = &cwins[i];
	    state &= (cmap->state & CM_INSTALLED);
	    cmap->state |= CM_INSTALL;
	}
    }
    Scr->cmapInfo.first_req = NextRequest(dpy);

    for ( ; n > 0 && maxcwin >= &cwins[0]; maxcwin--) {
	cmap = (*maxcwin)->colormap;
	if (cmap->state & CM_INSTALL) {
	    cmap->state &= ~CM_INSTALL;
	    if (!(state & CM_INSTALLED)) {
		cmap->install_req = NextRequest(dpy);
		/* printf ("XInstallColormap : %x, %x\n", cmap, cmap->c); */
		XInstallColormap(dpy, cmap->c);
	    }
	    cmap->state |= CM_INSTALLED;
	    n--;
	}
    }
    return (1);
}



/***********************************************************************
 *
 *  Procedures:
 *	<Uni/I>nstallRootColormap - Force (un)loads root colormap(s)
 *
 *	   These matching routines provide a mechanism to insure that
 *	   the root colormap(s) is installed during operations like
 *	   rubber banding or menu display that require colors from
 *	   that colormap.  Calls may be nested arbitrarily deeply,
 *	   as long as there is one UninstallRootColormap call per
 *	   InstallRootColormap call.
 *
 *	   The final UninstallRootColormap will cause the colormap list
 *	   which would otherwise have be loaded to be loaded, unless
 *	   Enter or Leave Notify events are queued, indicating some
 *	   other colormap list would potentially be loaded anyway.
 ***********************************************************************
 */

void InstallRootColormap(void)
{
    Colormaps *tmp;
    if (Scr->cmapInfo.root_pushes == 0) {
	/*
	 * The saving and restoring of cmapInfo.pushed_window here
	 * is a slimy way to remember the actual pushed list and
	 * not that of the root window.
	 */
	tmp = Scr->cmapInfo.pushed_cmaps;
	InstallColormaps(0, &Scr->RootColormaps);
	Scr->cmapInfo.pushed_cmaps = tmp;
    }
    Scr->cmapInfo.root_pushes++;
}



/* ARGSUSED*/
static Bool UninstallRootColormapQScanner(Display *display, XEvent *ev, char *args)
{
    if (!*args) {
	if (ev->type == EnterNotify) {
	    if (ev->xcrossing.mode != NotifyGrab)
		*args = 1;
	} else if (ev->type == LeaveNotify) {
	    if (ev->xcrossing.mode == NotifyNormal)
		*args = 1;
	}
    }

    return (False);
}



void UninstallRootColormap(void)
{
    char args;
    XEvent dummy;

    if (Scr->cmapInfo.root_pushes)
	Scr->cmapInfo.root_pushes--;
    
    if (!Scr->cmapInfo.root_pushes) {
	/*
	 * If we have subsequent Enter or Leave Notify events,
	 * we can skip the reload of pushed colormaps.
	 */
	XSync (dpy, 0);
	args = 0;
	(void) XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args);

	if (!args)
	    InstallColormaps(0, Scr->cmapInfo.pushed_cmaps);
    }
}

void ConfigureRootWindow (XEvent *ev)
{
    Window       root, child;
    int          x, y;
    unsigned int w, h, bw, d, oldw, oldh;

    XGetGeometry (dpy, Scr->CaptiveRoot, &root, &x, &y, &w, &h, &bw, &d);
    XTranslateCoordinates (dpy, Scr->CaptiveRoot, root, 0, 0, &Scr->crootx, &Scr->crooty, &child);

    oldw = Scr->crootw;
    oldh = Scr->crooth;
    Scr->crootw = ev->xconfigure.width;
    Scr->crooth = ev->xconfigure.height;
    /*
    fprintf (stderr, "ConfigureRootWindow: cx = %d, cy = %d, cw = %d, ch = %d\n",
	     Scr->crootx, Scr->crooty, Scr->crootw, Scr->crooth);
    */
    if (Scr->currentvs) {
      Scr->rootx = Scr->crootx + Scr->currentvs->x;
      Scr->rooty = Scr->crooty + Scr->currentvs->y;
    }
    Scr->rootw = Scr->crootw;
    Scr->rooth = Scr->crooth;

    if (captive && ((Scr->crootw != oldw) || (Scr->crooth != oldh))) {
      twmrc_error_prefix ();
      fprintf (stderr, "You cannot change root window geometry with virtual screens active,\n");
      fprintf (stderr, "from now on, the ctwm behaviour is unpredictable.\n");
    }
}

static void dumpevent (XEvent *e)
{
    char *name = "Unknown event";

    if (! tracefile) return;
    switch (e->type) {
      case KeyPress:  name = "KeyPress"; break;
      case KeyRelease:  name = "KeyRelease"; break;
      case ButtonPress:  name = "ButtonPress"; break;
      case ButtonRelease:  name = "ButtonRelease"; break;
      case MotionNotify:  name = "MotionNotify"; break;
      case EnterNotify:  name = "EnterNotify"; break;
      case LeaveNotify:  name = "LeaveNotify"; break;
      case FocusIn:  name = "FocusIn"; break;
      case FocusOut:  name = "FocusOut"; break;
      case KeymapNotify:  name = "KeymapNotify"; break;
      case Expose:  name = "Expose"; break;
      case GraphicsExpose:  name = "GraphicsExpose"; break;
      case NoExpose:  name = "NoExpose"; break;
      case VisibilityNotify:  name = "VisibilityNotify"; break;
      case CreateNotify:  name = "CreateNotify"; break;
      case DestroyNotify:  name = "DestroyNotify"; break;
      case UnmapNotify:  name = "UnmapNotify"; break;
      case MapNotify:  name = "MapNotify"; break;
      case MapRequest:  name = "MapRequest"; break;
      case ReparentNotify:  name = "ReparentNotify"; break;
      case ConfigureNotify:  name = "ConfigureNotify"; break;
      case ConfigureRequest:  name = "ConfigureRequest"; break;
      case GravityNotify:  name = "GravityNotify"; break;
      case ResizeRequest:  name = "ResizeRequest"; break;
      case CirculateNotify:  name = "CirculateNotify"; break;
      case CirculateRequest:  name = "CirculateRequest"; break;
      case PropertyNotify:  name = "PropertyNotify"; break;
      case SelectionClear:  name = "SelectionClear"; break;
      case SelectionRequest:  name = "SelectionRequest"; break;
      case SelectionNotify:  name = "SelectionNotify"; break;
      case ColormapNotify:  name = "ColormapNotify"; break;
      case ClientMessage:  name = "ClientMessage"; break;
      case MappingNotify:  name = "MappingNotify"; break;
    }
    fprintf (tracefile, "event:  %s in window 0x%x\n", name,
	     (unsigned int)e->xany.window);
    switch (e->type) {
      case KeyPress:
      case KeyRelease:
	  fprintf (tracefile, "     :  +%d,+%d (+%d,+%d)  state=%d, keycode=%d\n",
		   e->xkey.x, e->xkey.y,
		   e->xkey.x_root, e->xkey.y_root,
		   e->xkey.state, e->xkey.keycode);
	  break;
      case ButtonPress:
      case ButtonRelease:
	  fprintf (tracefile, "     :  +%d,+%d (+%d,+%d)  state=%d, button=%d\n",
		   e->xbutton.x, e->xbutton.y,
		   e->xbutton.x_root, e->xbutton.y_root,
		   e->xbutton.state, e->xbutton.button);
	  break;
    }
}
