/*
 * Copyright (C) 1995 Bo Yang
 * Copyright (C) 1993 Robert Nation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include "../configure.h"

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

#ifdef NeXT
#include <fcntl.h>
#endif

#include <X11/Intrinsic.h>
#ifdef XPM
#include <X11/xpm.h>
#endif				/* XPM */
#include "afterstep.h"
#include "menus.h"
#include "misc.h"
#include "parse.h"
#include "screen.h"
#include "module.h"

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

void GrabIconButtons(ASWindow *, Window);
void GrabIconKeys(ASWindow *, Window);
MyFont *IconFont;

/****************************************************************************
 *
 * Creates an icon window as needed
 *
 ****************************************************************************/
void CreateIconWindow(ASWindow * tmp_win, int def_x, int def_y)
{
    int final_x, final_y;
    unsigned long valuemask;	/* mask for create windows */
    XSetWindowAttributes attributes;	/* attributes for create windows */

    tmp_win->flags |= ICON_OURS;
    tmp_win->flags &= ~XPM_FLAG;
    tmp_win->flags &= ~PIXMAP_OURS;
    tmp_win->flags &= ~SHAPED_ICON;
    tmp_win->icon_pixmap_w = None;
    tmp_win->iconPixmap = None;
#ifndef NO_ICON_BACKGROUND
    tmp_win->icon_maskPixmap = None;	/* messo io */
#endif
    tmp_win->iconDepth = 0;

    if (tmp_win->flags & SUPPRESSICON)
	return;

/* First, see if it was specified in config. files  */
    SearchIcon(tmp_win, &tmp_win->icon_bitmap_file);
    GetIcon(tmp_win);

#ifdef NO_ICON_BACKGROUND
/* Tickle its size : figure out the icon window size */
    if (!(tmp_win->flags & NOICON_TITLE) || (tmp_win->icon_pm_height == 0)) {
	tmp_win->icon_t_width = XTextWidth(IconFont->font, tmp_win->icon_name,
					   strlen(tmp_win->icon_name));
	tmp_win->icon_w_height = ICON_HEIGHT;
    } else {
	tmp_win->icon_t_width = 0;
	tmp_win->icon_w_height = 0;
    }
    if ((tmp_win->flags & ICON_OURS) && (tmp_win->icon_pm_height > 0)) {
	tmp_win->icon_p_width += 4;
	tmp_win->icon_p_height += 4;
    }
    if (tmp_win->icon_pm_width == 0)
	tmp_win->icon_p_width = tmp_win->icon_t_width + 6;
    tmp_win->icon_w_width = tmp_win->icon_p_width;
#endif

    final_x = def_x;
    final_y = def_y;
    if (final_x < 0)
	final_x = 0;
    if (final_y < 0)
	final_y = 0;

#ifdef NO_ICON_BACKGROUND
    if (final_x + tmp_win->icon_w_width >= Scr.MyDisplayWidth)
	final_x = Scr.MyDisplayWidth - tmp_win->icon_w_width - 1;
    if (final_y + tmp_win->icon_w_height >= Scr.MyDisplayHeight)
	final_y = Scr.MyDisplayHeight - tmp_win->icon_w_height - 1;
#else
    if (final_x + tmp_win->icon_p_width >= Scr.MyDisplayWidth)
	final_x = Scr.MyDisplayWidth - tmp_win->icon_p_width - 1;
    if (final_y + tmp_win->icon_p_height >= Scr.MyDisplayHeight)
	final_y = Scr.MyDisplayHeight - tmp_win->icon_p_height - 1;
#endif
    tmp_win->icon_x_loc = final_x;
#ifdef NO_ICON_BACKGROUND
    tmp_win->icon_xl_loc = final_x;
#endif
    tmp_win->icon_y_loc = final_y;

    /* clip to fit on screen */
    attributes.background_pixel = Scr.StdColors.back;
    valuemask = CWBorderPixel | CWCursor | CWEventMask | CWBackPixel;
    attributes.border_pixel = Scr.StdColors.fore;
    attributes.cursor = Scr.ASCursors[DEFAULT];
    attributes.event_mask = (ButtonPressMask | ButtonReleaseMask |
			  ExposureMask | KeyPressMask | EnterWindowMask |
			     FocusChangeMask);

#ifdef NO_ICON_BACKGROUND
    if (!(tmp_win->flags & NOICON_TITLE) || (tmp_win->icon_pm_height == 0))
	tmp_win->icon_w =
	    XCreateWindow(dpy, Scr.Root, final_x,
			  final_y + tmp_win->icon_p_height,
			tmp_win->icon_w_width, tmp_win->icon_w_height, 0,
			  CopyFromParent, CopyFromParent, CopyFromParent,
			  valuemask, &attributes);

#endif

    if ((tmp_win->flags & ICON_OURS) && (tmp_win->icon_pm_width > 0)
	&& (tmp_win->icon_pm_height > 0)) {
	tmp_win->icon_pixmap_w =
	    XCreateWindow(dpy, Scr.Root, final_x, final_y,
			  tmp_win->icon_p_width, tmp_win->icon_p_height,
		       0, CopyFromParent, CopyFromParent, CopyFromParent,
			  valuemask, &attributes);
    } else {
#ifndef NO_ICON_BACKGROUND
	if (!(Scr.flags & KeepIconWindows)) {
	    tmp_win->icon_pixmap_w =
		XCreateWindow(dpy, Scr.Root, final_x, final_y,
			   tmp_win->icon_p_width, tmp_win->icon_p_height,
			      0, CopyFromParent,
		 CopyFromParent, CopyFromParent, valuemask, &attributes);

	    XReparentWindow(dpy, tmp_win->icon_pixmap_w,
			    tmp_win->icon_pixmap_w, 8, 8);

	    XMapWindow(dpy, tmp_win->icon_pixmap_w);

	    XResizeWindow(dpy, tmp_win->icon_pixmap_w,
		    tmp_win->icon_pm_width > tmp_win->icon_p_width - 16 ?
		     tmp_win->icon_p_width - 16 : tmp_win->icon_pm_width,
		  tmp_win->icon_pm_height > tmp_win->icon_p_height - 16 ?
		  tmp_win->icon_p_height - 16 : tmp_win->icon_pm_height);
	    tmp_win->flags |= ICON_OURS;
	}
#endif
	attributes.event_mask = (ButtonPressMask | ButtonReleaseMask |
				 KeyPressMask | EnterWindowMask |
				 FocusChangeMask | LeaveWindowMask);

	valuemask = CWEventMask;
	XChangeWindowAttributes(dpy, tmp_win->icon_pixmap_w, valuemask,
				&attributes);
    }

#ifdef XPM
#ifndef NO_SHAPE
#ifdef NO_ICON_BACKGROUND
    if (tmp_win->flags & KeepIconWindows) {
	XShapeCombineMask(dpy, tmp_win->icon_pixmap_w, ShapeBounding, 0, 0,
			  tmp_win->icon_maskPixmap, ShapeSet);
    }
#endif
#endif
#endif

#ifdef NO_ICON_BACKGROUND
    if (tmp_win->icon_w != None) {
	XSaveContext(dpy, tmp_win->icon_w, ASContext, (caddr_t) tmp_win);
	XDefineCursor(dpy, tmp_win->icon_w, Scr.ASCursors[DEFAULT]);
	GrabIconButtons(tmp_win, tmp_win->icon_w);
	GrabIconKeys(tmp_win, tmp_win->icon_w);
    }
#endif

    if (tmp_win->icon_pixmap_w != None) {
	XSaveContext(dpy, tmp_win->icon_pixmap_w, ASContext, (caddr_t) tmp_win);
	XDefineCursor(dpy, tmp_win->icon_pixmap_w, Scr.ASCursors[DEFAULT]);
	GrabIconButtons(tmp_win, tmp_win->icon_pixmap_w);
	GrabIconKeys(tmp_win, tmp_win->icon_pixmap_w);
    }
    return;
}


