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

#include "guiutils.h"
#include "cdialog.h"
#include "pulist.h"

#include "edv_types.h"
#include "edv_obj.h"
#include "edv_device.h"
#include "edv_devices_list.h"
#include "edv_utils.h"
#include "edv_mount_bar.h"
#include "endeavour2.h"
#include "edv_device_mount.h"
#include "edv_cb.h"
#include "edv_op.h"
#include "edv_utils_gtk.h"
#include "config.h"

#include "images/icon_mount_20x20.xpm"
#include "images/icon_unmount_20x20.xpm"
#include "images/icon_eject_20x20.xpm"
#include "images/icon_reload_20x20.xpm"
#include "images/icon_folder_drive_20x20.xpm"
#include "images/icon_properties2_20x20.xpm"
#include "images/icon_fsck_20x20.xpm"
#include "images/icon_tools_20x20.xpm"
#include "images/icon_floppy_20x20.xpm"
#include "images/icon_devices_list_20x20.xpm"


/* Callbacks */
static gint EDVMountBarCrossingCB(
	GtkWidget *widget, GdkEventCrossing *crossing, gpointer data
);
static gint EDVMountBarDeviceEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
);
static gint EDVMountBarStatsEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
);
static void EDVMountBarMapPUListCB(GtkWidget *widget, gpointer data);
static void EDVMountBarMountCB(GtkWidget *widget, gpointer data);
static void EDVMountBarEjectCB(GtkWidget *widget, gpointer data);
static void EDVMountBarGoToCB(GtkWidget *widget, gpointer data);
static void EDVMountBarPropertiesCB(GtkWidget *widget, gpointer data);
static void EDVMountBarFSCKCB(GtkWidget *widget, gpointer data);
static void EDVMountBarToolsCB(GtkWidget *widget, gpointer data);
static void EDVMountBarFormatCB(GtkWidget *widget, gpointer data);
static void EDVMountBarDevicesListCB(GtkWidget *widget, gpointer data);
static void EDVMountBarRefreshStatsCB(GtkWidget *widget, gpointer data);

/* Device Drawing */
static void EDVMountBarDeviceDraw(edv_mount_bar_struct *mb);

/* Stats Drawing & Setting */
static void EDVMountBarStatsDraw(edv_mount_bar_struct *mb);
static void EDVMountBarSetStats(edv_mount_bar_struct *mb);

/* Mount Bar */
edv_mount_bar_struct *EDVMountBarNew(
	edv_core_struct *core,
	GtkWidget *parent,
	void (*mount_cb)(
		edv_mount_bar_struct *, gint, edv_device_struct *,
		gpointer
	),
	void (*eject_cb)(
		edv_mount_bar_struct *, gint, edv_device_struct *,
		gpointer
	),
	void (*goto_cb)(
		edv_mount_bar_struct *, gint, edv_device_struct *,
		gpointer
	),
	void (*status_message_cb)(const gchar *, gpointer),
	gpointer data
);
void EDVMountBarUpdateMenus(edv_mount_bar_struct *mb);
void EDVMountBarMap(edv_mount_bar_struct *mb);
void EDVMountBarUnmap(edv_mount_bar_struct *mb);
void EDVMountBarDelete(edv_mount_bar_struct *mb);


#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)


/*
 *	Mount Bar any GtkWidget "enter_notify_event" or
 *	"leave_notify_event" signal callback.
 */
static gint EDVMountBarCrossingCB(
	GtkWidget *widget, GdkEventCrossing *crossing, gpointer data
)
{
	gint status = FALSE;
	const gchar *mesg = NULL;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if((widget == NULL) || (crossing == NULL) || (mb == NULL))
	    return(status);

	if(crossing->type == GDK_ENTER_NOTIFY)
	{
	    if(mb->mount_btn == widget)
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Mount/unmount dispositivo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Monter/Démonter un composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Mount/unmount vorrichtung"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Mount/unmount congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Mount/unmount apparaat"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mount/unmount artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Mount/unmount innretning"
#else
"Mount/unmount the device"
#endif
		;
	    else if(mb->eject_btn == widget)
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Expulse medios del dispositivo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Ejecter le support du composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Werfen sie medien von vorrichtung aus"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Espellere la stampa dal congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Stoot media van apparaat uit"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Expulse imprensa de artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kast ut medier fra innretning"
#else
"Eject the media from the device"
#endif
		;
	    else if(mb->refresh_btn == widget)
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Refresque toda estadística de dispositivo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Rafraîchir toutes les statistique composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Erfrischen sie alle gerätestatistik"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Rinfrescare tutto la statistica di congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Verfris alle apparaat statistieken"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Refresque-se toda estatística de artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Forfrisk all innretnings statistikk"
#else
"Refresh all device statistics"
#endif
		;
	    else if(mb->goto_btn == widget)
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Vaya a montar sendero"
#elif defined(PROG_LANGUAGE_FRENCH)
"Aller au répertoire monté"
#elif defined(PROG_LANGUAGE_GERMAN)
"Gehen sie, um pfad aufzustellen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Andare montare il sentiero"
#elif defined(PROG_LANGUAGE_DUTCH)
"Ga om pad te bestijgen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Vá montar caminho"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Dra montere sti"
#else
"Go to the mount path"
#endif
		;
	    else if(mb->properties_btn == widget)
		mesg =
"Modify the properties of the mount path"
		;
	    else if(mb->fsck_btn == widget)
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Verifique el sistema del archivo de dispositivo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Vérifier le système de fichier du composan"
#elif defined(PROG_LANGUAGE_GERMAN)
"Prüfen sie das dateisystem der vorrichtung"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Controllare il sistema di file del congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Controleer het dossier van het apparaat systeem"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Verifique o sistema de arquivo do artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Sjekk innretningens arkivsystem"
#else
"Check the device's file system"
#endif
		;
	    else if(mb->devices_list_btn == widget)
		mesg = "Devices list";
	    else if(mb->tools_btn == widget)
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Corra el programa de instrumentos de dispositivo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Lancer le panneau d'outil du composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laufen sie die werkzeuge der vorrichtung programmieren"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Ha correto il programma di attrezzi del congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Loop de werktuigen van het apparaat programma"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Corra o programa de ferramentas do artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kjør innretningens redskapprogram"
#else
"Run the device's tools program"
#endif
		;
	    else if(mb->format_btn == widget)
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Formatear los medios en el dispositivo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Formatter le support dans le composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Formatieren sie die medien in der vorrichtung"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Il formato la stampa nel congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Formatteer de media in het apparaat"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O formato a imprensa no artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Formater mediene i innretningen"
#else
"Format the media in the device"
#endif
		;
	    else if(mb->stats_da == widget)
	    { /* Ignore */ }
	}

	if(mb->status_message_cb != NULL)
	    mb->status_message_cb(
		mesg,			/* Message */
		mb->data		/* Data */
	    );

	return(status);
}

