/*-
 * Copyright (c) 2001 Jordan DeLong
 * Copyright (c) 2004 Florian octo Forster
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include "plugutil.h"

typedef enum icon_placement_type
{
   icon_place_with_window_c =  0x1,
   icon_place_on_edge       =  0x2
} icon_placement_type_t;

typedef enum icon_placement_edge
{
   icon_place_bottom_c      =  0x1,
   icon_place_right_c       =  0x2,
   icon_place_left_c        =  0x3,
   icon_place_top_c         =  0x4
} icon_placement_edge_t;

typedef enum icon_placement_direction
{
   icon_place_left_to_right_c = 0x1,
   icon_place_right_to_left_c = 0x2,
   icon_place_top_to_bottom_c = 0x3,
   icon_place_bottom_to_top_c = 0x4
} icon_placement_direction_t;

typedef struct icon_slot
{
   int x;
   int y;
   int used;
} icon_slot_t;

typedef struct icon_placement
{
   icon_placement_type_t      type :4;
   icon_placement_edge_t      edge :4;
   icon_placement_direction_t direction :8;
   int pad :16;

   icon_slot_t *icon_slots;
   int start_slot;
   int slot_count;
   int first_row_slot;
   int last_row_slot;
   int first_col_slot;
   int last_col_slot;
   int row_inc;
   int col_inc;
} icon_placement_t;

/* per screen structure */
static struct iconscr
{
   icon_placement_t placement;
   pixmap_t         pixmap;
} *iconscr;

/* structure describing an icon */
typedef struct icon
{
	Window		icon;    /* the icon window we created */
	client_t	  *client;  /* the client it represents */
	Pixmap		pixmap;  /* pixmap used for this icon */

   icon_slot_t *slot;
   int moved;

	TAILQ_ENTRY(icon) i_list;
} icon_t;

/* linked list of icons */
static TAILQ_HEAD(iconlist, icon) icon_list;

/* context for icon windows */
static XContext	icon_context;

/* information for dragging of icons */
static icon_t	*dragged_icon	= NULL;
static int	drag_x, drag_y;

/* config options */
static int take_screenshots = 0;
static int icon_must_be_smaller_than_src = 0;
static unsigned short int icon_size = 64;
static int icon_stays_when_moved = 1;
static int proportional_icons = 1;
static int scale_pixmaps = 1;

static icon_placement_type_t      placement_type = icon_place_with_window_c;
static icon_placement_edge_t      placement_edge = icon_place_bottom_c;
static icon_placement_direction_t placement_direction = icon_place_right_to_left_c;

static int icon_x_pad = 0;
static int icon_y_pad = 0;

#define COMPARE_GREATER_THAN 0
#define COMPARE_LESS_THAN    1