/****************************************************************************
 *
 * Draws the icon window
 *
 ****************************************************************************/
void DrawIconWindow(ASWindow * Tmp_win)
{

#ifdef NO_ICON_BACKGROUND
    GC Shadow, Relief;
    Pixel TextColor, BackColor;
#endif
    int w, h, x, y;

    if (Tmp_win->flags & SUPPRESSICON)
	return;

#ifdef NO_ICON_BACKGROUND
    if (Tmp_win->icon_w != None)
	flush_expose(Tmp_win->icon_w);
#endif

    if (Tmp_win->icon_pixmap_w != None) {
	flush_expose(Tmp_win->icon_pixmap_w);

#ifndef NO_ICON_BACKGROUND
	XSetWindowBackgroundPixmap(dpy, Tmp_win->icon_pixmap_w,
				   Scr.IconBgPixmap);
	XClearWindow(dpy, Tmp_win->icon_pixmap_w);
	XMoveWindow(dpy, Tmp_win->icon_pixmap_w, Tmp_win->icon_x_loc,
		    Tmp_win->icon_y_loc);
#endif
    }
#ifdef NO_ICON_BACKGROUND
    if (Scr.Hilite == Tmp_win) {
	if (Scr.d_depth < 2)
	    Relief = Scr.HiShadowGC;
	else
	    Relief = Scr.HiReliefGC;
	Shadow = Scr.HiShadowGC;
	/* resize the icon name window */
	if (Tmp_win->icon_w != None) {
	    Tmp_win->icon_w_width = Tmp_win->icon_t_width + 6;
	    if (Tmp_win->icon_w_width < Tmp_win->icon_p_width)
		Tmp_win->icon_w_width = Tmp_win->icon_p_width;
	    Tmp_win->icon_xl_loc = Tmp_win->icon_x_loc -
		(Tmp_win->icon_w_width - Tmp_win->icon_p_width) / 2;
	}
	TextColor = Scr.HiColors.fore;
	BackColor = Scr.HiColors.back;
    } else {
	if ((Tmp_win->flags & STICKY) && (Scr.d_depth < 2)) {
	    Relief = Scr.StickyShadowGC;
	    Shadow = Scr.StickyShadowGC;
	} else if (Scr.d_depth < 2) {
	    Relief = Scr.StdShadowGC;
	    Shadow = Scr.StdShadowGC;
	} else {
	    if (Tmp_win->BackPixel != Scr.StdColors.back) {
		Globalgcv.foreground = Tmp_win->ReliefPixel;
		Globalgcm = GCForeground;
		XChangeGC(dpy, Scr.ScratchGC1, Globalgcm, &Globalgcv);
		Relief = Scr.ScratchGC1;

		Globalgcv.foreground = Tmp_win->ShadowPixel;
		XChangeGC(dpy, Scr.ScratchGC2, Globalgcm, &Globalgcv);
		Shadow = Scr.ScratchGC2;
	    } else {
		Relief = Scr.StdReliefGC;
		Shadow = Scr.StdShadowGC;
	    }
	}
	/* resize the icon name window */
	if (Tmp_win->icon_w != None) {
	    Tmp_win->icon_w_width = Tmp_win->icon_p_width;
	    Tmp_win->icon_xl_loc = Tmp_win->icon_x_loc;
	}
	TextColor = Tmp_win->TextPixel;
	BackColor = Tmp_win->BackPixel;

    }

    if ((Tmp_win->flags & ICON_OURS) && (Tmp_win->icon_pixmap_w != None))
	XSetWindowBackground(dpy, Tmp_win->icon_pixmap_w, BackColor);

    if (Tmp_win->icon_w != None)
	XSetWindowBackground(dpy, Tmp_win->icon_w, BackColor);

    /* write the icon label */
      NewFontAndColor(IconFont->font->fid, TextColor, BackColor);

    if (Tmp_win->icon_pixmap_w != None)
	XMoveWindow(dpy, Tmp_win->icon_pixmap_w, Tmp_win->icon_x_loc,
		    Tmp_win->icon_y_loc);

    if (Tmp_win->icon_w != None) {
	XMoveResizeWindow(dpy, Tmp_win->icon_w, Tmp_win->icon_xl_loc,
			  Tmp_win->icon_y_loc + Tmp_win->icon_p_height,
			  Tmp_win->icon_w_width, ICON_HEIGHT);

	XClearWindow(dpy, Tmp_win->icon_w);
    }

   if ((Tmp_win->iconPixmap != None) && (!(Tmp_win->flags & SHAPED_ICON)))
	RelieveWindow(Tmp_win, Tmp_win->icon_pixmap_w, 0, 0,
		      Tmp_win->icon_p_width, Tmp_win->icon_p_height,
		      Relief, Shadow, FULL_HILITE);

    /* need to locate the icon pixmap */
    if (Tmp_win->iconPixmap != None) {
	if (Tmp_win->iconDepth == Scr.d_depth) {
	    XCopyArea(dpy, Tmp_win->iconPixmap, Tmp_win->icon_pixmap_w,
		      Scr.FontGC, 0, 0, Tmp_win->icon_p_width - 4,
		      Tmp_win->icon_p_height - 4, 0, 0);
	} else
	    XCopyPlane(dpy, Tmp_win->iconPixmap, Tmp_win->icon_pixmap_w,
		       Scr.FontGC, 0, 0, Tmp_win->icon_p_width - 4,
		       Tmp_win->icon_p_height - 4, 0, 0, 1);

    }
    if (Tmp_win->icon_w != None) {
	/* text position */
	x = (Tmp_win->icon_w_width - Tmp_win->icon_t_width) / 2;
	if (x < 3)
	    x = 3;

	XDrawString(dpy, Tmp_win->icon_w, Scr.IconGC, x,
	     Tmp_win->icon_w_height - IconFont->height + IconFont->y - 3,
		    Tmp_win->icon_name, strlen(Tmp_win->icon_name));


	RelieveWindow(Tmp_win, Tmp_win->icon_w, 0, 0, Tmp_win->icon_w_width,
		      ICON_HEIGHT, Relief, Shadow, FULL_HILITE);
    }
#else				/* NO_ICON_BACKGROUND */
/* need to locate the icon pixmap */
    if (Tmp_win->iconPixmap != None) {
	int titleH = 0;

	x = y = 0.0;
	w = Tmp_win->icon_pm_width;
	if (w > Tmp_win->icon_p_width - 16) {
	    x = (w - Tmp_win->icon_p_width + 16) / 2;
	    w = Tmp_win->icon_p_width - 16;
	}
	h = Tmp_win->icon_pm_height;
	if (h > Tmp_win->icon_p_height - 16) {
	    y = (h - Tmp_win->icon_p_height + 16) / 2;
	    h = Tmp_win->icon_p_height - 16;
	}
	if (Scr.flags & IconTitle && (Tmp_win->icon_name != NULL
				      || Tmp_win->name != NULL)) {
	    titleH = Scr.IconFont.height - 4;
	}
	if (Tmp_win->iconDepth == Scr.d_depth) {
	    XCopyArea(dpy, Tmp_win->iconPixmap, Tmp_win->icon_pixmap_w, Scr.FontGC,
		      x, y,
		      w, h,
		      (Tmp_win->icon_p_width - w) / 2,
		      (Tmp_win->icon_p_height - h) / 2 + titleH);
	} else
	    XCopyPlane(dpy, Tmp_win->iconPixmap, Tmp_win->icon_pixmap_w, Scr.FontGC,
		       x, y,
		       w, h,
		       (Tmp_win->icon_p_width - w) / 2,
		       (Tmp_win->icon_p_height - h) / 2 + titleH, 1);
#endif

#ifdef NO_ICON_BACKGROUND
	XShapeCombineMask(dpy, Tmp_win->icon_pixmap_w, ShapeBounding, 0, 0,
			  Tmp_win->iconPixmap, ShapeSet);
#else
	if (Scr.flags & IconTitle) {
	    int textX;
	    int cnt = 0;
	    char *text = NULL;

	    XSetForeground(dpy, Scr.IconGC, Scr.HiColors.back);

	    XFillRectangle(dpy, Tmp_win->icon_pixmap_w, Scr.IconGC, 1, 1,
			   Tmp_win->icon_p_width - 2, titleH + 6);

	    XSetForeground(dpy, Scr.IconGC, Scr.HiColors.fore);
	    if (Tmp_win->icon_name == NULL) {
		if (Tmp_win->name != NULL) {
		    cnt = strlen(Tmp_win->name);
		    textX = XTextWidth(Scr.IconFont.font, Tmp_win->name, cnt);
		    if (textX < Tmp_win->icon_p_width) {
			textX = (Tmp_win->icon_p_width - textX) / 2;
			text = Tmp_win->name;
		    } else {
			int i;
			/* try to find approx. characters that fit here */
			i = (Tmp_win->icon_p_width * cnt) / textX;
			textX = 1;
			text = &(Tmp_win->name[cnt - i]);
			cnt = i;
		    }
		}
	    } else {
		cnt = strlen(Tmp_win->icon_name);
		textX = XTextWidth(Scr.IconFont.font, Tmp_win->icon_name, cnt);
		if (textX < Tmp_win->icon_p_width) {
		    textX = (Tmp_win->icon_p_width - textX) / 2;
		    text = Tmp_win->icon_name;
		} else {
		    int i;
		    /* try to find approx. characters that fit here */
		    i = (Tmp_win->icon_p_width * cnt) / textX;
		    textX = 1;
		    text = &(Tmp_win->icon_name[cnt - i]);
		    cnt = i;
		}
	    }


	    XDrawString(dpy, Tmp_win->icon_pixmap_w, Scr.IconGC, textX,
			Scr.IconFont.font->ascent + 1, text, cnt);

	}
    }
#endif

}


