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

#include "../include/string.h"

#include "guiutils.h"
#include "cdialog.h"
#include "fb.h"

#include "cfg.h"
#include "edv_types.h"
#include "run_dlg.h"
#include "endeavour2.h"
#include "edv_op.h"
#include "edv_utils.h"
#include "edv_utils_gtk.h"
#include "edv_cfg_list.h"
#include "config.h"

#include "images/icon_run_20x20.xpm"
#include "images/icon_executable_48x48.xpm"
#include "images/icon_close_20x20.xpm"
#include "images/icon_browse_20x20.xpm"
#include "images/icon_clear_20x20.xpm"
#include "images/icon_run_dir_from_cmd_20x20.xpm"
#include "images/icon_options2_20x20.xpm"


static gint EDVRunDlgDeleteEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
);
static void EDVRunDlgRunCB(
	GtkWidget *widget, gpointer data
);
static gint EDVRunDlgCommandFocusEventCB(
	 GtkWidget *widget, GdkEventFocus *focus, gpointer data
);
static void EDVRunDlgBrowseCommandCB(
	GtkWidget *widget, gpointer data
);
static void EDVRunDlgBrowseWorkingDirCB(
	GtkWidget *widget, gpointer data
);
static void EDVRunDlgClearCB(
	GtkWidget *widget, gpointer data
);
static void EDVRunDlgGetWorkingDirFromCmdCB(
	GtkWidget *widget, gpointer data
);
static void EDVRunDlgOptionsCB(
	GtkWidget *widget, gpointer data
);
static void EDVRunDlgCloseCB(GtkWidget *widget, gpointer data);

/* Utilities */
static void EDVRunDlgCompleteCommand(edv_run_dlg_struct *d);

/* Set & Get Values */
void EDVRunDlgSetCommand(
	edv_run_dlg_struct *d, const char *command
);
void EDVRunDlgSetWorkingDir(
	edv_run_dlg_struct *d, const char *working_dir
);
void EDVRunDlgFetchValues(edv_run_dlg_struct *d);

/* Run Dialog */
edv_run_dlg_struct *EDVRunDlgNew(edv_core_struct *core);
void EDVRunDlgSetBusy(edv_run_dlg_struct *d, gboolean is_busy);
gboolean EDVRunDlgIsMapped(edv_run_dlg_struct *d);
void EDVRunDlgMap(edv_run_dlg_struct *d);
void EDVRunDlgUnmap(edv_run_dlg_struct *d);
void EDVRunDlgDelete(edv_run_dlg_struct *d);


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


#if defined(PROG_LANGUAGE_SPANISH)
# define RUNDLG_TITLE		"Corra"
#elif defined(PROG_LANGUAGE_FRENCH)
# define RUNDLG_TITLE		"Lancer"
#elif defined(PROG_LANGUAGE_GERMAN)
# define RUNDLG_TITLE		"Lauf"
#elif defined(PROG_LANGUAGE_ITALIAN)
# define RUNDLG_TITLE		"Ha Correto"
#elif defined(PROG_LANGUAGE_DUTCH)
# define RUNDLG_TITLE		"Tocht"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
# define RUNDLG_TITLE		"A Corrida"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
# define RUNDLG_TITLE		"Løp"
#else
# define RUNDLG_TITLE		"Run"
#endif

#define RUNDLG_WIDTH		500
#define RUNDLG_HEIGHT		-1


/*
 *	Run Dialog toplevel GtkWindow "delete_event" signal callback.
 */
static gint EDVRunDlgDeleteEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
)
{
	edv_run_dlg_struct *d = EDV_RUN_DLG(data);
	if(d == NULL)
	    return(TRUE);

	EDVRunDlgCloseCB(NULL, d);

	return(TRUE);
}

/*
 *      Run Dialog run callback.
 */
