/****************************************************************************
 * This module is based on Twm, but has been SIGNIFICANTLY modified 
 * by Rob Nation 
 * by Bo Yang
 * by Frank Fejes
 *****************************************************************************/

/*****************************************************************************/
/**       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.                                     **/
/*****************************************************************************/


/***********************************************************************
 *
 * afterstep window border drawing code
 *
 ***********************************************************************/

#include "../configure.h"

#include <stdio.h>
#include <signal.h>
#include <string.h>

#include "afterstep.h"
#include "menus.h"
#include "misc.h"
#include "parse.h"
#include "screen.h"
#include "module.h"
#ifndef NO_TEXTURE
#include "stepgfx.h"
#endif

#ifndef NO_SHAPE
#include <X11/extensions/shape.h>
#endif

/* macro to change window background color/pixmap */
#define ChangeWindowColor(window) {\
        if(NewColor)\
           {\
             XChangeWindowAttributes(dpy,window,valuemask, &attributes);\
             XClearWindow(dpy,window);\
           }\
         }

extern Window PressedW;



/**************************************************************
 * 
 * Sets the window background to the correct texture 
 * 
 **************************************************************/
#define STATE_FOCUSED	0
#define STATE_UNFOCUSED 1
#define STATE_STICKY	2
void SetBackgroundTexture(ASWindow * t, Window win, int type, int state)
{
    Pixmap grad = None, tile = None;
    unsigned long pixel = 0;

    switch (state) {
    case STATE_FOCUSED:
	grad = t->backPixmap;
	tile = Scr.ForeTitle;
	pixel = Scr.HiColors.back;
	break;
    case STATE_UNFOCUSED:
	grad = t->backPixmap2;
	tile = Scr.BackTitle;
	pixel = Scr.StdColors.back;
	break;
    case STATE_STICKY:
	grad = t->backPixmap3;
	tile = Scr.StickyTitle;
	pixel = Scr.StickyColors.back;
	break;
    }
    switch (type) {
    case 0:
	XSetWindowBackground(dpy, win, pixel);
	break;
    case TEXTURE_PIXMAP:
	XSetWindowBackgroundPixmap(dpy, win, tile);
	break;
    default:			/* gradients */
	XSetWindowBackgroundPixmap(dpy, win, grad);
	break;
    }
    XClearWindow(dpy, win);
    XFlush(dpy);
}

/************************************************************************
 * 
 * Sets the window borders to the correct background
 * 
 **********************************************************************/
int SetTitleBackground(ASWindow * t, Bool focused)
{
    int state, type;
    /* the title background */
    if (focused) {
	state = STATE_FOCUSED;
	type = Textures.Ttype;
    } else {
	if (t->flags & STICKY) {
	    state = STATE_STICKY;
	    type = Textures.Stype;
	} else {
	    state = STATE_UNFOCUSED;
	    type = Textures.Utype;
	}
    }

    SetBackgroundTexture(t, t->title_w, type, state);
    return type;
}

void SetBottomBackground(ASWindow * t, Bool focused)
{
    int state, type;

    /* the title background */
    if (focused) {
	state = STATE_FOCUSED;
	type = Textures.Ttype;
    } else {
	if (t->flags & STICKY) {
	    state = STATE_STICKY;
	    type = Textures.Stype;
	} else {
	    state = STATE_UNFOCUSED;
	    type = Textures.Utype;
	}
    }
    if (!(Textures.flags & TexturedHandle)) {
	/* if the user wants the NeXT style... */
	state = STATE_UNFOCUSED;
	type = 0;
    }
    /* middle bottom frame */
    SetBackgroundTexture(t, t->side, type, state);
    /* side bottom frames */
    SetBackgroundTexture(t, t->corners[0], type, state);
    SetBackgroundTexture(t, t->corners[1], type, state);
}

/****************************************************************************
 *
 * Redraws the windows borders
 *
 ****************************************************************************/