/***********************************************************************
 *
 *  Procedure:
 *	AutoPlace - Find a home for an icon
 *
 ************************************************************************/
void AutoPlace(ASWindow * t)
{
    int test_x = 0, test_y = 0, tw, th, tx, ty, i, temp_h, temp_w;
    int base_x, base_y;
    int width, height;
    ASWindow *test_window;
    Bool loc_ok;
    int real_x = 10, real_y = 10;

    /* New! Put icon in same page as the center of the window */
    /* Not a good idea for StickyIcons */
    if ((Scr.flags & StickyIcons) || (t->flags & STICKY)) {
	base_x = 0;
	base_y = 0;
    } else {
	base_x = ((t->frame_x + Scr.Vx + (t->frame_width >> 1)) /
		  Scr.MyDisplayWidth) * Scr.MyDisplayWidth - Scr.Vx;
	base_y = ((t->frame_y + Scr.Vy + (t->frame_height >> 1)) /
		  Scr.MyDisplayHeight) * Scr.MyDisplayHeight - Scr.Vy;
    }
    if (t->flags & ICON_MOVED) {
	/* just make sure the icon is on this screen */
	t->icon_x_loc = t->icon_x_loc % Scr.MyDisplayWidth + base_x;
	t->icon_y_loc = t->icon_y_loc % Scr.MyDisplayHeight + base_y;
	if (t->icon_x_loc < 0)
	    t->icon_x_loc += Scr.MyDisplayWidth;
	if (t->icon_y_loc < 0)
	    t->icon_y_loc += Scr.MyDisplayHeight;
    } else if (t->wmhints && t->wmhints->flags & IconPositionHint) {
	t->icon_x_loc = t->wmhints->icon_x;
	t->icon_y_loc = t->wmhints->icon_y;
    } else {
	width = t->icon_p_width;
	height = t->icon_p_height;
	loc_ok = False;

	/* check all boxes in order */
	i = 0;
	while ((i < Scr.NumBoxes) && (!loc_ok)) {
	    /* In each IconBox, start at the upper left, travel right, then
	     * down */
	    test_y = Scr.IconBoxes[i][1] + base_y;

	    temp_h = height;
	    temp_w = width;

	    /* OK second try at this.
	     * If the window is taller than the icon box, ignore the icon height
	     * when figuring where to put it. Same goes for the width */
	    /* This should permit reasonably graceful handling of big icons. */
	    if (width >= (Scr.IconBoxes[i][2] - Scr.IconBoxes[i][0]))
		temp_w = 0;
	    if (height >= (Scr.IconBoxes[i][3] - Scr.IconBoxes[i][1]))
		temp_h = 0;

	    while (((test_y + temp_h) < (Scr.IconBoxes[i][3] + base_y)) && (!loc_ok)) {

		test_x = Scr.IconBoxes[i][0] + base_x;
		while (((test_x + temp_w) < (Scr.IconBoxes[i][2] + base_x)) &&
		       (!loc_ok)) {
		    real_x = test_x;
		    real_y = test_y;

		    if (test_x + width > (Scr.MyDisplayWidth /*-2*/  + base_x))
			real_x = Scr.MyDisplayWidth - width /*-2*/  + base_x;
		    if (test_y + height > (Scr.MyDisplayHeight /*-2*/  + base_y))
			real_y = Scr.MyDisplayHeight - height /*-2*/  + base_y;
		    if (test_x < base_x)
			real_x = base_x;
		    if (test_y < base_y)
			real_y = base_y;
		    loc_ok = True;
		    test_window = Scr.ASRoot.next;
		    while ((test_window != (ASWindow *) 0) && (loc_ok == True)) {
			if (test_window->Desk == t->Desk) {
			    if ((test_window->flags & ICONIFIED) &&
				test_window->icon_pixmap_w &&
				(test_window != t)) {
				tw = test_window->icon_p_width;
				th = test_window->icon_p_height;
				tx = test_window->icon_x_loc;
				ty = test_window->icon_y_loc;

				if ((tx < (real_x + width + 1)) && ((tx + tw + 1) > real_x) &&
				    (ty < (real_y + height + 1)) && ((ty + th + 1) > real_y)) {
				    loc_ok = False;
				}
			    }
			    if (Scr.flags & StubbornIconPlacement) {
				if (!(test_window->flags & ICONIFIED) &&
				    (test_window != t)) {
				    tw = test_window->frame_width;
				    th = test_window->frame_height;
				    tx = test_window->frame_x;
				    ty = test_window->frame_y;

				    if ((tx < (real_x + width + 1)) &&
					((tx + tw + 1) > real_x) &&
					(ty < (real_y + height + 1)) &&
					((ty + th + 1) > real_y)) {
					loc_ok = False;
				    }
				}
			    }
			}
			test_window = test_window->next;
		    }
		    test_x += 1;
		}
		test_y += 1;
	    }
	    i++;
	}
	if (loc_ok == False)
	    return;
	t->icon_x_loc = real_x;
	t->icon_y_loc = real_y;
    }

    if (t->icon_pixmap_w)
	XMoveWindow(dpy, t->icon_pixmap_w, t->icon_x_loc, t->icon_y_loc);

#ifdef NO_ICON_BACKGROUND
    t->icon_w_width = t->icon_p_width;
    t->icon_xl_loc = t->icon_x_loc;

    if (t->icon_w != None)
	XMoveResizeWindow(dpy, t->icon_w, t->icon_xl_loc,
			  t->icon_y_loc + t->icon_p_height,
			  t->icon_w_width, ICON_HEIGHT);
#endif

    Broadcast(M_ICON_LOCATION, 7, t->w, t->frame,
	      (unsigned long) t,
	      t->icon_x_loc, t->icon_y_loc,
	      t->icon_p_width, t->icon_p_height);
}