static void EDVRunDlgRunCB(
	GtkWidget *widget, gpointer data
)
{
	gint euid;
	gchar *s, *pwd, *prog, *args, *cmd;
	const gchar *cmd_src, *wd;
	struct stat stat_buf;
	const cfg_item_struct *cfg_list;
	GtkWidget *toplevel;
	edv_core_struct *core;
	edv_run_dlg_struct *d = EDV_RUN_DLG(data);
	if(d == NULL)
	    return;

	toplevel = d->toplevel;
	core = d->core;
	cfg_list = core->cfg_list;
	euid = core->effective_user_id;

	EDVRunDlgSetBusy(d, TRUE);

	/* Complete command as needed */
	EDVRunDlgCompleteCommand(d);

	/* Get new and previous working directories */
	wd = gtk_entry_get_text(
	    GTK_ENTRY(d->working_dir_entry)
	);
	pwd = EDVGetCWD();

	/* Get command */
	cmd_src = gtk_entry_get_text(
	    GTK_ENTRY(GTK_COMBO(d->run_combo)->entry)
	);
	if(STRISEMPTY(cmd_src))
	{
	    g_free(pwd);
	    EDVRunDlgSetBusy(d, FALSE);
	    return;
	}

	/* Seek past initial spaces */
	while(ISBLANK(*cmd_src))
	    cmd_src++;

	/* Get program from command */
	prog = STRDUP(cmd_src);
	s = strpbrk(prog, " \t");
	if(s != NULL)
	    *s = '\0';

	/* Get arguments from command */
	s = strpbrk(cmd_src, " \t");
	if(s != NULL)
	{
	    while(ISBLANK(*s))
		s++;
	    args = STRDUP(s);
	}
	else
	{
	    args = NULL;
	}

	/* Record this command */
	if(args != NULL)
	    s = g_strdup_printf("%s %s", prog, args);
	else
	    s = g_strdup_printf("%s", prog);
	GUIComboAddItem(d->run_combo, s);
	g_free(s);

	/* Get program stats to see if it exists and is executable */
	if(stat(prog, &stat_buf))
	{
	    const gint error_code = (gint)errno;
	    gchar *error_msg = STRDUP(g_strerror(error_code));
	    if(error_msg != NULL)
	    {
		*error_msg = toupper(*error_msg);

		s = g_strdup_printf(
"%s:\n\
\n\
    %s",
		    error_msg, prog
		);
		EDVPlaySoundWarning(core);
		EDVMessageWarning(
		    "Run Failed", s, NULL, toplevel
		);
		g_free(s);
		g_free(error_msg);
	    }
	    g_free(pwd);
	    g_free(prog);
	    g_free(args);
	    EDVRunDlgSetBusy(d, FALSE);
	    return;
	}
	else if(((euid == stat_buf.st_uid) || (euid == 0)) ?
		 !(stat_buf.st_mode & S_IXUSR) :
		 !(stat_buf.st_mode & S_IXOTH)
	       )
	{
	    gchar *s = g_strdup_printf(
"Not executable:\n\
\n\
    %s\n\
\n\
The program must be set executable in order to run it.",
		prog
	    );
	    EDVPlaySoundWarning(core);
	    EDVMessageWarning(
		"Run Failed", s, NULL, toplevel
	    );
	    g_free(s);

	    g_free(pwd);
	    g_free(prog);
	    g_free(args);
	    EDVRunDlgSetBusy(d, FALSE);
	    return;
	}

	/* Format command */
	if(GTK_TOGGLE_BUTTON_GET_ACTIVE(d->run_in_terminal_check))
	{
	    /* Format command for running in a terminal */
	    const gchar *cmd_terminal_run = EDV_GET_S(
		EDV_CFG_PARM_PROG_TERMINAL_RUN
	    );
	    if(!STRISEMPTY(cmd_terminal_run))
	    {
		/* Format command for run in terminal */
		if(args != NULL)
		    cmd = g_strdup_printf(
		        "%s %s %s",
			cmd_terminal_run, prog, args
		    );
		else
		    cmd = g_strdup_printf(
			"%s %s",
			cmd_terminal_run, prog
		    );
	    }
	    else
	    {
		EDVPlaySoundWarning(core);
		EDVMessageWarning(   
		    "Run Failed",
"The \"Run In Terminal\" command is not set.\n\
\n\
To set the \"Run In Terminal\" command go to\n\
Settings->Options...->Programs.",
		    NULL,
		    toplevel
		);
		g_free(pwd);
		g_free(prog);
		g_free(args);
		EDVRunDlgSetBusy(d, FALSE);
		return;
	    }
	}
	else
	{
	    /* Format plain command */
	    if(args != NULL)
		cmd = g_strdup_printf(
		    "%s %s &",
		    prog, args
		);
	    else
		cmd = g_strdup_printf(
		    "%s &",
		    prog
		);
	}

	/* Generated command successfully? */
	if(cmd != NULL)
	{
	    gint p;
	    gchar *s;

	    /* Change to the new working directory */
	    EDVSetCWD(wd);

	    /* Execute command */
	    p = EDVSystem(cmd);

	    /* Change back to the previous working directory */
	    EDVSetCWD(pwd);

	    /* Error executing the command? */
	    if(p <= 0)
	    {
		s = g_strdup_printf(
"Unable to execute command:\n\
\n\
    %s",
		    cmd
		);
		EDVPlaySoundError(core);
		EDVMessageError(
"Run Failed",
		    s,
"Please verify that the program exists, is executable, and any\n\
specified arguments are valid.",
		    toplevel
		);
		g_free(s);
	    }
	}

	/* Do not keep dialog after running? */
	if(!GTK_TOGGLE_BUTTON_GET_ACTIVE(d->keep_dialog_check))
	    EDVRunDlgCloseCB(d->close_btn, d);

	g_free(pwd);
	g_free(cmd);
	g_free(prog);
	g_free(args);
	EDVRunDlgSetBusy(d, FALSE);
}


/*
 *	Run Dialog Command GtkEntry "focus_in_event" or
 *	"focus_out_event" signal callback.
 */
static gint EDVRunDlgCommandFocusEventCB(
	 GtkWidget *widget, GdkEventFocus *focus, gpointer data
)
{
	gint status = FALSE;
	edv_run_dlg_struct *d = EDV_RUN_DLG(data);
	if((widget == NULL) || (focus == NULL) || (d == NULL))
	    return(status);

	if(focus->in)
	{
	    status = TRUE;
	}
	else
	{
	    /* Complete the command as needed when focusing out */
	    EDVRunDlgCompleteCommand(d);
	    status = TRUE;
	}

	return(status);
}


/*
 *	Run Dialog browse command callback.
 */
