#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/stat.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

#include "guiutils.h"
#include "cdialog.h"
#include "config.h"

/* Message Icons */
#include "images/icon_info_32x32.xpm"
#include "images/icon_warning_32x32.xpm"
#include "images/icon_error_32x32.xpm"
#include "images/icon_question_32x32.xpm"
#include "images/icon_help_32x32.xpm"
#include "images/icon_wand_32x32.xpm"
#include "images/icon_search_32x32.xpm"
#include "images/icon_security_32x32.xpm"
#include "images/icon_print2_32x32.xpm"
#include "images/icon_sound_32x32.xpm"
#include "images/icon_bulb_32x32.xpm"
#include "images/icon_power_32x32.xpm"
#if defined(__linux__)
# include "images/icon_linux_32x32.xpm"
#else
# include "images/icon_linux_32x32.xpm"
#endif
#include "images/icon_terminal2_32x32.xpm"
#include "images/icon_tuning_32x32.xpm"
#include "images/icon_tools_32x32.xpm"
#include "images/icon_monitor2_32x32.xpm"
#include "images/icon_clipboard_32x32.xpm"
#include "images/icon_clipboard_empty_32x32.xpm"
#include "images/icon_install_32x32.xpm"
#include "images/icon_uninstall_32x32.xpm"
#include "images/icon_cpu_32x32.xpm"

#include "images/icon_file_32x32.xpm"
#include "images/icon_folder_closed_32x32.xpm"
#include "images/icon_folder_opened_32x32.xpm"
#include "images/icon_link_32x32.xpm"
#include "images/icon_pipe_32x32.xpm"
#include "images/icon_device_misc_32x32.xpm"
#include "images/icon_device_block_32x32.xpm"
#include "images/icon_device_character_32x32.xpm"
#include "images/icon_socket_32x32.xpm"

#if 0
/* TODO */
#include "images/icon_move_file_32x32.xpm"
#include "images/icon_copy_file_32x32.xpm"
#endif

#include "images/icon_planet_32x32.xpm"
#include "images/icon_ftp_32x32.xpm"
#include "images/icon_chat_32x32.xpm"
#include "images/icon_file_www_32x32.xpm"


/* Button icons */
#include "images/icon_ok_20x20.xpm"
#include "images/icon_cancel_20x20.xpm"
#include "images/icon_help_20x20.xpm"


typedef struct _CDlg			CDlg;
#define CDLG(p)				((CDlg *)(p))
#define CDLG_KEY			"/CDlg"


/*
 *	Flags:
 */
typedef enum {
	CDLG_MAPPED			= (1 << 0),
	CDLG_REALIZED			= (1 << 1)
} CDlgFlags;


/* Callbacks */
static void CDialogDestroyCB(gpointer data);
static gint CDialogDeleteEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
);
static gint CDialogKeyEventCB(
	GtkWidget *widget, GdkEventKey *key, gpointer data
);
static void CDialogRealizeCB(GtkWidget *widget, gpointer data);
static void CDialogButtonCB(GtkWidget *widget, gpointer data);

/* Utilities */
static guint8 **CDialogGetMessageIconDataFromCode(cdialog_icon icon_code);
static void CDialogSetIcon(
	CDlg *d,
	guint8 **icon_data
);

/* Front Ends */
gint CDialogInit(void);
void CDialogSetStyle(GtkRcStyle *rc_style);
void CDialogSetTransientFor(GtkWidget *w);
gboolean CDialogIsQuery(void);
void CDialogBreakQuery(void);
GtkWidget *CDialogGetToplevel(void);
static void CDialogRemapButtons(
	CDlg *d,
	const cdialog_btn_flags show_buttons,
	const cdialog_btn_flags default_button
);
gint CDialogGetResponse(
	const gchar *title,
	const gchar *message,
	const gchar *explaination,
	const cdialog_icon icon_code,
	const cdialog_btn_flags show_buttons,
	const cdialog_btn_flags default_button
);
gint CDialogGetResponseIconData(
	const gchar *title,
	const gchar *message,
	const gchar *explaination,
	guint8 **icon_data,
	const cdialog_btn_flags show_buttons,
	const cdialog_btn_flags default_button
);
gint CDialogGetResponseFile(
	const gchar *title,
	const gchar *path,
	const gchar *explaination,
	const cdialog_icon icon_code,
	const cdialog_btn_flags show_buttons,
	const cdialog_btn_flags default_button
);

void CDialogMap(void);
void CDialogUnmap(void);
void CDialogShutdown(void);


#if defined(PROG_LANGUAGE_SPANISH)
# define CDIALOG_DEF_TITLE	"El Mensaje"
#elif defined(PROG_LANGUAGE_FRENCH)
# define CDIALOG_DEF_TITLE	"Message"
#elif defined(PROG_LANGUAGE_GERMAN)
# define CDIALOG_DEF_TITLE	"Nachricht"
#elif defined(PROG_LANGUAGE_ITALIAN)
# define CDIALOG_DEF_TITLE	"Il Messaggio"
#elif defined(PROG_LANGUAGE_DUTCH)
# define CDIALOG_DEF_TITLE	"Bericht"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
# define CDIALOG_DEF_TITLE	"A Mensagem"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
# define CDIALOG_DEF_TITLE	"Budskap"
#else
# define CDIALOG_DEF_TITLE	"Message"
#endif