/***********************************************************************
 *
 *  Procedure:
 *	GrabIconButtons - grab needed buttons for the icon window
 *
 *  Inputs:
 *	tmp_win - the afterstep window structure to use
 *
 ***********************************************************************/
void GrabIconButtons(ASWindow * tmp_win, Window w)
{
    MouseButton *MouseEntry;

    MouseEntry = Scr.MouseButtonRoot;
    while (MouseEntry != (MouseButton *) 0) {
	if ((MouseEntry->func != (int) 0) && (MouseEntry->Context & C_ICON)) {
	    if (MouseEntry->Button > 0)
		MyXGrabButton(dpy, MouseEntry->Button, MouseEntry->Modifier, w,
			      True, ButtonPressMask | ButtonReleaseMask,
			      GrabModeAsync, GrabModeAsync, None,
			      Scr.ASCursors[DEFAULT]);
	    else {
		int i;
		for (i = 0; i < MAX_BUTTONS; i++) {
		    MyXGrabButton(dpy, i + 1, MouseEntry->Modifier, w,
			       True, ButtonPressMask | ButtonReleaseMask,
				  GrabModeAsync, GrabModeAsync, None,
				  Scr.ASCursors[DEFAULT]);
		}
	    }
	}
	MouseEntry = MouseEntry->NextButton;
    }
    return;
}