static void EDVRunDlgBrowseCommandCB(
	GtkWidget *widget, gpointer data
)
{
	gboolean status;
	gchar *s, *cur_prog;
	fb_type_struct **ftype = NULL, *ftype_rtn = NULL;
	gint total_ftypes = 0;
	gchar **path_rtn = NULL;
	gint total_path_rtns = 0;
	GtkWidget *toplevel, *w;
	GtkEntry *entry;
	edv_run_dlg_struct *d = EDV_RUN_DLG(data);
	if((d == NULL) || FileBrowserIsQuery())
	    return;

	toplevel = d->toplevel;
	w = d->run_combo;
	if(w == NULL)
	    return;
	entry = GTK_ENTRY(GTK_COMBO(w)->entry);

	cur_prog = STRDUP(gtk_entry_get_text(entry));
	s = strpbrk(cur_prog, " \t");
	if(s != NULL)
	    *s = '\0';


	EDVRunDlgSetBusy(d, TRUE);

	/* Create file types list */
	FileBrowserTypeListNew(
	    &ftype, &total_ftypes,
	    "*.*", "All files"
	);

	/* Query user for program */
	FileBrowserSetTransientFor(toplevel);
	status = FileBrowserGetResponse(
	    "Select Program",
	    "Select", "Cancel",
	    cur_prog,
	    ftype, total_ftypes,
	    &path_rtn, &total_path_rtns,
	    &ftype_rtn
	);
	FileBrowserSetTransientFor(NULL);

	/* Got user response? */
	if(status)
	{
	    const gchar *new_prog = (total_path_rtns > 0) ?
		path_rtn[0] : NULL;
	    if(!STRISEMPTY(new_prog))
	    {
		gtk_entry_set_text(entry, new_prog);
		gtk_entry_set_position(entry, -1);
	    }
	}

	/* Delete file types list */
	FileBrowserDeleteTypeList(ftype, total_ftypes);

	g_free(cur_prog);

	EDVRunDlgSetBusy(d, FALSE);
}

/*
 *	Run Dialog browse working directory callback.
 */
static void EDVRunDlgBrowseWorkingDirCB(
	GtkWidget *widget, gpointer data
)
{
	gboolean status;
	gchar *cur_dir;
	fb_type_struct **ftype = NULL, *ftype_rtn = NULL;
	gint total_ftypes = 0;
	gchar **path_rtn = NULL;
	gint total_path_rtns = 0;
	GtkWidget *toplevel, *w;
	GtkEntry *entry;
	edv_run_dlg_struct *d = EDV_RUN_DLG(data);
	if((d == NULL) || FileBrowserIsQuery())
	    return;

	toplevel = d->toplevel;
	w = d->working_dir_entry;
	if(w == NULL)
	    return;
	entry = GTK_ENTRY(w);

	cur_dir = STRDUP(gtk_entry_get_text(entry));


	EDVRunDlgSetBusy(d, TRUE);

	/* Create file types list */
	FileBrowserTypeListNew(
	    &ftype, &total_ftypes,
	    "*.*", "All files"
	);

	/* Query user for directory */
	FileBrowserSetTransientFor(toplevel);
	status = FileBrowserGetResponse(
	    "Select Directory",
	    "Select", "Cancel",
	    cur_dir,
	    ftype, total_ftypes,
	    &path_rtn, &total_path_rtns,
	    &ftype_rtn
	);
	FileBrowserSetTransientFor(NULL);

	/* Got user response? */
	if(status)
	{
	    const gchar *new_dir = (total_path_rtns > 0) ?
		path_rtn[0] : NULL;
	    if(!STRISEMPTY(new_dir))
	    {
		gtk_entry_set_text(entry, new_dir);
		gtk_entry_set_position(entry, -1);
	    }
	}

	/* Delete file types list */
	FileBrowserDeleteTypeList(ftype, total_ftypes);

	g_free(cur_dir);

	EDVRunDlgSetBusy(d, FALSE);
}

/*
 *	Run Dialog clear callback.
 *
 *      The data must be a GtkEntry.
 */
static void EDVRunDlgClearCB(
	GtkWidget *widget, gpointer data
)
{
	GtkWidget *w = (GtkWidget *)data;
	GtkEntry *entry;

	if((w != NULL) ? GTK_IS_ENTRY(w) : FALSE)
	    entry = GTK_ENTRY(w);
	else
	    return;

/*	EDVRunDlgSetBusy(d, TRUE); */

	gtk_entry_set_text(entry, "");
	gtk_entry_set_position(entry, 0);

/*	EDVRunDlgSetBusy(d, FALSE); */
}

/*
 *	Run dialog get working directory from current run command value
 *	callback.
 */
