#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

#include "../guiutils.h"
#include "../pie_chart.h"
#include "../toolbar.h"

#include "../edv_types.h"
#include "../edv_id.h"
#include "../edv_utils.h"
#include "../lib/endeavour2.h"

#include "ziptoolio.h"
#include "ziptool.h"
#include "ziptoolcb.h"
#include "config.h"

#include "../images/icon_drive_zip_48x48.xpm"
#include "../images/icon_mount_20x20.xpm"
#include "../images/icon_unmount_20x20.xpm"
#include "../images/icon_mounted_20x20.xpm"
#include "../images/icon_not_mounted_20x20.xpm"
#include "../images/icon_eject_20x20.xpm"
#include "../images/icon_power_20x20.xpm"
#include "../images/icon_security_20x20.xpm"
#include "../images/icon_browse_20x20.xpm"
#include "../images/icon_reload_20x20.xpm"
#include "../images/icon_fsck_20x20.xpm"
#include "../images/icon_exit_20x20.xpm"
#include "../images/icon_close_20x20.xpm"
#include "../images/icon_secure_20x20.xpm"
#include "../images/icon_insecure_20x20.xpm"


zip_tool_opid_struct *ZipToolOPIDListFind(GList *opid, gint id);
GList *ZipToolOPIDListNew(zip_tool_struct *zt);
void ZipToolOPIDListDelete(GList *opid);

void ZipToolSetDevice(
	zip_tool_struct *zt, edv_device_struct *dev
);
void ZipToolRefreshDevice(
	zip_tool_struct *zt, edv_device_struct *dev
);

zip_tool_struct *ZipToolNew(edv_context_struct *ctx);
void ZipToolUpdate(zip_tool_struct *zt);
void ZipToolSetBusy(zip_tool_struct *zt, gboolean is_busy);
void ZipToolStatusMessage(
	zip_tool_struct *zt, const gchar *mesg,
	gboolean allow_gtk_iteration

);
gboolean ZipToolIsMapped(zip_tool_struct *zt);
void ZipToolMap(zip_tool_struct *zt);
void ZipToolUnmap(zip_tool_struct *zt);
void ZipToolDelete(zip_tool_struct *zt);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)       (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


#define ZIP_TOOL_WIDTH			550
#define ZIP_TOOL_HEIGHT			350

#define EDV_STATUS_BAR_HEIGHT		26


/*
 *	Finds the Operation ID specified by id in the given Operation
 *	IDs list.
 */
zip_tool_opid_struct *ZipToolOPIDListFind(GList *opid, gint id)
{
	zip_tool_opid_struct *opid_ptr;

	while(opid != NULL)
	{
	    opid_ptr = ZIP_TOOL_OPID(opid->data);
	    if((opid_ptr != NULL) ? (opid_ptr->id == id) : FALSE)
		return(opid_ptr);

	    opid = g_list_next(opid);
	}

	return(NULL);
}


/*
 *	Creates a new list of Operation IDs.
 */
GList *ZipToolOPIDListNew(zip_tool_struct *zt)
{
	GList *opid = NULL;
	const gchar *name;
	const gchar *button_name;
	guint8 **icon_data;
	const gchar *tooltip;
	void (*func_cb)(GtkWidget *, gpointer);
	gint (*enter_notify_cb)(GtkWidget *, GdkEventCrossing *, gpointer);
	gint (*leave_notify_cb)(GtkWidget *, GdkEventCrossing *, gpointer);

#define DO_APPEND(_id_)	{				\
 zip_tool_opid_struct *opid_ptr = ZIP_TOOL_OPID(	\
  g_malloc0(sizeof(zip_tool_opid_struct))		\
 );							\
 opid_ptr->id = (_id_);					\
 opid_ptr->zt = zt;					\
 opid_ptr->name = STRDUP(name);				\
 opid_ptr->button_name = STRDUP(button_name);		\
 opid_ptr->icon_data = icon_data;			\
 opid_ptr->tooltip = STRDUP(tooltip);			\
 opid_ptr->func_cb = func_cb;				\
 opid_ptr->func_enter_cb = enter_notify_cb;		\
 opid_ptr->func_leave_cb = leave_notify_cb;		\
							\
 opid = g_list_append(opid, opid_ptr);			\
}

	enter_notify_cb = ZipToolMenuItemEnterCB;
	leave_notify_cb = ZipToolMenuItemLeaveCB;

	func_cb = ZipToolCloseBtnCB;
	icon_data = (guint8 **)icon_close_20x20_xpm;
	name = "Close";
	button_name = name;
	tooltip = "Close this window";
	DO_APPEND(ZIP_TOOL_OPID_CLOSE)

	func_cb = ZipToolExitCB;
	icon_data = (guint8 **)icon_exit_20x20_xpm;
	name = "Exit";
	button_name = name;
	tooltip = "Close all windows belonging to this application";
	DO_APPEND(ZIP_TOOL_OPID_EXIT)

	func_cb = ZipToolMountCB;
	icon_data = (guint8 **)icon_mount_20x20_xpm;
	name = "Mount";
	button_name = name;
	tooltip = "Mount the device";
	DO_APPEND(ZIP_TOOL_OPID_MOUNT)

	func_cb = ZipToolUnmountCB;
	icon_data = (guint8 **)icon_unmount_20x20_xpm;
	name = "Unmount";
	button_name = name;
	tooltip = "Unmount the device";
	DO_APPEND(ZIP_TOOL_OPID_UNMOUNT)

	func_cb = ZipToolSpinDownCB;
	icon_data = (guint8 **)icon_power_20x20_xpm;
	name = "Spin Down";
	button_name = "SpinDn";
	tooltip = "Spin down the device";
	DO_APPEND(ZIP_TOOL_OPID_SPIN_DOWN)

	func_cb = ZipToolEjectCB;
	icon_data = (guint8 **)icon_eject_20x20_xpm;
	name = "Eject";
	button_name = name;
	tooltip = "Eject the media from the device";
	DO_APPEND(ZIP_TOOL_OPID_EJECT)

	func_cb = ZipToolPasswordCB;
	icon_data = (guint8 **)icon_security_20x20_xpm;
	name = "Password";
	button_name = name;
	tooltip = "Lock/unlock the media";
	DO_APPEND(ZIP_TOOL_OPID_PASSWORD)

	func_cb = ZipToolBrowseCB;
	icon_data = (guint8 **)icon_browse_20x20_xpm;
	name = "Browse";
	button_name = name;
	tooltip = "Run the File Browser to browse the media";
	DO_APPEND(ZIP_TOOL_OPID_BROWSE)

	func_cb = ZipToolRefreshCB;
	icon_data = (guint8 **)icon_reload_20x20_xpm;
	name = "Refresh";
	button_name = name;
	tooltip = "Refresh device information";
	DO_APPEND(ZIP_TOOL_OPID_REFRESH)

	func_cb = ZipToolFSCKCB;
	icon_data = (guint8 **)icon_fsck_20x20_xpm;
	name = "File System Check";
	button_name = "FSCK";
	tooltip = "Run FSCK to check the media";
	DO_APPEND(ZIP_TOOL_OPID_FSCK)

#undef DO_APPEND

	return(opid);
}