/***********************************************************************
 *
 *  Procedure:
 *	GrabIconKeys - grab needed keys for the icon window
 *
 *  Inputs:
 *	tmp_win - the afterstep window structure to use
 *
 ***********************************************************************/
void GrabIconKeys(ASWindow * tmp_win, Window w)
{
    FuncKey *tmp;
    for (tmp = Scr.FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) {
	if (tmp->cont & C_ICON) {
	    MyXGrabKey(dpy, tmp->keycode, tmp->mods, w, True,
		       GrabModeAsync, GrabModeAsync);
	}
    }
    return;
}


/***********************************************************************
 *
 *  Procedure:
 *	DeIconify a window
 *
 ***********************************************************************/
void DeIconify(ASWindow * tmp_win)
{
    ASWindow *t, *tn, *tmp;
    int new_x, new_y, w2, h2;

    /* now de-iconify transients */
    for (t = Scr.ASRoot.next; t != NULL; t = tn) {
	tn = t->next;
	if ((t == tmp_win) ||
	    ((t->flags & TRANSIENT) && (t->transientfor == tmp_win->w))) {
	    t->flags |= MAPPED;
	    if (Scr.Hilite == t)
		SetBorder(t, False, True, True, None);
	    /* make sure that the window is on this screen */
	    if ((t->frame_x < 0) || (t->frame_y < 0) ||
		(t->frame_x >= Scr.MyDisplayWidth) ||
		(t->frame_y >= Scr.MyDisplayHeight)) {
		/* try to put at least half the window
		 * in the current screen, if the current desktop
		 * is the windows desktop */
		if (Scr.flags & StubbornIcons)
		    t->Desk = t->DeIconifyDesk;
		else
		    t->Desk = Scr.CurrentDesk;

		if (t->Desk == Scr.CurrentDesk) {
		    new_x = t->frame_x;
		    new_y = t->frame_y;
		    w2 = (t->frame_width >> 1);
		    h2 = (t->frame_height >> 1);
		    if (!(Scr.flags & StubbornIcons)) {
			if ((new_x < -w2) || (new_x > (Scr.MyDisplayWidth - w2))) {
			    new_x = new_x % Scr.MyDisplayWidth;
			    if (new_x < -w2)
				new_x += Scr.MyDisplayWidth;
			}
			if ((new_y < -h2) || (new_y > (Scr.MyDisplayHeight - h2))) {
			    new_y = new_y % Scr.MyDisplayHeight;
			    if (new_y < -h2)
				new_y += Scr.MyDisplayHeight;
			}
		    }
		    SetupFrame(t, new_x, new_y,
			       t->frame_width, t->frame_height, False);
		}
	    }
#ifdef NO_ICON_BACKGROUND
	    if (t->icon_w)
		XUnmapWindow(dpy, t->icon_w);
#endif
	    if (t->icon_pixmap_w)
		XUnmapWindow(dpy, t->icon_pixmap_w);
	    Broadcast(M_DEICONIFY, 5, t->w, t->frame, (unsigned long) t,
		      t->icon_x_loc, t->icon_y_loc,
		      t->icon_p_width, t->icon_p_height);
	    XFlush(dpy);

	    XMapWindow(dpy, t->w);
	    if (t->Desk == Scr.CurrentDesk) {
		XMapWindow(dpy, t->frame);
		t->flags |= MAP_PENDING;
	    }
	    XMapWindow(dpy, t->Parent);
	    SetMapStateProp(t, NormalState);
	    t->flags &= ~ICONIFIED;
	    t->flags &= ~ICON_UNMAPPED;
	    /* Need to make sure the border is colored correctly,
	     * in case it was stuck or unstuck while iconified. */
	    tmp = Scr.Hilite;
	    Scr.Hilite = t;
	    SetBorder(t, False, True, True, None);
	    Scr.Hilite = tmp;
	    XRaiseWindow(dpy, t->w);
	}
    }
    RaiseWindow(tmp_win);

    if ((Scr.flags & StubbornIcons) || (Scr.flags & ClickToFocus))
	FocusOn(tmp_win, 1, False, 0);

    for (t = Scr.ASRoot.next; t != NULL; t = t->next) {
	/* If its an icon, and its sticking, autoplace it so
	   * that it doesn't wind up on top a a stationary
	   * icon */
	if (((Scr.flags & StickyIcons)) && (t->flags & ICONIFIED)
	  && (!(t->flags & ICON_MOVED)) && (!(t->flags & ICON_UNMAPPED)))
	    AutoPlace(t);
    }

/* ßß MoveResizePagerView */

    return;
}