void SetBorder(ASWindow * t, Bool onoroff, Bool force, Bool Mapped,
	       Window expose_win)
{
    Window w = None;
    int i, x, y, z = 0;
    GC ReliefGC, ShadowGC;
    GC HReliefGC, HShadowGC;
    Pixel BorderColor, BackColor;
    Pixmap BackPixmap, TextColor;
    Bool NewColor = False;
    XSetWindowAttributes attributes;
    unsigned long valuemask;
    static unsigned int corners[2];

    corners[0] = BOTTOM_HILITE | LEFT_HILITE;
    corners[1] = BOTTOM_HILITE | RIGHT_HILITE;

    if (!t)
	return;

    if (onoroff) {
	/* don't re-draw just for kicks */
	if ((!force) && (Scr.Hilite == t))
	    return;


	if (Scr.Hilite != t)
	    NewColor = True;

	/* make sure that the previously highlighted window got unhighlighted */
	if ((Scr.Hilite != t) && (Scr.Hilite != NULL))
	    SetBorder(Scr.Hilite, False, False, True, None);

	/* set the keyboard focus */
	if ((Mapped) && (t->flags & MAPPED) && (Scr.Hilite != t))
	    w = t->w;
#ifdef NO_ICON_BACKGROUND
	else if ((t->flags & ICONIFIED) &&
		 (Scr.Hilite != t) && (!(t->flags & SUPPRESSICON)))
	    w = t->icon_w;
#endif
	Scr.Hilite = t;

	TextColor = Scr.HiColors.fore;
	BackPixmap = Scr.gray_pixmap;
	BackColor = Scr.HiColors.back;
	ReliefGC = Scr.StdReliefGC;
	ShadowGC = Scr.StdShadowGC;

#ifndef NO_TEXTURE
	if (Textures.flags & TitlebarNoPush &&
	  Textures.flags & TexturedHandle && Scr.BevelReliefGC != None) {
	    HReliefGC = Scr.BevelReliefGC;
	    HShadowGC = Scr.BevelShadowGC;
	} else {
	    if (t->flags & STICKY) {
		HReliefGC = Scr.StickyReliefGC;
		HShadowGC = Scr.StickyShadowGC;
	    } else {
		HReliefGC = ReliefGC;
		HShadowGC = ShadowGC;
	    }
	}
#else
	HReliefGC = ReliefGC;
	HShadowGC = ShadowGC;
#endif
	BorderColor = Scr.HiRelief.back;
    } else {
	/* don't re-draw just for kicks */
	if ((!force) && (Scr.Hilite != t))
	    return;

	if (Scr.Hilite == t) {
	    Scr.Hilite = NULL;
	    NewColor = True;
	}
	TextColor = t->TextPixel;
	BackPixmap = Scr.light_gray_pixmap;
	if (t->flags & STICKY)
	    BackPixmap = Scr.sticky_gray_pixmap;
	BackColor = t->BackPixel;
	if (t->BackPixel != Scr.StdColors.back) {
	    Globalgcv.foreground = t->ReliefPixel;
	    Globalgcm = GCForeground;
	    XChangeGC(dpy, Scr.ScratchGC1, Globalgcm, &Globalgcv);
	    ReliefGC = Scr.ScratchGC1;

	    Globalgcv.foreground = t->ShadowPixel;
	    XChangeGC(dpy, Scr.ScratchGC2, Globalgcm, &Globalgcv);
	    ShadowGC = Scr.ScratchGC2;
	} else {
	    ReliefGC = Scr.StdReliefGC;
	    ShadowGC = Scr.StdShadowGC;
	}
	BorderColor = t->ShadowPixel;
	HReliefGC = ReliefGC;
	HShadowGC = ShadowGC;
    }

    if (t->flags & ICONIFIED) {
	DrawIconWindow(t);
	return;
    }
    valuemask = CWBorderPixel;
    attributes.border_pixel = BorderColor;
    if (Scr.d_depth < 2) {
	attributes.background_pixmap = BackPixmap;
	valuemask |= CWBackPixmap;
    } else {
	attributes.background_pixel = BackColor;
	valuemask |= CWBackPixel;
    }

    if (t->flags & (TITLE | BORDER)) {
	XSetWindowBorder(dpy, t->Parent, BlackPixel(dpy, DefaultScreen(dpy)));
	XSetWindowBorder(dpy, t->frame, BlackPixel(dpy, DefaultScreen(dpy)));
    }
    if (t->flags & TITLE) {
	ChangeWindowColor(t->title_w);
	for (i = 0; i < Scr.nr_left_buttons; i++) {
	    if (t->left_w[i] != None) {
		if (flush_expose(t->left_w[i]) ||
		    (expose_win == t->left_w[i]) ||
		    (expose_win == None)) {
		    RelieveWindow(t, t->left_w[i], 0, 0, t->button_height,
				  t->button_height,
		       (PressedW == t->right_w[i] ? ShadowGC : ReliefGC),
		       (PressedW == t->right_w[i] ? ReliefGC : ShadowGC),
				  BOTTOM_HILITE | RIGHT_HILITE);
		    switch (Scr.button_style[i * 2 + 1]) {
		    case XPM_BUTTON_STYLE:

			if (PressedW == t->left_w[i]) {		/* Pressed! */
			    XShapeCombineMask(dpy, t->left_w[i], ShapeBounding, 0, 0, Scr.dbutton_pixmap_mask[i * 2 + 1], ShapeSet);

			    XCopyArea(dpy, Scr.dbutton_pixmap[i * 2 + 1], t->left_w[i], Scr.MaskGC, 0, 0, Scr.button_width[i * 2 + 1],
				      Scr.button_height[i * 2 + 1], 0, 0);
			} else {
			    /* Not Pressed */
			    XShapeCombineMask(dpy, t->left_w[i], ShapeBounding, 0, 0,
			    Scr.button_pixmap_mask[i * 2 + 1], ShapeSet);
			    XCopyArea(dpy, Scr.button_pixmap[i * 2 + 1], t->left_w[i], Scr.MaskGC, 0, 0, Scr.button_width[i * 2 + 1],
				      Scr.button_height[i * 2 + 1], 0, 0);
			}
			break;

		    default:
			afterstep_err("old button styles should not be used\n", NULL, NULL, NULL);
			exit(1);
		    }
		}
	    }
	}

	for (i = 0; i < Scr.nr_right_buttons; i++) {
	    if (t->right_w[i] != None) {
		if (flush_expose(t->right_w[i]) ||
		    (expose_win == t->right_w[i]) ||
		    (expose_win == None)) {

		    if (Scr.ButtonType == 0) {
			RelieveWindow(t, t->right_w[i], 0, 0, t->button_height,
				      t->button_height,
			(PressedW == t->right_w[i] ? ShadowGC : ReliefGC),
			(PressedW == t->right_w[i] ? ReliefGC : ShadowGC),
				      BOTTOM_HILITE | RIGHT_HILITE);
			z = 2;
		    }
		    switch (Scr.button_style[(i * 2 + 2) % 10]) {
		    case XPM_BUTTON_STYLE:
			if ((PressedW == t->right_w[i]) && (Scr.ButtonType == 1)) {
/* Pressed! */
			    XShapeCombineMask(dpy, t->right_w[i], ShapeBounding, 0, 0,
					      Scr.dbutton_pixmap_mask[(i * 2 + 2) % 10], ShapeSet);

			    XCopyArea(dpy, Scr.dbutton_pixmap[(i * 2 + 2) % 10], t->right_w[i],
				      Scr.MaskGC, 0, 0, Scr.button_width[(i * 2 + 2) % 10],
			      Scr.button_height[(i * 2 + 2) % 10], z, z);

			} else {
/* Not Pressed */
			    if (Scr.ButtonType == 1)
				XShapeCombineMask(dpy, t->right_w[i], ShapeBounding, 0, 0,
						  Scr.button_pixmap_mask[(i * 2 + 2) % 10], ShapeSet);
			    XCopyArea(dpy, Scr.button_pixmap[(i * 2 + 2) % 10], t->right_w[i],
				      Scr.MaskGC, 0, 0, Scr.button_width[(i * 2 + 2) % 10],
			      Scr.button_height[(i * 2 + 2) % 10], z, z);

			}
			break;

		    default:
			afterstep_err("old button styles should not be used\n", NULL, NULL, NULL);
			exit(1);
		    }
		}
	    }
	}
	SetTitleBar(t, onoroff, False);
    }
    if (t->flags & BORDER) {
	/* draw relief lines */
	GC rgc, sgc;

	rgc = onoroff ? Scr.HiReliefGC : Scr.StdReliefGC;
	sgc = onoroff ? Scr.HiShadowGC : Scr.StdShadowGC;

	y = t->frame_height - 2 * t->corner_width;
	x = t->frame_width - 2 * t->corner_width + t->bw;
	SetBottomBackground(t, onoroff);
/*
 *       if((flush_expose (t->side))||(expose_win == t->side)||
 *       (expose_win == None)) {
 */

	RelieveWindow(t, t->side, 0, 0, x, t->boundary_height,
		      rgc, sgc, 0x0004);

/* } */
	for (i = 0; i < 2; i++) {
	    RelieveWindow(t, t->corners[i], 0, 0, t->corner_width,
			  t->corner_width + t->bw, rgc, sgc, corners[i]);
/*
 *  if((flush_expose(t->corners[i]))||(expose_win==t->corners[i])||
 *  (expose_win == None))
 *  {
 *
 *
 *          GC rgc, sgc;
 *
 *        rgc = HReliefGC;
 *        sgc = HShadowGC;
 *
 *        RelieveWindow(t, t->corners[i], 0, 0, t->corner_width,
 *                      t->corner_width + t->bw,
 *                      rgc, sgc, corners[i]);
 */

	    if (t->boundary_height > 1)
		RelieveParts(t, i, rgc, sgc);
	    else
		RelieveParts(t, i, rgc, sgc);
/* } */
	}
    } else {			/* no decorative border */
	/* for mono - put a black border on 
	 * for color, make it the color of the decoration background */
	if (t->boundary_height < 2) {
	    t->boundary_height = 0;
	    flush_expose(t->frame);
	    if (Scr.d_depth < 2) {
		XSetWindowBorder(dpy, t->frame, BlackPixel(dpy, DefaultScreen(dpy)));
		XSetWindowBorder(dpy, t->Parent, BlackPixel(dpy, DefaultScreen(dpy)));
		XSetWindowBackgroundPixmap(dpy, t->frame, BackPixmap);
		XClearWindow(dpy, t->frame);
		XSetWindowBackgroundPixmap(dpy, t->Parent, BackPixmap);
		XClearWindow(dpy, t->Parent);
	    } else {
		XSetWindowBackground(dpy, t->frame, BorderColor);
/*           XSetWindowBorder(dpy,t->frame,BorderColor);
 */
		XClearWindow(dpy, t->frame);
		XSetWindowBackground(dpy, t->Parent, BorderColor);
/*            XSetWindowBorder(dpy,t->Parent,BorderColor);
 */
		XClearWindow(dpy, t->Parent);
/*            XSetWindowBorder(dpy,t->w,BorderColor);         
 */
	    }
	} else {
	    GC rgc, sgc;

/*  XSetWindowBorder(dpy,t->Parent,BorderColor);
 *  XSetWindowBorder(dpy,t->frame,BorderColor);    
 */

	    rgc = ReliefGC;
	    sgc = ShadowGC;
	    ChangeWindowColor(t->frame);

	    if ((flush_expose(t->frame)) || (expose_win == t->frame) ||
		(expose_win == None)) {

		if (t->boundary_height > 2) {
		    RelieveWindow(t, t->frame, t->boundary_width - 1 - t->bw,
				  t->boundary_width - 1 - t->bw,
				  t->frame_width -
				(t->boundary_width << 1) + 2 + 3 * t->bw,
				  t->frame_height -
				(t->boundary_width << 1) + 2 + 3 * t->bw,
				  sgc, rgc,
				TOP_HILITE | LEFT_HILITE | RIGHT_HILITE |
				  BOTTOM_HILITE);
		    RelieveWindow(t, t->frame, 0, 0, t->frame_width + t->bw,
				  t->frame_height + t->bw, rgc, sgc,
				TOP_HILITE | LEFT_HILITE | RIGHT_HILITE |
				  BOTTOM_HILITE);
		} else {
		    RelieveWindow(t, t->frame, 0, 0, t->frame_width + t->bw,
				  t->frame_height + t->bw, rgc, rgc,
				TOP_HILITE | LEFT_HILITE | RIGHT_HILITE |
				  BOTTOM_HILITE);
		}
	    } else {
		XSetWindowBackground(dpy, t->Parent, BorderColor);
	    }
	}
    }
}