/*
 *	Mount Bar device GtkDrawingArea event signal callback.
 */
static gint EDVMountBarDeviceEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
)
{
	gint status = FALSE;
	guint keyval, state;
	gboolean press;
	GdkEventFocus *focus;
	GdkEventKey *key;
	GdkEventButton *button;
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if((widget == NULL) || (event == NULL) || (mb == NULL))
	    return(status);

	core = mb->core;
	if(core == NULL)
	    return(status);

	switch((gint)event->type)
	{
	  case GDK_EXPOSE:
	    EDVMountBarDeviceDraw(mb);
	    status = TRUE;
	    break;

	  case GDK_FOCUS_CHANGE:
	    focus = (GdkEventFocus *)event;
	    if(focus->in && !GTK_WIDGET_HAS_FOCUS(widget))
	    {
	        GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
	        gtk_widget_queue_draw(widget);
	        status = TRUE;
	    }
	    else if(!focus->in && GTK_WIDGET_HAS_FOCUS(widget))
	    {   
	        GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
	        gtk_widget_queue_draw(widget);
	        status = TRUE;
	    }
	    break;

	  case GDK_KEY_PRESS:
	  case GDK_KEY_RELEASE:
	    key = (GdkEventKey *)event;
	    press = (key->type == GDK_KEY_PRESS) ? TRUE : FALSE;
 	    keyval = key->keyval;
	    state = key->state;
#define DO_STOP_KEY_SIGNAL_EMIT	{		\
 gtk_signal_emit_stop_by_name(			\
  GTK_OBJECT(widget),				\
  press ?					\
   "key_press_event" : "key_release_event"	\
 );						\
}
	    /* Handle by key value */
	    switch(keyval)
	    {
	      case GDK_Return:
	      case GDK_KP_Enter:
	      case GDK_ISO_Enter:
	      case GDK_3270_Enter:
	      case GDK_space:
	      case GDK_KP_Space:
		if(press)
		{
		    EDVMountBarMountCB(NULL, mb);
		}
		DO_STOP_KEY_SIGNAL_EMIT
		status = TRUE;
		break;

	      case GDK_Up:
	      case GDK_KP_Up:
	      case GDK_Page_Up:
	      case GDK_KP_Page_Up:
		if(press)
		{
		    gint i = mb->selected_dev_num;
		    edv_device_struct *dev;

		    /* Current selection in bounds? */
		    if((i >= 0) && (i < core->total_devices))
		    {
			/* Check previous device and see if it is selectable.
			 * Iterate on to previous device if the current is
			 * not selectable.
			 */
			for(i--; i >= 0; i--)
			{
			    dev = core->device[i];
			    if(dev == NULL)
				continue;
			    if(EDV_DEVICE_IS_UNLISTED(dev))
				continue;
			    break;	/* This device is selectable */
			}
			/* Found a selectable device index? */
			if(i >= 0)
			    mb->selected_dev_num = i;
		    }
		    else
		    {
			/* Current selection is out of bounds, so select
			 * the first valid device
			 */
			for(i = 0; i < core->total_devices; i++)
			{
			    dev = core->device[i];
			    if(dev == NULL)
				continue;
			    if(EDV_DEVICE_IS_UNLISTED(dev))
				continue;

			    mb->selected_dev_num = i;
			}
		    }
		    EDVMountBarUpdateMenus(mb);
		}
		DO_STOP_KEY_SIGNAL_EMIT
		status = TRUE;
		break;

	      case GDK_Down:
	      case GDK_KP_Down:
	      case GDK_Page_Down:
	      case GDK_KP_Page_Down:
		if(press)
		{
		    gint i = mb->selected_dev_num;
		    edv_device_struct *dev;

		    /* Current selection in bounds? */
		    if((i >= 0) && (i < core->total_devices))
		    {
			/* Check next device and see if it is selectable.
			 * Iterate on to next device if the current is
			 * not selectable.
			 */
			for(i++; i < core->total_devices; i++)
			{
			    dev = core->device[i];
			    if(dev == NULL)
				continue;
			    if(EDV_DEVICE_IS_UNLISTED(dev))
				continue;
			    break;	/* This device is selectable */
			}
			/* Found a selectable device index? */
			if(i < core->total_devices)
			    mb->selected_dev_num = i;
		    }
		    else
		    {
			/* Current selection is out of bounds, so select
			 * the first valid device.
			 */
			for(i = 0; i < core->total_devices; i++)
			{
			    dev = core->device[i];
			    if(dev == NULL)
				continue;
			    if(EDV_DEVICE_IS_UNLISTED(dev))
				continue;

			    mb->selected_dev_num = i;
			}
		    }
		    EDVMountBarUpdateMenus(mb);
		}
		DO_STOP_KEY_SIGNAL_EMIT
		status = TRUE;
		break;

	      case GDK_Home:
		if(press)
		{
		    gint i;
		    edv_device_struct *dev;

		    /* Look for the first device that is selectable */
		    for(i = 0; i < core->total_devices; i++)
		    {
			dev = core->device[i];
			if(dev == NULL)
			    continue;
			if(EDV_DEVICE_IS_UNLISTED(dev))
			    continue;
			break;		/* This device is selectable */
		    }
		    /* Found a selectable device index? */
		    if(i < core->total_devices)
		    {
			mb->selected_dev_num = i;
			EDVMountBarUpdateMenus(mb);
		    }
		}
		DO_STOP_KEY_SIGNAL_EMIT
		status = TRUE;
		break;

	      case GDK_End:
		if(press)
		{
		    gint i;
		    edv_device_struct *dev;

		    /* Look for the last device that is selectable */
		    for(i = core->total_devices - 1; i >= 0; i--)
		    {
			dev = core->device[i];
			if(dev == NULL)
			    continue;
			if(EDV_DEVICE_IS_UNLISTED(dev))
			    continue;
			break;		/* This device is selectable */
		    }
		    /* Found a selectable device index? */
		    if(i >= 0)
		    {
			mb->selected_dev_num = i;
			EDVMountBarUpdateMenus(mb);
		    }
		}
		DO_STOP_KEY_SIGNAL_EMIT
		status = TRUE;
		break;
	    }
	    break;

	  case GDK_BUTTON_PRESS:
	    button = (GdkEventButton *)event;
	    if(!GTK_WIDGET_HAS_FOCUS(widget))
		gtk_widget_grab_focus(widget);
	    switch(button->button)
	    {
	      case 1:
		EDVMountBarMapPUListCB(mb->map_btn, mb);
		status = TRUE;
		break;
	    }
	    break;
	}

	return(status);
}