/****************************************************************************
 *
 * Iconifies the selected window
 *
 ****************************************************************************/
void Iconify(ASWindow * tmp_win, int def_x, int def_y)
{
    ASWindow *t;
    XWindowAttributes winattrs;
    unsigned long eventMask;

    XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
    eventMask = winattrs.your_event_mask;

    if ((tmp_win) && (tmp_win == Scr.Hilite) &&
	(Scr.flags & ClickToFocus) && (tmp_win->next)) {
	SetFocus(tmp_win->next->w, tmp_win->next, False);
    }
    /* iconify transients first */
    for (t = Scr.ASRoot.next; t != NULL; t = t->next) {
	if ((t == tmp_win) ||
	    ((t->flags & TRANSIENT) && (t->transientfor == tmp_win->w))) {
	    /*
	     * Prevent the receipt of an UnmapNotify, since that would
	     * cause a transition to the Withdrawn state.
	     */
	    t->flags &= ~MAPPED;
	    XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
	    XUnmapWindow(dpy, t->w);
	    XSelectInput(dpy, t->w, eventMask);
	    XUnmapWindow(dpy, t->frame);
	    t->DeIconifyDesk = t->Desk;
#ifdef NO_ICON_BACKGROUND
	    if (t->icon_w)
		XUnmapWindow(dpy, t->icon_w);
#endif
	    if (t->icon_pixmap_w)
		XUnmapWindow(dpy, t->icon_pixmap_w);

	    SetMapStateProp(t, IconicState);
	    SetBorder(t, False, False, False, None);
	    if (t != tmp_win) {
		t->flags |= ICONIFIED | ICON_UNMAPPED;

		Broadcast(M_ICONIFY, 7, t->w, t->frame,
			  (unsigned long) t,
			  -10000, -10000,
			  t->icon_p_width,
			  t->icon_p_height);
		BroadcastConfig(M_CONFIGURE_WINDOW, t);
	    }
/*	    if (t != tmp_win) ßß MoveResizePagerView */
	}
    }

#ifdef NO_ICON_BACKGROUND
    if (tmp_win->icon_w == None)
#endif
	if (tmp_win->flags & ICON_MOVED)
	    CreateIconWindow(tmp_win, tmp_win->icon_x_loc, tmp_win->icon_y_loc);
	else
	    CreateIconWindow(tmp_win, def_x, def_y);

    AutoPlace(tmp_win);
    tmp_win->flags |= ICONIFIED;
    tmp_win->flags &= ~ICON_UNMAPPED;

    XFlush(dpy);

    Broadcast(M_ICONIFY, 7, tmp_win->w, tmp_win->frame,
	      (unsigned long) tmp_win,
	      tmp_win->icon_x_loc, tmp_win->icon_y_loc,
	      tmp_win->icon_p_width,
	      tmp_win->icon_p_height);
    BroadcastConfig(M_CONFIGURE_WINDOW, tmp_win);

    LowerWindow(tmp_win);
    if (tmp_win->Desk == Scr.CurrentDesk) {
#ifdef NO_ICON_BACKGROUND
	if (tmp_win->icon_w != None)
	    XMapWindow(dpy, tmp_win->icon_w);
#endif
	if (tmp_win->icon_pixmap_w != None)
	    XMapWindow(dpy, tmp_win->icon_pixmap_w);
/* ßß MoveResizePagerView */
    }
    if ((Scr.flags & ClickToFocus) || (Scr.flags & SloppyFocus)) {
	if ((tmp_win) && (tmp_win == Scr.Focus)) {
	    if (Scr.PreviousFocus == Scr.Focus)
		Scr.PreviousFocus = NULL;
	    if ((Scr.flags & ClickToFocus) && (tmp_win->next))
		SetFocus(tmp_win->next->w, tmp_win->next, False);
	    else {
		SetFocus(Scr.NoFocusWin, NULL, False);
	    }
	}
    }
    return;
}