/*
 *	Deletes the list of Operation IDs.
 */
void ZipToolOPIDListDelete(GList *opid)
{
	if(opid == NULL)
	    return;

	g_list_foreach(opid, ZipToolOPIDDeleteCB, NULL);
	g_list_free(opid);
}

/*
 *	Sets the new device specified by dev on the zip tools
 *	window. If a device already exists then it will be deallocated
 *	first.
 *
 *	The given device will be taken by this function and should no
 *	longer be referenced by the calling function.
 */
void ZipToolSetDevice(zip_tool_struct *zt, edv_device_struct *dev)
{
	GtkWidget *w;

	if(zt == NULL)
	    return;

	/* Delete existing device reference (if any) and set new
	 * device reference
	 */
	EDVDeviceDelete(zt->device);
	zt->device = dev;

	/* Update title */
	w = zt->toplevel;
	if(w != NULL)
	{
	    if(dev != NULL)
	    {
		gchar *buf;

		if((dev->name != NULL) && (dev->device_path != NULL))
		    buf = g_strdup_printf(
			"%s: %s (%s)",
			PROG_NAME, dev->name, dev->device_path
		    );
		else
		    buf = g_strdup_printf(
			"%s: %s",
			PROG_NAME,
			(dev->name != NULL) ? dev->name :
			    dev->device_path
		    );
		gtk_window_set_title(GTK_WINDOW(w), buf);
		g_free(buf);
	    }
	    else
	    {
		gtk_window_set_title(GTK_WINDOW(w), PROG_NAME);
	    }
	}
}

/*
 *	Rescans the specified device (or the current device on the Zip
 *	Tool Window if dev is NULL) and updates the display widgets.
 */