/*
 *	Mount Bar stats GtkDrawingArea event signal callback.
 */
static gint EDVMountBarStatsEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
)
{
	gint status = FALSE;
	GdkEventFocus *focus;
	GdkEventButton *button;
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if((widget == NULL) || (event == NULL) || (mb == NULL))
	    return(status);

	core = mb->core;
	if(core == NULL)
	    return(status);

	switch((gint)event->type)
	{
	  case GDK_EXPOSE:
	    EDVMountBarStatsDraw(mb);
	    status = TRUE;
	    break;

	  case GDK_FOCUS_CHANGE:
	    focus = (GdkEventFocus *)event;
	    if(focus->in && !GTK_WIDGET_HAS_FOCUS(widget))
	    {
	        GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
	        gtk_widget_queue_draw(widget);
	        status = TRUE;
	    }
	    else if(!focus->in && GTK_WIDGET_HAS_FOCUS(widget))
	    {   
	        GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
	        gtk_widget_queue_draw(widget);
	        status = TRUE;
	    }
	    break;

	  case GDK_BUTTON_PRESS:
	    button = (GdkEventButton *)event;
	    if(!GTK_WIDGET_HAS_FOCUS(widget))
		gtk_widget_grab_focus(widget);
	    switch(button->button)
	    {
	      case GDK_BUTTON1:
		if(button->state & GDK_SHIFT_MASK)
		{
		    mb->dev_stats_page--;
		    if(mb->dev_stats_page < 0)
			mb->dev_stats_page = 2;
		}
		else
		{
		    mb->dev_stats_page++;
		    if(mb->dev_stats_page >= 3)
			mb->dev_stats_page = 0;
		}
		EDVMountBarSetStats(mb);
		status = TRUE;
		break;
	    }
	    break;
	}

	return(status);
}

/*
 *	Map Devices Popup List callback.
 */
static void EDVMountBarMapPUListCB(GtkWidget *widget, gpointer data)
{
	gint dev_num, nitems, nitems_visible;
	const gchar *value;
	edv_device_struct *dev;
	pulist_struct *pulist;
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if(mb == NULL)
	    return;

	core = mb->core;
	pulist = (core != NULL) ? core->devices_pulist : NULL;
	if(pulist == NULL)
	    return;
	if(PUListIsQuery(pulist))
	    return;

	nitems = PUListGetTotalItems(pulist);
	nitems_visible = MIN(10, nitems);

	/* Block input and get value */
	value = PUListMapQuery(
	    pulist,
	    mb->dev_text,
	    nitems_visible,
	    PULIST_RELATIVE_BELOW,
	    mb->dev_da,			/* Relative widget */
	    widget			/* Map widget */
	);

	/* User canceled? */
	if(value == NULL)
	    return;

	gtk_widget_grab_focus(mb->dev_da);

	/* Get device index number from the selected value */
	dev_num = (gint)PUListGetDataFromValue(pulist, value);
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;

	/* Got valid device? */
	if(dev != NULL)
	{
	    /* Set new selected device on the mount bar structure */
	    mb->selected_dev_num = dev_num;

	    EDVMountBarUpdateMenus(mb);
	}
}

/*
 *	Mount/Unmount callback.
 */
static void EDVMountBarMountCB(GtkWidget *widget, gpointer data)
{
	gint dev_num;
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if(mb == NULL)
	    return;

	core = mb->core;
	if(core == NULL)
	    return;

	dev_num = mb->selected_dev_num;
	if((dev_num >= 0) && (dev_num < core->total_devices))
	{
	    edv_device_struct *dev = core->device[dev_num];
	    if((dev != NULL) && (mb->mount_cb != NULL))
		mb->mount_cb(
		    mb,			/* Mount Bar */
		    dev_num,		/* Device Number */
		    dev,		/* Device */
		    mb->data		/* Data */
		);
	}
}

/*
 *	Eject callback.
 */
static void EDVMountBarEjectCB(GtkWidget *widget, gpointer data)
{
	gint dev_num;
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if(mb == NULL)
	    return;

	core = mb->core;
	if(core == NULL)
	    return;

	dev_num = mb->selected_dev_num;
	if((dev_num >= 0) && (dev_num < core->total_devices))
	{
	    edv_device_struct *dev = core->device[dev_num];
	    if((dev != NULL) && (mb->eject_cb != NULL))
		mb->eject_cb(
		    mb,			/* Mount Bar */
		    dev_num,		/* Device Number */
		    dev,		/* Device */
		    mb->data		/* Data */
		);
	}
}

/*
 *	Go To Mount Path callback.
 */
static void EDVMountBarGoToCB(GtkWidget *widget, gpointer data)
{
	gint dev_num;
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if(mb == NULL)
	    return;

	core = mb->core;
	if(core == NULL)
	    return;

	dev_num = mb->selected_dev_num;
	if((dev_num >= 0) && (dev_num < core->total_devices))
	{
	    edv_device_struct *dev = core->device[dev_num];
	    if((dev != NULL) && (mb->goto_cb != NULL))
		mb->goto_cb(
		    mb,			/* Mount Bar */
		    dev_num,		/* Device Number */
		    dev,		/* Device */
		    mb->data		/* Data */
		);
	}
}

