/*
 * Copyright 1989 Massachusetts Institute of Technology
 *
 * 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 permission notice appear in supporting
 * documentation, and that the name of M.I.T. not be used in advertising
 * or publicity pertaining to distribution of the software without specific,
 * written prior permission.  M.I.T. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
 * 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.
 */
/* 
 *  [ 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: iconmgr.c,v 1.48 91/09/10 15:27:07 dave Exp $
 *
 * Icon Manager routines
 *
 * 09-Mar-89 Tom 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 "twm.h"
#ifdef VMS
#include <decw$include/Xatom.h>
#else
#include <X11/Xatom.h>
#endif
#include "util.h"
#include "parse.h"
#include "screen.h"
#include "resize.h"
#include "add_window.h"
#define __WANT_SICONIFY_BITS
#include "siconify.bm"
#ifdef VMS
#include <decw$include/Xos.h>
#include <X11Xmu/CharSet.h>
#else
#include <X11/Xos.h>
#include <X11/Xmu/CharSet.h>
#endif
#ifdef macII
int strcmp(); /* missing from string.h in AUX 2.0 */
#endif

int iconmgr_textx = siconify_width+11;
WList *Active = NULL;
WList *Current = NULL;
WList *DownIconManager = NULL;
int iconifybox_width = siconify_width;
int iconifybox_height = siconify_height;

/***********************************************************************
 *
 *  Procedure:
 *	CreateIconManagers - creat all the icon manager windows
 *		for this screen.
 *
 *  Returned Value:
 *	none
 *
 *  Inputs:
 *	none
 *
 ***********************************************************************
 */

void CreateIconManagers(void)
{
    IconMgr *p, *q;
    int mask;
    char str[100];
    char str1[100];
    Pixel background;
    char *icon_name;
    WorkSpace    *ws;
    XWMHints	  wmhints;
    XSizeHints	  sizehints;
    int		  gravity;
    int bw;

    if (Scr->NoIconManagers)
	return;

    if (Scr->use3Diconmanagers) iconmgr_textx += Scr->IconManagerShadowDepth;
    if (Scr->siconifyPm == None)
    {
	Scr->siconifyPm = XCreatePixmapFromBitmapData(dpy, Scr->Root,
	    (char *)siconify_bits, siconify_width, siconify_height, 1, 0, 1);
    }

    ws = Scr->workSpaceMgr.workSpaceList;
    for (q = Scr->iconmgr; q != NULL; q = q->nextv) {
      for (p = q; p != NULL; p = p->next)
      {
	sprintf(str, "%s Icon Manager", p->name);
	sprintf(str1, "%s Icons", p->name);
	if (p->icon_name)
	    icon_name = p->icon_name;
	else
	    icon_name = str1;

	if (!p->geometry || !strlen(p->geometry)) p->geometry = "+0+0";
	mask = XParseGeometry(p->geometry, &JunkX, &JunkY,
			      (unsigned int *) &p->width, (unsigned int *)&p->height);

	bw = LookInList (Scr->NoBorder, str, NULL) ? 0 :
		(Scr->ThreeDBorderWidth ? Scr->ThreeDBorderWidth : Scr->BorderWidth);

	if (mask & XNegative) {
	    JunkX += Scr->rootw - p->width - 2 * bw;
	    gravity = (mask & YNegative) ? SouthEastGravity : NorthEastGravity;
	} else {
	    gravity = (mask & YNegative) ? SouthWestGravity : NorthWestGravity;
	}
	if (mask & YNegative)
	    JunkY += Scr->rooth - p->height - 2 * bw;

	background = Scr->IconManagerC.back;
	GetColorFromList(Scr->IconManagerBL, p->name, (XClassHint *)NULL,
			 &background);

	if (p->width  < 1) p->width  = 1;
	if (p->height < 1) p->height = 1;
	p->w = XCreateSimpleWindow(dpy, Scr->Root,
	    JunkX, JunkY, p->width, p->height, 1,
	    Scr->Black, background);

	XSetStandardProperties(dpy, p->w, str, icon_name, None, NULL, 0, NULL);

	/* Scr->workSpaceMgr.activeWSPC = ws; */
	wmhints.initial_state = NormalState;
	wmhints.input         = True;
	wmhints.flags         = InputHint | StateHint;
	XSetWMHints (dpy, p->w, &wmhints);
	p->twm_win = AddWindow(p->w, TRUE, p);
	if (ws)
	  p->twm_win->occupation = 1 << ws->number;
	else
	  p->twm_win->occupation = 1;

	sizehints.flags       = PWinGravity;
	sizehints.win_gravity = gravity;
	XSetWMSizeHints (dpy, p->w, &sizehints, XA_WM_NORMAL_HINTS);

	p->twm_win->mapped = FALSE;
	SetMapStateProp (p->twm_win, WithdrawnState);
	if (p->twm_win && p->twm_win->wmhints &&
	    (p->twm_win->wmhints->initial_state == IconicState)) {
	    p->twm_win->isicon = TRUE;
	}
	else
	if (!Scr->NoIconManagers && Scr->ShowIconManager) {
	    p->twm_win->isicon = FALSE;
	}
	else {
	    p->twm_win->isicon = TRUE;
	}
      }
      if (ws != NULL) ws = ws->next;
    }
    for (p = Scr->iconmgr; p != NULL; p = p->next) {
      p->twm_win->vs = Scr->vScreenList;
    }
    if (Scr->workSpaceManagerActive)
	Scr->workSpaceMgr.workSpaceList->iconmgr = Scr->iconmgr;

    for (q = Scr->iconmgr; q != NULL; q = q->nextv) {
      for (p = q; p != NULL; p = p->next) {
	GrabButtons(p->twm_win);
	GrabKeys(p->twm_win);
      }
    }

}