#if defined(PROG_LANGUAGE_SPANISH)
# define CDIALOG_MESG_NO_HELP_AVAILABLE	"Ninguna ayuda disponible."
#elif defined(PROG_LANGUAGE_FRENCH)
# define CDIALOG_MESG_NO_HELP_AVAILABLE	"Aucune aide disponible."
#elif defined(PROG_LANGUAGE_GERMAN)
# define CDIALOG_MESG_NO_HELP_AVAILABLE	"Keine hilfe verfügbar."
#elif defined(PROG_LANGUAGE_ITALIAN)
# define CDIALOG_MESG_NO_HELP_AVAILABLE	"Nessuno aiuto disponibile."
#elif defined(PROG_LANGUAGE_DUTCH)
# define CDIALOG_MESG_NO_HELP_AVAILABLE	"Geen hulp verkrijgbaar."
#elif defined(PROG_LANGUAGE_PORTUGUESE)
# define CDIALOG_MESG_NO_HELP_AVAILABLE	"A nenhuma ajuda disponível."
#elif defined(PROG_LANGUAGE_NORWEGIAN)
# define CDIALOG_MESG_NO_HELP_AVAILABLE	"Ingen hjelp tilgjengelig."
#else
# define CDIALOG_MESG_NO_HELP_AVAILABLE	"No help available."
#endif


#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) ? (gint)strlen(s) : 0)
#define STRISEMPTY(s)	(((s) != NULL) ? (*(s) == '\0') : TRUE)


/*
 *	Confirmation Dialog:
 */
struct _CDlg {

	GtkWidget	*toplevel;
	GtkAccelGroup	*accelgrp;
	gint		freeze_count,
			main_level,
			response_code;
	CDlgFlags	flags;

	GtkWidget	*main_vbox,
			*label_hbox,
			*icon_pm,
			*label,
			*help_vbox,
			*help_icon_pm,
			*help_label,
			*button_hbox;

	GtkWidget	*ok_btn,
			*yes_btn,
			*yes_to_all_btn,
			*no_btn,
			*cancel_btn,
			*retry_btn,
			*ignore_btn,
			*abort_btn,
			*help_btn;

	GtkWidget	*last_transient_for;	/* Reference */
	cdialog_icon	last_icon_code;

};

static CDlg	*cdlg = NULL;


/*
 *	Toplevel GtkWindow "destroy" signal callback.
 */
static void CDialogDestroyCB(gpointer data)
{
	CDlg *d = CDLG(data);
	if(d == NULL)
	    return;

	/* Clear the global cdlg reference if it is referencing
	 * this Confirmation Dialog
	 */
	if(d == cdlg)
	    cdlg = NULL;

	d->freeze_count++;

/*	d->toplevel = NULL; */
	gtk_accel_group_unref(d->accelgrp);

	d->freeze_count--;

	g_free(d);
}

/*
 *	Toplevel GtkWindow "delete_event" signal callback.
 */
static gint CDialogDeleteEventCB(GtkWidget *widget, GdkEvent *event, gpointer data)
{
	CDlg *d = CDLG(data);
	if((widget == NULL) || (d == NULL))
	    return(FALSE);

	if(d->freeze_count > 0)
	    return(TRUE);

	/* Set the response code to "cancel" */
	d->response_code = CDIALOG_RESPONSE_CANCEL;

	/* Break out of our main loop */
	if(d->main_level > 0)
	{
	    gtk_main_quit();
	    d->main_level--;
	}

	return(TRUE);
}

/*
 *	Toplevel GtkWindow "key_press_event" or "key_release_event"
 *	signal callback.
 */
static gint CDialogKeyEventCB(
	GtkWidget *widget, GdkEventKey *key, gpointer data
)
{
	gboolean press;
	gint status = FALSE;
	CDlg *d = CDLG(data);
	if((widget == NULL) || (key == NULL) || (d == NULL))
	    return(status);

	if(d->freeze_count > 0)
	    return(status);

	press = (key->type == GDK_KEY_PRESS) ? TRUE : FALSE;

	switch(key->keyval)
	{
	  case GDK_Escape:
	    if(press)
	    {
		/* Set the response code to "cancel" */
		d->response_code = CDIALOG_RESPONSE_CANCEL;

		/* Break out of our main loop */
		if(d->main_level > 0)
		{
		    gtk_main_quit();
		    d->main_level--;
		}
	    }
	    status = TRUE;
	    break;
	}

	return(status);
}

/*
 *	Toplevel GtkWindow "realize" signal callback.
 */
static void CDialogRealizeCB(GtkWidget *widget, gpointer data)
{
	GdkWindow *window;
	CDlg *d = CDLG(data);
	if((widget == NULL) || (d == NULL))
	    return;

	window = widget->window;
	if(window != NULL)
	{
	    GdkGeometry geo;
	    geo.min_width = 100;
	    geo.min_height = 70;
	    geo.max_width = gdk_screen_width() - 10;
	    geo.max_height = gdk_screen_height() - 10;
	    geo.base_width = 0;
	    geo.base_height = 0;
	    geo.width_inc = 1;
	    geo.height_inc = 1;
	    geo.min_aspect = 1.3f;
	    geo.max_aspect = 1.3f;
	    gdk_window_set_geometry_hints(
		window,
		&geo,
		GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE |
		GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC
	    );
	    gdk_window_set_decorations(
		window,
		GDK_DECOR_BORDER | GDK_DECOR_TITLE
	    );
	    gdk_window_set_functions(
		window,
		GDK_FUNC_MOVE | GDK_FUNC_CLOSE
	    );
	}

	/* Mark the Confirmation Dialog as realized */
	d->flags |= CDLG_REALIZED;
}

/*
 *	Dialog GtkButton "clicked" signal callback.
 */