static void EDVRunDlgGetWorkingDirFromCmdCB(
	GtkWidget *widget, gpointer data
)
{
	const gchar *cmd;
	GtkWidget *w;
	GtkEntry *entry;
	GtkCombo *combo;
	edv_run_dlg_struct *d = EDV_RUN_DLG(data);
	if(d == NULL)
	    return;

	w = d->run_combo;
	if(w != NULL)
	    combo = GTK_COMBO(w);
	else
	    return;

	w = d->working_dir_entry;
	if(w != NULL)
	    entry = GTK_ENTRY(w);
	else
	    return;

	EDVRunDlgSetBusy(d, TRUE);

	cmd = gtk_entry_get_text(GTK_ENTRY(combo->entry));
	if(cmd != NULL)
	{
	    while(ISBLANK(*cmd))
		cmd++;

	    /* Run command starts with an absolute path? */
	    if(*cmd == G_DIR_SEPARATOR)
	    {
		gchar	*s, *parent_path,
			*new_working_dir = STRDUP(cmd);

		/* Seek strptr to first space (if any) in
		 * new_working_dir
		 */
		s = new_working_dir;
		while(!ISBLANK(*s) && (*s != '\0'))
		    s++;
		/* Cap new_working_dir at first blank character */
		*s = '\0';

		parent_path = g_dirname(new_working_dir);

		gtk_entry_set_text(entry, parent_path);
		gtk_entry_set_position(entry, -1);

		g_free(new_working_dir);
		g_free(parent_path);
	    }
	}

	EDVRunDlgSetBusy(d, FALSE);
}

/*
 *	Options button callback.
 */
static void EDVRunDlgOptionsCB(
	GtkWidget *widget, gpointer data
)
{
	edv_core_struct *core;
	edv_run_dlg_struct *d = EDV_RUN_DLG(data);
	if(d == NULL)
	    return;

	core = d->core;

	EDVRunDlgSetBusy(d, TRUE);

	EDVMapOptionsWinPage(
	    core,
	    "Programs",		/* Page Name */
	    d->toplevel	/* Toplevel */
	);

	EDVRunDlgSetBusy(d, FALSE);
}

/*
 *	Run dialog close button callback.
 */
static void EDVRunDlgCloseCB(
	GtkWidget *widget, gpointer data
)
{
	GtkWidget *w;
	edv_core_struct *core;
	cfg_item_struct *cfg_list;
	edv_run_dlg_struct *d = EDV_RUN_DLG(data);
	if(d == NULL)
	    return;

	core = d->core;
	cfg_list = (core != NULL) ? core->cfg_list : NULL;

	/* Begin recording current widget values to global
	 * configuration
	 */

	/* Run history */
	w = d->run_combo;
	if(w != NULL)
	{
	    EDVSaveFileGList(
		EDV_GET_S(EDV_CFG_PARM_FILE_RUNDLG_HISTORY),
		GUIComboGetList(w)
	    );
	}

	/* Toplevel geometry */
	w = d->toplevel;
	if(w != NULL)
	{
	    gint x = 0, y = 0;
	    GdkWindow *window = w->window;
	    if(window != NULL)
		gdk_window_get_root_origin(window, &x, &y);

	    CFGItemListSetValueI(
		cfg_list, EDV_CFG_PARM_RUNDLG_X,
		x, FALSE
	    );
	    CFGItemListSetValueI(
		cfg_list, EDV_CFG_PARM_RUNDLG_Y,
		y, FALSE
	    );
	}

	/* Last working directory */
	w = d->working_dir_entry;
	if(w != NULL)
	    CFGItemListSetValueS(
		cfg_list, EDV_CFG_PARM_RUNDLG_LAST_WORKING_DIR,
		gtk_entry_get_text(GTK_ENTRY(w)), FALSE
	    );

	/* Run in terminal */
	w = d->run_in_terminal_check;
	if(w != NULL)
	    CFGItemListSetValueI(
		cfg_list, EDV_CFG_PARM_RUNDLG_RUN_IN_TERMINAL,
		GTK_TOGGLE_BUTTON(w)->active, FALSE
	    );

	/* Keep dialog */
	w = d->keep_dialog_check;
	if(w != NULL)
	    CFGItemListSetValueI(
		cfg_list, EDV_CFG_PARM_RUNDLG_KEEP_DIALOG,
		GTK_TOGGLE_BUTTON(w)->active, FALSE
	    );


	/* Now close dialog */
	EDVRunDlgUnmap(d);
}


/*
 *	Completes the Run Dialog's command as needed and updates the
 *	command.
 */
static void EDVRunDlgCompleteCommand(edv_run_dlg_struct *d)
{
	const gchar *cmd_src;

	if(d == NULL)
	    return;

	/* Get current command */
	cmd_src = gtk_entry_get_text(
	    GTK_ENTRY(GTK_COMBO(d->run_combo)->entry)
	);   
	if(!STRISEMPTY(cmd_src))
	{
	    gchar *s, *prog, *args;

	    /* Seek past spaces in command */
	    while(ISBLANK(*cmd_src))
		cmd_src++;

	    /* Get program from command */
	    prog = STRDUP(cmd_src);
	    s = strpbrk(prog, " \t");
	    if(s != NULL)
		*s = '\0';   

	    /* Get arguments from command */
	    s = strpbrk(cmd_src, " \t");
	    if(s != NULL)
	    {
		while(ISBLANK(*s))
		    s++;
		args = STRDUP(s);
	    }
	    else
	    {
		args = NULL;
	    }

	    /* If the program location is not an absolute path then
	     * we need to complete it
	     */
	    s = g_path_is_absolute(prog) ? NULL : EDVWhich(prog);
	    if(s != NULL)
	    {
		GtkCombo *combo = GTK_COMBO(d->run_combo);

		/* Set new program with completed path */
		g_free(prog);
		prog = s;

		/* Format and set new command */
		s = (args != NULL) ?
		    g_strconcat(prog, " ", args, NULL) : g_strdup(prog);
		gtk_entry_set_text(GTK_ENTRY(combo->entry), s);
		g_free(s);
	    }

	    g_free(prog);
	    g_free(args);
	}
}