void ZipToolRefreshDevice(
	zip_tool_struct *zt, edv_device_struct *dev
)
{
	const gint	border_major = 5,
			border_minor = 2;
	GtkWidget *w, *parent, *parent2, *parent3, *parent4;

	if(zt == NULL)
	    return;

	if(dev == NULL)
	    dev = zt->device;
	if(dev == NULL)
	    return;

	/* Update the Device's mount state and stats */
	EDVDeviceUpdateMountState(dev);
	EDVDeviceUpdateStats(dev);

	/* Get lock state */
	zt->lock_state = ZipToolDeviceIsProtected(dev);


	/* Destroy existing display widgets */
	PieChartDelete(zt->capacity_piechart);
	zt->capacity_piechart = NULL;
	GTK_WIDGET_DESTROY(zt->display_mount_path_btn)
	zt->display_mount_path_btn = NULL;
 	GTK_WIDGET_DESTROY(zt->display_mount_btn)
	zt->display_mount_btn = NULL;
	GTK_WIDGET_DESTROY(zt->display_lock_btn)
	zt->display_lock_btn = NULL;
	GTK_WIDGET_DESTROY(zt->display_child)
	zt->display_child = NULL;


	/* Begin creating display widgets */

	/* Get display parent and begin recreating display widgets */
	parent = zt->display_parent;
	if(parent != NULL)
	{
	    gint prefix_label_width;
	    gchar *buf, *buf2;
	    pie_chart_struct *pc;
	    GdkColor c, color_fg, color_bg;
	    GdkPixmap *pixmap = NULL;
	    GdkBitmap *mask = NULL;
	    GtkAdjustment *adj;
	    GtkRcStyle *rcstyle;
	    gulong adj_division = 10;
	    struct stat stat_buf;
	    gint stat_status;

#define SET_FLAT_BUTTON_STYLE(_w_)      {               \
 if((_w_) != NULL) {                                    \
  GtkStateType state, state2 = GTK_STATE_NORMAL;        \
  GtkStyle *style = gtk_widget_get_style(_w_);          \
  GtkRcStyle *rcstyle = gtk_rc_style_new();		\
  state = GTK_STATE_NORMAL;                             \
  rcstyle->color_flags[state] = GTK_RC_FG | GTK_RC_BG | \
   GTK_RC_TEXT;                                         \
  memcpy(&rcstyle->fg[state], &style->fg[state2], sizeof(GdkColor));\
  memcpy(&rcstyle->bg[state], &style->bg[state2], sizeof(GdkColor));\
  GDK_COLOR_SET_COEFF(&rcstyle->text[state], 0.0f, 0.0f, 1.0f)\
  state = GTK_STATE_PRELIGHT;                           \
  rcstyle->color_flags[state] = GTK_RC_FG | GTK_RC_BG | \
   GTK_RC_TEXT;                                         \
  memcpy(&rcstyle->fg[state], &style->fg[state2], sizeof(GdkColor));\
  memcpy(&rcstyle->bg[state], &style->bg[state2], sizeof(GdkColor));\
  GDK_COLOR_SET_COEFF(&rcstyle->text[state], 0.0f, 0.0f, 1.0f)\
  state = GTK_STATE_ACTIVE;                             \
  rcstyle->color_flags[state] = GTK_RC_FG | GTK_RC_BG | \
   GTK_RC_TEXT;                                         \
  memcpy(&rcstyle->fg[state], &style->fg[state2], sizeof(GdkColor));\
  memcpy(&rcstyle->bg[state], &style->bg[state2], sizeof(GdkColor));\
  GDK_COLOR_SET_COEFF(&rcstyle->text[state], 1.0f, 0.0f, 0.0f)\
							\
  gtk_widget_modify_style_recursive((_w_), rcstyle);    \
  GTK_RC_STYLE_UNREF(rcstyle);                          \
							\
  gtk_button_set_relief(GTK_BUTTON(_w_), GTK_RELIEF_NONE);\
} }

#define SET_BUTTON_CB(_w_,_id_)         {               \
 zip_tool_opid_struct *opid_ptr = ZipToolOPIDListFind(  \
  zt->opid, (_id_)                                      \
 );                                                     \
 if(((_w_) != NULL) && (opid_ptr != NULL)) {            \
  gtk_signal_connect(                                   \
   GTK_OBJECT(_w_), "clicked",                          \
   GTK_SIGNAL_FUNC(opid_ptr->func_cb), opid_ptr->zt     \
  );                                                    \
  gtk_signal_connect(                                   \
   GTK_OBJECT(_w_), "enter_notify_event",               \
   GTK_SIGNAL_FUNC(opid_ptr->func_enter_cb), opid_ptr   \
  );                                                    \
  gtk_signal_connect(                                   \
   GTK_OBJECT(_w_), "leave_notify_event",               \
   GTK_SIGNAL_FUNC(opid_ptr->func_leave_cb), opid_ptr   \
  );                                                    \
  GUISetWidgetTip((_w_), opid_ptr->tooltip);            \
} }

	    /* Get stats of the mount path */
	    stat_status = !STRISEMPTY(dev->mount_path) ?
		stat(dev->mount_path, &stat_buf) : -1;


	    /* Hbox for multiple columns */
	    zt->display_child = w = gtk_hbox_new(TRUE, 0);
	    gtk_container_border_width(GTK_CONTAINER(w), border_major);
	    gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
	    gtk_widget_show(w);
	    parent = w;

	    /* Left side column vbox */
	    w = gtk_vbox_new(FALSE, border_major);
	    gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent2 = w;

	    /* Hbox for device icon and label */
	    w = gtk_hbox_new(FALSE, border_major);
	    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent3 = w;
 
	    /* Get pixmap and mask to display device icon */
	    if(EDV_DEVICE_IS_MOUNTED(dev) &&
	       (EDV_DEVICE_TOTAL_ICON_STATES > EDV_DEVICE_ICON_STATE_STANDARD)
	    )
	    {
		edv_device_icon_state i = EDV_DEVICE_ICON_STATE_STANDARD;
		pixmap = GDK_PIXMAP_NEW_FROM_XPM_FILE(
		    &mask, dev->large_icon_file[i]
		);
		if(pixmap == NULL)
		    pixmap = GDK_PIXMAP_NEW_FROM_XPM_FILE(
			&mask, dev->medium_icon_file[i]
		    );
		if(pixmap == NULL)
		    pixmap = GDK_PIXMAP_NEW_FROM_XPM_FILE(
			&mask, dev->small_icon_file[i]
		    );
	    }
	    else if(EDV_DEVICE_TOTAL_ICON_STATES > EDV_DEVICE_ICON_STATE_UNMOUNTED)
	    {
		edv_device_icon_state i = EDV_DEVICE_ICON_STATE_UNMOUNTED;
		pixmap = GDK_PIXMAP_NEW_FROM_XPM_FILE(
		    &mask, dev->large_icon_file[i]
		);
		if(pixmap == NULL)
		    pixmap = GDK_PIXMAP_NEW_FROM_XPM_FILE(
			&mask, dev->medium_icon_file[i]
		    );
		if(pixmap == NULL)
		    pixmap = GDK_PIXMAP_NEW_FROM_XPM_FILE(
			&mask, dev->small_icon_file[i]
		    );
		i = EDV_DEVICE_ICON_STATE_STANDARD;
		if(pixmap == NULL)
		    pixmap = GDK_PIXMAP_NEW_FROM_XPM_FILE(
			&mask, dev->large_icon_file[i]
		    );
		if(pixmap == NULL)
		    pixmap = GDK_PIXMAP_NEW_FROM_XPM_FILE(
			&mask, dev->medium_icon_file[i]
		    );
		if(pixmap == NULL)
		    pixmap = GDK_PIXMAP_NEW_FROM_XPM_FILE(
			&mask, dev->small_icon_file[i]
		    );
	    }
	    if(pixmap != NULL)
	    {
		w = gtk_pixmap_new(pixmap, mask);
		gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
		gtk_widget_show(w);
	    }
	    /* Vbox for name and location labels */
	    w = gtk_vbox_new(TRUE, 0);
	    gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent4 = w;
	    /* Device Name Label */
	    rcstyle = gtk_rc_style_new();
	    rcstyle->font_name = STRDUP( 
"-adobe-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1"
	    );
	    if(!STRISEMPTY(dev->name))
		buf = STRDUP(dev->name);
	    else
		buf = STRDUP("Untitled");
	    w = gtk_label_new(buf);
	    g_free(buf);
	    gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	    gtk_widget_modify_style(w, rcstyle);                     
	    gtk_widget_show(w);
	    GTK_RC_STYLE_UNREF(rcstyle)

	    /* Device Path Label */
	    if(!STRISEMPTY(dev->device_path))
		buf = EDVShortenPath(dev->device_path, 35);
	    else
		buf = STRDUP("*path not set*");
	    w = gtk_label_new(buf);
	    g_free(buf);
	    gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);

	    /* Mount Path Button */
	    if(!STRISEMPTY(dev->mount_path))
	    {
		/* Hbox */
		w = gtk_hbox_new(TRUE, 0); 
		gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
		gtk_widget_show(w);
		parent3 = w;
		/* Button */
		buf2 = EDVShortenPath(dev->mount_path, 35);
		buf = g_strdup_printf(
"Mount Path: %s",
		    buf2
		);
		zt->display_mount_path_btn = w = GUIButtonPixmapLabelH(
		    (guint8 **)icon_browse_20x20_xpm, buf, NULL
		);
		g_free(buf);
		g_free(buf2);
		gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
		SET_FLAT_BUTTON_STYLE(w)
		SET_BUTTON_CB(w, ZIP_TOOL_OPID_BROWSE)
		gtk_widget_show(w);
	    }

	    /* Usage Pie Chart */
	    if(EDV_DEVICE_IS_MOUNTED(dev))
	    {
		gchar *ss_kb, *ss_mb;

		adj = (GtkAdjustment *)gtk_adjustment_new(
		    0.0f, 0.0f,
		    (gfloat)(dev->blocks_total / adj_division),
		    0.0f, 0.0f, 0.0f
		);
		GDK_COLOR_SET_COEFF(&c, 0.0f, 0.0f, 1.0f)
		ss_kb = STRDUP(
		    EDVSizeStrDelim(dev->blocks_total)
		);
		ss_mb = STRDUP(
		    EDVSizeStrDelim(dev->blocks_total / 1000)
		);
		buf = g_strdup_printf(
		    "%s: %s kb (%s mb)",
#ifdef PROG_LANGUAGE_ENGLISH
"Total Capacity"
#endif
#ifdef PROG_LANGUAGE_SPANISH
"La Capacidad Total"
#endif
#ifdef PROG_LANGUAGE_FRENCH
"Capacité Totale"
#endif
		    , ss_kb, ss_mb
		);
		g_free(ss_kb);
		g_free(ss_mb);

		ss_kb = STRDUP(
		    EDVSizeStrDelim(dev->blocks_free)
		);
		ss_mb = STRDUP(
		    EDVSizeStrDelim(dev->blocks_free / 1000)
		);
		buf2 = g_strdup_printf(
		    "%s kb (%s mb)",
		    ss_kb, ss_mb
		);
		g_free(ss_kb);
		g_free(ss_mb);

		zt->capacity_piechart = pc = PieChartNew(
		    adj, &c, 110, 70,
		    NULL, buf,
#ifdef PROG_LANGUAGE_ENGLISH
"Free"
#endif
#ifdef PROG_LANGUAGE_SPANISH
"Libre"
#endif
#ifdef PROG_LANGUAGE_FRENCH
"Libre"
#endif
		    ":", buf2
		);
		gtk_object_unref(GTK_OBJECT(adj));
		g_free(buf);
		g_free(buf2);
		w = pc->toplevel;
		gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
		gtk_widget_show(w);

		GDK_COLOR_SET_COEFF(&c, 0.0f, 1.0f, 1.0f)
		adj = (GtkAdjustment *)gtk_adjustment_new(
		    0.0f, 0.0f,
		    (gfloat)(dev->blocks_available / adj_division),
		    0.0f, 0.0f, 0.0f
		);
		ss_kb = STRDUP(
		    EDVSizeStrDelim(dev->blocks_available)
		);
		ss_mb = STRDUP(
		    EDVSizeStrDelim(dev->blocks_available / 1000)
		);
		buf = g_strdup_printf(
		    "%s kb (%s mb)",
		    ss_kb, ss_mb
		);
		g_free(ss_kb);
		g_free(ss_mb);
		PieChartValueAdd(
		    pc, adj, &c,
#ifdef PROG_LANGUAGE_ENGLISH
"Free & Available"
#endif
#ifdef PROG_LANGUAGE_SPANISH
"Libre & Disponible"
#endif
#ifdef PROG_LANGUAGE_FRENCH
"Libre & Disponible"
#endif
		    ":", buf
		);
		gtk_object_unref(GTK_OBJECT(adj));
		g_free(buf);

		GDK_COLOR_SET_COEFF(&c, 1.0f, 0.0f, 1.0f)
		adj = (GtkAdjustment *)gtk_adjustment_new(
		    0.0, 0.0,
		    (gfloat)(
			(dev->blocks_total - dev->blocks_free) /
			    adj_division
		    ),
		    0.0f, 0.0f, 0.0f
		);
		ss_kb = STRDUP(
		    EDVSizeStrDelim(
			dev->blocks_total - dev->blocks_free
		    )
		);
		ss_mb = STRDUP(
		    EDVSizeStrDelim(
			(dev->blocks_total - dev->blocks_free) / 1000
		    )
		);
		buf = g_strdup_printf(
		    "%s kb (%s mb)",
		    ss_kb, ss_mb
		);
		g_free(ss_kb);                      
		g_free(ss_mb); 
		PieChartValueAdd(
		    pc, adj, &c,
#ifdef PROG_LANGUAGE_ENGLISH
"Used"
#endif
#ifdef PROG_LANGUAGE_SPANISH
"Usado"
#endif
#ifdef PROG_LANGUAGE_FRENCH
"Utilisé"
#endif
		    ":", buf
		);
		gtk_object_unref(GTK_OBJECT(adj));
		g_free(buf);
	    }

	    /* Right side column vbox */
	    w = gtk_vbox_new(FALSE, border_minor);
	    gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent2 = w;