/*
 *	Properties callback.
 *
 *	Maps the Properties Dialog with the selected Device's mount
 *	path.
 */
static void EDVMountBarPropertiesCB(GtkWidget *widget, gpointer data)
{
	gint dev_num;
	const gchar *mount_path;
	struct stat lstat_buf;
	edv_object_struct *obj;
	edv_device_struct *dev;
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if(mb == NULL)
	    return;

	core = mb->core;
	if(core == NULL)  
	    return;

	/* Get the selected device */
	dev_num = mb->selected_dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;
	if(dev == NULL)
	    return;

	mount_path = dev->mount_path;
	if(STRISEMPTY(mount_path))
	    return;

	if(lstat(mount_path, &lstat_buf))
	    return;

	obj = EDVObjectNew();
	if(obj == NULL)
	    return;

	EDVObjectSetPath(obj, mount_path);
	EDVObjectSetStat(obj, &lstat_buf);
	EDVObjectUpdateLinkFlags(obj);

	EDVNewPropertiesDialogPage(
	    core, obj,
	    "Device",
	    gtk_widget_get_toplevel(mb->toplevel)
	); 

	EDVObjectDelete(obj);
}

/*
 *	FSCK callback.
 */
static void EDVMountBarFSCKCB(GtkWidget *widget, gpointer data)
{
	gint dev_num;
	edv_device_struct *dev;
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if(mb == NULL)
	    return;

	core = mb->core;
	if(core == NULL)
	    return;

	/* Get the selected device */
	dev_num = mb->selected_dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;
	if(dev == NULL)
	    return;

	/* Run the device check */
	EDVRunDeviceCheck(
	    core, dev, gtk_widget_get_toplevel(mb->toplevel)
	);
}

/*
 *	Tools callback.
 */
static void EDVMountBarToolsCB(GtkWidget *widget, gpointer data)
{
	gint dev_num;
	edv_device_struct *dev;
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if(mb == NULL)
	    return;

	core = mb->core;
	if(core == NULL)
	    return;

	/* Get the selected device */
	dev_num = mb->selected_dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;
	if(dev == NULL)  
	    return;

	/* Run the device tools */
	EDVRunDeviceTools(
	    core, dev, gtk_widget_get_toplevel(mb->toplevel)
	);
}

/*
 *	Format callback.
 */
static void EDVMountBarFormatCB(GtkWidget *widget, gpointer data)
{
	gint dev_num;
	edv_device_struct *dev;
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if(mb == NULL)
	    return;

	core = mb->core;
	if(core == NULL)
	    return;

	/* Get the selected device */
	dev_num = mb->selected_dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;
	if(dev == NULL)
	    return;

	/* Run the device format */
	EDVRunDeviceFormat(
	    core, dev, gtk_widget_get_toplevel(mb->toplevel)
	);
}

/*
 *	Devices list callback.
 */
static void EDVMountBarDevicesListCB(GtkWidget *widget, gpointer data)
{
        edv_core_struct *core;
        edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
        if(mb == NULL)
            return;

        core = mb->core;
        if(core == NULL)
            return;

	EDVMapDevicesListWin(core, gtk_widget_get_toplevel(mb->toplevel));
}


/*
 *	Refresh callback.
 *
 *	Updates the mount states and stats of all Devices and updates
 *	the selected Device's stats.
 */
static void EDVMountBarRefreshStatsCB(GtkWidget *widget, gpointer data)
{
	edv_core_struct *core;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(data);
	if(mb == NULL)
	    return;

	core = mb->core;
	if(core == NULL)
	    return;

	/* Refresh all device mount states and device stats, then get
	 * device path or mount path that matches the given disk
	 * object's path
	 */
	EDVDevicesListUpdateMountStates(
	    core->device, core->total_devices
	);
	EDVDevicesListUpdateStats(
	    core->device, core->total_devices
	);

	EDVMountBarUpdateMenus(mb);
}



/*
 *	Draws the Mount Bar's device GtkDrawingArea.
 */
static void EDVMountBarDeviceDraw(edv_mount_bar_struct *mb)
{
	const gint	border_minor = 2;
	gint	width, height, font_height,
		icon_width = 0, icon_height = 0;
	gboolean has_focus;
	GdkFont *font;
	GdkWindow *window;
	GdkDrawable *drawable;
	GdkGC *gc;
	GtkStateType state;
	GtkStyle *style;
	GtkWidget *w;

	if(mb == NULL)
	    return;

	w = mb->dev_da;
	if(w == NULL)
	    return;

	state = GTK_WIDGET_STATE(w);
	has_focus = GTK_WIDGET_HAS_FOCUS(w) ||
	    GTK_WIDGET_HAS_FOCUS(mb->map_btn);
	window = w->window;
	style = gtk_widget_get_style(w);
	if((window == NULL) || (style == NULL))
	    return;

	font = style->font;
	font_height = (font != NULL) ?
	    (font->ascent + font->descent) : 0;
	drawable = window;
	gdk_window_get_size(drawable, &width, &height);

	/* Create the mount bar graphic context as needed */
	gc = mb->gc;
	if(gc == NULL)
	    mb->gc = gc = GDK_GC_NEW();

	/* Draw the background */
	gdk_draw_rectangle(
	    drawable,
	    has_focus ?
		style->bg_gc[GTK_STATE_SELECTED] :
		style->base_gc[state],
	    TRUE,
	    0, 0, width, height
	);

	/* Draw the icon? */
	if(mb->dev_pixmap != NULL)
	{
	    gint	x = border_minor + border_minor,
			y;
	    GdkBitmap *mask = mb->dev_mask;
	    GdkPixmap *pixmap = mb->dev_pixmap;

	    gdk_window_get_size(pixmap, &icon_width, &icon_height);
	    y = (height - icon_height) / 2;

	    gdk_gc_set_clip_mask(gc, mask);
	    gdk_gc_set_clip_origin(gc, x, y);
	    gdk_draw_pixmap(
		drawable, gc, pixmap,
		0, 0,
		x, y,
		icon_width, icon_height
	    );
	    gdk_gc_set_clip_mask(gc, NULL);
	}

	/* Draw the label? */
	if(!STRISEMPTY(mb->dev_text) && (font != NULL))
	{
	    gint        x = border_minor + border_minor + icon_width +
			border_minor,
			y;
	    const gchar *s = mb->dev_text;
	    GdkTextBounds b;

	    gdk_string_bounds(font, s, &b);
	    y = (height - font_height) / 2;

	    gdk_draw_string(
		drawable, font,
		has_focus ?
		    style->text_gc[GTK_STATE_SELECTED] :
		    style->text_gc[state],
		x - b.lbearing,
		y + font->ascent,
		s
	    );
	}

	/* Draw focus if this widget is focused */
	if(has_focus && GTK_WIDGET_SENSITIVE(w))
	{
	    gdk_gc_set_function(gc, GDK_INVERT);
	    gdk_gc_set_foreground(gc, &style->fg[state]);
            gdk_draw_rectangle(
                drawable, gc, FALSE,
		0, 0, width - 1, height - 1
	    );
	    gdk_gc_set_function(gc, GDK_COPY);
	}

	/* Send drawable to window if drawable is not the window */
	if(drawable != window)
	    gdk_draw_pixmap(
		window, style->fg_gc[state], drawable,
		0, 0, 0, 0, width, height
	    );
}