/***********************************************************************
 *
 *  Procedure:
 *	AllocateIconManager - allocate a new icon manager
 *
 *  Inputs:
 *	name	- the name of this icon manager
 *	icon_name - the name of the associated icon
 *	geom	- a geometry string to eventually parse
 *	columns	- the number of columns this icon manager has
 *
 ***********************************************************************
 */

IconMgr *AllocateIconManager(char *name, char *icon_name, char *geom,
			     int columns)
{
    IconMgr *p;

#ifdef DEBUG_ICONMGR
    fprintf(stderr, "AllocateIconManager\n");
    fprintf(stderr, "  name=\"%s\" icon_name=\"%s\", geom=\"%s\", col=%d\n",
	name, icon_name, geom, columns);
#endif

    if (Scr->NoIconManagers)
	return NULL;

    if (columns < 1) columns = 1;
    p = (IconMgr *)malloc(sizeof(IconMgr));
    p->name = name;
    p->icon_name = icon_name;
    p->geometry = geom;
    p->columns = columns;
    p->first = NULL;
    p->last = NULL;
    p->active = NULL;
    p->scr = Scr;
    p->count = 0;
    p->x = 0;
    p->y = 0;
    p->width = 150;
    p->height = 10;
    p->next = NULL;
    p->prev = NULL;
    p->nextv = NULL;

    if (Scr->iconmgr == NULL) {
	Scr->iconmgr = p;
	Scr->iconmgr->lasti = p;
    }
    else {
	Scr->iconmgr->lasti->next = p;
	p->prev = Scr->iconmgr->lasti;
	Scr->iconmgr->lasti = p;
    }
    return(p);
}

/***********************************************************************
 *
 *  Procedure:
 *	MoveIconManager - move the pointer around in an icon manager
 *
 *  Inputs:
 *	dir	- one of the following:
 *			F_FORWICONMGR	- forward in the window list
 *			F_BACKICONMGR	- backward in the window list
 *			F_UPICONMGR	- up one row
 *			F_DOWNICONMGR	- down one row
 *			F_LEFTICONMGR	- left one column
 *			F_RIGHTICONMGR	- right one column
 *
 *  Special Considerations:
 *	none
 *
 ***********************************************************************
 */