/****************************************************************************
 *
 *  Redraws just the title bar
 *
 ****************************************************************************/
void SetTitleBar(ASWindow * t, Bool onoroff, Bool NewTitle)
{
    int hor_off, w;
    int type;
    GC ReliefGC, ShadowGC, tGC;
    Pixel Forecolor, BackColor;

    if (!t)
	return;
    if (!(t->flags & TITLE))
	return;

    if (onoroff) {
	Forecolor = Scr.HiColors.fore;
	BackColor = Scr.HiColors.back;
#ifndef NO_TEXTURE
	if (Textures.flags & TitlebarNoPush) {
	    ReliefGC = (onoroff ? Scr.HiReliefGC : Scr.StdReliefGC);
	    ShadowGC = (onoroff ? Scr.HiShadowGC : Scr.StdShadowGC);
	} else
#endif
	{
	    if (onoroff || !(Textures.flags & TexturedHandle)) {
		ReliefGC = (PressedW == t->title_w ? Scr.HiShadowGC : Scr.HiReliefGC);
		ShadowGC = (PressedW == t->title_w ? Scr.HiReliefGC : Scr.HiShadowGC);
	    } else {
		ReliefGC = (PressedW == t->title_w ? Scr.StdShadowGC : Scr.StdReliefGC);
		ShadowGC = (PressedW == t->title_w ? Scr.StdReliefGC : Scr.StdShadowGC);
	    }
	}
    } else {
	Forecolor = t->TextPixel;
	BackColor = t->BackPixel;
	if (t->BackPixel != Scr.StdColors.back) {
	    Globalgcv.foreground = t->ReliefPixel;
	    Globalgcm = GCForeground;
	    XChangeGC(dpy, Scr.ScratchGC1, Globalgcm, &Globalgcv);
	    ReliefGC = Scr.ScratchGC1;

	    Globalgcv.foreground = t->ShadowPixel;
	    XChangeGC(dpy, Scr.ScratchGC2, Globalgcm, &Globalgcv);
	    ShadowGC = Scr.ScratchGC2;
	} else {
	    ReliefGC = Scr.StdReliefGC;
	    ShadowGC = Scr.StdShadowGC;
	}
	if (PressedW == t->title_w) {
	    tGC = ShadowGC;
	    ShadowGC = ReliefGC;
	    ReliefGC = tGC;
	}
    }
    flush_expose(t->title_w);

    if (t->name != (char *) NULL) {
	w = XTextWidth(Scr.WindowFont.font, t->name, strlen(t->name));
	if (w > t->title_width - 12)
	    w = t->title_width - 4;
	if (w < 0)
	    w = 0;
    } else
	w = 0;

#ifndef NO_TEXTURE
    if (Scr.TitleStyle == TITLE_NEXT4)
	hor_off = t->nr_left_buttons > 0 ? t->title_height + 10 : 5;
    else
#endif
	switch (Scr.TitleTextAlign) {
	case JUSTIFY_LEFT:
	    hor_off = t->nr_left_buttons * t->title_height + 6;
	    break;
	case JUSTIFY_RIGHT:
	    hor_off = t->title_width - w - t->nr_right_buttons * t->title_height - 6;
	    break;
	case JUSTIFY_CENTER:
	default:
	    hor_off = (t->title_width - w) / 2;
	}

    NewFontAndColor(Scr.WindowFont.font->fid, Forecolor, BackColor);


    if (NewTitle)
	XClearWindow(dpy, t->title_w);

    /* for mono, we clear an area in the title bar where the window
     * title goes, so that its more legible. For color, no need */
    if (Scr.d_depth < 2) {
	RelieveWindow(t, t->title_w, 0, 0, hor_off - 2, t->title_height,
		      ReliefGC, ShadowGC, BOTTOM_HILITE);
	RelieveWindow(t, t->title_w, hor_off + w + 2, 0,
		      t->title_width - w - hor_off - 2, t->title_height,
		      ReliefGC, ShadowGC, BOTTOM_HILITE);
	XFillRectangle(dpy, t->title_w,
		       (PressedW == t->title_w ? ShadowGC : ReliefGC),
		       hor_off - 2, 0, w + 4, t->title_height);

	XDrawLine(dpy, t->title_w, ShadowGC, hor_off + w + 1, 0, hor_off + w + 1,
		  t->title_height);
	if (t->name != (char *) NULL)
	    XDrawString(dpy, t->title_w, Scr.FontGC, hor_off,
			Scr.WindowFont.y + 4,
			t->name, strlen(t->name));
    } else {
#ifndef NO_TEXTURE
	type = SetTitleBackground(t, onoroff);

	if (!(Textures.flags & TitlebarNoPush) || type == 0
	    || type == TEXTURE_PIXMAP) {
	    RelieveWindow(t, t->title_w, 0, 0, t->bp_width, t->bp_height,
		       ReliefGC, ShadowGC, BOTTOM_HILITE | RIGHT_HILITE);
	    XFlush(dpy);
	}
	if (t->name != (char *) NULL) {
	    if (onoroff && (Textures.flags & GradientText)) {
		DrawTexturedText(dpy, t->title_w, Scr.WindowFont.font, hor_off,
			 4, Scr.TitleGradient, t->name, strlen(t->name));
	    } else {
		if (Scr.TitleTextType == 1) {
		    if (onoroff) {
/* If on, check */
			tGC = PressedW == t->title_w ? Scr.HiFontReliefGC : Scr.HiFontGC;
			ReliefGC = PressedW == t->title_w ? Scr.HiFontShadowGC : Scr.HiFontReliefGC;
			ShadowGC = PressedW == t->title_w ? Scr.HiFontGC : Scr.HiFontShadowGC;

		    } else {	/* If Off, then just use Lo */
			ReliefGC = Scr.LoFontReliefGC;
			ShadowGC = Scr.LoFontShadowGC;
			tGC = Scr.LoFontGC;
		    }

		    XDrawString(dpy, t->title_w, ReliefGC, hor_off, Scr.WindowFont.y + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ReliefGC, hor_off + 1, Scr.WindowFont.y + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ReliefGC, hor_off + 2, Scr.WindowFont.y + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ReliefGC, hor_off + 3, Scr.WindowFont.y + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ReliefGC, hor_off + 4, Scr.WindowFont.y + Scr.TitleTextY, t->name, strlen(t->name));

		    XDrawString(dpy, t->title_w, ReliefGC, hor_off, Scr.WindowFont.y + 1 + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ReliefGC, hor_off, Scr.WindowFont.y + 2 + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ReliefGC, hor_off, Scr.WindowFont.y + 3 + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ReliefGC, hor_off, Scr.WindowFont.y + 4 + Scr.TitleTextY, t->name, strlen(t->name));

		    XDrawString(dpy, t->title_w, ShadowGC, hor_off + 4, Scr.WindowFont.y + 2 + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ShadowGC, hor_off + 4, Scr.WindowFont.y + 3 + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ShadowGC, hor_off + 4, Scr.WindowFont.y + 4 + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ShadowGC, hor_off + 3, Scr.WindowFont.y + 4 + Scr.TitleTextY, t->name, strlen(t->name));
		    XDrawString(dpy, t->title_w, ShadowGC, hor_off + 2, Scr.WindowFont.y + 4 + Scr.TitleTextY, t->name, strlen(t->name));

		    XDrawString(dpy, t->title_w, tGC, hor_off + 2, Scr.WindowFont.y + 2 + Scr.TitleTextY, t->name, strlen(t->name));
		} else if (Scr.TitleTextType == 2) {
		    tGC = (onoroff ? Scr.HiFontGC : Scr.LoFontGC);
		    ReliefGC = (onoroff ? Scr.HiFontReliefGC : Scr.HiFontReliefGC);
		    ShadowGC = (onoroff ? Scr.HiFontShadowGC : Scr.LoFontShadowGC);

		    if (PressedW != t->title_w) {
			XDrawString(dpy, t->title_w, ShadowGC, hor_off + 1, Scr.WindowFont.y + 1 + Scr.TitleTextY, t->name, strlen(t->name));
			XDrawString(dpy, t->title_w, ReliefGC, hor_off + 2, Scr.WindowFont.y + 2 + Scr.TitleTextY, t->name, strlen(t->name));
			XDrawString(dpy, t->title_w, tGC, hor_off + 3, Scr.WindowFont.y + 3 + Scr.TitleTextY, t->name, strlen(t->name));
		    } else
			XDrawString(dpy, t->title_w, Scr.HiFontGC, hor_off + 1, Scr.WindowFont.y + 1 + Scr.TitleTextY, t->name, strlen(t->name));


		} else {	/* Default Window Draw */
		    XDrawString(dpy, t->title_w, Scr.FontGC, hor_off,
				Scr.WindowFont.y + 4,
				t->name, strlen(t->name));
		}
	    }
	}
#else
	if (t->name != (char *) NULL)
	    XDrawString(dpy, t->title_w, Scr.FontGC, hor_off,
			Scr.WindowFont.y + 4,
			t->name, strlen(t->name));

	RelieveWindow(t, t->title_w, 0, 0, t->title_width, t->title_height,
		      ReliefGC, ShadowGC, BOTTOM_HILITE | RIGHT_HILITE);
#endif
    }
    XFlush(dpy);
}