/*
 *	Draws the Mount Bar's stats GtkDrawingArea.
 */
static void EDVMountBarStatsDraw(edv_mount_bar_struct *mb)
{
	const gint	border_minor = 2;
	gint x, y, width, height, font_height, dev_num;
	GdkFont *font;
	GdkWindow *window;
	GdkDrawable *drawable;
	GdkGC *gc;
	GtkStateType state;
	GtkStyle *style;
	GtkWidget *w;
	edv_device_struct *dev;
	edv_core_struct *core;

	if(mb == NULL)
	    return;

	w = mb->stats_da;
	core = mb->core;
	if((w == NULL) || (core == NULL))
	    return;

	state = GTK_WIDGET_STATE(w);
	window = w->window;
	style = gtk_widget_get_style(w);
	if((window == NULL) || (style == NULL))
	    return;

	font = style->font;
	font_height = (font != NULL) ?
	    (font->ascent + font->descent) : 0;
	drawable = window;
	gdk_window_get_size(drawable, &width, &height);

	/* Create the mount bar graphic context as needed */
	gc = mb->gc;
	if(gc == NULL)
	    mb->gc = gc = GDK_GC_NEW();

	/* Get the selected device */
	dev_num = mb->selected_dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;

	/* Draw the background */
	gdk_draw_rectangle(
	    drawable, style->base_gc[state], TRUE,
	    0, 0, width, height
	);

	/* Set the starting drawing coordinates */
	x = border_minor + border_minor;

	switch(mb->dev_stats_page)
	{
	  case 2:
	    /* Device Icon */
	    if(EDV_DEVICE_IS_MOUNTED(dev) && (mb->dev_pixmap != NULL))
	    {
		gint icon_width, icon_height;
		GdkBitmap *mask = mb->dev_mask;
		GdkPixmap *pixmap = mb->dev_pixmap;
		gdk_window_get_size(pixmap, &icon_width, &icon_height);
		y = (height - icon_height) / 2;
		gdk_gc_set_clip_mask(gc, mask);
		gdk_gc_set_clip_origin(gc, x, y);
		gdk_draw_pixmap(
		    drawable, gc, pixmap,
		    0, 0,
		    x, y,
		    icon_width, icon_height
		);
		gdk_gc_set_clip_mask(gc, NULL);
		x += icon_width + border_minor;
	    }
	    /* Label */
	    if(!STRISEMPTY(mb->dev_stats_label) && (font != NULL))
	    {
		const gchar *s = mb->dev_stats_label;
		GdkTextBounds b;
		gdk_string_bounds(font, s, &b);
		y = (height - font_height) / 2;
		gdk_draw_string(
		    drawable, font, style->text_gc[state],
		    x - b.lbearing,
		    y + font->ascent,
		    s
		);
		x += b.width + border_minor + border_minor;
	    }
	    break;
	  case 1:
	    /* Label */
	    if(!STRISEMPTY(mb->dev_stats_label) && (font != NULL))
	    {
		const gchar *s = mb->dev_stats_label;
		GdkTextBounds b;
		gdk_string_bounds(font, s, &b);
		y = (height - font_height) / 2;
		gdk_draw_string(
		    drawable, font, style->text_gc[state],
		    x - b.lbearing,
		    y + font->ascent,
		    s
		);
		x += b.width + border_minor + border_minor;
	    }
	    break;
	  default:
	    /* Used bar */
	    if(EDV_DEVICE_IS_MOUNTED(dev))
	    {
	        const gint	bar_width = 80,
				bar_height = MAX(
		    (gint)((height - (2 * border_minor)) * 0.60f), 4
				);
		const gint bar_used_width = (bar_width - 4)
		    * mb->dev_stats_used_coeff;

		y = (height - bar_height) / 2;
		if(bar_used_width > 0)
		    gdk_draw_rectangle(
			drawable, style->bg_gc[GTK_STATE_SELECTED], TRUE,
			x + 2, y + 2, bar_used_width, bar_height - 4
		    );
		gdk_draw_rectangle(
		    drawable, style->fg_gc[state], FALSE,
		    x, y, bar_width - 1, bar_height - 1
		);
		x += bar_width + border_minor + border_minor;
	    }
	    /* Label */
	    if(!STRISEMPTY(mb->dev_stats_label) && (font != NULL))
	    {
		const gchar *s = mb->dev_stats_label;
		GdkTextBounds b;
		gdk_string_bounds(font, s, &b);
		y = (height - font_height) / 2;
		gdk_draw_string(
		    drawable, font, style->text_gc[state],
		    x - b.lbearing,
		    y + font->ascent,
		    s
		);
		x += b.width + border_minor + border_minor;
	    }
	    break;
	}     


	/* Draw frame */
	gtk_draw_shadow(
	    style, drawable, state, GTK_SHADOW_IN,
	    0, 0, width - 1, height - 1
	);

	/* Draw focus if widget is focused */
	if(GTK_WIDGET_HAS_FOCUS(w) && GTK_WIDGET_SENSITIVE(w))
	    gtk_draw_focus(
		style, drawable,
		0, 0, width - 1, height - 1
	    );

	/* Send drawable to window if drawable is not the window */
	if(drawable != window)
	    gdk_draw_pixmap(
		window, style->fg_gc[state], drawable,
		0, 0, 0, 0, width, height
	    );
}