/*
 *	Sets the command value.
 */
void EDVRunDlgSetCommand(
	edv_run_dlg_struct *d, const char *command
)
{
	GtkEntry *entry;
	GtkCombo *combo;

	if(d == NULL)
	    return;

	combo = (GtkCombo *)d->run_combo;
	if(combo == NULL)
	    return;

	entry = GTK_ENTRY(combo->entry);
	gtk_entry_set_text(entry, (command != NULL) ? command : "");
	gtk_entry_set_position(entry, -1);
}

/*
 *	Sets the working directory value.
 */
void EDVRunDlgSetWorkingDir(
	edv_run_dlg_struct *d, const char *working_dir
)
{
	GtkEntry *entry;

	if(d == NULL)
	    return;

	entry = (GtkEntry *)d->working_dir_entry;
	if(entry == NULL)
	    return;

	gtk_entry_set_text(entry, (working_dir != NULL) ? working_dir : "");
	gtk_entry_set_position(entry, -1);
}

/*
 *	Regets list of past runned objects and updates the widgets to
 *	match the current configuration.
 */
void EDVRunDlgFetchValues(edv_run_dlg_struct *d)
{
	GtkCombo *combo;
	const cfg_item_struct *cfg_list;
	edv_core_struct *core;

	if(d == NULL)
	    return;

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

	cfg_list = core->cfg_list;

	/* Begin fetching values from global configuration and
	 * updating the Run Dialog's widgets
	 */

	/* Run History */
	combo = (GtkCombo *)d->run_combo;
	if(combo != NULL)
	{
	    const gchar *path = EDV_GET_S(EDV_CFG_PARM_FILE_RUNDLG_HISTORY);
	    GList *glist = EDVOpenFileGList(path, 0);
	    if(glist != NULL)
	    {
		/* Set the new glist to the run combo's history, this
		 * glist will be managed by the call and should not
		 * be referenced afterwards
		 */
		GUIComboSetList(GTK_WIDGET(combo), glist);
		glist = NULL;
	    }
	}

	/* Run In Terminal */
	GTK_TOGGLE_BUTTON_SET_ACTIVE(
	    d->run_in_terminal_check,
	    EDV_GET_B(EDV_CFG_PARM_RUNDLG_RUN_IN_TERMINAL)
	);

	/* Keep Dialog */
	GTK_TOGGLE_BUTTON_SET_ACTIVE(
	    d->keep_dialog_check,
	    EDV_GET_B(EDV_CFG_PARM_RUNDLG_KEEP_DIALOG)
	);
}


/*
 *	Creates a new Run Dialog.
 */