#define ADD_LABEL(_pfx_,_val_)		{		\
 w = gtk_hbox_new(FALSE, border_major);			\
 gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);\
 gtk_widget_show(w);					\
 parent3 = w;						\
 w = gtk_alignment_new(1.0f, 0.5f, 0.0f, 0.0f);		\
 gtk_widget_set_usize(w, prefix_label_width, -1);	\
 gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);\
 gtk_widget_show(w);					\
 parent4 = w;						\
 w = gtk_label_new(_pfx_);				\
 gtk_container_add(GTK_CONTAINER(parent4), w);		\
 gtk_widget_show(w);					\
 w = gtk_label_new(_val_);				\
 gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);\
 gtk_widget_show(w);					\
}

	    /* Status Banner */
	    GDK_COLOR_SET_COEFF(&color_fg, 1.0f, 1.0f, 1.0f)
	    GDK_COLOR_SET_COEFF(&color_bg, 0.0f, 0.0f, 0.0f) 
	    w = GUIBannerCreate(
		"Status",
"-adobe-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1",
		color_fg, color_bg,
		GTK_JUSTIFY_CENTER,
		FALSE
	    );
	    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);

	    /* Hbox for mount or unmount button */
	    w = gtk_hbox_new(FALSE, border_minor);
	    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent3 = w;
	    /* Button */
	    if(EDV_DEVICE_IS_MOUNTED(dev))
	    {
		buf = g_strdup_printf(
		    "Mounted (%s)",
		    EDV_DEVICE_IS_READ_ONLY(dev) ? "Read Only" : "Read/Write"
		);
		zt->display_mount_btn = w = GUIButtonPixmapLabelH(
		    (guint8 **)icon_mounted_20x20_xpm,
		    buf,
		    NULL
		);
		g_free(buf);
		gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
		SET_FLAT_BUTTON_STYLE(w)
		SET_BUTTON_CB(w, ZIP_TOOL_OPID_UNMOUNT)
		gtk_widget_show(w);
	    }
	    else
	    {
		zt->display_mount_btn = w = GUIButtonPixmapLabelH(
		    (guint8 **)icon_not_mounted_20x20_xpm,
		    "Not Mounted",
		    NULL
		);
		gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
		SET_FLAT_BUTTON_STYLE(w)                                  
		SET_BUTTON_CB(w, ZIP_TOOL_OPID_MOUNT)
		gtk_widget_show(w);
	    }

	    /* Hbox for locked/unlocked button */
	    w = gtk_hbox_new(FALSE, border_minor);
	    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent3 = w;
	    /* Locked icon and label */
	    if(zt->lock_state != ZIP_TOOL_LOCK_STATE_UNLOCKED)
		w = GUIButtonPixmapLabelH(
		    (guint8 **)icon_secure_20x20_xpm,
		    (zt->lock_state == ZIP_TOOL_LOCK_STATE_LOCKED_PASSWORD) ?
			"Locked With Password" : "Write Protected",
		    NULL
		);
	    else
		w = GUIButtonPixmapLabelH(
		    (guint8 **)icon_insecure_20x20_xpm,
		    "Not Protected",
		    NULL
		);
	    zt->display_lock_btn = w;
	    gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	    SET_FLAT_BUTTON_STYLE(w)
	    SET_BUTTON_CB(w, ZIP_TOOL_OPID_PASSWORD)
	    gtk_widget_show(w);

	    /* Ownership widgets (only if mounted) */
	    if(EDV_DEVICE_IS_MOUNTED(dev))
	    {
		prefix_label_width = 70;

		/* Ownership Banner */
		GDK_COLOR_SET_COEFF(&color_fg, 1.0f, 1.0f, 1.0f)   
		GDK_COLOR_SET_COEFF(&color_bg, 0.0f, 0.0f, 0.0f)
		w = GUIBannerCreate(
		    "Ownership",
"-adobe-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1",
		    color_fg, color_bg,
		    GTK_JUSTIFY_CENTER,
		    FALSE
		);
		gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
		gtk_widget_show(w);

		/* Owner Label */
		buf = STRDUP(
		    stat_status ? "" :
		    EDVUIDGetNameFromUID(
			zt->uid, zt->total_uids,
			stat_buf.st_uid, NULL
		    )
		);
		ADD_LABEL("Owner:", buf)
		g_free(buf);

		/* Group Label */
		buf = STRDUP(
		    stat_status ? "" :
		    EDVGIDGetNameFromGID(
			zt->gid, zt->total_gids,
			stat_buf.st_gid, NULL
		    )
		);
		ADD_LABEL("Group:", buf)
		g_free(buf);

		/* Permissions Label */
		if(stat_status)
		{
		    buf = STRDUP("");
		}
		else
		{
		    const mode_t m = stat_buf.st_mode;
#if defined(S_IRUSR) && defined(S_IWUSR) && defined(S_IXUSR) && defined(S_IRGRP) && defined(S_IWGRP) && defined(S_IXGRP) && defined(S_IROTH) && defined(S_IWOTH) && defined(S_IXOTH) && defined(S_ISUID) && defined(S_ISGID) && defined(S_ISVTX)
		    buf = g_strdup_printf(
			"%c%c%c%c%c%c%c%c%c",
			(m & S_IRUSR) ? 'r' : '-',
			(m & S_IWUSR) ? 'w' : '-',
			(m & S_ISUID) ? 'S' :
			    ((m & S_IXUSR) ? 'x' : '-'),
			(m & S_IRGRP) ? 'r' : '-',
			(m & S_IWGRP) ? 'w' : '-',
			(m & S_ISGID) ? 'S' :
			    ((m & S_IXGRP) ? 'x' : '-'),
			(m & S_IROTH) ? 'r' : '-',
			(m & S_IWOTH) ? 'w' : '-',
			(m & S_ISVTX) ? 'S' :
			    ((m & S_IXOTH) ? 'x' : '-')
		    );
#else
		    buf = STRDUP("");
#endif
		}
		ADD_LABEL("Permissions:", buf)
		g_free(buf);
	    }

	    /* Details widgets (only if mounted) */
	    if(EDV_DEVICE_IS_MOUNTED(dev))
	    {
		prefix_label_width = 90;

		/* Details Banner */
		GDK_COLOR_SET_COEFF(&color_fg, 1.0f, 1.0f, 1.0f)
		GDK_COLOR_SET_COEFF(&color_bg, 0.0f, 0.0f, 0.0f)
		w = GUIBannerCreate(
		    "Details",
"-adobe-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1",
		    color_fg, color_bg,
		    GTK_JUSTIFY_CENTER,
		    FALSE
		);
		gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
		gtk_widget_show(w);

		/* Device Label */
		if(stat_status)
		    buf = STRDUP("");
		else  
		    buf = g_strdup_printf(
			"%ld",
			(gulong)stat_buf.st_dev
		    );
		ADD_LABEL("Device:", buf)
		g_free(buf);

		/* Filesystem Label */
		buf = STRDUP(
		    EDVDeviceGetFSNameFromType(dev->fs_type)
		);
		ADD_LABEL("Filesystem:", buf)   
		g_free(buf);

		/* IO Block Size Label */
		if(stat_status)
		    buf = STRDUP("");
		else
		    buf = g_strdup_printf(
			"%ld bytes",
			stat_buf.st_blksize
		    );
		ADD_LABEL("IO Block Size:", buf)
		g_free(buf);      
	    }