static void CDialogButtonCB(GtkWidget *widget, gpointer data)
{
	GtkWidget *w;
	CDlg *d = CDLG(data);
	if((widget == NULL) || (d == NULL))
	    return;

	if(d->freeze_count > 0)
	    return;

	/* If this button is not mapped (which implies this signal
	 * was received synthetically or from an keyboard accelerator)
	 * then it should be ignored
	 */
	if(!GTK_WIDGET_MAPPED(widget))
	    return;

	/* Check which button was pressed */
	if(widget == d->ok_btn)
	    d->response_code = CDIALOG_RESPONSE_OK;
	else if(widget == d->yes_btn)
	    d->response_code = CDIALOG_RESPONSE_YES;
	else if(widget == d->yes_to_all_btn)
	    d->response_code = CDIALOG_RESPONSE_YES_TO_ALL;
	else if(widget == d->no_btn)
	    d->response_code = CDIALOG_RESPONSE_NO;
	else if(widget == d->cancel_btn)
	    d->response_code = CDIALOG_RESPONSE_CANCEL;
	else if(widget == d->retry_btn)
	    d->response_code = CDIALOG_RESPONSE_RETRY;
	else if(widget == d->ignore_btn)
	    d->response_code = CDIALOG_RESPONSE_IGNORE;
	else if(widget == d->abort_btn)
	    d->response_code = CDIALOG_RESPONSE_ABORT;
	else if(widget == d->help_btn)
	{
	    d->response_code = CDIALOG_RESPONSE_HELP;
	    w = d->help_vbox;
	    if(w != NULL)
		gtk_widget_show(w);
	    w = d->help_btn;
	    if(w != NULL)
		gtk_widget_hide(w);

	    return;	/* Return, do not break out of a main level */
	}

	/* Break out of our main loop */
	if(d->main_level > 0)
	{
	    gtk_main_quit();
	    d->main_level--;
	}
}


/*
 *	Returns the icon data that corresponds to the specified
 *	icon_code.
 *
 *	The returned pointer must not be modified or deleted.
 */
static guint8 **CDialogGetMessageIconDataFromCode(cdialog_icon icon_code)
{
	guint8 **d = (guint8 **)icon_info_32x32_xpm;

	switch(icon_code)
	{
	  case CDIALOG_ICON_INFO:
	    d = (guint8 **)icon_info_32x32_xpm;
	    break;
	  case CDIALOG_ICON_WARNING:
	    d = (guint8 **)icon_warning_32x32_xpm;
	    break;
	  case CDIALOG_ICON_ERROR:
	    d = (guint8 **)icon_error_32x32_xpm;
	    break;
	  case CDIALOG_ICON_QUESTION:
	    d = (guint8 **)icon_question_32x32_xpm;
	    break;
	  case CDIALOG_ICON_HELP:
	    d = (guint8 **)icon_help_32x32_xpm;
	    break;
	  case CDIALOG_ICON_WIZARD:
	    d = (guint8 **)icon_wand_32x32_xpm;
	    break;
	  case CDIALOG_ICON_SEARCH:
	    d = (guint8 **)icon_search_32x32_xpm;
	    break;
	  case CDIALOG_ICON_SECURITY:
	    d = (guint8 **)icon_security_32x32_xpm;
	    break;
	  case CDIALOG_ICON_PRINTER:
	    d = (guint8 **)icon_print2_32x32_xpm;
	    break;
	  case CDIALOG_ICON_SPEAKER:
	    d = (guint8 **)icon_sound_32x32_xpm;
	    break;
	  case CDIALOG_ICON_BULB:
	    d = (guint8 **)icon_bulb_32x32_xpm;
	    break;
	  case CDIALOG_ICON_POWER:
	    d = (guint8 **)icon_power_32x32_xpm;
	    break;
	  case CDIALOG_ICON_OS:
#if defined(__linux__)
	    d = (guint8 **)icon_linux_32x32_xpm;
#else
	    d = (guint8 **)icon_linux_32x32_xpm;
#endif
	    break;
	  case CDIALOG_ICON_TERMINAL:
	    d = (guint8 **)icon_terminal2_32x32_xpm;
	    break;
	  case CDIALOG_ICON_SETTINGS:
	    d = (guint8 **)icon_tuning_32x32_xpm;
	    break;
	  case CDIALOG_ICON_TOOLS:
	    d = (guint8 **)icon_tools_32x32_xpm;
	    break;
	  case CDIALOG_ICON_MONITOR:
	    d = (guint8 **)icon_monitor2_32x32_xpm;
	    break;
	  case CDIALOG_ICON_CLIPBOARD_EMPTY:
	    d = (guint8 **)icon_clipboard_empty_32x32_xpm;
	    break;
	  case CDIALOG_ICON_CLIPBOARD_FULL:
	    d = (guint8 **)icon_clipboard_32x32_xpm;
	    break;
	  case CDIALOG_ICON_INSTALL:
	    d = (guint8 **)icon_install_32x32_xpm;
	    break;
	  case CDIALOG_ICON_UNINSTALL:
	    d = (guint8 **)icon_uninstall_32x32_xpm;
	    break;
	  case CDIALOG_ICON_CPU:
	    d = (guint8 **)icon_cpu_32x32_xpm;
	    break;

	  case CDIALOG_ICON_FILE:
	    d = (guint8 **)icon_file_32x32_xpm;
	    break;
	  case CDIALOG_ICON_FOLDER_CLOSER:
	    d = (guint8 **)icon_folder_closed_32x32_xpm;
	    break;
	  case CDIALOG_ICON_FOLDER_OPENED:
	    d = (guint8 **)icon_folder_opened_32x32_xpm;
	    break;
	  case CDIALOG_ICON_LINK:
	    d = (guint8 **)icon_link_32x32_xpm;
	    break;
	  case CDIALOG_ICON_PIPE:
	    d = (guint8 **)icon_pipe_32x32_xpm;
	    break;
	  case CDIALOG_ICON_DEVICE:
	    d = (guint8 **)icon_device_misc_32x32_xpm;
	    break;
	  case CDIALOG_ICON_DEVICE_BLOCK:
	    d = (guint8 **)icon_device_block_32x32_xpm;
	    break;
	  case CDIALOG_ICON_DEVICE_CHARACTER:
	    d = (guint8 **)icon_device_character_32x32_xpm;
	    break;
	  case CDIALOG_ICON_SOCKET:
	    d = (guint8 **)icon_socket_32x32_xpm;
	    break;

	  case CDIALOG_ICON_FILE_MOVE:
	    d = (guint8 **)icon_file_32x32_xpm;
	    break;
	  case CDIALOG_ICON_FILE_COPY:
	    d = (guint8 **)icon_file_32x32_xpm;
	    break;

	  case CDIALOG_ICON_PLANET:
	    d = (guint8 **)icon_planet_32x32_xpm;
	    break;
	  case CDIALOG_ICON_FTP:
	    d = (guint8 **)icon_ftp_32x32_xpm;
	    break;
	  case CDIALOG_ICON_CHAT:
	    d = (guint8 **)icon_chat_32x32_xpm;
	    break;
	  case CDIALOG_ICON_FILE_WWW:
	    d = (guint8 **)icon_file_www_32x32_xpm;
	    break;

	  case CDIALOG_ICON_USER_DEFINED:
	    break;
	}
	return(d);
}