void MoveIconManager(int dir)
{
    IconMgr *ip;
    WList *tmp = NULL;
    int cur_row, cur_col, new_row, new_col;
    int row_inc, col_inc;
    int got_it;

    if (!Current) return;

    cur_row = Current->row;
    cur_col = Current->col;
    ip = Current->iconmgr;

    row_inc = 0;
    col_inc = 0;
    got_it = FALSE;

    switch (dir)
    {
	case F_FORWICONMGR:
	    if ((tmp = Current->next) == NULL)
		tmp = ip->first;
	    got_it = TRUE;
	    break;

	case F_BACKICONMGR:
	    if ((tmp = Current->prev) == NULL)
		tmp = ip->last;
	    got_it = TRUE;
	    break;

	case F_UPICONMGR:
	    row_inc = -1;
	    break;

	case F_DOWNICONMGR:
	    row_inc = 1;
	    break;

	case F_LEFTICONMGR:
	    col_inc = -1;
	    break;

	case F_RIGHTICONMGR:
	    col_inc = 1;
	    break;
    }

    /* If got_it is FALSE ast this point then we got a left, right,
     * up, or down, command.  We will enter this loop until we find
     * a window to warp to.
     */
    new_row = cur_row;
    new_col = cur_col;

    while (!got_it)
    {
	new_row += row_inc;
	new_col += col_inc;
	if (new_row < 0)
	    new_row = ip->cur_rows - 1;
	if (new_col < 0)
	    new_col = ip->cur_columns - 1;
	if (new_row >= ip->cur_rows)
	    new_row = 0;
	if (new_col >= ip->cur_columns)
	    new_col = 0;
	    
	/* Now let's go through the list to see if there is an entry with this
	 * new position
	 */
	for (tmp = ip->first; tmp != NULL; tmp = tmp->next)
	{
	    if (tmp->row == new_row && tmp->col == new_col)
	    {
		got_it = TRUE;
		break;
	    }
	}
    }

    if (!got_it)
    {
	fprintf (stderr, 
		 "%s:  unable to find window (%d, %d) in icon manager\n", 
		 ProgramName, new_row, new_col);
	return;
    }

    if (tmp == NULL)
      return;

    /* raise the frame so the icon manager is visible */
    if (ip->twm_win->mapped) {
	RaiseWindow(ip->twm_win);
	XWarpPointer(dpy, None, tmp->icon, 0,0,0,0, 5, 5);
    } else {
	if (tmp->twm->title_height) {
	    int tbx = Scr->TBInfo.titlex;
	    int x = tmp->twm->highlightxr;
	    XWarpPointer (dpy, None, tmp->twm->title_w, 0, 0, 0, 0,
			  tbx + (x - tbx) / 2,
			  Scr->TitleHeight / 4);
	} else {
	    XWarpPointer (dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5);
	}
    }
}

/***********************************************************************
 *
 *  Procedure:
 *	MoveMappedIconManager - move the pointer around in an icon manager
 *
 *  Inputs:
 *	dir	- one of the following:
 *			F_FORWMAPICONMGR	- forward in the window list
 *			F_BACKMAPICONMGR	- backward in the window list
 *
 *  Special Considerations:
 *	none
 *
 ***********************************************************************
 */

void MoveMappedIconManager(int dir)
{
    IconMgr *ip;
    WList *tmp = NULL;
    WList *orig = NULL;
    int got_it;

    if (!Current) Current = Active; 
    if (!Current) return;

    ip = Current->iconmgr;

    got_it = 0;
    tmp = Current;
    orig = Current;

    while(!got_it) {
	switch(dir)
	{
	    case F_FORWMAPICONMGR:
		if ((tmp = tmp->next) == NULL)
		    tmp = ip->first;
		break;

	    case F_BACKMAPICONMGR:
		if ((tmp = tmp->prev) == NULL)
		    tmp = ip->last;
		break;
	}
	if (tmp->twm->mapped) {
	    got_it = 1;
	    break;
	}
	if (tmp == orig)
	    break;
    }

    if (!got_it)
    {
	fprintf (stderr, "%s:  unable to find open window in icon manager\n", 
		 ProgramName);
	return;
    }

    if (tmp == NULL)
      return;

    /* raise the frame so the icon manager is visible */
    if (ip->twm_win->mapped) {
	RaiseWindow(ip->twm_win);
	XWarpPointer(dpy, None, tmp->icon, 0,0,0,0, 5, 5);
    } else {
	if (tmp->twm->title_height) {
	    XWarpPointer (dpy, None, tmp->twm->title_w, 0, 0, 0, 0,
			  tmp->twm->title_width / 2, 
			  Scr->TitleHeight / 4);
	} else {
	    XWarpPointer (dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5);
	}
    }
}