#undef SET_BUTTON_CB
#undef SET_FLAT_BUTTON_STYLE
#undef ADD_LABEL
	}

	gtk_widget_queue_resize(zt->toplevel);
}



/*
 *	Creates a new zip tools window.
 */
zip_tool_struct *ZipToolNew(edv_context_struct *ctx)
{
	gint border_minor = 2;
	GdkWindow *window;
	GtkWidget	*w, *parent, *parent2, *parent3,
			*main_vbox;
	GtkAccelGroup *accelgrp;
	toolbar_struct *toolbar;
	toolbar_item_struct **tb_item;
	gint total_tb_items;
	zip_tool_struct *zt = (zip_tool_struct *)g_malloc0(
	    sizeof(zip_tool_struct)
	);
	if(zt == NULL)
	    return(NULL);


	/* Reset values */
	zt->accelgrp = accelgrp = gtk_accel_group_new();
	zt->ctx = ctx;
	zt->busy_count = 0;
	zt->freeze_count = 0;
	zt->opid = ZipToolOPIDListNew(zt);
	zt->uid = EDVUIDGetSystem(&zt->total_uids);
	zt->gid = EDVGIDGetSystem(&zt->total_gids);
	zt->device = NULL;
	zt->lock_state = ZIP_TOOL_LOCK_STATE_UNLOCKED;

	/* Load cursors */
	zt->busy_cur = gdk_cursor_new(GDK_WATCH);
	zt->text_cur = gdk_cursor_new(GDK_XTERM);

	/* Toplevel */
	zt->toplevel = w = gtk_window_new(GTK_WINDOW_DIALOG);
	gtk_widget_set_usize(w, ZIP_TOOL_WIDTH, ZIP_TOOL_HEIGHT);
	gtk_window_set_title(GTK_WINDOW(w), PROG_NAME);
	gtk_window_set_wmclass(                        
	    GTK_WINDOW(w), "ziptool", PROG_NAME
	);
	gtk_widget_realize(w);
	window = w->window;
	if(window != NULL)
	{
	    gdk_window_set_decorations(
		window,
                GDK_DECOR_BORDER | GDK_DECOR_TITLE | GDK_DECOR_MENU |
                GDK_DECOR_MINIMIZE
	    );
	    gdk_window_set_functions(
		window,
		GDK_FUNC_MOVE | GDK_FUNC_MINIMIZE | GDK_FUNC_CLOSE
	    );
	    GUISetWMIcon(window, (guint8 **)icon_drive_zip_48x48_xpm);
	}
	gtk_signal_connect(
	    GTK_OBJECT(w), "delete_event",
	    GTK_SIGNAL_FUNC(ZipToolCloseCB), zt
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "destroy",
	    GTK_SIGNAL_FUNC(ZipToolDestroyCB), zt
	);
	gtk_container_border_width(GTK_CONTAINER(w), 0);
	gtk_window_add_accel_group(GTK_WINDOW(w), accelgrp);
	parent = w;

	/* Main vbox */
	zt->main_vbox = main_vbox = w = gtk_vbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(parent), w);
	gtk_widget_show(w);
	parent = w;


	/* Create Tool Bar Items list */
	total_tb_items = 0;
	tb_item = NULL;