void GetIcon(ASWindow * tmp_win)
{
    tmp_win->icon_pm_height = 0;
    tmp_win->icon_pm_width = 0;

    /* First, check for a monochrome bitmap */
    if (tmp_win->icon_bitmap_file != NULL)
	GetBitmapFile(tmp_win);

    /* Next, check for a color pixmap */
    if ((tmp_win->icon_bitmap_file != NULL) &&
	(tmp_win->icon_pm_height == 0) && (tmp_win->icon_pm_width == 0))
	GetXPMFile(tmp_win);

    /* Next, See if the app supplies its own icon window */
    if ((tmp_win->icon_pm_height == 0) && (tmp_win->icon_pm_width == 0) &&
	(tmp_win->wmhints) && (tmp_win->wmhints->flags & IconWindowHint))
	GetIconWindow(tmp_win);

    /* Finally, try to get icon bitmap from the application */
    if ((tmp_win->icon_pm_height == 0) && (tmp_win->icon_pm_width == 0) &&
	(tmp_win->wmhints) && (tmp_win->wmhints->flags & IconPixmapHint))
	GetIconBitmap(tmp_win);

#ifndef NO_ICON_BACKGROUND
    if (tmp_win->icon_pm_width == 0)
	tmp_win->icon_pm_width = Scr.IconBgWidth - 16;
#endif

    if ((tmp_win->flags & ICON_OURS) || !(Scr.flags & KeepIconWindows)) {
	tmp_win->icon_p_width = Scr.IconBgWidth;
	tmp_win->icon_p_height = Scr.IconBgHeight;
    } else {


	tmp_win->icon_p_width = tmp_win->icon_pm_width;
	tmp_win->icon_p_height = tmp_win->icon_pm_height;
    }

}

#ifdef NO_ICON_BACKGROUND
void RedoIconName(ASWindow * Tmp_win)
{
    if (Tmp_win->flags & SUPPRESSICON)
	return;

    if (Tmp_win->icon_w == (int) NULL)
	return;

/* resize text subwindow while icon is selected */

    Tmp_win->icon_t_width = XTextWidth(IconFont->font, Tmp_win->icon_name,
				       strlen(Tmp_win->icon_name));

    /* clear the icon window, and trigger a re-draw via an expose event */
    if (Tmp_win->flags & ICONIFIED)
	XClearArea(dpy, Tmp_win->icon_w, 0, 0, 0, 0, True);
    return;
}
#endif

/****************************************************************************
 *
 * Looks for a monochrome icon bitmap file
 *
 ****************************************************************************/