/****************************************************************************
 *
 *  Draws the relief pattern around a window
 *
 ****************************************************************************/
AFTER_INLINE void RelieveWindow(ASWindow * t, Window win,
				int x, int y, int w, int h,
				GC ReliefGC, GC ShadowGC, int hilite)
{
    XSegment seg[4];
    int i;
    int edge;

    if (!win)
	return;

    edge = 0;
    if (win == t->side)
	edge = -1;
    if (win == t->corners[0])
	edge = 1;
    if (win == t->corners[1])
	edge = 2;

    i = 0;
    seg[i].x1 = x;
    seg[i].y1 = y;
    seg[i].x2 = w + x - 1;
    seg[i++].y2 = y;

    seg[i].x1 = x;
    seg[i].y1 = y;
    seg[i].x2 = x;
    seg[i++].y2 = h + y - 1;

    if (((t->boundary_height > 2) || (edge == 0)) &&
	((t->boundary_height > 3) || (edge < 1)) &&
	(((edge == 0) || (t->boundary_height > 3)) && (hilite & TOP_HILITE))) {
	seg[i].x1 = x + 1;
	seg[i].y1 = y + 1;
	seg[i].x2 = x + w - 2;
	seg[i++].y2 = y + 1;
    }
    if (((t->boundary_height > 2) || (edge == 0)) &&
	((t->boundary_height > 3) || (edge < 1)) &&
	(((edge == 0) || (t->boundary_height > 3)) && (hilite & LEFT_HILITE))) {
	seg[i].x1 = x + 1;
	seg[i].y1 = y + 1;
	seg[i].x2 = x + 1;
	seg[i++].y2 = y + h - 2;
    }
    XDrawSegments(dpy, win, ReliefGC, seg, i);
    i = 0;
    seg[i].x1 = x;
    seg[i].y1 = y + h - 1;
    seg[i].x2 = w + x - 1;
    seg[i++].y2 = y + h - 1;

    if (((t->boundary_height > 2) || (edge == 0)) &&
	(((edge == 0) || (t->boundary_height > 3)) && (hilite & BOTTOM_HILITE))) {
	seg[i].x1 = x + 1;
	seg[i].y1 = y + h - 2;
	seg[i].x2 = x + w - 2;
	seg[i++].y2 = y + h - 2;
    }
    seg[i].x1 = x + w - 1;
    seg[i].y1 = y;
    seg[i].x2 = x + w - 1;
    seg[i++].y2 = y + h - 1;

    if (((t->boundary_height > 2) || (edge == 0)) &&
	(((edge == 0) || (t->boundary_height > 3)) && (hilite & RIGHT_HILITE))) {
	seg[i].x1 = x + w - 2;
	seg[i].y1 = y + 1;
	seg[i].x2 = x + w - 2;
	seg[i++].y2 = y + h - 2;
    }
    XDrawSegments(dpy, win, ShadowGC, seg, i);

}