#define DO_APPEND_BUTTON(_id_)	{			\
 zip_tool_opid_struct *opid = ZipToolOPIDListFind(	\
  zt->opid, (_id_)					\
 );							\
 if(opid != NULL) {					\
  ToolBarItemListAppend(				\
   &tb_item, &total_tb_items,				\
   ToolBarItemNew(					\
    TOOLBAR_ITEM_BUTTON, opid->button_name,		\
    opid->icon_data, opid->tooltip, opid->id,		\
    ZipToolOPIDCB, opid,				\
    ZipToolOPIDEnterCB, opid,				\
    ZipToolOPIDLeaveCB, opid				\
   )							\
  );							\
} }
#define DO_APPEND_SEPARATOR	{			\
  ToolBarItemListAppend(				\
   &tb_item, &total_tb_items,				\
   ToolBarItemNew(					\
    TOOLBAR_ITEM_SEPARATOR, NULL,			\
    NULL, NULL,						\
    0,							\
    NULL, NULL, NULL, NULL, NULL, NULL			\
   )							\
  );							\
}

	DO_APPEND_BUTTON(ZIP_TOOL_OPID_MOUNT)
	DO_APPEND_BUTTON(ZIP_TOOL_OPID_UNMOUNT)
	DO_APPEND_SEPARATOR
	DO_APPEND_BUTTON(ZIP_TOOL_OPID_SPIN_DOWN)
	DO_APPEND_BUTTON(ZIP_TOOL_OPID_EJECT)
	DO_APPEND_BUTTON(ZIP_TOOL_OPID_PASSWORD)
	DO_APPEND_SEPARATOR
	DO_APPEND_BUTTON(ZIP_TOOL_OPID_FSCK)
	DO_APPEND_SEPARATOR
	DO_APPEND_BUTTON(ZIP_TOOL_OPID_REFRESH)
	DO_APPEND_SEPARATOR
	DO_APPEND_BUTTON(ZIP_TOOL_OPID_CLOSE)