void icon_place( client_t *client,
                 icon_t *icon,
                 int icon_height, int icon_width,
                 int *x, int *y )
{
   int i = client->screen->num;
   int slot;
   int start_slot = 0;
   int slot_step = 1;
   int we_care_about_y_wrap = 0;
   int we_care_about_x_wrap = 0;
   int last_slot;
   int count;
   int pos_neg_multiplier;

   if( iconscr[i].placement.type == icon_place_with_window_c )
   {
      *x = client->x + ((client->width + client->dgroup->left_space
                         + client->dgroup->right_space) / 2) - icon_width / 2;
      *y = client->y + ((client->height + client->dgroup->top_space
                         + client->dgroup->bottom_space) / 2) - icon_height / 2;
   }
   else
   {
      if( iconscr[i].placement.type == icon_place_on_edge )
      {
         /* top/bottom, right->left/left->right */
         if( iconscr[i].placement.direction == icon_place_left_to_right_c )
         {
            slot_step = 1;
            we_care_about_x_wrap = 1;
         }

         if( iconscr[i].placement.direction == icon_place_right_to_left_c )
         {
            we_care_about_x_wrap = 1;
            slot_step = -1;
         }

         /* right/left, top->bottom/bottom->top */
         if( iconscr[i].placement.direction == icon_place_top_to_bottom_c )
         {
            slot_step = iconscr[i].placement.row_inc;
            we_care_about_y_wrap = 1;
         }

         if( iconscr[i].placement.direction == icon_place_bottom_to_top_c )
         {
            slot_step = -(iconscr[i].placement.row_inc);
            we_care_about_y_wrap = 1;
         }


         /* edges */
         if( iconscr[i].placement.edge == icon_place_right_c )
         {
            if( iconscr[i].placement.direction == icon_place_bottom_to_top_c )
            {
               start_slot = iconscr[i].placement.slot_count - 1;
            }
            else
            {
               start_slot = iconscr[i].placement.last_col_slot;
            }

            pos_neg_multiplier = -1;
         }

         if( iconscr[i].placement.edge == icon_place_left_c )
         {
            if( iconscr[i].placement.direction == icon_place_bottom_to_top_c )
            {
               start_slot = iconscr[i].placement.last_row_slot;
            }
            else
            {
               start_slot = 0;
            }

            pos_neg_multiplier = 1;
         }

         if( iconscr[i].placement.edge == icon_place_bottom_c )
         {
            if( iconscr[i].placement.direction == icon_place_right_to_left_c )
            {
               start_slot = iconscr[i].placement.slot_count - 1;
            }
            else
            {
               start_slot = iconscr[i].placement.last_row_slot;
            }

            pos_neg_multiplier = -1;
         }

         if( iconscr[i].placement.edge == icon_place_top_c )
         {
            if( iconscr[i].placement.direction == icon_place_right_to_left_c )
            {
               start_slot = iconscr[i].placement.last_col_slot;
            }
            else
            {
               start_slot = 0;
            }

            pos_neg_multiplier = 1;
         }
      }


      slot = start_slot;
      count = 0;
      while( slot < iconscr[i].placement.slot_count &&
             slot >= 0 &&
             iconscr[i].placement.icon_slots[slot].used == 1 )
      {
         last_slot = slot;
         slot += slot_step;
         count++;

         if( we_care_about_y_wrap )
         {
            if( (count % iconscr[i].placement.col_inc) == 0 )
            {
               slot = start_slot + (iconscr[i].placement.col_inc * pos_neg_multiplier);
               count = 0;
            }
         }
         if( we_care_about_x_wrap )
         {
            if( (count % iconscr[i].placement.row_inc) == 0 )
            {
               slot = start_slot + (iconscr[i].placement.row_inc * pos_neg_multiplier);
               count = 0;
            }
         }
      }

      iconscr[i].placement.icon_slots[slot].used = 1;
      *x = iconscr[i].placement.icon_slots[slot].x;
      *y = iconscr[i].placement.icon_slots[slot].y;

      icon->slot = &iconscr[i].placement.icon_slots[slot];
   }

}