void RelieveParts(ASWindow * t, int i, GC hor, GC vert)
{
    XSegment seg[2];

    if (!t->corners[i])
	return;
    switch (i) {
    case 0:
	seg[0].x1 = t->boundary_width - 1;
	/* used to be -2 */
	seg[0].x2 = t->corner_width - 2;
	seg[0].y1 = t->corner_width - t->boundary_height + t->bw;
	seg[0].y2 = t->corner_width - t->boundary_height + t->bw;
	break;
    case 1:
	seg[0].x1 = 0;
	seg[0].x2 = t->corner_width - t->boundary_width;
	seg[0].y1 = t->corner_width - t->boundary_height + t->bw;
	seg[0].y2 = t->corner_width - t->boundary_height + t->bw;
	break;
    }
    XDrawSegments(dpy, t->corners[i], hor, seg, 1);
    switch (i) {
    case 0:
	seg[0].y1 = 0;
	seg[0].y2 = t->corner_width - t->boundary_height;
	seg[0].x1 = t->boundary_width - 1;
	seg[0].x2 = t->boundary_width - 1;
	break;
    case 1:
	seg[0].y1 = 0;
	seg[0].y2 = t->corner_width - t->boundary_height + t->bw;
	seg[0].x1 = t->corner_width - t->boundary_width;
	seg[0].x2 = t->corner_width - t->boundary_width;
	break;
    }
    XDrawSegments(dpy, t->corners[i], vert, seg, 1);
}