/*
 *	Updates the Mount Bar's stats with the selected device.
 */
static void EDVMountBarSetStats(edv_mount_bar_struct *mb)
{
	gint dev_num;
	edv_device_struct *dev;
	edv_core_struct *core;

	if(mb == NULL)
	    return;

	core = mb->core;
	if(core == NULL)
	    return;

	/* Get the selected device */
	dev_num = mb->selected_dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;

	/* Got selected device? */
	if(dev != NULL)
	{
	    const gulong	used = dev->blocks_total - dev->blocks_free,
				total = dev->blocks_total;

	    /* Update stats used coefficient */
	    mb->dev_stats_used_coeff = (total > 0l) ?
		CLIP(((gfloat)used / (gfloat)total), 0.0f, 1.0f) : 0.0f;

	    /* Update stats label */
	    if(EDV_DEVICE_IS_MOUNTED(dev))
	    {
		const gchar *fmt;
		gchar	*s_used = STRDUP(EDVGetObjectSizeStr(
			core, used
		)),
			*s_total = STRDUP(EDVGetObjectSizeStr(
			core, total
		)),
			*s_free_avail = STRDUP(EDVGetObjectSizeStr(
			core, dev->blocks_available
		)),
			*s_free = STRDUP(EDVGetObjectSizeStr(
			core, dev->blocks_free
		));

		switch(mb->dev_stats_page)
		{
		  case 2:
		    g_free(mb->dev_stats_label);
		    mb->dev_stats_label = g_strdup_printf(
			"%s   %s   %s",
			dev->mount_path,
			EDVDeviceGetFSNameFromType(dev->fs_type),
			EDV_DEVICE_IS_READ_ONLY(dev) ?
			    "(ro)" : "(rw)"
		    );
		    break;
		  case 1:
		    fmt = "Total: %s kb  \
Free & Available: %s kb  Free: %s kb";
		    g_free(mb->dev_stats_label);
		    mb->dev_stats_label = g_strdup_printf(
			fmt,
			s_total,
			s_free_avail,
			s_free
		    );
		    break;
		  default:
		    fmt = "%i%% of %s kb used";
		    g_free(mb->dev_stats_label);
		    mb->dev_stats_label = g_strdup_printf(
			fmt,
			(gint)(mb->dev_stats_used_coeff * 100.0f),
			s_total
		    );
		    break;
		}

		g_free(s_used);
		g_free(s_total);
		g_free(s_free_avail);
		g_free(s_free);
	    }
	    else
	    {
		const gchar *fmt;
#if defined(PROG_LANGUAGE_SPANISH)
		fmt = "El Artefacto \"%s\" No Montó";
#elif defined(PROG_LANGUAGE_FRENCH)
		fmt = "Composant \"%s\" Non Monté";
#else
		fmt = "Device \"%s\" Not Mounted";
#endif
		g_free(mb->dev_stats_label);
		mb->dev_stats_label = g_strdup_printf(
		    fmt,
		    !STRISEMPTY(dev->name) ? dev->name : "(Untitled)"
		);
	    }
	}
	else
	{
	    /* No device selected */
	    mb->dev_stats_used_coeff = 0.0f;
	    g_free(mb->dev_stats_label);
	    mb->dev_stats_label = NULL;
	}

	gtk_widget_queue_draw(mb->stats_da);
}


/*
 *	Create a new mount bar.
 */