void GetBitmapFile(ASWindow * tmp_win)
{
    char *path = NULL;
    int HotX, HotY;
    extern char *IconPath;

    path = findIconFile(tmp_win->icon_bitmap_file, IconPath, R_OK);

    if (path == NULL)
	return;
    if (XReadBitmapFile(dpy, Scr.Root, path,
			(unsigned int *) &tmp_win->icon_pm_width,
			(unsigned int *) &tmp_win->icon_pm_height,
			&tmp_win->iconPixmap,
			&HotX, &HotY) != BitmapSuccess) {
	tmp_win->icon_pm_width = 0;
	tmp_win->icon_pm_height = 0;
    }
#ifdef NO_ICON_BACKGROUND
    Scr.IconBgWidth = tmp_win->icon_pm_width;
    Scr.IconBgHeight = tmp_win->icon_pm_height;
#endif
    free(path);
}

/****************************************************************************
 *
 * Looks for a color XPM icon file
 *
 ****************************************************************************/
void GetXPMFile(ASWindow * tmp_win)
{
#ifdef XPM
    XWindowAttributes root_attr;
    XpmAttributes xpm_attributes;
    extern char *PixmapPath;
    char *path = NULL;

    path = findIconFile(tmp_win->icon_bitmap_file, PixmapPath, R_OK);
    if (path == NULL)
	return;

    XGetWindowAttributes(dpy, Scr.Root, &root_attr);
    xpm_attributes.colormap = root_attr.colormap;
    xpm_attributes.closeness = 40000;	/* Allow for "similar" colors */
    xpm_attributes.valuemask = XpmSize | XpmReturnPixels | XpmColormap | XpmCloseness;

    if (XpmReadFileToPixmap(dpy, Scr.Root, path,
			 &tmp_win->iconPixmap, &tmp_win->icon_maskPixmap,
			    &xpm_attributes) == XpmSuccess) {

	tmp_win->icon_pm_width = xpm_attributes.width;
	tmp_win->icon_pm_height = xpm_attributes.height;
	tmp_win->flags |= XPM_FLAG;
	tmp_win->flags |= PIXMAP_OURS;
	tmp_win->iconDepth = Scr.d_depth;

#ifdef NO_ICON_BACKGROUND
	Scr.IconBgWidth = xpm_attributes.width;
	Scr.IconBgHeight = xpm_attributes.height;
#endif

#ifndef NO_SHAPE
	if (tmp_win->icon_maskPixmap)
	    tmp_win->flags |= SHAPED_ICON;
#endif
    }
    free(path);
#endif				/* XPM */
}

/****************************************************************************
 *
 * Looks for an application supplied icon window
 *
 ****************************************************************************/
void GetIconWindow(ASWindow * tmp_win)
{
    /* We are guaranteed that wmhints is non-null when calling this
     * routine */
    if (XGetGeometry(dpy, tmp_win->wmhints->icon_window, &JunkRoot,
		&JunkX, &JunkY, (unsigned int *) &tmp_win->icon_pm_width,
		     (unsigned int *) &tmp_win->icon_pm_height,
		     &JunkBW, &JunkDepth) == 0) {
	fprintf(stderr, "Help! Bad Icon Window!\n");
    }
    tmp_win->icon_pm_width += JunkBW << 1;
    tmp_win->icon_pm_height += JunkBW << 1;
    /*
     * 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).
     */
    if (tmp_win->wmhints->flags & IconMaskHint) {
#ifndef NO_SHAPE
	tmp_win->flags |= SHAPED_ICON;
#endif
	tmp_win->icon_maskPixmap = tmp_win->wmhints->icon_mask;
    }

    /* Make sure that the window is a child of the root window ! */
    /* Olwais screws this up, maybe others do too! */
    tmp_win->icon_pixmap_w = tmp_win->wmhints->icon_window;

#ifndef NO_ICON_BACKGROUND
    XResizeWindow(dpy, tmp_win->icon_pixmap_w, 64, 64);
#else
    Scr.IconBgWidth = tmp_win->icon_pm_width;
    Scr.IconBgHeight = tmp_win->icon_pm_height;
#endif
    XReparentWindow(dpy, tmp_win->icon_pixmap_w, Scr.Root, 0, 0);
    tmp_win->flags &= ~ICON_OURS;
}


/****************************************************************************
 *
 * Looks for an application supplied bitmap or pixmap
 *
 ****************************************************************************/
void GetIconBitmap(ASWindow * tmp_win)
{
    /* We are guaranteed that wmhints is non-null when calling this
     * routine */
    XGetGeometry(dpy, tmp_win->wmhints->icon_pixmap, &JunkRoot, &JunkX, &JunkY,
		 (unsigned int *) &tmp_win->icon_pm_width,
	 (unsigned int *) &tmp_win->icon_pm_height, &JunkBW, &JunkDepth);
    tmp_win->iconPixmap = tmp_win->wmhints->icon_pixmap;
    tmp_win->iconDepth = JunkDepth;

    if (tmp_win->wmhints->flags & IconMaskHint) {
#ifndef NO_SHAPE
	tmp_win->flags |= SHAPED_ICON;
#endif
	tmp_win->icon_maskPixmap = tmp_win->wmhints->icon_mask;
    }

#ifdef NO_ICON_BACKGROUND
    Scr.IconBgWidth = tmp_win->icon_pm_width;
    Scr.IconBgHeight = tmp_win->icon_pm_height;
#endif
}