/*
 *	Updates the CDialog's icon from XPM data.
 */
static void CDialogSetIcon(
	CDlg *d,
	guint8 **icon_data
)
{
	GdkBitmap *mask;
	GdkPixmap *pixmap;
	GtkWidget *w;

	if(icon_data == NULL)
	    return;

	/* Load new icon from the XPM data */
	pixmap = GDK_PIXMAP_NEW_FROM_XPM_DATA(
	    &mask,
	    icon_data
	);
	if(pixmap == NULL)
	    return;

	/* Set the new icon */
	gtk_pixmap_set(GTK_PIXMAP(d->icon_pm), pixmap, mask);

	GDK_PIXMAP_UNREF(pixmap);
	GDK_BITMAP_UNREF(mask);

	w = d->toplevel;
	if(!GTK_WIDGET_REALIZED(w))
	    gtk_widget_realize(w);

	/* Toplevel needs to be resized since new icon size may be
	 * different from the previous one
	 */
	gtk_widget_queue_resize(w);

	/* Set the WM icon */
	GUISetWMIcon(
	    w->window,
	    icon_data
	);
}


/*
 *	Initializes the CDialog.
 */
gint CDialogInit(void)
{
	const gint border_major = 5;
	GtkStateType state;
	GdkBitmap *mask;
	GdkPixmap *pixmap;
	GtkAccelGroup *accelgrp;
	GtkRcStyle *rcstyle;
	GtkWidget	*w,
			*parent, *parent2, *parent3, *parent4,
			*parent5,
			*toplevel;
	CDlg *d;

	/* Already initialized? */
	if(cdlg != NULL)
	    return(0);

	/* Create a new Confirmation Dialog */
	cdlg = d = CDLG(g_malloc0(sizeof(CDlg)));
	if(d == NULL)
	    return(-3);

	d->toplevel = toplevel = gtk_window_new(GTK_WINDOW_DIALOG);
	d->accelgrp = accelgrp = gtk_accel_group_new();
/*	d->freeze_count = 0; */
	d->response_code = CDIALOG_RESPONSE_NOT_AVAILABLE;
/*
	d->main_level = 0;
	d->flags = 0;
	d->last_transient_for = NULL;
 */
	d->last_icon_code = CDIALOG_ICON_INFO;

	d->freeze_count++;

	/* Toplevel GtkWindow */
	w = toplevel;
	gtk_object_set_data_full(
	    GTK_OBJECT(w), CDLG_KEY,
	    d, CDialogDestroyCB
	);
#ifdef PROG_NAME
	gtk_window_set_wmclass(
	    GTK_WINDOW(w),
	    "dialog",
	    PROG_NAME
	);
#endif
	gtk_window_set_policy(GTK_WINDOW(w), TRUE, TRUE, TRUE);
	gtk_window_set_title(GTK_WINDOW(w), CDIALOG_DEF_TITLE);
	gtk_widget_add_events(
	    w,
	    GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "realize",
	    GTK_SIGNAL_FUNC(CDialogRealizeCB), d
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "delete_event",
	    GTK_SIGNAL_FUNC(CDialogDeleteEventCB), d
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "key_press_event",
	    GTK_SIGNAL_FUNC(CDialogKeyEventCB), d
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "key_release_event",
	    GTK_SIGNAL_FUNC(CDialogKeyEventCB), d
	);
	gtk_window_add_accel_group(GTK_WINDOW(w), accelgrp);
	parent = w;

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


	/* Icon and message GtkHBox */
	d->label_hbox = w = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* Icon GtkVBox */
	w = gtk_vbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, border_major);
	gtk_widget_show(w);
	parent3 = w;
	/* Icon */
	pixmap = GDK_PIXMAP_NEW_FROM_XPM_DATA(
	    &mask,
	    (guint8 **)icon_info_32x32_xpm
	);
	if(pixmap != NULL)
	{
	    d->icon_pm = w = gtk_pixmap_new(pixmap, mask);
	    GDK_PIXMAP_UNREF(pixmap);
	    GDK_BITMAP_UNREF(mask);
	    gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
	    gtk_widget_show(w);
	}

	/* Message GtkHBox */
	w = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, border_major);
	gtk_widget_show(w);
	parent3 = w;
	/* Message GtkLabel */
	d->label = w = gtk_label_new("");
	gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);


	/* Help widgets GtkRCStyle */
	rcstyle = gtk_rc_style_new();
	state = GTK_STATE_NORMAL;
	rcstyle->color_flags[state] = GTK_RC_FG | GTK_RC_BG |
	    GTK_RC_TEXT | GTK_RC_BASE;
	GDK_COLOR_SET_COEFF(
	    &rcstyle->fg[state],
	    0.0f, 0.0f, 0.0f
	);
	GDK_COLOR_SET_COEFF(
	    &rcstyle->bg[state],
	    1.0f, 1.0f, 0.8f
	);
	GDK_COLOR_SET_COEFF(
	    &rcstyle->text[state],
	    0.0f, 0.0f, 0.0f
	);
	GDK_COLOR_SET_COEFF(
	    &rcstyle->base[state],
	    1.0f, 1.0f, 0.8f
	);
	state = GTK_STATE_INSENSITIVE;
	rcstyle->color_flags[state] = GTK_RC_FG | GTK_RC_BG |
	    GTK_RC_TEXT | GTK_RC_BASE;
	GDK_COLOR_SET_COEFF(
	    &rcstyle->fg[state],
	    0.25f, 0.25f, 0.25f
	);
	GDK_COLOR_SET_COEFF(
	    &rcstyle->bg[state],
	    1.0f, 1.0f, 0.8f
	);
	GDK_COLOR_SET_COEFF(
	    &rcstyle->text[state],
	    0.25f, 0.25f, 0.25f
	);
	GDK_COLOR_SET_COEFF(
	    &rcstyle->base[state],
	    1.0f, 1.0f, 0.8f
	);

	/* GtkVBox for the help GtkWidgets */
	d->help_vbox = w = gtk_vbox_new(FALSE, 0);	
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, border_major);
	parent2 = w;
	w = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;

	/* Help GtkFrame */
	w = gtk_frame_new(NULL);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_IN);
	gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, TRUE, border_major);
 	gtk_widget_show(w);
	parent4 = w;
	/* Help background GtkEventBox */
	w = gtk_event_box_new();
	gtk_container_add(GTK_CONTAINER(parent4), w);
	gtk_widget_modify_style(w, rcstyle);
	gtk_widget_show(w);
	parent4 = w;

	/* Help GtkHBox inside the GtkFrame */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_container_add(GTK_CONTAINER(parent4), w);
	gtk_widget_show(w);
	parent4 = w;

	/* Help icon GtkVBox */
	w = gtk_vbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent5 = w;
	/* Help icon pixmap */
	pixmap = GDK_PIXMAP_NEW_FROM_XPM_DATA(
	    &mask,
	    (guint8 **)icon_help_32x32_xpm
	);
	if(pixmap != NULL)
	{
	    d->help_icon_pm = w = gtk_pixmap_new(pixmap, mask);
	    GDK_PIXMAP_UNREF(pixmap);
	    GDK_BITMAP_UNREF(mask);
	    gtk_box_pack_start(GTK_BOX(parent5), w, TRUE, FALSE, 0);
	    gtk_widget_modify_style(w, rcstyle);
	    gtk_widget_show(w);
	}

	/* Help message GtkHBox */
	w = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	parent5 = w;
	/* Help message GtkLabel */
	d->help_label = w = gtk_label_new(
	    CDIALOG_MESG_NO_HELP_AVAILABLE
	);
	gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_modify_style(w, rcstyle);
	gtk_widget_show(w);

	GTK_RC_STYLE_UNREF(rcstyle);

	/* Horizontal GtkSeparator */
	w = gtk_hseparator_new();
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);


	/* Buttons GtkHBox */
	w = gtk_hbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* OK GtkButton */
	d->ok_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_ok_20x20_xpm,
	    "OK",
	    NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(CDialogButtonCB), d
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_o, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	/* Let the default/focus grabbed button receive the
	 * GDK_space and GDK_Return keys
	 */
	GUIButtonLabelUnderline(w, GDK_o);

	/* Yes GtkButton */
	d->yes_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_ok_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Si"