/* add an icon */
static icon_t *icon_add( client_t *client )
{
	XSetWindowAttributes attr;
	icon_t *icon;
	Window dumwin;
	int x, y;
   unsigned int width, height;
	int dumint;
	unsigned int dumuint;

	int icon_width;
	int icon_height;
	image_t *image, *scaled;
	Pixmap pixmap;
   int use_default_pixmap = 0;

	PDEBUG ("icon_add entered");

	icon = calloc(1, sizeof(icon_t));
	if (!icon)
		return NULL;

	icon->client = client;
   icon->moved = 0;

   if( proportional_icons )
   {
      if (client->width > client->height)
      {
         icon_width = icon_size;
         icon_height = ((double) (icon_size * client->height) / (double) client->width) + .5;
      }
      else
      {
         icon_height = icon_size;
         icon_width = ((double) (icon_size * client->width) / (double) client->height) + .5;
      }
   }
   else
   {
      icon_width = icon_size;
      icon_height = icon_size;
   }

	PDEBUG ("  Calculated the dimensions: %ux%u -> %ux%u\n",
           client->width, client->height,
           icon_width, icon_height);

	if( client->wmhints && client->wmhints->flags & IconPositionHint )
	{
		x = client->wmhints->icon_x;
		y = client->wmhints->icon_y;
	}
	else
	{
      icon_place( client, icon, icon_height, icon_width, &x, &y );
	}

	if ((x + icon_width) > client->screen->width)
   {
		x = client->screen->width - icon_width;
   }
	if ((y + icon_height) > client->screen->height)
   {
		y = client->screen->height - icon_height;
   }

	image = NULL;
   use_default_pixmap = 1;
	if (take_screenshots)
	{
		PDEBUG ("  Taking screenshot");
		image = image_fromscreenshot (client);
	}
   else
   {
      if( scale_pixmaps )
      {
         image = image_frompixmap ( &iconscr[client->screen->num].pixmap,
                                    client->screen );
      }
   }

	if( image )
	{
      use_default_pixmap = 0;

		pixmap = XCreatePixmap( display, client->screen->root,
                              icon_width, icon_height,
                              DefaultDepth (display, client->screen->num) );
		icon->pixmap = pixmap;

      if( pixmap )
      {
         PDEBUG ("  Scaling image");
         if( take_screenshots )
         {
            scaled = image_scale_hq (client, image, icon_width, icon_height,
                                     icon_must_be_smaller_than_src );
         }
         else
         {
            scaled = image_scale (image, icon_width, icon_height);
         }

         if( scaled )
         {
            PDEBUG ("  Generating pixmap");

            image_put( scaled, pixmap, DefaultGC (display, client->screen->num),
                       0, 0, 0, 0, icon_width, icon_height );

            PDEBUG ("  done");
            image_destroy(scaled);
         }
         else
         {
            /* back to the default, we tried! */
            use_default_pixmap = 1;
         }

         image_destroy(image);
      }
      else
      {
         /* back to the default, we tried! */
         use_default_pixmap = 1;
         image_destroy(image);
      }
	}

   if( use_default_pixmap )
	{
		pixmap = iconscr[client->screen->num].pixmap.pixmaps[0];
	}

	/* create the window */
	attr.override_redirect = 1;
	attr.background_pixmap = pixmap;
	icon->icon = XCreateWindow( display, RootWindow(display, client->screen->num),
                               x, y,
                               icon_width, icon_height, 0, CopyFromParent, CopyFromParent, CopyFromParent,
                               CWOverrideRedirect | CWBackPixmap, &attr );
	plugin_setcontext(plugin_this, icon->icon);
	XSaveContext(display, icon->icon, icon_context, (XPointer) icon);
	XSaveContext(display, icon->client->frame, icon_context, (XPointer) icon);

	/* use it's icon window if it has one */
	if( client->wmhints && client->wmhints->flags & IconWindowHint )
   {
		XGetGeometry(display, client->wmhints->icon_window, &dumwin,
                   &dumint, &dumint, &width, &height, &dumuint, &dumuint);
		XSetWindowBorder(display, client->wmhints->icon_window, 0);
		XReparentWindow(display, client->wmhints->icon_window, icon->icon,
                      icon_size / 2 - width / 2, icon_size / 2 - height / 2);
		XMapWindow(display, client->wmhints->icon_window);
	}

	TAILQ_INSERT_HEAD(&icon_list, icon, i_list);

	XSelectInput(display, icon->icon, ButtonPressMask | ButtonReleaseMask | Button1MotionMask);
	XMapRaised(display, icon->icon);

	return icon;
}

/* get rid of an icon */
static void icon_rm(icon_t *icon, int destroy )
{
	PDEBUG ("icon_rm entered");

   if( destroy || icon->moved == 0 || icon_stays_when_moved == 0 )
   {
      if( icon->slot )
      {
         icon->slot->used = 0;
      }

      if (icon->pixmap)
      {
         XFreePixmap(display, icon->pixmap);
      }

      plugin_rmcontext(icon->icon);
      XDeleteContext(display, icon->icon, icon_context);
      XDeleteContext(display, icon->client->frame, icon_context);
      XDestroyWindow(display, icon->icon);

      TAILQ_REMOVE(&icon_list, icon, i_list);
      free(icon);
   }
   else
   {
      TAILQ_REMOVE(&icon_list, icon, i_list);
   }
}