edv_run_dlg_struct *EDVRunDlgNew(edv_core_struct *core)
{
	const gint	border_major = 5,
			border_minor = 2;
	gint x = 0, y = 0;
	GdkWindow *window;
	GtkAccelGroup *accelgrp;
	GtkStyle *style;
	gpointer combo_rtn;
	GtkWidget *w, *parent, *parent2;
	GtkCombo *combo;
	const cfg_item_struct *cfg_list;
	edv_run_dlg_struct *d = EDV_RUN_DLG(
	    g_malloc0(sizeof(edv_run_dlg_struct))
	);
	if((d == NULL) || (core == NULL))
	{
	    g_free(d);
	    return(NULL);
	}

	cfg_list = core->cfg_list;
	if(cfg_list != NULL)
	{
	    x = EDV_GET_I(EDV_CFG_PARM_RUNDLG_X);
	    y = EDV_GET_I(EDV_CFG_PARM_RUNDLG_Y);
	}

	d->accelgrp = accelgrp = gtk_accel_group_new();
	d->processing = FALSE;
	d->busy_count = 0;
	d->core = core;


	/* Begin creating widgets */

	/* Toplevel */
	d->toplevel = w = gtk_window_new(GTK_WINDOW_DIALOG);
	gtk_widget_set_usize(w, RUNDLG_WIDTH, RUNDLG_HEIGHT);
	gtk_widget_set_uposition(w, x, y);
	gtk_window_set_title(GTK_WINDOW(w), RUNDLG_TITLE);
	gtk_window_set_wmclass(
	    GTK_WINDOW(w), "dialog", 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_executable_48x48_xpm);
	}
	gtk_signal_connect(
	    GTK_OBJECT(w), "delete_event",
	    GTK_SIGNAL_FUNC(EDVRunDlgDeleteEventCB), d
	);
	gtk_window_add_accel_group(GTK_WINDOW(w), accelgrp);
	style = gtk_widget_get_style(w);
	parent = w;


	/* Main vbox */
	d->main_vbox = w = gtk_vbox_new(FALSE, border_major);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_container_add(GTK_CONTAINER(parent), w);
	gtk_widget_show(w);
	parent = w;


	/* Hbox for run combo, browse button, and clear button */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent2 = w;

	w = GUIComboCreate(
#if defined(PROG_LANGUAGE_SPANISH)
"La Orden:"
#elif defined(PROG_LANGUAGE_FRENCH)
"Commande:"
#elif defined(PROG_LANGUAGE_GERMAN)
"Befehl:"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Il Comando:"
#elif defined(PROG_LANGUAGE_DUTCH)
"Bevel:"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Comando:"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kommando:"
#else
"Command:"
#endif
	    , "",
	    NULL,		/* Set list later */
	    20,			/* Maximum items */
	    &combo_rtn,
	    d,
	    EDVRunDlgRunCB,
	    NULL
	);
	d->run_combo = (GtkWidget *)combo_rtn;
	combo = (GtkCombo *)combo_rtn;
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
	gtk_widget_show(w);

	if(combo != NULL)
	{
	    w = combo->entry;
	    gtk_signal_connect(
		GTK_OBJECT(w), "focus_in_event",
	        GTK_SIGNAL_FUNC(EDVRunDlgCommandFocusEventCB), d
	    );
	    gtk_signal_connect(
		GTK_OBJECT(w), "focus_out_event",
		GTK_SIGNAL_FUNC(EDVRunDlgCommandFocusEventCB), d
	    );
	    EDVEntrySetDND(core, w);
	    EDVEntrySetCompletePath(core, w);
	    GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Entre el nombre del programa más cualquier argumento"
#elif defined(PROG_LANGUAGE_FRENCH)
"Entrer le nom du programme avec les arguments"
#elif defined(PROG_LANGUAGE_GERMAN)
"Tragen Sie den Namen des Programms und irgendeine Argumente ein"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Entrare il nome del programma più qualunque discussioni"
#elif defined(PROG_LANGUAGE_DUTCH)
"Ga de naam van het programma bovendien enig argumenten binnen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Entre o nome do programa com mais qualquer argumentos"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Gå inn i navnet av programet pluss noen argumenter"
#else
"Enter the name of the program plus any arguments"
#endif
	    );
	}

	/* Browse button */
	d->browse_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_browse_20x20_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	combo = (GtkCombo *)d->run_combo;
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVRunDlgBrowseCommandCB), d
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Hojee"
#elif defined(PROG_LANGUAGE_FRENCH)
"Parcourir"
#elif defined(PROG_LANGUAGE_GERMAN)
"Brausen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Curiosare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Grasduin"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Olhe"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Browse"
#else
"Browse"
#endif
	);
	gtk_widget_show(w);

	/* Clear button */
	d->clear_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_clear_20x20_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVRunDlgClearCB), combo->entry
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Claro"
#elif defined(PROG_LANGUAGE_FRENCH)
"Effacer"
#elif defined(PROG_LANGUAGE_GERMAN)
"Klar"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Chiaro"
#elif defined(PROG_LANGUAGE_DUTCH)
"Helder"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Claro"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Klar"
#else
"Clear"
#endif
	);
	gtk_widget_show(w);


	/* Hbox for working directory entry and get from command
	 * button
	 */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent2 = w;

	/* Working Directory entry */
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Guía Trabajo:"
#elif defined(PROG_LANGUAGE_FRENCH)
"Répertoire de travail:"
#elif defined(PROG_LANGUAGE_GERMAN)
"Arbeitenden Verzeichnis:"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Che Lavorando L'Elenco:"
#elif defined(PROG_LANGUAGE_DUTCH)
"Werkende Gids:"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Que trabalhando Guia:"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Arbeidende Directory:"
#else
"Working Directory:"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	d->working_dir_entry = w = gtk_entry_new();
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
	gtk_entry_set_text(
	    GTK_ENTRY(w),
	    EDV_GET_S(EDV_CFG_PARM_RUNDLG_LAST_WORKING_DIR)
	);
	EDVEntrySetDND(core, w);
	EDVEntrySetCompletePath(core, w);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
"Entre la guía de trabajo que se usará cuándo correr el programa"
#elif defined(PROG_LANGUAGE_FRENCH)
"Entrer le répertoire de travail utilisé par le programme programme"
#elif defined(PROG_LANGUAGE_GERMAN)
"Tragen Sie das arbeitende Verzeichnis, das benutzt werden wird,\
 beim Laufen des Programms ein"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Entrare il che lavorando elenco che sarà usato quando correre il\
 programma"
#elif defined(PROG_LANGUAGE_DUTCH)
"Ga de werking gids die gebruikt worden zal wanneer lopen het\
 programma binnen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Entre o que trabalhando guia que será usado quando correr o programa"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Gå inn i den arbeidende katalogen som brukt ved kjøre av av programet"
#else
"Enter the working directory that will be used when running the\
 program"