/***********************************************************************
 *
 *  Procedure:
 *	JumpIconManager - jump from one icon manager to another,
 *		possibly even on another screen
 *
 *  Inputs:
 *	dir	- one of the following:
 *			F_NEXTICONMGR	- go to the next icon manager 
 *			F_PREVICONMGR	- go to the previous one
 *
 ***********************************************************************
 */

void JumpIconManager(register int dir)
{
    IconMgr *ip, *tmp_ip = NULL;
    int got_it = FALSE;
    ScreenInfo *sp;
    int screen;

    if (!Current) return;


#define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev)
#define IPOFSP(sp) (dir == F_NEXTICONMGR ? sp->iconmgr : sp->iconmgr->lasti)
#define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \
		 { got_it = TRUE; break; }

    ip = Current->iconmgr;
    for (tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) {
	TEST (tmp_ip);
    }

    if (!got_it) {
	int origscreen = ip->scr->screen;
	int inc = (dir == F_NEXTICONMGR ? 1 : -1);

	for (screen = origscreen + inc; ; screen += inc) {
	    if (screen >= NumScreens)
	      screen = 0;
	    else if (screen < 0)
	      screen = NumScreens - 1;

	    sp = ScreenList[screen];
	    if (sp) {
		for (tmp_ip = IPOFSP (sp); tmp_ip; tmp_ip = ITER(tmp_ip)) {
		    TEST (tmp_ip);
		}
	    }
	    if (got_it || screen == origscreen) break;
	}
    }

#undef ITER
#undef IPOFSP
#undef TEST

    if (!got_it) {
	XBell (dpy, 0);
	return;
    }

    /* raise the frame so it is visible */
    RaiseWindow(tmp_ip->twm_win);
    if (tmp_ip->active)
	XWarpPointer(dpy, None, tmp_ip->active->icon, 0,0,0,0, 5, 5);
    else
	XWarpPointer(dpy, None, tmp_ip->w, 0,0,0,0, 5, 5);
}

/***********************************************************************
 *
 *  Procedure:
 *	AddIconManager - add a window to an icon manager
 *
 *  Inputs:
 *	tmp_win	- the TwmWindow structure
 *
 ***********************************************************************
 */