Pixmap
MakeGradient(int type, int From[3], int To[3],
	     int w, int h, int maxcols, Pixmap cache)
{
    Pixmap pixmap;

    pixmap = XCreatePixmap(dpy, Scr.Root, w - 1, h - 1, Scr.d_depth);

    switch (type) {
    case 1:			/* NW to SE gradient */
	if (!DrawDegradeRelief(dpy, pixmap, 0, 0, w - 1, h - 1, From, To, 1,
			       maxcols)) {
	    XFreePixmap(dpy, pixmap);
	    pixmap = None;
	}
	break;
    case 2:			/* horizontal gradient */
    case 3:			/* horizn. cilyndrical */
	/* use cached thing */
	XCopyArea(dpy, cache, pixmap, Scr.ScratchGC1,
		  0, 0, w - 1, h - 1, 0, 0);
	XCopyArea(dpy, cache, pixmap, Scr.ScratchGC1,
		  Scr.MyDisplayWidth - 2, 0, 1, h - 1, w - 2, 0);
	break;
    case 4:			/* vertical gradient */
    case 5:			/* vert. cilyndrical */
	if (!DrawVGradient(dpy, pixmap, 0, 0,
			 w - 1, h - 1, From, To, 1, maxcols, type - 4)) {
	    XFreePixmap(dpy, pixmap);
	    pixmap = None;
	}
	break;
    default:
	XFreePixmap(dpy, pixmap);
	pixmap = None;
    }
    return pixmap;
}


/***********************************************************************
 *
 *  Procedure:
 *      Setupframe - set window sizes, this was called from either
 *              AddWindow, EndResize, or HandleConfigureNotify.
 *
 *  Inputs:
 *      tmp_win - the ASWindow pointer
 *      x       - the x coordinate of the upper-left outer corner of the frame
 *      y       - the y coordinate of the upper-left outer corner of the frame
 *      w       - the width of the frame window w/o border
 *      h       - the height of the frame window w/o border
 *
 *  Special Considerations:
 *      This routine will check to make sure the window is not completely
 *      off the display, if it is, it'll bring some of it back on.
 *
 *      The tmp_win->frame_XXX variables should NOT be updated with the
 *      values of x,y,w,h prior to calling this routine, since the new
 *      values are compared against the old to see whether a synthetic
 *      ConfigureNotify event should be sent.  (It should be sent if the
 *      window was moved but not resized.)
 *
 ************************************************************************/