edv_mount_bar_struct *EDVMountBarNew(
	edv_core_struct *core,
	GtkWidget *parent,
	void (*mount_cb)(
		edv_mount_bar_struct *, gint, edv_device_struct *,
		gpointer
	),
	void (*eject_cb)(
		edv_mount_bar_struct *, gint, edv_device_struct *,
		gpointer
	),
	void (*goto_cb)(
		edv_mount_bar_struct *, gint, edv_device_struct *,
		gpointer
	),
	void (*status_message_cb)(const gchar *, gpointer),
	gpointer data
)
{
	const gint border_minor = 2;
	GtkWidget *w, *parent2, *parent3;
	edv_mount_bar_struct *mb = EDV_MOUNT_BAR(
	    g_malloc0(sizeof(edv_mount_bar_struct))
	);
	if((mb == NULL) || (core == NULL))
	{
	    g_free(mb);
	    return(NULL);
	}

	mb->gc = NULL;
	mb->busy_count = 0;
	mb->freeze_count = 0;
	mb->core = core;
	mb->selected_dev_num = 0;
	mb->dev_text = NULL;
	mb->dev_pixmap = NULL;
	mb->dev_mask = NULL;
	mb->dev_stats_page = 0;
	mb->dev_stats_used_coeff = 0.0f;
	mb->dev_stats_label = NULL;
	mb->mount_cb = mount_cb;
	mb->eject_cb = eject_cb;
	mb->goto_cb = goto_cb;
	mb->status_message_cb = status_message_cb;
	mb->data = data;


	/* Set first device from the core structure as the initially
	 * selected device. This first device is not always device
	 * index 0, but rather the first one that is not marked as
	 * unlisted
	 */
	if(core != NULL)
	{
	    gint i;
	    edv_device_struct *dev;

	    for(i = 0; i < core->total_devices; i++)
	    {
		dev = core->device[i];
		if(dev == NULL)
		    continue;
		if(EDV_DEVICE_IS_UNLISTED(dev))
		    continue;

		mb->selected_dev_num = i;
		break;
	    }
	}

	/* Create toplevel */
	mb->toplevel = w = gtk_hbox_new(FALSE, border_minor);
	gtk_container_border_width(GTK_CONTAINER(w), border_minor);
	gtk_container_add(GTK_CONTAINER(parent), w);
	parent = w;


	/* GtkHbox for the devices list */
	w = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent2 = w;

	/* Device GtkFrame */
	w = gtk_frame_new(NULL);
	gtk_widget_set_usize(w, 180, 20 + (2 * border_minor));
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_IN);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;
	/* Device GtkDrawingArea */
	mb->dev_da = w = gtk_drawing_area_new();
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_FOCUS);
	gtk_widget_add_events(
	    w,
	    GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK |
	    GDK_FOCUS_CHANGE_MASK |
	    GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
	    GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "expose_event",
	    GTK_SIGNAL_FUNC(EDVMountBarDeviceEventCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "focus_in_event",
	    GTK_SIGNAL_FUNC(EDVMountBarDeviceEventCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "focus_out_event",
	    GTK_SIGNAL_FUNC(EDVMountBarDeviceEventCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "key_press_event",
	    GTK_SIGNAL_FUNC(EDVMountBarDeviceEventCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "key_release_event",
	    GTK_SIGNAL_FUNC(EDVMountBarDeviceEventCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_press_event",
	    GTK_SIGNAL_FUNC(EDVMountBarDeviceEventCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_release_event",
	    GTK_SIGNAL_FUNC(EDVMountBarDeviceEventCB), mb
	);
	gtk_container_add(GTK_CONTAINER(parent3), w);
	gtk_widget_show(w);

	/* Popup list map button */
	mb->map_btn = w = PUListNewMapButtonArrow(
	    GTK_ARROW_DOWN, GTK_SHADOW_OUT,
	    EDVMountBarMapPUListCB, mb
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);



	/* Mount/unmount button */
	mb->mount_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_mount_20x20_xpm
	);
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVMountBarMountCB), mb
	);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
	    "El monte/artefacto de unmount"
#elif defined(PROG_LANGUAGE_FRENCH)
	    "Monte/démonte le composant"
#else
	    "Mount/unmount the device"
#endif
	);
	gtk_widget_show(w);

	/* Eject button */
	mb->eject_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_eject_20x20_xpm
	);
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVMountBarEjectCB), mb
	);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
	    "Expulse medios del artefacto"
#elif defined(PROG_LANGUAGE_FRENCH)
	    "Ejecter le support du composant"
#else
	    "Eject the media from the device"
#endif
	);
	gtk_widget_show(w);

	/* Refresh button */
	mb->refresh_btn = w = GUIButtonPixmap( 
	    (guint8 **)icon_reload_20x20_xpm
	);
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVMountBarRefreshStatsCB), mb
	);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
	    "Refresque toda estadística de artefacto"
#elif defined(PROG_LANGUAGE_FRENCH)
	    "Rafraîchir toute statistique composant"
#else
	    "Refresh all device statistics"
#endif
	);
	gtk_widget_show(w);

	/* Separator */
	w = gtk_vseparator_new();
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* Go To Mount Path button */
	mb->goto_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_folder_drive_20x20_xpm
	);
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVMountBarGoToCB), mb
	);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
	    "Vaya a montar sendero"
#elif defined(PROG_LANGUAGE_FRENCH)
	    "Aller au point de montage"
#else
	    "Go to the mount path"
#endif
	);
	gtk_widget_show(w);

	/* Properties button */
	mb->properties_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_properties2_20x20_xpm
	);
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVMountBarPropertiesCB), mb
	);
	GUISetWidgetTip(
	    w,
	    "Modify the properties of the mount path"
	);
	gtk_widget_show(w);

	/* Separator */
	w = gtk_vseparator_new();
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* Devices List button */
	mb->devices_list_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_devices_list_20x20_xpm
	);
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVMountBarDevicesListCB), mb
	);
	GUISetWidgetTip(
	    w, "Devices list"
	);
	gtk_widget_show(w);

	/* Separator */
	w = gtk_vseparator_new();
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* FSCK button */
	mb->fsck_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_fsck_20x20_xpm
	);
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVMountBarFSCKCB), mb
	);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
"Verifique el sistema del archivo de dispositivo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Vérifier le système de fichier du composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Prüfen sie das dateisystem der vorrichtung"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Controllare il sistema di file del congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Controleer het dossier van het apparaat systeem"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Verifique o sistema de arquivo do artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Sjekk innretningens arkivsystem"
#else
"Check the device's file system"
#endif
	);
	gtk_widget_show(w);

	/* Tools button */
	mb->tools_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_tools_20x20_xpm
	);
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVMountBarToolsCB), mb
	);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
"Corra el programa de instrumentos de dispositivo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Lancer le panneau de contrôle du composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laufen sie die werkzeuge der vorrichtung programmieren"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Ha correto il programma di attrezzi del congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Loop de werktuigen van het apparaat programma"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Corra o programa de ferramentas do artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kjør innretningens redskapprogram"
#else
"Run the device's tools program"
#endif
	);
	gtk_widget_show(w);

	/* Format button */
	mb->format_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_floppy_20x20_xpm
	);
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVMountBarCrossingCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVMountBarFormatCB), mb
	);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