#endif
	);
	gtk_widget_show(w);

	/* Browse button */
	d->working_dir_browse_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_browse_20x20_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	combo = (GtkCombo *)d->run_combo;
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVRunDlgBrowseWorkingDirCB), d
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Hojee"
#elif defined(PROG_LANGUAGE_FRENCH)
"Parcourir"
#elif defined(PROG_LANGUAGE_GERMAN)
"Brausen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Curiosare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Grasduin"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Olhe"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Browse"
#else
"Browse"
#endif
	);
	gtk_widget_show(w);

	/* Clear button */
	d->working_dir_clear_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_clear_20x20_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVRunDlgClearCB), d->working_dir_entry
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Claro"
#elif defined(PROG_LANGUAGE_FRENCH)
"Effacer"
#elif defined(PROG_LANGUAGE_GERMAN)
"Klar"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Chiaro"
#elif defined(PROG_LANGUAGE_DUTCH)
"Helder"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Claro"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Klar"
#else
"Clear"
#endif
	);
	gtk_widget_show(w);

	/* Get from command button */
	d->working_dir_get_from_cmd_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_run_dir_from_cmd_20x20_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVRunDlgGetWorkingDirFromCmdCB), d
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Obtenga trabajando guía del valor actual de la orden"
#elif defined(PROG_LANGUAGE_FRENCH)
"Recevoir le répertoire de travail depuis la commande"
#elif defined(PROG_LANGUAGE_GERMAN)
"Erhalten Sie arbeitenden Verzeichnis vom jetzigen Befehl Wert"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Prendere che lavorando l'elenco dal valore di comando attuale"
#elif defined(PROG_LANGUAGE_DUTCH)
"Krijg werkende gids van de huidig bevel waarde"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Fique trabalhando guia do valor atual de comando"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Bli arbeidende katalog fra den nåværendee kommandoverdi"
#else
"Get working directory from the current command value"
#endif
	);
	gtk_widget_show(w);


	/* Hbox for run in terminal and keep dialog checks */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent2 = w;

	d->run_in_terminal_check = w = gtk_check_button_new_with_label(
#if defined(PROG_LANGUAGE_SPANISH)
"Corra En La Terminal"
#elif defined(PROG_LANGUAGE_FRENCH)
"Ouvrir Dans un Terminal"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laufen Sie In Terminal"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Ha Correto Nell'Estremità"
#elif defined(PROG_LANGUAGE_DUTCH)
"Loop In Eindpunt"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Corra Em Terminal"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kjør In Terminal"
#else
"Run In Terminal"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Corra el programa especificado en una terminal, esto a\
 menudo se necesita para programas basados de texto"
#elif defined(PROG_LANGUAGE_FRENCH)
"Ouvrir le programme spécifié dans un terminal, ceci\
 est souvent nexessaire pour les programmes basé sur du texte"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laufen Sie das angegebene Programm in ein Terminal, dies ist often,\
 der für Text basiert Programme gebraucht wird"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Ha correto il programma specificato in un'estremità, questo è often\
 ha avuto bisogno di per i programmi testo basati"
#elif defined(PROG_LANGUAGE_DUTCH)
"Loop het gespecificeerd programma in een eindpunt, dit is often nood\
 aan tekst gebaseerd programma's"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Corra o programa especificado num terminal, isto é often necessitou\
 para programas texto baseados"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kjør det spesifiserte programet i en terminal, dette er often som\
 trengt for tekst basert programer"
#else
"Check this to run the specified program in a terminal, this is needed\
 when running text-based programs"
#endif
	);
	gtk_widget_show(w);

	d->keep_dialog_check = w = gtk_check_button_new_with_label(
#if defined(PROG_LANGUAGE_SPANISH)
"Mantenga El Diálogo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Garder Le Dialogue"
#elif defined(PROG_LANGUAGE_GERMAN)
"Behalten Sie Dialog"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Tenere Il Dialogo"
#elif defined(PROG_LANGUAGE_DUTCH)
"Houd Dialoog Bij"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mantenha Dialog"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Behold Dialog"
#else
"Keep Dialog"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Mantenga este diálogo trazado después de correr un programa"
#elif defined(PROG_LANGUAGE_FRENCH)
"Garder cette boite de dialogue après avoir exécuter le programme"
#elif defined(PROG_LANGUAGE_GERMAN)
"Behalten Sie diesen Dialog, der nach Laufen jedes Programms\
 aufgezeichnet wird"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Tenere questo mapped di dialogo dopo correre ogni programma"
#elif defined(PROG_LANGUAGE_DUTCH)
"Houd deze dialoog bracht in kaart na lopen van elk programma bij"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mantenha este mapped de dialog depois de correr cada programa"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Behold denne dialogen som kartlagt etter kjøring av hver program"
#else
"Check this to keep this dialog mapped after running each program"
#endif
	);
	gtk_widget_show(w);

	/* Options button */
	d->options_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_options2_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Las Opciones"
#elif defined(PROG_LANGUAGE_FRENCH)
"Options"
#elif defined(PROG_LANGUAGE_GERMAN)
"Optionen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Opzioni"
#elif defined(PROG_LANGUAGE_DUTCH)
"Opties"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Opções"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Alternativer"
#else
"Options"
#endif
	    , NULL
	);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH, GUI_BUTTON_HLABEL_HEIGHT
	);
	gtk_box_pack_end(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVRunDlgOptionsCB), d
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"El clic para configurar los programas terminales"
#elif defined(PROG_LANGUAGE_FRENCH)
"Configuer le terminal"
#elif defined(PROG_LANGUAGE_GERMAN)
"Klicken, letzte Programme zu gestalten"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Lo scatto di configurare i programmi terminali"
#elif defined(PROG_LANGUAGE_DUTCH)
"Klik Eindprogramma's te vormen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O estalido configurar programas terminais"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Klikk forme avsluttende programer"
#else
"Click to configure terminal programs"
#endif
	);
	gtk_accel_group_add(
	    accelgrp, GDK_o, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_o);
	gtk_widget_show(w);


	w = gtk_hseparator_new();
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);


	/* Hbox for buttons */
	w = gtk_hbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent2 = w;

	/* Run button */
	d->run_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_run_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Corra"