#elif defined(PROG_LANGUAGE_FRENCH)
"Oui"
#elif defined(PROG_LANGUAGE_GERMAN)
"Ja"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Sì"
#elif defined(PROG_LANGUAGE_DUTCH)
"Ja"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Sim"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Ja"
#else
"Yes"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(CDialogButtonCB), d
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_y, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_y);


	/* Yes To All GtkButton */
	d->yes_to_all_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_ok_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Si A Todo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Oui à Tout"
#elif defined(PROG_LANGUAGE_GERMAN)
"Ja Allen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Sì A Tutto"
#elif defined(PROG_LANGUAGE_DUTCH)
"Ja Aan Alle"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Sim A Todo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Ja Til All"
#else
"Yes To All"
#endif
	     , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(CDialogButtonCB), d
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_a, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_a);

	/* No GtkButton */  
	d->no_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_cancel_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"No"
#elif defined(PROG_LANGUAGE_FRENCH)
"Non"
#elif defined(PROG_LANGUAGE_GERMAN)
"Nein"
#elif defined(PROG_LANGUAGE_ITALIAN)
"No"
#elif defined(PROG_LANGUAGE_DUTCH)
"Geen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Não"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Ingen"
#else
"No"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(CDialogButtonCB), d
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_n, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_n);

	/* Cancel GtkButton */
	d->cancel_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_cancel_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Cancela"
#elif defined(PROG_LANGUAGE_FRENCH)
"Annuler"
#elif defined(PROG_LANGUAGE_GERMAN)
"Heben"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Annulla"
#elif defined(PROG_LANGUAGE_DUTCH)
"Annuleer"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Cancelamento"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kanseller"
#else
"Cancel"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(CDialogButtonCB), d
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_c, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_c);

	/* Retry GtkButton */
	d->retry_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_ok_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Otra Vez"
#elif defined(PROG_LANGUAGE_FRENCH)
"Juger"
#elif defined(PROG_LANGUAGE_GERMAN)
"Wiederholen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Ritentare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Probeer"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Novamente"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Omprøving"
#else
"Retry"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(CDialogButtonCB), d
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_r, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_r);

	/* Ignore GtkButton */
	d->ignore_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_cancel_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Ignore"
#elif defined(PROG_LANGUAGE_FRENCH)
"Négliger"
#elif defined(PROG_LANGUAGE_GERMAN)
"Ignorieren"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Ignorare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Negeer"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Ignore"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Ignorer"
#else
"Ignore"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(CDialogButtonCB), d
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_i, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_i);

	/* Abort GtkButton */
	d->abort_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_cancel_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Aborte"
#elif defined(PROG_LANGUAGE_FRENCH)
"Avorter"
#elif defined(PROG_LANGUAGE_GERMAN)
"Brechen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Abortire"
#elif defined(PROG_LANGUAGE_DUTCH)
"Breek"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Aborte"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Aborter"
#else
"Abort"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(CDialogButtonCB), d
	);
	/* Use 'b' as the keyboard accel key for "Abort", since 'a' is
	 * taken by "Yes To All"
	 */
	gtk_accel_group_add(
	    accelgrp,
	    GDK_b, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_b);

	/* Help GtkButton */
	d->help_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_help_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Ayuda"