"Formatear los medios en el dispositivo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Formatte le support dans le composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Formatieren sie die medien in der vorrichtung"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Il formato la stampa nel congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Formatteer de media in het apparaat"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O formato a imprensa no artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Formater mediene i innretningen"
#else
"Format the media in the device"
#endif
	);
	gtk_widget_show(w);


	/* Stats GtkDrawingArea */
	mb->stats_da = w = gtk_drawing_area_new();
	gtk_widget_set_usize(w, -1, 20 + (2 * border_minor));
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_FOCUS);
	gtk_widget_add_events(
	    w,
	    GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK |
	    GDK_FOCUS_CHANGE_MASK |
	    GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
	    GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "expose_event",
	    GTK_SIGNAL_FUNC(EDVMountBarStatsEventCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "focus_in_event",
	    GTK_SIGNAL_FUNC(EDVMountBarStatsEventCB), mb
	);
	gtk_signal_connect(  
	    GTK_OBJECT(w), "focus_out_event",
	    GTK_SIGNAL_FUNC(EDVMountBarStatsEventCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_press_event",
	    GTK_SIGNAL_FUNC(EDVMountBarStatsEventCB), mb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_release_event",
	    GTK_SIGNAL_FUNC(EDVMountBarStatsEventCB), mb
	);
	gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
	gtk_widget_show(w);


	EDVMountBarUpdateMenus(mb);

	return(mb);
}


/*
 *	Updates the Mount Bar's widgets to reflect current values.
 */
void EDVMountBarUpdateMenus(edv_mount_bar_struct *mb)
{
	gint dev_num;
	edv_device_struct *dev;
	edv_core_struct *core;

	if(mb == NULL)
	    return;

	core = mb->core;
	if(core == NULL)
	    return;

	/* Get selected device index number and pointer (if any) */
	dev_num = mb->selected_dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;

	/* Update device icon */
	if(dev != NULL)
	{
	    edv_device_icon_state i;
	    GdkPixmap *pixmap = NULL;
	    GdkBitmap *mask = NULL;

	    EDVDeviceRealize(dev, FALSE);

	    /* Get device icon pixmap and mask pair from selected
	     * device
	     */
	    for(i = 0; i < EDV_DEVICE_TOTAL_ICON_STATES; i++)
	    {
		pixmap = dev->small_pixmap[i];
		mask = dev->small_mask[i];
		if(pixmap != NULL)
		    break;
	    }
	    /* Got device icon pixmap and mask pair? */
	    if(pixmap != NULL)
	    {
		GdkPixmap *old_pixmap = mb->dev_pixmap;
		GdkBitmap *old_mask = mb->dev_mask;

		GDK_PIXMAP_REF(pixmap);
		GDK_BITMAP_REF(mask);
		mb->dev_pixmap = pixmap;
		mb->dev_mask = mask;

		GDK_PIXMAP_UNREF(old_pixmap);
		GDK_BITMAP_UNREF(old_mask);
	    }
	}

	/* Update the device label */
	if(dev != NULL)
	{
	    const gchar *s = dev->name;
	    if((s == NULL) && (dev->device_path != NULL))
		s = g_basename(dev->device_path);
	    if(s == NULL)
		s = "(null)";

	    g_free(mb->dev_text);
	    mb->dev_text = STRDUP(s);
	}

	GUIButtonPixmapUpdate(
	    mb->mount_btn,
	    (guint8 **)(
		EDV_DEVICE_IS_MOUNTED(dev) ?
		icon_unmount_20x20_xpm : icon_mount_20x20_xpm
	    ),
	    NULL
	);
	GTK_WIDGET_SET_SENSITIVE(
	    mb->mount_btn,
	    (dev != NULL) ? !EDV_DEVICE_IS_NO_UNMOUNT(dev) : FALSE
	);
	GTK_WIDGET_SET_SENSITIVE(
	    mb->eject_btn,
	    (dev != NULL) ? (!STRISEMPTY(dev->command_eject) &&
		!EDV_DEVICE_IS_NO_UNMOUNT(dev)) : FALSE
	);
	GTK_WIDGET_SET_SENSITIVE(
	    mb->refresh_btn,
	    TRUE
	);
	GTK_WIDGET_SET_SENSITIVE(
	    mb->goto_btn,
	    ((dev != NULL) && (mb->goto_cb != NULL)) ? TRUE : FALSE
	);
	GTK_WIDGET_SET_SENSITIVE(
	    mb->properties_btn,
	    (dev != NULL) ? !STRISEMPTY(dev->mount_path) : FALSE
	);
	GTK_WIDGET_SET_SENSITIVE(
	    mb->fsck_btn,
	    (dev != NULL) ? !STRISEMPTY(dev->command_check) : FALSE
	);
	GTK_WIDGET_SET_SENSITIVE(
	    mb->tools_btn,
	    (dev != NULL) ? !STRISEMPTY(dev->command_tools) : FALSE
	);
	GTK_WIDGET_SET_SENSITIVE(
	    mb->format_btn,
	    (dev != NULL) ? !STRISEMPTY(dev->command_format) : FALSE
	);


	/* Redraw the device icon and label */
	gtk_widget_queue_draw(mb->dev_da);

	/* Update and redraw the stats label */
	EDVMountBarSetStats(mb);
}

/*
 *	Maps the Mount Bar.
 */
void EDVMountBarMap(edv_mount_bar_struct *mb)
{
	GtkWidget *w = (mb != NULL) ? mb->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_show(w);
}

/*
 *	Unmaps the Mount Bar.
 */
void EDVMountBarUnmap(edv_mount_bar_struct *mb)
{
	GtkWidget *w = (mb != NULL) ? mb->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_hide(w);
}

/*
 *	Deletes the Mount Bar.
 */
void EDVMountBarDelete(edv_mount_bar_struct *mb)
{
	if(mb == NULL)
	    return;

	GTK_WIDGET_DESTROY(mb->dev_da);
	GTK_WIDGET_DESTROY(mb->map_btn);
	GTK_WIDGET_DESTROY(mb->mount_btn);
	GTK_WIDGET_DESTROY(mb->eject_btn);
	GTK_WIDGET_DESTROY(mb->refresh_btn);
	GTK_WIDGET_DESTROY(mb->goto_btn);
	GTK_WIDGET_DESTROY(mb->properties_btn);
	GTK_WIDGET_DESTROY(mb->devices_list_btn);
	GTK_WIDGET_DESTROY(mb->fsck_btn);
	GTK_WIDGET_DESTROY(mb->tools_btn);
	GTK_WIDGET_DESTROY(mb->format_btn);
	GTK_WIDGET_DESTROY(mb->stats_da);
	GTK_WIDGET_DESTROY(mb->toplevel);

	GDK_GC_UNREF(mb->gc);

	GDK_PIXMAP_UNREF(mb->dev_pixmap);
	GDK_BITMAP_UNREF(mb->dev_mask);
	g_free(mb->dev_text);

	g_free(mb->dev_stats_label);

	g_free(mb);
}