#undef DO_APPEND_BUTTON
#undef DO_APPEND_SEPARATOR

	/* Create tool bar */
	zt->tool_bar_handle = w = gtk_handle_box_new();
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent2 = w;

	zt->tool_bar = toolbar = ToolBarNew(
	    tb_item, total_tb_items, parent2,
	    TOOLBAR_DISPLAY_PICTURES_AND_TEXT,
	    TOOLBAR_RELIEF_NONE, FALSE
	);
	ToolBarMap(toolbar);

	/* Delete Tool Bar Items list */
	ToolBarItemListDeleteAll(&tb_item, &total_tb_items);


	/* Event box to hold display parent */
	zt->display_event_box = w = gtk_event_box_new();
	gtk_widget_add_events(
	    w,
	    GDK_EXPOSURE_MASK |
	    GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "expose_event",
	    GTK_SIGNAL_FUNC(ZipToolExposeEventCB), zt
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_press_event",
	    GTK_SIGNAL_FUNC(ZipToolButtonPressEventCB), zt
	);
	gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
	gtk_widget_realize(w);
	gtk_widget_show(w);
	parent2 = w;

	/* Set style for event box */
	if(TRUE)
	{
#if 0
	    const gchar *rcstr = "\n\
style \"ziptool-base-style\" { \n\
 bg[NORMAL] = \"#ffffc0\"\n\
 fg[NORMAL] = \"#000000\"\n\
}\n\
widget \"*ziptool-base\" style \"ziptool-base-style\"\n\
";
	    gtk_rc_parse_string(rcstr);

#endif
	}

	/* Display parent vbox */
	zt->display_parent = w = gtk_vbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_widget_show(w);
	parent2 = w;

	zt->display_child = NULL;
	zt->capacity_piechart = NULL;
	zt->display_mount_path_btn = NULL;
	zt->display_mount_btn = NULL;
	zt->display_lock_btn = NULL;



	/* Status bar frame */
	w = gtk_frame_new(NULL);
	gtk_widget_set_usize(w, -1, EDV_STATUS_BAR_HEIGHT);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_OUT);
	gtk_container_border_width(GTK_CONTAINER(w), 0);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent2 = w;

	/* Table in main frame */
	w = gtk_table_new(1, 1, FALSE);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_widget_show(w);
	parent2 = w;

	/* Frame for label */
	w = gtk_frame_new(NULL);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_IN);
	gtk_table_attach(
	    GTK_TABLE(parent2), w,
	    0, 1, 0, 1,
	    GTK_SHRINK | GTK_EXPAND | GTK_FILL,
	    GTK_SHRINK,
	    border_minor, border_minor
	);
	gtk_widget_show(w);
	parent3 = w;
	/* Hbox in frame for label */
	w = gtk_hbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(parent3), w);
	gtk_widget_show(w);
	parent3 = w;
	/* Label */
	zt->status_label = w = gtk_label_new("");
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, border_minor);
	gtk_widget_show(w);


	/* Display area right click menu */
	if(TRUE)
	{
#define DO_ADD_MENU_ITEM_LABEL(_id_,_ak_,_am_)	{	\
 zip_tool_opid_struct *opid = ZipToolOPIDListFind(	\
  zt->opid, (_id_)					\
 );							\
 if(opid != NULL) {					\
  w = GUIMenuItemCreate(				\
   menu, GUI_MENU_ITEM_TYPE_LABEL, accelgrp,		\
   opid->icon_data, opid->name,				\
   (_ak_), (_am_), NULL,				\
   zt, opid->func_cb					\
  );							\
  GUISetMenuItemCrossingCB(				\
   w,							\
   (gpointer)opid->func_enter_cb, opid,			\
   (gpointer)opid->func_leave_cb, opid			\
  );							\
} }
#define DO_ADD_MENU_SEP			{		\
 w = GUIMenuItemCreate(					\
  menu, GUI_MENU_ITEM_TYPE_SEPARATOR, NULL,		\
  NULL, NULL, 0, 0, NULL,				\
  NULL, NULL						\
 );							\
}

	    GtkWidget *menu = GUIMenuCreate();
	    GtkAccelGroup *accelgrp = NULL;

	    zt->menu = menu;

	    DO_ADD_MENU_ITEM_LABEL(ZIP_TOOL_OPID_MOUNT, 0, 0)
	    zt->mount_mi = w;
	    DO_ADD_MENU_ITEM_LABEL(ZIP_TOOL_OPID_UNMOUNT, 0, 0)
	    zt->unmount_mi = w;

	    DO_ADD_MENU_SEP

	    DO_ADD_MENU_ITEM_LABEL(ZIP_TOOL_OPID_SPIN_DOWN, 0, 0)
	    zt->spin_down_mi = w;
	    DO_ADD_MENU_ITEM_LABEL(ZIP_TOOL_OPID_EJECT, 0, 0)
	    zt->eject_mi = w;
	    DO_ADD_MENU_ITEM_LABEL(ZIP_TOOL_OPID_PASSWORD, 0, 0)
	    zt->password_mi = w;

	    DO_ADD_MENU_SEP

	    DO_ADD_MENU_ITEM_LABEL(ZIP_TOOL_OPID_FSCK, 0, 0)
	    zt->fsck_mi = w;

	    DO_ADD_MENU_SEP

	    DO_ADD_MENU_ITEM_LABEL(ZIP_TOOL_OPID_REFRESH, 0, 0)
	    zt->refresh_mi = w;

#undef DO_ADD_MENU_ITEM_LABEL
#undef DO_ADD_MENU_SEP
	}



	ZipToolUpdate(zt);

	return(zt);
}

/*
 *	Updates the Zip Tool Window's widgets to reflect current
 *	values.
 */