/* client window gets unmmapped, and client_t subsequently becomes invalid */
static int window_death(int pcall, client_t *client)
{
	icon_t *icon;

	if (XFindContext(display, client->frame, icon_context, (XPointer *) &icon))
   {
		return PLUGIN_OK;
   }

	icon_rm(icon,1);

	return PLUGIN_OK;
}

/* client iconification */
static int iconify_notify(int pcall, client_t *client)
{
	icon_t *icon;

	if( XFindContext(display, client->frame, icon_context, (XPointer *) &icon) )
   {
		if (!icon_add(client))
      {
			return PLUGIN_UNLOAD;
      }
	}
   else
   {
		XMapRaised(display, icon->icon);
      TAILQ_INSERT_HEAD(&icon_list, icon, i_list);
   }

	return PLUGIN_OK;
}

/* client deiconification */
static int restore_notify(int pcall, client_t *client)
{
	icon_t *icon;

	if (XFindContext(display, client->frame, icon_context, (XPointer *) &icon))
   {
		return PLUGIN_OK;
   }

	XUnmapWindow(display, icon->icon);

	icon_rm(icon,0);

	return PLUGIN_OK;
}

/* x event handler for button presses */
static void button_press(XButtonEvent *e)
{
	icon_t *icon;

	if (XFindContext(display, e->window, icon_context, (XPointer *) &icon))
		return;

	drag_x = e->x;
	drag_y = e->y;
	XRaiseWindow(display, icon->icon);
}

/* x event handler for presses on the icons */
static void button_release(XButtonEvent *e)
{
	icon_t *icon;

	if (XFindContext(display, e->window, icon_context, (XPointer *) &icon))
		return;

	/* they were dragging, not clicking */
	if (dragged_icon)
   {
		dragged_icon = NULL;
		return;
	}

	/* restore it if it's still over the icon */
	if (e->x < icon_size && e->y < icon_size && e->x > 0 && e->y > 0)
   {
		action_restore(icon->client);
   }
}

/* x event handler to allow the icons to be dragged */
static void pointer_motion(XMotionEvent *e)
{
   int new_x, new_y;

	if (!dragged_icon)
   {
		if( XFindContext( display, e->window, icon_context,
                        (XPointer *) &dragged_icon) )
      {
			return; /* ---------> */
      }
	}
   else
   {
		/* this shouldn't happen */
		if (e->window != dragged_icon->icon)
      {
			dragged_icon = NULL;
			return; /* ---------> */
		}
	}

   new_x = e->x_root - drag_x;
   new_y = e->y_root - drag_y;
	XMoveWindow( display, dragged_icon->icon,
                new_x, new_y );

   /* have we moved outside the slot to the right ? */
   if( new_x > dragged_icon->slot->x + icon_size )
   {
      dragged_icon->slot->used = 0;
   }
   /* have we moved out to the left ? */
   if( new_x + icon_size < dragged_icon->slot->x )
   {
      dragged_icon->slot->used = 0;
   }
   if( new_y > dragged_icon->slot->y + icon_size )
   {
      dragged_icon->slot->used = 0;
   }
   if( new_y + icon_size < dragged_icon->slot-> y )
   {
      dragged_icon->slot->used = 0;
   }

   dragged_icon->moved = 1;
}

/* x event processor */
int box_iconify_xevent_handler(XEvent *e)
{
	switch (e->type)
   {
      case ButtonPress:
         button_press(&e->xbutton);
         break;
      case ButtonRelease:
         button_release(&e->xbutton);
         break;
      case MotionNotify:
         pointer_motion(&e->xmotion);
         break;
	}

	return PLUGIN_OK;
}