#elif defined(PROG_LANGUAGE_FRENCH)
"Aide"
#elif defined(PROG_LANGUAGE_GERMAN)
"Hilfe"
#elif defined(PROG_LANGUAGE_ITALIAN)
"L'Aiuto"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Hulp"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Ajuda"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Hjelp"
#else
"Help"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(CDialogButtonCB), d
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_h, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_F1, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_question, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_questiondown, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	gtk_accel_group_add(
	    accelgrp,
	    GDK_Arabic_question_mark, 0,
	    GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w),
	    "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_h);

	d->freeze_count--;

	return(0);
}

/*
 *	Sets the Dialog's style.
 */
void CDialogSetStyle(GtkRcStyle *rc_style)
{
	GtkWidget *w;
	CDlg *d = cdlg;
	if(d == NULL)
	    return;

	w = d->toplevel;
	if(w != NULL)
	{
	    if(rc_style != NULL)
	    {
		gtk_widget_modify_style_recursive(w, rc_style);
	    }
	    else
	    {
		rc_style = gtk_rc_style_new();
		gtk_widget_modify_style_recursive(w, rc_style);
		GTK_RC_STYLE_UNREF(rc_style);
	    }
	}
}

/*
 *	Sets the Dialog to be a transient for the given GtkWindow w.
 *
 *	If w is NULL then transient for will be unset.
 */
void CDialogSetTransientFor(GtkWidget *w)
{
	CDlg *d = cdlg;
	if(d == NULL)
	    return;

	if(d->toplevel != NULL)
	{
	    if(w != NULL)
	    {
		if(!GTK_IS_WINDOW(w))
		    return;

		if(GTK_WINDOW(w)->modal)
		    gtk_window_set_modal(
			GTK_WINDOW(w),
			FALSE
		    );

		gtk_window_set_modal(
		    GTK_WINDOW(d->toplevel),
		    TRUE
		);
		gtk_window_set_transient_for(
		    GTK_WINDOW(d->toplevel),
		    GTK_WINDOW(w)
		);
		d->last_transient_for = w;
	    }
	    else
	    {
		gtk_window_set_modal(
		    GTK_WINDOW(d->toplevel),
		    FALSE
		);
		gtk_window_set_transient_for(
		    GTK_WINDOW(d->toplevel),
		    NULL
		);
		d->last_transient_for = NULL;
	    }
	}
}

/*
 *	Checks if the CDialog is currently waiting for user input.
 */
gboolean CDialogIsQuery(void)
{
	CDlg *d = cdlg;
	if(d == NULL)
	    return(FALSE);

	return((d->main_level > 0) ? TRUE : FALSE);
}

/*
 *	Breaks user query (if any) and causes the querying function to
 *	return CDIALOG_RESPONSE_NOT_AVAILABLE.
 */
void CDialogBreakQuery(void)
{
	CDlg *d = cdlg;
	if(d == NULL)
	    return;

	d->response_code = CDIALOG_RESPONSE_NOT_AVAILABLE;

	/* Break out of all our main loops */
	while(d->main_level > 0)
	{
	    gtk_main_quit();
	    d->main_level--;
	}
	d->main_level = 0;
}

/*
 *	Returns the CDialog's toplevel GtkWindow.
 */
GtkWidget *CDialogGetToplevel(void)
{
	CDlg *d = cdlg;
	return((d != NULL) ? d->toplevel : NULL);
}


/*
 *	Maps or unmaps the CDialog's buttons with respect to the
 *	specified button flags.
 *
 *	The button in default_button will be grabbed and set as default.
 */