void SetupFrame(ASWindow * tmp_win, int x, int y, int w, int h, Bool sendEvent)
{
    XEvent client_event;
    XWindowChanges frame_wc, xwc;
    unsigned long frame_mask, xwcm;
    int cx, cy, i;
    Bool Resized = False;
    int xwidth, ywidth, left, right;

    if (tmp_win->flags & SHADED)
	return;
    /* if windows is not being maximized, save size in case of maximization */
    if (!(tmp_win->flags & MAXIMIZED)) {
	tmp_win->orig_x = x;
	tmp_win->orig_y = y;
	tmp_win->orig_wd = w;
	tmp_win->orig_ht = h;
    }
    if (Scr.flags & DontMoveOff) {
	if (x + Scr.Vx + w < 16)
	    x = 16 - Scr.Vx - w;
	if (y + Scr.Vy + h < 16)
	    y = 16 - Scr.Vy - h;
    }
    if (x >= Scr.MyDisplayWidth + Scr.VxMax - Scr.Vx - 16)
	x = Scr.MyDisplayWidth + Scr.VxMax - Scr.Vx - 16;
    if (y >= Scr.MyDisplayHeight + Scr.VyMax - Scr.Vy - 16)
	y = Scr.MyDisplayHeight + Scr.VyMax - Scr.Vy - 16;

    /*
     * According to the July 27, 1988 ICCCM draft, we should send a
     * "synthetic" ConfigureNotify event to the client if the window
     * was moved but not resized.
     */
    if ((x != tmp_win->frame_x || y != tmp_win->frame_y) &&
	(w == tmp_win->frame_width && h == tmp_win->frame_height))
	sendEvent = TRUE;

    if ((w != tmp_win->frame_width) || (h != tmp_win->frame_height))
	Resized = True;

    if (Resized) {
	left = tmp_win->nr_left_buttons;
	right = tmp_win->nr_right_buttons;

	tmp_win->title_width = w - 2 * tmp_win->boundary_width + tmp_win->bw;


	if (tmp_win->title_width < 1)
	    tmp_win->title_width = 1;

	if (tmp_win->flags & TITLE) {
	    xwcm = CWWidth | CWX | CWY;
	    tmp_win->title_x = tmp_win->boundary_width;
	    if (tmp_win->title_x >= w - tmp_win->boundary_width)
		tmp_win->title_x = -10;
	    tmp_win->title_y = 0;
	    xwc.width = tmp_win->title_width;
	    xwc.x = tmp_win->title_x;
	    xwc.y = tmp_win->title_y;
	    XConfigureWindow(dpy, tmp_win->title_w, xwcm, &xwc);


	    xwcm = CWX | CWY;
	    xwc.y = 3;

	    xwc.x = 3;
	    for (i = 0; i < Scr.nr_left_buttons; i++) {
		if (tmp_win->left_w[i] != None) {
		    if (xwc.x + tmp_win->title_height < w - tmp_win->boundary_width)
			XConfigureWindow(dpy, tmp_win->left_w[i], xwcm, &xwc);
		    else {
			xwc.x = -tmp_win->title_height;
			XConfigureWindow(dpy, tmp_win->left_w[i], xwcm, &xwc);
		    }
		    xwc.x += tmp_win->title_height;
		}
	    }

	    xwc.x = w - tmp_win->boundary_width -
		(tmp_win->button_height - tmp_win->title_height) / 2 + tmp_win->bw;
	    for (i = 0; i < Scr.nr_right_buttons; i++) {
		if (tmp_win->right_w[i] != None) {
		    xwc.x -= tmp_win->title_height;
		    if (xwc.x > tmp_win->boundary_width)
			XConfigureWindow(dpy, tmp_win->right_w[i], xwcm, &xwc);
		    else {
			xwc.x = -tmp_win->title_height;
			XConfigureWindow(dpy, tmp_win->right_w[i], xwcm, &xwc);
		    }
		}
	    }
	}
	if ((tmp_win->flags & BORDER)
	    && (((tmp_win->wmhints) && (!(tmp_win->wmhints->initial_state == ZoomState)))
	      || (!tmp_win->wmhints && !(tmp_win->flags & MAXIMIZED)))) {
	    xwidth = w - 2 * tmp_win->corner_width + tmp_win->bw;
	    ywidth = h - 2 * tmp_win->corner_width;
	    xwcm = CWWidth | CWHeight | CWX | CWY;
	    if (xwidth < 2)
		xwidth = 2;
	    if (ywidth < 2)
		ywidth = 2;

	    xwc.x = tmp_win->corner_width;
	    xwc.y = h - tmp_win->boundary_height + tmp_win->bw;
	    xwc.height = tmp_win->boundary_height + tmp_win->bw;
	    xwc.width = xwidth;
	    XConfigureWindow(dpy, tmp_win->side, xwcm, &xwc);

	    xwcm = CWX | CWY;
	    for (i = 0; i < 2; i++) {
		if (i)
		    xwc.x = w - tmp_win->corner_width + tmp_win->bw;
		else
		    xwc.x = 0;

		xwc.y = h - tmp_win->corner_width;
		XConfigureWindow(dpy, tmp_win->corners[i], xwcm, &xwc);
	    }
	}
    }
    tmp_win->attr.width = w - 2 * tmp_win->boundary_width;
    tmp_win->attr.height = h - tmp_win->title_height - tmp_win->boundary_height;
    /* may need to omit the -1 for shaped windows, next two lines */
    cx = tmp_win->boundary_width - tmp_win->bw;
    cy = tmp_win->title_height - tmp_win->bw;

/*
   change 09/25/96
   if (tmp_win->attr.height<0) tmp_win->attr.height=1;
 */
    if (tmp_win->attr.height <= 0)
	tmp_win->attr.height = tmp_win->hints.height_inc;

    XResizeWindow(dpy, tmp_win->w, tmp_win->attr.width,
		  tmp_win->attr.height);
    XMoveResizeWindow(dpy, tmp_win->Parent, cx, cy,
		      tmp_win->attr.width, tmp_win->attr.height);

    /* 
     * fix up frame and assign size/location values in tmp_win
     */
    frame_wc.x = tmp_win->frame_x = x;
    frame_wc.y = tmp_win->frame_y = y;
    frame_wc.width = tmp_win->frame_width = w;
    frame_wc.height = tmp_win->frame_height = h;
    frame_mask = (CWX | CWY | CWWidth | CWHeight);
    XConfigureWindow(dpy, tmp_win->frame, frame_mask, &frame_wc);

#ifndef NO_TEXTURE
    /* 
     * rebuild titlebar background pixmap 
     */
    tmp_win->bp_height = tmp_win->title_height;
    /* Titlebar */
    if (tmp_win->flags & TITLE) {
	if ((Textures.Ttype > 0) && (Textures.Ttype < TEXTURE_PIXMAP)
	  && (tmp_win->title_width > 2) && ((tmp_win->backPixmap == None)
		       || (tmp_win->bp_width != tmp_win->title_width))) {

	    if (tmp_win->backPixmap != None) {
		XFreePixmap(dpy, tmp_win->backPixmap);
	    }
	    tmp_win->backPixmap = MakeGradient(Textures.Ttype,
					    Textures.Tfrom, Textures.Tto,
					       tmp_win->title_width,
					       tmp_win->title_height,
					       Textures.Tmaxcols,
					       Scr.ForeTitle);
	    if (tmp_win->backPixmap == None) {
		afterstep_err("Invalid TextureType %i specified for titlebar\n",
			      (char *) Textures.Ttype, NULL, NULL);
		Textures.Ttype = 0;
	    }
	} else if (Textures.Ttype == 0 || Textures.Ttype == TEXTURE_PIXMAP) {
	    tmp_win->backPixmap = None;
	}
    } else
	tmp_win->backPixmap = None;

    /* Unfocused titlebar */
    if (tmp_win->flags & TITLE) {
	if ((Textures.Utype > 0) && (Textures.Utype < TEXTURE_PIXMAP)
	 && (tmp_win->title_width > 2) && ((tmp_win->backPixmap2 == None)
		       || (tmp_win->bp_width != tmp_win->title_width))) {

	    if (tmp_win->backPixmap2 != None) {
		XFreePixmap(dpy, tmp_win->backPixmap2);
	    }
	    tmp_win->backPixmap2 = MakeGradient(Textures.Utype,
					    Textures.Ufrom, Textures.Uto,
						tmp_win->title_width,
						tmp_win->title_height,
						Textures.Umaxcols,
						Scr.BackTitle);
	    if (tmp_win->backPixmap2 == None) {
		afterstep_err("Invalid UTextureType %i specified for titlebar\n",
			      (char *) Textures.Utype, NULL, NULL);
		Textures.Utype = 0;
	    }
	} else if (Textures.Utype == 0 || Textures.Utype == TEXTURE_PIXMAP) {
	    tmp_win->backPixmap2 = None;
	}
    } else
	tmp_win->backPixmap2 = None;

    /* Unfocused sticky titlebar */
    if (tmp_win->flags & TITLE) {
	if ((Textures.Stype > 0) && (Textures.Stype < TEXTURE_PIXMAP)
	 && (tmp_win->title_width > 2) && ((tmp_win->backPixmap3 == None)
		       || (tmp_win->bp_width != tmp_win->title_width))) {

	    if (tmp_win->backPixmap3 != None) {
		XFreePixmap(dpy, tmp_win->backPixmap3);
	    }
	    tmp_win->backPixmap3 = MakeGradient(Textures.Stype,
					    Textures.Sfrom, Textures.Sto,
						tmp_win->title_width,
						tmp_win->title_height,
						Textures.Smaxcols,
						Scr.StickyTitle);
	    if (tmp_win->backPixmap3 == None) {
		afterstep_err("Invalid STextureType %i specified for titlebar\n",
			      (char *) Textures.Stype, NULL, NULL);
		Textures.Stype = 0;
	    }
	} else if (Textures.Stype == 0 || Textures.Stype == TEXTURE_PIXMAP) {
	    tmp_win->backPixmap3 = None;
	}
    } else
	tmp_win->backPixmap3 = None;
    tmp_win->bp_width = tmp_win->title_width;

#endif				/* ! NO_TEXTURE */

#ifndef NO_SHAPE
    if ((Resized) && (tmp_win->wShaped)) {
	SetShape(tmp_win, w);
    }
#endif				/* ! NO_SHAPE */
    XSync(dpy, 0);
    if (sendEvent) {
	client_event.type = ConfigureNotify;
	client_event.xconfigure.display = dpy;
	client_event.xconfigure.event = tmp_win->w;
	client_event.xconfigure.window = tmp_win->w;

	client_event.xconfigure.x = x + tmp_win->boundary_width;
	client_event.xconfigure.width = w - 2 * tmp_win->boundary_width;
	client_event.xconfigure.y = y + tmp_win->title_height;
	client_event.xconfigure.height = h - tmp_win->boundary_height -
	    tmp_win->title_height;
/*
   change 09/25/96
   if (client_event.xconfigure.height<0) 
   client_event.xconfigure.height=1;
 */

	if (client_event.xconfigure.height <= 0)
	    client_event.xconfigure.height = tmp_win->hints.height_inc;


	client_event.xconfigure.border_width = tmp_win->bw;
	/* Real ConfigureNotify events say we're above title window, so ... */
	/* what if we don't have a title ????? */
	client_event.xconfigure.above = tmp_win->frame;
	client_event.xconfigure.override_redirect = False;
	XSendEvent(dpy, tmp_win->w, False, StructureNotifyMask, &client_event);
    }
    BroadcastConfig(M_CONFIGURE_WINDOW, tmp_win);
}