/* read parameters */
int box_iconify_init()
{
	char *pmfn;
	int i, cnt;
   char *edge_string = NULL;
   char *dir_string = NULL;
   char *icon_placement_type = NULL;
	int dumint;
	unsigned int dumuint;
   Window dumwin;

	TAILQ_INIT(&icon_list);
	REQUIRED_PARAM(&plugin_this->params, "pixmap", string, pmfn);
	OPTIONAL_PARAM(&plugin_this->params, "take_screenshots", bool, take_screenshots, 0);
   OPTIONAL_PARAM(&plugin_this->params, "proportional_icons", bool, proportional_icons, 0);
	OPTIONAL_PARAM(&plugin_this->params, "icon_size", int, i, 64);
	OPTIONAL_PARAM(&plugin_this->params, "icon_must_be_smaller_than_src", bool,
                  icon_must_be_smaller_than_src, 1 );
   OPTIONAL_PARAM(&plugin_this->params, "icon_stays_when_moved",  bool,
                  icon_stays_when_moved, 0);
   OPTIONAL_PARAM(&plugin_this->params, "scale_pixmaps",  bool,
                  scale_pixmaps, 0);


   /* ---------[ type ]--------- */
   OPTIONAL_PARAM(&plugin_this->params, "icon_placement_type", string, icon_placement_type, NULL );
   if( icon_placement_type )
   {
      if( strcmp( "icon_follows_window", icon_placement_type ) == 0 )
      {
         placement_type = icon_place_with_window_c;
      }
      else if( strcmp( "icon_on_edge", icon_placement_type ) == 0 )
      {
         placement_type = icon_place_on_edge;

         /* ---------[ edge type details ]--------- */
         OPTIONAL_PARAM(&plugin_this->params, "icon_edge", string, edge_string, NULL );
         if( edge_string )
         {
            if( strcmp( "top", edge_string ) == 0 )
            {
               placement_edge = icon_place_top_c;
            }
            else if( strcmp( "bottom", edge_string ) == 0 )
            {
               placement_edge = icon_place_bottom_c;
            }
            else if( strcmp( "right", edge_string ) == 0 )
            {
               placement_edge = icon_place_right_c;
            }
            else if( strcmp( "left", edge_string ) == 0 )
            {
               placement_edge = icon_place_left_c;
            }
         }

         /* ---------[ direction details ]--------- */
         OPTIONAL_PARAM(&plugin_this->params, "icon_flow", string, dir_string, NULL );
         if( dir_string )
         {
            if( strcmp( "left_to_right", dir_string ) == 0 )
            {
               placement_direction = icon_place_left_to_right_c;
            }
            else if( strcmp( "right_to_left", dir_string ) == 0 )
            {
               placement_direction = icon_place_right_to_left_c;
            }
            else if( strcmp( "top_to_bottom", dir_string ) == 0 )
            {
               placement_direction = icon_place_top_to_bottom_c;
            }
            else if( strcmp( "bottom_to_top", dir_string ) == 0 )
            {
               placement_direction = icon_place_bottom_to_top_c;
            }
         }
      }
   }


   if ((i >= 16) && (i < 512))
   {
		icon_size = i;
   }
	else
   {
		icon_size = 64;
   }

	PDEBUG ("init: screenshots are %s", take_screenshots ? "enabled" : "disabled");
	PDEBUG ("init: icon size: %i", icon_size);

	cnt = ScreenCount(display);
	iconscr = calloc(cnt, sizeof(struct iconscr));
	if (!iconscr)
		goto free;


	for (i = 0; i < cnt; i++)
   {
      iconscr[i].pixmap.pixmaps = malloc(sizeof(Pixmap));
      if (!iconscr[i].pixmap.pixmaps)
      {
         return -1;
      }
      iconscr[i].pixmap.shapemasks = malloc(sizeof(Pixmap));
      if (!iconscr[i].pixmap.shapemasks)
      {
         return -1;
      }

      XpmReadFileToPixmap(display, RootWindow(display, i),
                          pmfn,
                          &iconscr[i].pixmap.pixmaps[0],
                          &iconscr[i].pixmap.shapemasks[0], NULL);
      XGetGeometry(display, iconscr[i].pixmap.pixmaps[0],
                   &dumwin,
                   &dumint, &dumint, (unsigned int*) &iconscr[i].pixmap.width,
                   (unsigned int*) &iconscr[i].pixmap.height, &dumuint, &dumuint);
   }



	free(pmfn);
	return PLUGIN_OK;

free:
	free(pmfn);
	return PLUGIN_UNLOAD;
}