static void CDialogRemapButtons(
	CDlg *d,
	const cdialog_btn_flags show_buttons,
	const cdialog_btn_flags default_button
)
{
	GtkWidget *w;

	if(d == NULL)
	    return;

#define DO_MAP_BUTTON(w)		\
{ if((w) != NULL) { gtk_widget_show(w); } }
#define DO_UNMAP_BUTTON(w)		\
{ if((w) != NULL) { gtk_widget_hide(w); } }
#define DO_DEFAULT_BUTTON(w)		\
{ if((w) != NULL) {			\
  gtk_widget_grab_focus(w);		\
  gtk_widget_grab_default(w);		\
} }
#define DO_UNDEFAULT_BUTTON(w)		\
{ if((w) != NULL) {			\
/*  GTK_WIDGET_UNSET_FLAGS(w, GTK_HAS_DEFAULT); \
  GTK_WIDGET_UNSET_FLAGS(w, GTK_RECEIVES_DEFAULT);  */ \
} }

	/* Begin mapping or unmapping buttons */

	/* OK Button */
	w = d->ok_btn;
	if(show_buttons & CDIALOG_BTNFLAG_OK)
	    DO_MAP_BUTTON(w)
	else
	    DO_UNMAP_BUTTON(w)
	if(default_button & CDIALOG_BTNFLAG_OK)
	    DO_DEFAULT_BUTTON(w)
	else
	    DO_UNDEFAULT_BUTTON(w)

	/* Yes Button */
	w = d->yes_btn;
	if(show_buttons & CDIALOG_BTNFLAG_YES)
	    DO_MAP_BUTTON(w)
	else
	    DO_UNMAP_BUTTON(w)
	if(default_button & CDIALOG_BTNFLAG_YES)
	    DO_DEFAULT_BUTTON(w)
	else
	    DO_UNDEFAULT_BUTTON(w)

	/* Yes To All Button */
	w = d->yes_to_all_btn;
	if(show_buttons & CDIALOG_BTNFLAG_YES_TO_ALL)
	    DO_MAP_BUTTON(w)
	else
	    DO_UNMAP_BUTTON(w)
	if(default_button & CDIALOG_BTNFLAG_YES_TO_ALL)
	    DO_DEFAULT_BUTTON(w)
	else
	    DO_UNDEFAULT_BUTTON(w)

	/* No Button */
	w = d->no_btn;
	if(show_buttons & CDIALOG_BTNFLAG_NO)
	    DO_MAP_BUTTON(w)
	else
	    DO_UNMAP_BUTTON(w)
	if(default_button & CDIALOG_BTNFLAG_NO)
	    DO_DEFAULT_BUTTON(w)
	else
	    DO_UNDEFAULT_BUTTON(w)

	/* Cancel Button */
	w = d->cancel_btn;
	if(show_buttons & CDIALOG_BTNFLAG_CANCEL)
	    DO_MAP_BUTTON(w)
	else
	    DO_UNMAP_BUTTON(w)
	if(default_button & CDIALOG_BTNFLAG_CANCEL)
	    DO_DEFAULT_BUTTON(w)
	else
	    DO_UNDEFAULT_BUTTON(w)

	/* Ignore Button */
	w = d->ignore_btn;
	if(show_buttons & CDIALOG_BTNFLAG_IGNORE)
	    DO_MAP_BUTTON(w)
	else
	    DO_UNMAP_BUTTON(w)
	if(default_button & CDIALOG_BTNFLAG_IGNORE)
	    DO_DEFAULT_BUTTON(w)
	else
	    DO_UNDEFAULT_BUTTON(w)

	/* Retry Button */
	w = d->retry_btn;
	if(show_buttons & CDIALOG_BTNFLAG_RETRY)
	    DO_MAP_BUTTON(w)
	else
	    DO_UNMAP_BUTTON(w)
	if(default_button & CDIALOG_BTNFLAG_RETRY)
	    DO_DEFAULT_BUTTON(w)
	else
	    DO_UNDEFAULT_BUTTON(w)

	/* Abort Button */
	w = d->abort_btn;
	if(show_buttons & CDIALOG_BTNFLAG_ABORT)
	    DO_MAP_BUTTON(w)
	else
	    DO_UNMAP_BUTTON(w)
	if(default_button & CDIALOG_BTNFLAG_ABORT)
	    DO_DEFAULT_BUTTON(w)
	else
	    DO_UNDEFAULT_BUTTON(w)

	/* Help Button */
	w = d->help_btn;
	if(show_buttons & CDIALOG_BTNFLAG_HELP)
	    DO_MAP_BUTTON(w)
	else
	    DO_UNMAP_BUTTON(w)
	if(default_button & CDIALOG_BTNFLAG_HELP)
	    DO_DEFAULT_BUTTON(w)
	else
	    DO_UNDEFAULT_BUTTON(w)

#undef DO_MAP_BUTTON
#undef DO_UNMAP_BUTTON
#undef DO_DEFAULT_BUTTON
#undef DO_UNDEFAULT_BUTTON
}

/*
 *	Maps the CDialog and blocks input until a user response is
 *	received.
 *
 *	Returns one of CDIALOG_RESPONSE_*.
 */
gint CDialogGetResponse(
	const gchar *title,
	const gchar *message,
	const gchar *explaination,
	const cdialog_icon icon_code,
	const cdialog_btn_flags show_buttons,
	const cdialog_btn_flags default_button
)
{
	GtkWidget *w, *toplevel;
	CDlg *d = cdlg;
	if(d == NULL)
	    return(CDIALOG_RESPONSE_NOT_AVAILABLE);

	/* Already waiting for user response? */
	if(d->main_level > 0)
	    return(CDIALOG_RESPONSE_NOT_AVAILABLE);

	/* Reset values */
	d->response_code = CDIALOG_RESPONSE_NOT_AVAILABLE;
	d->main_level = 0;

	toplevel = d->toplevel;

	/* Set title */
	if(title != NULL)
	{
	    w = toplevel;
	    if(w != NULL)
		gtk_window_set_title(GTK_WINDOW(w), title);
	}

	/* Set message */
	if(message != NULL)
	{
	    w = d->label;
	    if(w != NULL)
		gtk_label_set_text(GTK_LABEL(w), message);
	}

	/* Set the help message */
	w = d->help_label;
	if(w != NULL)
	    gtk_label_set_text(
		GTK_LABEL(w),
		(explaination != NULL) ?
		    explaination : CDIALOG_MESG_NO_HELP_AVAILABLE
	    );

	/* Set the icon */
	if(icon_code != d->last_icon_code)
	{
	    guint8 **icon_data = CDialogGetMessageIconDataFromCode(icon_code);
	    d->last_icon_code = icon_code;
	    CDialogSetIcon(d, icon_data);
	}

	/* Remap buttons */
	CDialogRemapButtons(
	    d,
	    show_buttons,
	    default_button
	);

	/* Unmap the help GtkVBox initially */
	w = d->help_vbox;
	if(w != NULL)
	    gtk_widget_hide(w);

	/* Since new values have been set and widgets have been
	 * mapped/unmapped we need to resize the CDialog
	 */
	if(toplevel != NULL)
	    gtk_widget_queue_resize(toplevel);

#if 0
	/* Center toplevel if not transient for */
/* GTK_WIN_POS_NONE does not seem to work in "resetting" the position */
	w = d->toplevel;
	if((w != NULL) ? GTK_IS_WINDOW(w) : FALSE)
	    gtk_window_set_position(
		GTK_WINDOW(w),
		(d->last_transient_for != NULL) ?
		    GTK_WIN_POS_NONE : GTK_WIN_POS_CENTER
	    );
#endif

	/* Map the CDialog */
	CDialogMap();

	/* Wait for the user's confirmation */
	d->main_level++;
	gtk_main();

	/* Unmap the CDialog */
	CDialogUnmap();

	/* Break out of all our main loops */
	while(d->main_level > 0)
	{
	    gtk_main_quit();
	    d->main_level--;
	}
	d->main_level = 0;

	return(d->response_code);
}

/*
 *      Same as CDialogGetResponse() except that the icon is set by
 *	the specified icon data.
 */