#elif defined(PROG_LANGUAGE_FRENCH)
"Exécuter"
#elif defined(PROG_LANGUAGE_GERMAN)
"Lauf"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Correto"
#elif defined(PROG_LANGUAGE_DUTCH)
"Tocht"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Corrida"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Løp"
#else
"Run"
#endif
	    , NULL
	);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVRunDlgRunCB), d
	);
	gtk_accel_group_add(
	    accelgrp, GDK_Return, 0, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	gtk_accel_group_add(
	    accelgrp, GDK_r, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_r);
	gtk_widget_show(w);

	/* Close button */
	d->close_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_close_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Cierre"
#elif defined(PROG_LANGUAGE_FRENCH)
"Fermer"
#elif defined(PROG_LANGUAGE_GERMAN)
"Nah"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Vicino"
#elif defined(PROG_LANGUAGE_DUTCH)
"Einde"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Próximo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Nær"
#else
"Close"
#endif
	    , NULL
	);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVRunDlgCloseCB), d
	);
	gtk_accel_group_add(
	    accelgrp, GDK_Escape, 0, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	gtk_accel_group_add(
	    accelgrp, GDK_c, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_c);
	gtk_widget_show(w);



	return(d);
}

/*
 *	Marks the Run Dialog as busy or ready.
 */
void EDVRunDlgSetBusy(edv_run_dlg_struct *d, gboolean is_busy)
{
	GdkCursor *cursor;
	GtkWidget *w;
	edv_core_struct *core;


	if(d == NULL)
	    return;

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

	w = d->toplevel;
	if(w != NULL)
	{
	    if(is_busy)
	    {
		/* Increase busy count */
		d->busy_count++;

		/* If already busy then don't change anything */
		if(d->busy_count > 1)
		    return;

		cursor = EDVGetCursor(core, EDV_CURSOR_CODE_BUSY);
	    }
	    else
	    {
		/* Reduce busy count */
		d->busy_count--;
		if(d->busy_count < 0)
		    d->busy_count = 0;

		/* If still busy do not change anything */
		if(d->busy_count > 0)
		    return;

		cursor = NULL;  /* Use default cursor */
	    }

	    /* Update toplevel window's cursor */
	    if(w->window != NULL)
	    {
		gdk_window_set_cursor(w->window, cursor);
		gdk_flush();
	    }
	}
}

/*
 *	Checks if the Run Dialog is mapped.
 */
gboolean EDVRunDlgIsMapped(edv_run_dlg_struct *d)
{
	GtkWidget *w = (d != NULL) ? d->toplevel : NULL;
	return((w != NULL) ? GTK_WIDGET_MAPPED(w) : FALSE);
}

/*
 *	Maps the Run Dialog.
 */
void EDVRunDlgMap(edv_run_dlg_struct *d)
{
	GtkWidget *w = (d != NULL) ? d->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_show_raise(w);

	/* Set the Run Combo as the default widget */
	w = d->run_combo;
	if(w != NULL)
	{
	    GtkCombo *combo = GTK_COMBO(w);
	    gtk_widget_grab_focus(combo->entry);
/*	    gtk_entry_set_position(GTK_ENTRY(combo->entry), 0); */
	}
}

/*
 *	Unmaps the Run Dialog.
 */
void EDVRunDlgUnmap(edv_run_dlg_struct *d)
{
	GtkWidget *w = (d != NULL) ? d->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_hide(w);
}

/*
 *	Deletes the Run Dialog.
 */
void EDVRunDlgDelete(edv_run_dlg_struct *d)
{
	if(d == NULL)
	    return;

	/* Begin destroying widgets */
	GTK_WIDGET_DESTROY(d->run_combo)
	d->run_combo = NULL;
	GTK_WIDGET_DESTROY(d->browse_btn)
	d->browse_btn = NULL;
	GTK_WIDGET_DESTROY(d->clear_btn)
	d->clear_btn = NULL;

	GTK_WIDGET_DESTROY(d->working_dir_entry)
	d->working_dir_entry = NULL;
	GTK_WIDGET_DESTROY(d->working_dir_browse_btn)
	d->working_dir_browse_btn = NULL;
	GTK_WIDGET_DESTROY(d->working_dir_clear_btn)
	d->working_dir_clear_btn = NULL;
	GTK_WIDGET_DESTROY(d->working_dir_get_from_cmd_btn)
	d->working_dir_get_from_cmd_btn = NULL;

	GTK_WIDGET_DESTROY(d->run_in_terminal_check)
	d->run_in_terminal_check = NULL;
	GTK_WIDGET_DESTROY(d->keep_dialog_check)
	d->keep_dialog_check = NULL;
	GTK_WIDGET_DESTROY(d->options_btn)
	d->options_btn = NULL;

	GTK_WIDGET_DESTROY(d->run_btn)
	d->run_btn = NULL;
	GTK_WIDGET_DESTROY(d->close_btn)
	d->close_btn = NULL;

	GTK_WIDGET_DESTROY(d->toplevel)
	d->toplevel = NULL;

	GTK_ACCEL_GROUP_UNREF(d->accelgrp)
	d->accelgrp = NULL;

	g_free(d);
}