/****************************************************************************
 *
 * Sets up the shaped window borders 
 * 
 ****************************************************************************/
void SetShape(ASWindow * tmp_win, int w)
{
#ifndef NO_SHAPE
    XRectangle rect;

    XShapeCombineShape(dpy, tmp_win->frame, ShapeBounding,
		       tmp_win->boundary_width,
		       tmp_win->title_height + tmp_win->boundary_width,
		       tmp_win->w,
		       ShapeBounding, ShapeSet);
    if (tmp_win->title_w) {
	/* windows w/ titles */
	rect.x = tmp_win->boundary_width;
	rect.y = tmp_win->title_y;
	rect.width = w - 2 * tmp_win->boundary_width + tmp_win->bw;
	rect.height = tmp_win->title_height;


	XShapeCombineRectangles(dpy, tmp_win->frame, ShapeBounding,
				0, 0, &rect, 1, ShapeUnion, Unsorted);
    }
#endif
}

/********************************************************************
 *
 * Sets the input focus to the indicated window.
 *
 **********************************************************************/

Bool
SetFocus(Window w, ASWindow * Fw, Bool circulated)
{
    int i;
    extern Time lastTimestamp;
    Bool focusAccepted = True;

    if (!circulated && Fw)
	SetCirculateSequence(Fw, 1);

    /* ClickToFocus focus queue manipulation */
    if (Fw && Fw != Scr.Focus && Fw != &Scr.ASRoot)
	Fw->focus_sequence = Scr.next_focus_sequence++;

    if (Scr.NumberOfScreens > 1) {
	XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
		      &JunkX, &JunkY, &JunkX, &JunkY, &JunkMask);
	if (JunkRoot != Scr.Root) {
	    if ((Scr.flags & ClickToFocus) && (Scr.Ungrabbed != NULL)) {
		/* Need to grab buttons for focus window */
		XSync(dpy, 0);
		for (i = 0; i < MAX_BUTTONS; i++)
		    if (Scr.buttons2grab & (1 << i))
			MyXGrabButton(dpy, i + 1, 0, Scr.Ungrabbed->frame,
				      True, ButtonPressMask, GrabModeSync,
				GrabModeAsync, None, Scr.ASCursors[SYS]);
		Scr.Focus = NULL;
		Scr.Ungrabbed = NULL;
		XSetInputFocus(dpy, Scr.NoFocusWin, RevertToParent, lastTimestamp);
	    }
	    return False;
	}
    }
    if (Fw && Fw->focus_var)
	return False;

    if (Fw && (Fw->Desk != Scr.CurrentDesk)) {
	Fw = NULL;
	w = Scr.NoFocusWin;
	focusAccepted = False;
    }
    if ((Scr.flags & ClickToFocus) && (Scr.Ungrabbed != Fw)) {
	/* need to grab all buttons for window that we are about to
	 * unfocus */
	if (Scr.Ungrabbed != NULL) {
	    XSync(dpy, 0);
	    for (i = 0; i < MAX_BUTTONS; i++)
		if (Scr.buttons2grab & (1 << i)) {
		    MyXGrabButton(dpy, i + 1, 0, Scr.Ungrabbed->frame,
				  True, ButtonPressMask, GrabModeSync,
				GrabModeAsync, None, Scr.ASCursors[SYS]);
		}
	    Scr.Ungrabbed = NULL;
	}
	/* if we do click to focus, remove the grab on mouse events that
	 * was made to detect the focus change */
	if ((Scr.flags & ClickToFocus) && (Fw != NULL)) {
	    for (i = 0; i < MAX_BUTTONS; i++)
		if (Scr.buttons2grab & (1 << i)) {
		    MyXUngrabButton(dpy, i + 1, 0, Fw->frame);
		}
	    Scr.Ungrabbed = Fw;
	}
    }
#ifdef NO_ICON_BACKGROUND
    if ((Fw) && (Fw->flags & ICONIFIED) && (Fw->icon_w))
	w = Fw->icon_w;
#endif

    /* do not set focus to shaded windows */
    if (Fw && (Fw->flags & SHADED))
	return False;

    if (!((Fw) && (Fw->wmhints) && (Fw->wmhints->flags & InputHint) &&
	  (Fw->wmhints->input == False))) {
	/* Window will accept input focus */
	XSetInputFocus(dpy, w, RevertToParent, lastTimestamp);
	Scr.Focus = Fw;
    } else if ((Scr.Focus) && (Scr.Focus->Desk == Scr.CurrentDesk)) {
	/* Window doesn't want focus. Leave focus alone */
	/* XSetInputFocus (dpy,Scr.Hilite->w , RevertToParent, lastTimestamp); */
	focusAccepted = False;
    } else {
	XSetInputFocus(dpy, Scr.NoFocusWin, RevertToParent, lastTimestamp);
	Scr.Focus = NULL;
	focusAccepted = False;
    }
    if ((Fw) && (Fw->flags & DoesWmTakeFocus))
	send_clientmessage(w, _XA_WM_TAKE_FOCUS, lastTimestamp);

    XSync(dpy, 0);

    return focusAccepted;
}