gint CDialogGetResponseIconData(
	const gchar *title,
	const gchar *message,
	const gchar *explaination,
	guint8 **icon_data,
	const cdialog_btn_flags show_buttons,
	const cdialog_btn_flags default_button
)
{
	GtkWidget *w, *toplevel;
	CDlg *d = cdlg;
	if(d == NULL)
	    return(CDIALOG_RESPONSE_NOT_AVAILABLE);

	/* Already waiting for user response? */
	if(d->main_level > 0)
	    return(CDIALOG_RESPONSE_NOT_AVAILABLE);

	/* Reset the values */
	d->response_code = CDIALOG_RESPONSE_NOT_AVAILABLE;
	d->main_level = 0;

	toplevel = d->toplevel;

	/* Set title */
	if(title != NULL)
	{
	    w = toplevel;
	    if(w != NULL)
		gtk_window_set_title(GTK_WINDOW(w), title);
	}

	/* Set message */
	if(message != NULL)
	{
	    w = d->label;
	    if(w != NULL)
		gtk_label_set_text(GTK_LABEL(w), message);
	}

	/* Set help message */
	w = d->help_label;
	if(w != NULL)
	    gtk_label_set_text(
		GTK_LABEL(w),
		(explaination != NULL) ?
		    explaination : CDIALOG_MESG_NO_HELP_AVAILABLE
 	    );

	/* Set icon */
	if(icon_data != NULL)
	{
	    d->last_icon_code = CDIALOG_ICON_USER_DEFINED;
	    CDialogSetIcon(d, icon_data);
	}

	/* Remap the buttons */
	CDialogRemapButtons(
	    d,
	    show_buttons,
	    default_button
	);

	/* Unmap help vbox initially */
	w = d->help_vbox;
	if(w != NULL)
	    gtk_widget_hide(w);

	/* Since new values have been set and widgets have been
	 * mapped/unmapped we need to resize the CDialog
	 */
	if(toplevel != NULL)
	    gtk_widget_queue_resize(toplevel);

#if 0
	/* Center toplevel if not transient for */
	w = d->toplevel;
	if((w != NULL) ? GTK_IS_WINDOW(w) : FALSE)
	    gtk_window_set_position(
		GTK_WINDOW(w),
		(d->last_transient_for != NULL) ?
		    GTK_WIN_POS_NONE : GTK_WIN_POS_CENTER
	    );
#endif

	/* Map the CDialog */
	CDialogMap();

	/* Block until user response */
	d->main_level++;
	gtk_main();

	/* Unmap the CDialog */
	CDialogUnmap();

	/* Break out of all our main loops */
	while(d->main_level > 0)
	{
	    gtk_main_quit();
	    d->main_level--;
	}
	d->main_level = 0;

	return(d->response_code);
}

/*
 *	Similar to CDialogGetResponse() except that it displays a
 *	message from the file specified by message_path.
 */
gint CDialogGetResponseFile(
	const gchar *title,
	const gchar *path,
	const gchar *explaination,
	const cdialog_icon icon_code,
	const cdialog_btn_flags show_buttons,
	const cdialog_btn_flags default_button
)
{
	gint response;
	gchar *msg;

	if(path != NULL)
	{
	    FILE *fp = fopen((const char *)path, "rb");
	    if(fp != NULL)
	    {
		struct stat stat_buf;
		if(fstat(fileno(fp), &stat_buf))
		{
		    const gint error_code = (gint)errno;
		    msg = g_strdup_printf(
"%s:\n\
\n\
    %s",
			path,
			g_strerror(error_code)
		    );
		}
		else
		{
		    const gint msg_len = (gint)stat_buf.st_size;
		    msg = (gchar *)g_malloc((msg_len + 1) * sizeof(gchar));
		    if(msg != NULL)
		    {
			const size_t units_read = fread(
			    msg,
			    sizeof(gchar),
			    msg_len,
			    fp
			);
			if((units_read > 0l) && (units_read <= (size_t)msg_len))
			{
			    msg[units_read] = '\0';
			}
			else
			{
			    if(ferror(fp))
			    {
				const gint error_code = (gint)errno;
				g_free(msg);
				msg = g_strdup_printf(
"%s:\n\
\n\
    %s",
				    path,
				    g_strerror(error_code)
				);
			    }
			    else
			    {
				*msg = '\0';
			    }
			}
		    }
		}
		(void)fclose(fp);
	    }
	    else
	    {
		const gint error_code = (gint)errno;
		msg = g_strdup_printf(
"%s:\n\
\n\
    %s",
		    g_strerror(error_code),
		    path
		);
	    }
	}
	else
	{
	    msg = g_strdup("No file specified");
	}

	response = CDialogGetResponse(
	    title,
	    msg,
	    explaination,
	    icon_code,
	    show_buttons,
	    default_button
	);

	g_free(msg);

	return(response);
}

/*
 *	Maps the CDialog.
 */
void CDialogMap(void)
{
	CDlg *d = cdlg;
	if(d == NULL)
	    return;

	gtk_widget_show_raise(d->toplevel);
	d->flags |= CDLG_MAPPED;
}

/*
 *	Unmaps the CDialog.
 */
void CDialogUnmap(void)
{
	CDlg *d = cdlg;
	if(d == NULL)
	    return;

	gtk_widget_hide(d->toplevel);
	d->flags &= ~CDLG_MAPPED;
}

/*
 *	Shuts down the CDialog.
 */
void CDialogShutdown(void)
{
	CDlg *d = cdlg;
	if(d == NULL)
	    return;

	d->response_code = CDIALOG_RESPONSE_NOT_AVAILABLE;

	/* Break out of all our main loops */
	while(d->main_level > 0)
	{
	    gtk_main_quit();
	    d->main_level--;
	}
	d->main_level = 0;

	/* Unmap the dialog */
	CDialogUnmap();

	/* Destroy the toplevel GtkWindow which will call
	 * CDialogDestroyCB() to clear the global reference to
	 * this Confirmation Dialog and delete the rest of this
	 * Confirmation Dialog
	 */
	gtk_widget_destroy(d->toplevel);
}