/* setup for the plugin */
int box_iconify_start()
{
   int max_icons;
   screen_t *screen;
   int j, i;
   int x,y;
   int row,col;

	icon_context = XUniqueContext();

	/* register plugin callbacks */
	plugin_callback_add(plugin_this, PCALL_WINDOW_DEATH, window_death);
	plugin_callback_add(plugin_this, PCALL_ICONIFY_NOTIFY, iconify_notify);
	plugin_callback_add(plugin_this, PCALL_RESTORE_NOTIFY, restore_notify);

   TAILQ_FOREACH(screen, &screen_list, s_list)
   {
      i = screen->num;

      /* if the height of the icons isn't a even multiple of the screen size, we
         need to pad out until it is */
      while( (screen->height % (icon_size + icon_y_pad )) != 0 )
      {
         icon_y_pad++;
      }
      /* if the width of the icons isn't a even multiple of the screen size, we
         need to pad out until it is */
      while( (screen->width % (icon_size + icon_x_pad )) != 0 )
      {
         icon_x_pad++;
      }

       max_icons = ( screen->width / (icon_size + icon_x_pad) ) * (screen->height / (icon_size + icon_y_pad ) );

      iconscr[i].placement.icon_slots = calloc(max_icons, sizeof(icon_slot_t));
      iconscr[i].placement.start_slot = 0;
      iconscr[i].placement.slot_count = max_icons;
      iconscr[i].placement.first_row_slot = 0;
      iconscr[i].placement.last_row_slot = 0;
      iconscr[i].placement.first_col_slot = 0;
      iconscr[i].placement.last_col_slot = 0;
      iconscr[i].placement.row_inc = (screen->width / (icon_size + icon_x_pad) );
      iconscr[i].placement.col_inc = (screen->height / (icon_size + icon_y_pad) );;

      /* fill the slots in with x/y pairs */
      x = icon_x_pad;
      y = icon_y_pad;
      row = 0;
      col = 0;
      for( j = 0; j < max_icons; j++ )
      {
         iconscr[i].placement.icon_slots[j].used = 0;
         iconscr[i].placement.icon_slots[j].x = x;
         iconscr[i].placement.icon_slots[j].y = y;

         x += icon_size + icon_x_pad;
         col++;
         if( x + icon_size + icon_x_pad > screen->width )
         {
            if( iconscr[i].placement.last_col_slot == 0 )
            {
               iconscr[i].placement.last_col_slot = j;
            }
            x = 0;
            y += icon_size + icon_y_pad;
            if( y + icon_size + icon_y_pad >= screen->height )
            {
               if( iconscr[i].placement.last_row_slot == 0 )
               {
                  iconscr[i].placement.last_row_slot = j + 1;
               }
            }
         }
      }

      iconscr[i].placement.type = placement_type;
      iconscr[i].placement.edge = placement_edge;
      iconscr[i].placement.direction = placement_direction;
   }

	return PLUGIN_OK;
}

/* plugin shutdown */
void box_iconify_shutdown()
{
	icon_t *icon;
	int i;

	while (!TAILQ_EMPTY(&icon_list))
   {
		icon = TAILQ_FIRST(&icon_list);
		icon_rm(icon,1);
	}

	if (iconscr)
   {
		for (i = 0; i < screen_count; i++)
      {
			XFreePixmap(display, iconscr[i].pixmap.pixmaps[0] );
         free( iconscr[i].pixmap.shapemasks );
         free( iconscr[i].pixmap.pixmaps );
         free( iconscr[i].placement.icon_slots );
      }
		free(iconscr);
	}
}