WList *AddIconManager(TwmWindow *tmp_win)
{
    WList *tmp, *old;
    int h, offs;
    unsigned long valuemask;		/* mask for create windows */
    XSetWindowAttributes attributes;	/* attributes for create windows */
    IconMgr *ip;

    if (tmp_win->iconmgr || tmp_win->transient || Scr->NoIconManagers ||
	tmp_win->wspmgr ||
	tmp_win->w == Scr->workSpaceMgr.occupyWindow->w)
	return NULL;

    if (LookInList(Scr->IconMgrNoShow, tmp_win->full_name, &tmp_win->class))
	return NULL;
    if (Scr->IconManagerDontShow &&
	!LookInList(Scr->IconMgrShow, tmp_win->full_name, &tmp_win->class))
	return NULL;
    if ((ip = (IconMgr *)LookInList(Scr->IconMgrs, tmp_win->full_name,
	    &tmp_win->class)) == NULL) {
	if (Scr->workSpaceManagerActive)
	    ip = Scr->workSpaceMgr.workSpaceList->iconmgr;
	else
	    ip = Scr->iconmgr;
    }

  tmp = NULL;
  old = tmp_win->iconmanagerlist;
  while (ip != NULL) {
    if ((tmp_win->occupation & ip->twm_win->occupation) == 0) {
      ip = ip->nextv;
      continue;
    }
    tmp = (WList *) malloc(sizeof(WList));
    tmp->iconmgr = ip;
    tmp->next = NULL;
    tmp->active = FALSE;
    tmp->down = FALSE;

    InsertInIconManager(ip, tmp, tmp_win);

    tmp->twm = tmp_win;

    tmp->cp.fore = Scr->IconManagerC.fore;
    tmp->cp.back = Scr->IconManagerC.back;
    tmp->highlight = Scr->IconManagerHighlight;

    GetColorFromList(Scr->IconManagerFL, tmp_win->full_name, &tmp_win->class,
	&tmp->cp.fore);
    GetColorFromList(Scr->IconManagerBL, tmp_win->full_name, &tmp_win->class,
	&tmp->cp.back);
    GetColorFromList(Scr->IconManagerHighlightL, tmp_win->full_name,
	&tmp_win->class, &tmp->highlight);

    if (Scr->use3Diconmanagers) {
	if (!Scr->BeNiceToColormap) GetShadeColors (&tmp->cp);
	tmp->iconifypm = Create3DIconManagerIcon (tmp->cp);
	h = Scr->IconManagerFont.height + 2 * Scr->IconManagerShadowDepth + 6;
    }
    else
	h = Scr->IconManagerFont.height + 10;
    if (h < (siconify_height + 4))
	h = siconify_height + 4;

    ip->height = h * ip->count;
    tmp->me = ip->count;
    tmp->x = -1;
    tmp->y = -1;
    
    valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
    attributes.background_pixel = tmp->cp.back;
    attributes.border_pixel = tmp->cp.back;
    attributes.event_mask = (KeyPressMask | ButtonPressMask |
			     ButtonReleaseMask | ExposureMask);
    if (Scr->IconManagerFocus)
	attributes.event_mask |= (EnterWindowMask | LeaveWindowMask);
    attributes.cursor = Scr->IconMgrCursor;
    tmp->w = XCreateWindow (dpy, ip->w, 0, 0, (unsigned int) 1, 
			    (unsigned int) h, (unsigned int) 0, 
			    CopyFromParent, (unsigned int) CopyFromParent,
			    (Visual *) CopyFromParent, valuemask, &attributes);

    valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
    attributes.background_pixel = tmp->cp.back;
    attributes.border_pixel = Scr->Black;
    attributes.event_mask = (ButtonReleaseMask| ButtonPressMask | ExposureMask);
    attributes.cursor = Scr->ButtonCursor;
    offs = Scr->use3Diconmanagers ? Scr->IconManagerShadowDepth : 2;
    tmp->icon = XCreateWindow (dpy, tmp->w, offs + 3,
			       (int) (h - siconify_height)/2,
			       (unsigned int) siconify_width,
			       (unsigned int) siconify_height,
			       (unsigned int) 0, CopyFromParent,
			       (unsigned int) CopyFromParent,
			       (Visual *) CopyFromParent,
			       valuemask, &attributes);

    ip->count += 1;
    PackIconManager(ip);
    if (Scr->WindowMask) XRaiseWindow (dpy, Scr->WindowMask);
    XMapWindow(dpy, tmp->w);

    XSaveContext(dpy, tmp->w, IconManagerContext, (XPointer) tmp);
    XSaveContext(dpy, tmp->w, TwmContext, (XPointer) tmp_win);
    XSaveContext(dpy, tmp->w, ScreenContext, (XPointer) Scr);
    XSaveContext(dpy, tmp->icon, TwmContext, (XPointer) tmp_win);
    XSaveContext(dpy, tmp->icon, ScreenContext, (XPointer) Scr);

    if (!ip->twm_win->isicon)
    {
	if (visible (ip->twm_win)) {
	    SetMapStateProp (ip->twm_win, NormalState);
	    XMapWindow (dpy, ip->w);
	    XMapWindow (dpy, ip->twm_win->frame);
	}
	ip->twm_win->mapped = TRUE;
    }
    tmp->nextv = old;
    old = tmp;
    ip = ip->nextv;
  }
    if (tmp == NULL) return NULL;
    tmp_win->iconmanagerlist = tmp;
    if (! visible (tmp->iconmgr->twm_win)) {
	old = tmp;
	tmp = tmp->nextv;
	while (tmp != NULL) {
	    if (visible (tmp->iconmgr->twm_win)) break;
	    old = tmp;
	    tmp = tmp->nextv;
	}
	if (tmp != NULL) {
	    old->nextv = tmp->nextv;
	    tmp->nextv = tmp_win->iconmanagerlist;
	    tmp_win->iconmanagerlist = tmp;
	}
    }
    return tmp_win->iconmanagerlist;
}

/***********************************************************************
 *
 *  Procedure:
 *	InsertInIconManager - put an allocated entry into an icon 
 *		manager
 *
 *  Inputs:
 *	ip	- the icon manager pointer
 *	tmp	- the entry to insert
 *
 ***********************************************************************
 */

void InsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win)
{
    WList *tmp1;
    int added;

    added = FALSE;
    if (ip->first == NULL)
    {
	ip->first = tmp;
	tmp->prev = NULL;
	ip->last = tmp;
	added = TRUE;
    }
    else if (Scr->SortIconMgr)
    {
	for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next)
	{
	    int compresult;
	    if (Scr->CaseSensitive)
		compresult = strcmp(tmp_win->icon_name,tmp1->twm->icon_name);
	    else
		compresult = XmuCompareISOLatin1(tmp_win->icon_name,tmp1->twm->icon_name);
	    if (compresult < 0)
	    {
		tmp->next = tmp1;
		tmp->prev = tmp1->prev;
		tmp1->prev = tmp;
		if (tmp->prev == NULL)
		    ip->first = tmp;
		else
		    tmp->prev->next = tmp;
		added = TRUE;
		break;
	    }
	}
    }

    if (!added)
    {
	ip->last->next = tmp;
	tmp->prev = ip->last;
	ip->last = tmp;
    }
}

void RemoveFromIconManager(IconMgr *ip, WList *tmp)
{
    if (tmp->prev == NULL)
	ip->first = tmp->next;
    else
	tmp->prev->next = tmp->next;

    if (tmp->next == NULL)
	ip->last = tmp->prev;
    else
	tmp->next->prev = tmp->prev;

    /* pebl: If the list was the current and tmp was the last in the list
       reset current list */
    if (Current == tmp) Current = ip->first;
}

/***********************************************************************
 *
 *  Procedure:
 *	RemoveIconManager - remove a window from the icon manager
 *
 *  Inputs:
 *	tmp_win	- the TwmWindow structure
 *
 ***********************************************************************
 */

void RemoveIconManager(TwmWindow *tmp_win)
{
    IconMgr *ip;
    WList *tmp, *tmp1, *save;

    if (tmp_win->iconmanagerlist == NULL)
	return;

    tmp  = tmp_win->iconmanagerlist;
    tmp1 = NULL;

  while (tmp != NULL) {
    ip = tmp->iconmgr;
    if ((tmp_win->occupation & ip->twm_win->occupation) != 0) {
	tmp1 = tmp;
	tmp  = tmp->nextv;
	continue;
    }
    RemoveFromIconManager(ip, tmp);
    
    XDeleteContext(dpy, tmp->icon, TwmContext);
    XDeleteContext(dpy, tmp->icon, ScreenContext);
    XDestroyWindow(dpy, tmp->icon);
    XDeleteContext(dpy, tmp->w, IconManagerContext);
    XDeleteContext(dpy, tmp->w, TwmContext);
    XDeleteContext(dpy, tmp->w, ScreenContext);
    XDestroyWindow(dpy, tmp->w);
    ip->count -= 1;

    PackIconManager(ip);

    if (ip->count == 0)
    {
	XUnmapWindow(dpy, ip->twm_win->frame);
	ip->twm_win->mapped = FALSE;
    }
    if (tmp1 == NULL)
	tmp_win->iconmanagerlist = tmp_win->iconmanagerlist->nextv;
    else
	tmp1->nextv = tmp->nextv;

    save = tmp;
    tmp = tmp->nextv;
    free((char *) save);
  }
}

void CurrentIconManagerEntry (WList *current)
{
    Current = current;
}

void ActiveIconManager(WList *active)
{
    active->active = TRUE;
    Active = active;
    Active->iconmgr->active = active;
    Current = Active;
    DrawIconManagerBorder(active, False);
}

void NotActiveIconManager(WList *active)
{
    active->active = FALSE;
    DrawIconManagerBorder(active, False);
}

void DrawIconManagerBorder(WList *tmp, int fill)
{
    if (Scr->use3Diconmanagers) {
	if (tmp->active && Scr->Highlight)
	    Draw3DBorder (tmp->w, 0, 0, tmp->width, tmp->height, Scr->IconManagerShadowDepth,
				tmp->cp, on, fill, False);
	else
	    Draw3DBorder (tmp->w, 0, 0, tmp->width, tmp->height, Scr->IconManagerShadowDepth,
				tmp->cp, off, fill, False);
    }
    else {
	XSetForeground(dpy, Scr->NormalGC, tmp->cp.fore);
	XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2, tmp->width-5, tmp->height-5);

	if (tmp->active && Scr->Highlight)
	    XSetForeground(dpy, Scr->NormalGC, tmp->highlight);
	else
	    XSetForeground(dpy, Scr->NormalGC, tmp->cp.back);

        XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0, tmp->width-1, tmp->height-1);
        XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1, tmp->width-3, tmp->height-3);
    }
}