void ZipToolUpdate(zip_tool_struct *zt)
{
	gboolean sensitive;
	GtkWidget *w;
	toolbar_struct *tb;
	edv_device_struct *dev;

	if(zt == NULL)
	    return;

	tb = zt->tool_bar;
	dev = zt->device;

	/* Mount */
	sensitive = (dev != NULL) ? !EDV_DEVICE_IS_MOUNTED(dev) : TRUE;
	ToolBarItemSetSensitiveID(
	    tb, ZIP_TOOL_OPID_MOUNT, sensitive
	);
	GTK_WIDGET_SET_SENSITIVE(zt->mount_mi, sensitive)

	/* Unmount */
	sensitive = (dev != NULL) ? EDV_DEVICE_IS_MOUNTED(dev) : FALSE;
	ToolBarItemSetSensitiveID(
	    tb, ZIP_TOOL_OPID_UNMOUNT, sensitive
	);
	GTK_WIDGET_SET_SENSITIVE(zt->unmount_mi, sensitive)

	/* Eject */
	sensitive = (dev != NULL) ? !EDV_DEVICE_IS_MOUNTED(dev) : TRUE;
	ToolBarItemSetSensitiveID(
	    tb, ZIP_TOOL_OPID_EJECT, sensitive
	);
	GTK_WIDGET_SET_SENSITIVE(zt->eject_mi, sensitive)

	/* Lock/unlock */
	sensitive = (dev != NULL) ? !EDV_DEVICE_IS_MOUNTED(dev) : TRUE;
	ToolBarItemUpdateByID(
	    tb,
	    ZIP_TOOL_OPID_PASSWORD,
	    (zt->lock_state != ZIP_TOOL_LOCK_STATE_UNLOCKED) ?
		"Unlock" : "Lock",
	    NULL,
	    NULL
	);
	ToolBarItemSetSensitiveID(
	    tb, ZIP_TOOL_OPID_PASSWORD, sensitive
	);
	w = zt->password_mi,
	GUIMenuItemSetLabel(
	    w,
	    (zt->lock_state != ZIP_TOOL_LOCK_STATE_UNLOCKED) ?
		"Unlock" : "Lock"
	);
	GTK_WIDGET_SET_SENSITIVE(w, sensitive)

	/* FSCK */
	sensitive = (dev != NULL) ? !EDV_DEVICE_IS_MOUNTED(dev) : TRUE;
	ToolBarItemSetSensitiveID(
	    tb, ZIP_TOOL_OPID_FSCK, sensitive
	);
	GTK_WIDGET_SET_SENSITIVE(zt->fsck_mi, sensitive)
}

/*
 *	Sets the Zip Tool Window as busy or ready.
 */
void ZipToolSetBusy(zip_tool_struct *zt, gboolean is_busy)
{
	GdkCursor *cur;
	GdkWindow *window;
	GtkWidget *w = (zt != NULL) ? zt->toplevel : NULL;
	if(w == NULL)
	    return;

	if(is_busy)
	{
	    /* Increase busy count */
	    zt->busy_count++;

	    /* Already busy? */
	    if(zt->busy_count > 1)
		return;

	    cur = zt->busy_cur;
	}
	else
	{
	    /* Reduce busy count */
	    zt->busy_count--;
	    if(zt->busy_count < 0)
		zt->busy_count = 0;

	    /* Still busy? */
	    if(zt->busy_count > 0)
		return;

	    cur = NULL;
	}

	window = w->window;
	if(window != NULL)
	{
	    gdk_window_set_cursor(window, cur);
	    gdk_flush();
	}
}

/*
 *	Sets the Zip Tool Window status bar's message.
 */
void ZipToolStatusMessage(
	zip_tool_struct *zt, const gchar *mesg,
	gboolean allow_gtk_iteration

)
{
	GtkWidget *w = (zt != NULL) ? zt->status_label : NULL;
	if(w == NULL)
	    return;

	gtk_label_set_text(
	    GTK_LABEL(w), (mesg != NULL) ? mesg : ""
	);

	while((gtk_events_pending() > 0) && allow_gtk_iteration)
	    gtk_main_iteration();
}

/*
 *	Checks if the Zip Tool Window is mapped.
 */
gboolean ZipToolIsMapped(zip_tool_struct *zt)
{
	GtkWidget *w = (zt != NULL) ? zt->toplevel : NULL;
	return((w != NULL) ? GTK_WIDGET_MAPPED(w) : FALSE);
}

/*
 *      Maps the Zip Tool Window.
 */
void ZipToolMap(zip_tool_struct *zt)
{
	GtkWidget *w = (zt != NULL) ? zt->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_show_raise(w);
}

/*
 *	Unmaps the Zip Tool Window.
 */
void ZipToolUnmap(zip_tool_struct *zt)
{
	GtkWidget *w = (zt != NULL) ? zt->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_hide(w);
}

/*
 *	Deletes the Zip Tool Window.
 */
void ZipToolDelete(zip_tool_struct *zt)
{
	gint i;

	if(zt == NULL)
	    return;

	GTK_WIDGET_DESTROY(zt->menu)

	ToolBarDelete(zt->tool_bar);
	GTK_WIDGET_DESTROY(zt->tool_bar_handle)

	GTK_WIDGET_DESTROY(zt->status_label)

	PieChartDelete(zt->capacity_piechart);
	GTK_WIDGET_DESTROY(zt->display_mount_path_btn)
	GTK_WIDGET_DESTROY(zt->display_mount_btn)
	GTK_WIDGET_DESTROY(zt->display_lock_btn)

	GTK_WIDGET_DESTROY(zt->display_child)
	GTK_WIDGET_DESTROY(zt->display_parent)
	GTK_WIDGET_DESTROY(zt->display_event_box)

	GTK_WIDGET_DESTROY(zt->main_vbox)
	GTK_WIDGET_DESTROY(zt->toplevel)

	GTK_ACCEL_GROUP_UNREF(zt->accelgrp)

	ZipToolOPIDListDelete(zt->opid);

	GDK_CURSOR_DESTROY(zt->busy_cur)
	GDK_CURSOR_DESTROY(zt->text_cur)

	EDVDeviceDelete(zt->device);

	for(i = 0; i < zt->total_uids; i++)
	    EDVUIDDelete(zt->uid[i]);
	g_free(zt->uid);
	for(i = 0; i < zt->total_gids; i++)
	    EDVGIDDelete(zt->gid[i]);
	g_free(zt->gid);

	g_free(zt);
}