/***********************************************************************
 *
 *  Procedure:
 *	SortIconManager - sort the dude
 *
 *  Inputs:
 *	ip	- a pointer to the icon manager struture
 *
 ***********************************************************************
 */

void SortIconManager(IconMgr *ip)
{
    WList *tmp1, *tmp2;
    int done;

    if (ip == NULL)
	ip = Active->iconmgr;

    done = FALSE;
    do
    {
	for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next)
	{
	    int compresult;
	    if ((tmp2 = tmp1->next) == NULL)
	    {
		done = TRUE;
		break;
	    }
	    if (Scr->CaseSensitive)
		compresult = strcmp(tmp1->twm->icon_name,tmp2->twm->icon_name);
	    else
		compresult = XmuCompareISOLatin1(tmp1->twm->icon_name,tmp2->twm->icon_name);
	    if (compresult > 0)
	    {
		/* take it out and put it back in */
		RemoveFromIconManager(ip, tmp2);
		InsertInIconManager(ip, tmp2, tmp2->twm);
		break;
	    }
	}
    }
    while (!done);
    PackIconManager(ip);
}

/***********************************************************************
 *
 *  Procedure:
 *	PackIconManager - pack the icon manager windows following
 *		an addition or deletion
 *
 *  Inputs:
 *	ip	- a pointer to the icon manager struture
 *
 ***********************************************************************
 */

void PackIconManager(IconMgr *ip)
{
    int newwidth, i, row, col, maxcol,  colinc, rowinc, wheight, wwidth;
    int new_x, new_y;
    int savewidth;
    WList *tmp;
    int mask;
    unsigned int JunkW, JunkH;

    if (Scr->use3Diconmanagers) {
	wheight = Scr->IconManagerFont.height + 2 * Scr->IconManagerShadowDepth + 6;
    } else {
	wheight = Scr->IconManagerFont.height + 10;
    }
    if (wheight < (siconify_height + 4))
	wheight = siconify_height + 4;

    wwidth = ip->width / ip->columns;

    rowinc = wheight;
    colinc = wwidth;

    row = 0;
    col = ip->columns;
    maxcol = 0;
    for (i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next)
    {
	tmp->me = i;
	if (++col >= ip->columns)
	{
	    col = 0;
	    row += 1;
	}
	if (col > maxcol)
	    maxcol = col;

	new_x = col * colinc;
	new_y = (row-1) * rowinc;

	/* if the position or size has not changed, don't touch it */
	if (tmp->x != new_x || tmp->y != new_y ||
	    tmp->width != wwidth || tmp->height != wheight)
	{
	    XMoveResizeWindow(dpy, tmp->w, new_x, new_y, wwidth, wheight);

	    tmp->row = row-1;
	    tmp->col = col;
	    tmp->x = new_x;
	    tmp->y = new_y;
	    tmp->width = wwidth;
	    tmp->height = wheight;
	}
    }
    maxcol += 1;

    ip->cur_rows = row;
    ip->cur_columns = maxcol;
    ip->height = row * rowinc;
    if (ip->height == 0)
    	ip->height = rowinc;
    newwidth = maxcol * colinc;
    if (newwidth == 0)
	newwidth = colinc;

    XResizeWindow(dpy, ip->w, newwidth, ip->height);

    mask = XParseGeometry (ip->geometry, &JunkX, &JunkY, &JunkW, &JunkH);
    if (mask & XNegative) {
	ip->twm_win->frame_x += ip->twm_win->frame_width - newwidth -
				2 * ip->twm_win->frame_bw3D;
    }
    if (mask & YNegative) {
	ip->twm_win->frame_y += ip->twm_win->frame_height - ip->height -
				2 * ip->twm_win->frame_bw3D - ip->twm_win->title_height;
    }
    savewidth = ip->width;
    if (ip->twm_win)
      SetupWindow (ip->twm_win,
		   ip->twm_win->frame_x, ip->twm_win->frame_y,
		   newwidth + 2 * ip->twm_win->frame_bw3D,
		   ip->height + ip->twm_win->title_height + 2 * ip->twm_win->frame_bw3D, -1);
    ip->width = savewidth;
}
