Logo Search packages:      
Sourcecode: libjsw version File versions  Download package

pdialog.c

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

#include "../include/disk.h"

#include "guiutils.h"
#include "pdialog.h"
#include "config.h"

#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_print_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_terminal_32x32.xpm"
#include "images/icon_tuning_32x32.xpm"
#include "images/icon_tools_32x32.xpm"
#include "images/icon_monitor_32x32.xpm"
#include "images/icon_clipboard_32x32.xpm"
#include "images/icon_clipboard_empty_32x32.xpm"
#include "images/icon_edit_32x32.xpm"
#include "images/icon_install_32x32.xpm"
#include "images/icon_uninstall_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_link2_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"

/* TODO */
#include "images/icon_move_file_32x32.xpm"
#include "images/icon_copy_file_32x32.xpm"
#include "images/icon_properties2_32x32.xpm"
#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_browse_20x20.xpm"
#include "images/icon_ok_20x20.xpm"
#include "images/icon_cancel_20x20.xpm"
#include "images/icon_help_20x20.xpm"


/*
 *    Prompt Types:
 */
typedef enum {
      PDIALOG_PROMPT_TYPE_LABEL,
      PDIALOG_PROMPT_TYPE_ENTRY,
      PDIALOG_PROMPT_TYPE_SPIN,
      PDIALOG_PROMPT_TYPE_SCALE,
      PDIALOG_PROMPT_TYPE_COMBO,
      PDIALOG_PROMPT_TYPE_RADIO,
      PDIALOG_PROMPT_TYPE_TOGGLE,
      PDIALOG_PROMPT_TYPE_SEPARATOR
} pdialog_prompt_type;


typedef struct _pdialog_struct            pdialog_struct;
typedef struct _pdialog_prompt_struct     pdialog_prompt_struct;


/*
 *    Prompt Dialog Prompt:
 */
struct _pdialog_prompt_struct {

      pdialog_prompt_type     type;
      GtkWidget       *toplevel,
                  *icon_pm,
                  *label,
                  *value,
                  *browse_btn;

      GtkWidget   *radio_toplevel, **radio;
      gchar       **radio_label;
      gint        total_radios;
  
      gpointer    client_data;

      gchar *(*browse_cb)(
            gpointer,   /* PDialog */
            gpointer,   /* Data */
            gint        /* Prompt Number */
      );

};
#define PDIALOG_PROMPT(p)     ((pdialog_prompt_struct *)(p))

/*
 *    Prompt Dialog:
 */
struct _pdialog_struct {

      gboolean    initialized;
      GtkAccelGroup   *accelgrp;
      GtkWidget       *toplevel,
                  *main_vbox, /* GtkBox for the prompts */
                  *icon_pm,
                  *message_label_hbox,
                  *message_label;

      pdialog_prompt_struct   **prompt;
      gint              total_prompts;

      GtkWidget       *submit_btn,
                  *submit_btn_label,
                  *cancel_btn,
                  *cancel_btn_label,
                  *help_btn;

      GtkWidget   *last_transient_for;    /* Do not reference */
      pdialog_icon      last_icon_code;

      gint        block_loop_level;

      gchar       **response_val;
      gint        response_nvals;
};
#define PDIALOG(p)      ((pdialog_struct *)(p))


/* Callbacks */
static gint PDialogCloseCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
);
static void PDialogBrowseButtonCB(GtkWidget *widget, gpointer data);
static void PDialogEntryEnterCB(GtkWidget *widget, gpointer data);
static gint PDialogEntryCompletePathKeyCB(
      GtkWidget *widget, GdkEventKey *key, gpointer data
);
static void PDialogButtonCB(GtkWidget *widget, gpointer data);
static void PDialogPromptDragDataReceivedCB(
      GtkWidget *widget, GdkDragContext *dc, gint x, gint y,
      GtkSelectionData *selection_data, guint info, guint t,
      gpointer data
);
static gboolean PDialogPromptDragMotionCB(
      GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint t,
      gpointer data
);

/* Utilities */
static guint8 **PDialogGetMessageIconDataFromCode(pdialog_icon icon_code);
static void PDialogSetIcon(pdialog_struct *d, guint8 **icon_data);
static pdialog_prompt_struct *PDialogPromptNewNexus(
      pdialog_prompt_type type,
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value,
      gboolean hide_value,          /* For passwords */
      pdialog_struct *d,
      gpointer client_data,
      gchar *(*browse_cb)(gpointer, gpointer, gint)
);
static void PDialogPromptDelete(pdialog_prompt_struct *p);

/* Front Ends */
gint PDialogInit(void);
void PDialogSetStyle(GtkRcStyle *rc_style);
void PDialogSetTransientFor(GtkWidget *w);
gboolean PDialogIsQuery(void);
void PDialogBreakQuery(void);
GtkWidget *PDialogGetToplevel(void);

static pdialog_prompt_struct *PDialogAddPromptNexus(
      pdialog_prompt_type type,
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value,
      gboolean hide_value,          /* For passwords */
      gpointer client_data,
      gchar *(*browse_cb)(gpointer, gpointer, gint)
);
void PDialogAddPromptLabel(const gchar *label);
void PDialogAddPrompt(
      const guint8 **icon_data,     /* Can be NULL */
      const gchar *label,           /* Can be NULL */
      const gchar *value            /* Can be NULL */
);
void PDialogAddPromptPassword(
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value
);
void PDialogAddPromptWithBrowse(
      const guint8 **icon_data,     /* Can be NULL */
      const gchar *label,           /* Can be NULL */
      const gchar *value,           /* Can be NULL */
      gpointer client_data,         /* Can be NULL */
      gchar *(*browse_cb)(gpointer, gpointer, gint)   /* Can be NULL */
);
void PDialogAddPromptSpin(
      const guint8 **icon_data,
      const gchar *label,
      gfloat value, gfloat lower, gfloat upper,
      gfloat step_increment, gfloat page_increment,
      gfloat climb_rate, guint digits
);
void PDialogAddPromptScale(
      const guint8 **icon_data,
      const gchar *label,
      gfloat value, gfloat lower, gfloat upper,
      gfloat step_increment, gfloat page_increment,
      gboolean show_value, guint digits
);
void PDialogAddPromptCombo(
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value,
      GList *list,
      gboolean editable, gboolean case_sensitive
);
void PDialogAddPromptRadio(
      const guint8 **icon_data,
      const gchar *label,
      GList *list,            /* List of radio button names */
      gint start_num          /* Initial radio button to select */
);
void PDialogAddPromptToggle(
      const guint8 **icon_data,
      const gchar *label, gboolean value
);
void PDialogAddPromptSeparator(void);
void PDialogSetPromptValue(
      gint prompt_num,
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value
);
void PDialogSetPromptTip(gint prompt_num, const gchar *tip);
const gchar *PDialogGetPromptValue(gint prompt_num);
void PDialogSetPromptCompletePath(gint prompt_num);
void PDialogDeleteAllPrompts(void);
gchar **PDialogGetResponse(
      const gchar *title,
      const gchar *message,
      const gchar *explaination,
      pdialog_icon icon_code,
      const gchar *submit_label,
      const gchar *cancel_label,
      pdialog_btn_flags show_buttons,           /* Any of PDIALOG_BTNFLAG_* */
      pdialog_btn_flags default_button,   /* One of PDIALOG_BTNFLAG_* */
      gint *nvalues
);
gchar **PDialogGetResponseIconData(
      const gchar *title,
      const gchar *message,
      const gchar *explaination,
      guint8 **icon_data,
      const gchar *submit_label,
      const gchar *cancel_label,
      pdialog_btn_flags show_buttons,           /* Any of PDIALOG_BTNFLAG_* */
      pdialog_btn_flags default_button,   /* One of PDIALOG_BTNFLAG_* */
      gint *nvalues
);
void PDialogSetSize(gint width, gint height);
void PDialogMap(void);
void PDialogUnmap(void);
void PDialogShutdown(void);


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


static pdialog_struct   pdialog;


/*
 *    Dialog toplevel GtkWindow "delete_event" signal callback.
 */
static gint PDialogCloseCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
)
{
      pdialog_struct *d = PDIALOG(data);
      if((widget == NULL) || (d == NULL))
          return(TRUE);

      /* Break out of one main loop level */
      gtk_main_quit();
      d->block_loop_level--;

      return(TRUE);
}

/*
 *    Dialog prompt browse GtkButton "clicked" signal callback.
 */
static void PDialogBrowseButtonCB(GtkWidget *widget, gpointer data)
{
      gint i;
      const gchar *s;
      GtkWidget *w;
      pdialog_prompt_struct *p;
      pdialog_struct *d = PDIALOG(data);
      if((widget == NULL) || (d == NULL))
          return;

      /* Check which browse button was pressed */
      for(i = 0; i < d->total_prompts; i++)
      {
          p = d->prompt[i];
          if(p == NULL)
            continue;

          if(widget != p->browse_btn)
              continue;

          if(p->browse_cb != NULL)
          {
            s = (const gchar *)p->browse_cb(
                d,                  /* Prompt dialog */
                p->client_data,     /* Client data */
                i             /* Prompt number */
            );
            w = p->value;
            if((w != NULL) && (s != NULL))
            {
                if(GTK_IS_ENTRY(w))
                  gtk_entry_set_text(GTK_ENTRY(w), s);
            }
          }
          break;
      }
}

/*
 *    Dialog prompt GtkEntry "activate" signal callback.
 */
static void PDialogEntryEnterCB(GtkWidget *widget, gpointer data)
{
      pdialog_struct *d = PDIALOG(data);
      if((widget == NULL) || (d == NULL))
          return;

      /* Call button callback and pass the submit button as the
       * widget
       */
      PDialogButtonCB(d->submit_btn, d);
}

/*
 *    Dialog prompt GtkEntry complete path "key_press_event" or
 *    "key_release_event" signal callback.
 */
static gint PDialogEntryCompletePathKeyCB(
      GtkWidget *widget, GdkEventKey *key, gpointer data
)
{
      gint status = 0;
      gboolean press;
      GtkEntry *entry;
      pdialog_struct *d = PDIALOG(data);
      if((widget == NULL) || (key == NULL) || (d == NULL))
          return(status);

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

      /* Given widget must have or be a GtkEntry */
      if(GTK_IS_COMBO(widget))
      {
          GtkCombo *combo = GTK_COMBO(widget);
          entry = GTK_ENTRY(combo->entry);
      }
      else if(GTK_IS_ENTRY(widget))
      {
          entry = GTK_ENTRY(widget);
      }
      else
      {
          return(status);
      }

#define SIGNAL_EMIT_STOP      {           \
 gtk_signal_emit_stop_by_name(                  \
  GTK_OBJECT(widget),                     \
  press ?                           \
   "key_press_event" : "key_release_event"      \
 );                                 \
}

      switch(key->keyval)
      {
        case GDK_Tab:
          if(press)
          {
            gchar *s = STRDUP(gtk_entry_get_text(entry));
            if(s != NULL)
            {
                gint status;

                s = CompletePath(s, &status);
                gtk_entry_set_text(entry, (s != NULL) ? s : "");
                gtk_entry_set_position(entry, -1);
                g_free(s);

                switch(status)
                {
                  case COMPLETE_PATH_NONE:
                  case COMPLETE_PATH_AMBIGUOUS:
                  gdk_beep();
                  break;
                }
            }
          }
          SIGNAL_EMIT_STOP
          status = TRUE;
          break;
      }

#undef SIGNAL_EMIT_STOP

      return(status);
}

/*
 *    Dialog GtkButton "clicked" signal callback.
 */
static void PDialogButtonCB(GtkWidget *widget, gpointer data)
{
      pdialog_struct *d = PDIALOG(data);
      if((widget == NULL) || (d == NULL))
          return;

      /* Check which widget this signal is for */

      /* Submit */
      if(widget == d->submit_btn)
      {
          gint i;

          /* Clear existing responses values */
          for(i = 0; i < d->response_nvals; i++)
            g_free(d->response_val[i]);
          g_free(d->response_val);
          d->response_val = NULL;
          d->response_nvals = 0;

          /* Fetch values from each prompt and copy them to
           * the response values
           *
           * The number of response values is equal to the number
           * of prompts on the dialog
           */
          d->response_nvals = d->total_prompts;
          d->response_val = (d->response_nvals > 0) ?
            (gchar **)g_malloc0(d->response_nvals * sizeof(gchar *)) : NULL;
          if(d->response_val == NULL)
          {
            d->response_nvals = 0;
          }
          else
          {
            GtkWidget *w;
            pdialog_prompt_struct *p;

            /* Fetch values for each response value, thus going
             * through each prompt
             */
            for(i = 0; i < d->response_nvals; i++)
            {
                p = d->prompt[i];
                if(p == NULL)
                {
                  d->response_val[i] = STRDUP("");
                  continue;
                }

                w = p->value;

                switch(p->type)
                {
                  case PDIALOG_PROMPT_TYPE_LABEL:
                  d->response_val[i] = STRDUP("");
                  break;

                  case PDIALOG_PROMPT_TYPE_ENTRY:
                  if(GTK_IS_ENTRY(w))
                  {
                      const gchar *s = gtk_entry_get_text(GTK_ENTRY(w));
                      d->response_val[i] = STRDUP((s != NULL) ? s : "");
                  }
                  break;

                  case PDIALOG_PROMPT_TYPE_SPIN:
                  if(GTK_IS_SPIN_BUTTON(w))
                  {
                      const gchar *s = gtk_entry_get_text(GTK_ENTRY(w));
                      d->response_val[i] = STRDUP((s != NULL) ? s : "");
                  }
                  break;

                  case PDIALOG_PROMPT_TYPE_SCALE:
                  if(GTK_IS_SCALE(w))
                  {
                      GtkRange *range = GTK_RANGE(w);
                      GtkAdjustment *adj = range->adjustment;
                      if(adj != NULL)
                      {
                        gchar fmt_str[80];
                        g_snprintf(
                            fmt_str, sizeof(fmt_str),
                            "%%.%if", 
                            range->digits
                        );
                        d->response_val[i] = g_strdup_printf(
                            fmt_str, adj->value
                        );
                      }
                  }
                  break;

                  case PDIALOG_PROMPT_TYPE_COMBO:
                  if(GTK_IS_COMBO(w))
                  {
                      GtkCombo *combo = GTK_COMBO(w);
                      const gchar *s = gtk_entry_get_text(
                        GTK_ENTRY(combo->entry)
                      );
                      d->response_val[i] = STRDUP((s != NULL) ? s : "");
                  }
                  break;

                  case PDIALOG_PROMPT_TYPE_RADIO:
                  if(p->total_radios > 0)
                  {
                      gint n;
                      for(n = 0; n < p->total_radios; n++)
                      {
                        if(GTK_TOGGLE_BUTTON_GET_ACTIVE(p->radio[n]))
                        {
                            const gchar *s = p->radio_label[n];
                            d->response_val[i] = STRDUP(
                              (s != NULL) ? s : ""
                            );
                            break;
                        }
                      }
                  }
                  break;

                  case PDIALOG_PROMPT_TYPE_TOGGLE:
                  if(GTK_IS_TOGGLE_BUTTON(w))
                  {
                      GtkToggleButton *tb = GTK_TOGGLE_BUTTON(w);
                      d->response_val[i] = STRDUP(
                        (tb->active) ? "1" : "0"
                      );
                  }
                  break;

                  case PDIALOG_PROMPT_TYPE_SEPARATOR:
                  d->response_val[i] = STRDUP("");
                  break;
                }
            }
          }

          /* Break out of one main loop level */
          gtk_main_quit();
          d->block_loop_level--;
      }
      /* Cancel */
      else if(widget == d->cancel_btn)
      {
          /* Break out of one main loop level */
          gtk_main_quit();
          d->block_loop_level--;
      }
      /* Help */
      else if(widget == d->help_btn)
      {

      }
}

/*
 *    Prompt GtkEntry "drag_data_received" signal callback.
 */
static void PDialogPromptDragDataReceivedCB(
      GtkWidget *widget, GdkDragContext *dc, gint x, gint y,
      GtkSelectionData *selection_data, guint info, guint t,
      gpointer data
)
{
      if((widget == NULL) || (dc == NULL) || (selection_data == NULL))
          return;

      if((selection_data->data == NULL) || (selection_data->length <= 0))
          return;

      if((info == 0) || /* "text/plain" */
         (info == 1) || /* "text/uri-list" */
         (info == 2)          /* "STRING" */
      )
      {
          gint buf_len = selection_data->length;
          gchar *buf = (gchar *)g_malloc((buf_len + 1) * sizeof(gchar));
          memcpy(buf, selection_data->data, buf_len * sizeof(gchar));
          buf[buf_len] = '\0';

          if(GTK_IS_ENTRY(widget))
          {
            GtkEntry *entry = GTK_ENTRY(widget);
            gtk_entry_set_text(entry, buf);
            gtk_entry_set_position(entry, -1);
          }

          g_free(buf);
      }
}

/*
 *    Prompt GtkEntry "drag_motion" signal callback.
 */
static gboolean PDialogPromptDragMotionCB(
      GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint t,
      gpointer data
)
{
      if(dc == NULL)
          return(FALSE);

      if(dc->actions & GDK_ACTION_COPY)
          gdk_drag_status(dc, GDK_ACTION_COPY, t);
      else
          gdk_drag_status(dc, 0, t);

      return(TRUE);
}


/*
 *    Returns the icon data for the specified icon code.
 */
static guint8 **PDialogGetMessageIconDataFromCode(pdialog_icon icon_code)
{
      guint8 **d = (guint8 **)icon_question_32x32_xpm;

      switch(icon_code)
      {
        case PDIALOG_ICON_INFO:
          d = (guint8 **)icon_info_32x32_xpm;
          break;
        case PDIALOG_ICON_WARNING:
          d = (guint8 **)icon_warning_32x32_xpm;
          break;
        case PDIALOG_ICON_ERROR:
          d = (guint8 **)icon_error_32x32_xpm;
          break;
        case PDIALOG_ICON_QUESTION:
          d = (guint8 **)icon_question_32x32_xpm;
          break;
        case PDIALOG_ICON_HELP:
          d = (guint8 **)icon_help_32x32_xpm;
          break;
        case PDIALOG_ICON_WIZARD:
          d = (guint8 **)icon_wand_32x32_xpm;
          break;
        case PDIALOG_ICON_SEARCH:
          d = (guint8 **)icon_search_32x32_xpm;
          break;
        case PDIALOG_ICON_SECURITY:
          d = (guint8 **)icon_security_32x32_xpm;
          break;
        case PDIALOG_ICON_PRINTER:
          d = (guint8 **)icon_print_32x32_xpm;
          break;
        case PDIALOG_ICON_SPEAKER:
          d = (guint8 **)icon_sound_32x32_xpm;
          break;
        case PDIALOG_ICON_BULB:
          d = (guint8 **)icon_bulb_32x32_xpm;
          break;
        case PDIALOG_ICON_POWER:
          d = (guint8 **)icon_power_32x32_xpm;
          break;
        case PDIALOG_ICON_OS:
#if defined(__linux__)
          d = (guint8 **)icon_linux_32x32_xpm;
#else
          d = (guint8 **)icon_linux_32x32_xpm;
#endif
          break;
        case PDIALOG_ICON_TERMINAL:
          d = (guint8 **)icon_terminal_32x32_xpm;
          break;
        case PDIALOG_ICON_SETTINGS:
          d = (guint8 **)icon_tuning_32x32_xpm;
          break;
        case PDIALOG_ICON_TOOLS:
          d = (guint8 **)icon_tools_32x32_xpm;
          break;
        case PDIALOG_ICON_MONITOR:
          d = (guint8 **)icon_monitor_32x32_xpm;
          break;
        case PDIALOG_ICON_CLIPBOARD_EMPTY:
          d = (guint8 **)icon_clipboard_empty_32x32_xpm;
          break;
        case PDIALOG_ICON_CLIPBOARD_FULL:
          d = (guint8 **)icon_clipboard_32x32_xpm;
          break;
        case PDIALOG_ICON_EDIT:
          d = (guint8 **)icon_edit_32x32_xpm;
          break;
        case PDIALOG_ICON_INSTALL:
          d = (guint8 **)icon_install_32x32_xpm;
          break;
        case PDIALOG_ICON_UNINSTALL:
          d = (guint8 **)icon_uninstall_32x32_xpm;
          break;

        case PDIALOG_ICON_FILE:
          d = (guint8 **)icon_file_32x32_xpm;
          break;
        case PDIALOG_ICON_FOLDER_CLOSER:
          d = (guint8 **)icon_folder_closed_32x32_xpm;
          break;
        case PDIALOG_ICON_FOLDER_OPENED:
          d = (guint8 **)icon_folder_opened_32x32_xpm;
          break;
        case PDIALOG_ICON_LINK:
          d = (guint8 **)icon_link2_32x32_xpm;
          break;
        case PDIALOG_ICON_PIPE:
          d = (guint8 **)icon_pipe_32x32_xpm;
          break;
        case PDIALOG_ICON_DEVICE:
          d = (guint8 **)icon_device_misc_32x32_xpm;
          break;
        case PDIALOG_ICON_DEVICE_BLOCK:
          d = (guint8 **)icon_device_block_32x32_xpm;
          break;
        case PDIALOG_ICON_DEVICE_CHARACTER:
          d = (guint8 **)icon_device_character_32x32_xpm;
          break;
        case PDIALOG_ICON_SOCKET:
          d = (guint8 **)icon_socket_32x32_xpm;
          break;

        case PDIALOG_ICON_FILE_MOVE:
          d = (guint8 **)icon_move_file_32x32_xpm;
          break;
        case PDIALOG_ICON_FILE_COPY:
          d = (guint8 **)icon_copy_file_32x32_xpm;
          break;
        case PDIALOG_ICON_FILE_PROPERTIES:
          d = (guint8 **)icon_properties2_32x32_xpm;
          break;

        case PDIALOG_ICON_PLANET:
          d = (guint8 **)icon_planet_32x32_xpm;
          break;
        case PDIALOG_ICON_FTP:
          d = (guint8 **)icon_ftp_32x32_xpm;
          break;
        case PDIALOG_ICON_CHAT:
          d = (guint8 **)icon_chat_32x32_xpm;
          break;
        case PDIALOG_ICON_FILE_WWW:
          d = (guint8 **)icon_file_www_32x32_xpm;
          break;

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

/*
 *    Updates the icon for the dialog. Updates the member icon_pm
 *    as needed.
 */
static void PDialogSetIcon(pdialog_struct *d, guint8 **icon_data)
{
      gint width, height;
      GdkBitmap *mask;
      GdkPixmap *pixmap;
      GtkWidget *w = (d != NULL) ? d->icon_pm : NULL;
      if((w == NULL) || (icon_data == NULL))
          return;

      /* Load new pixmap for icon */
      pixmap = GDK_PIXMAP_NEW_FROM_XPM_DATA(&mask, icon_data);
      if(pixmap == NULL)
          return;

      gdk_window_get_size(pixmap, &width, &height);

      /* Set icon GtkPixmap */
      gtk_pixmap_set(GTK_PIXMAP(w), pixmap, mask);
      gtk_widget_set_usize(w, width, height);

      GDK_PIXMAP_UNREF(pixmap);
      GDK_BITMAP_UNREF(mask);

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

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

/*
 *    Allocates and creates a new prompt structure, but does not 
 *    add it to the prompt dialog.
 */
static pdialog_prompt_struct *PDialogPromptNewNexus(
      pdialog_prompt_type type,
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value,
      gboolean hide_value,          /* For passwords */
      pdialog_struct *d,
      gpointer client_data,
      gchar *(*browse_cb)(gpointer, gpointer, gint)
)
{
      const gint  border_major = 5,
                  border_minor = 2;
      GdkWindow *window;
      GtkStyle *style;
      GtkWidget *w, *parent;
      pdialog_prompt_struct *p = PDIALOG_PROMPT(
          g_malloc0(sizeof(pdialog_prompt_struct))
      );
      if(p == NULL)
          return(p);

      w = d->toplevel;
      window = (w != NULL) ? w->window : NULL;
      style = gtk_widget_get_style(w); 

      p->type = type;
      p->toplevel = parent = w = gtk_hbox_new(FALSE, border_minor);

      /* Create icon? */
      if(icon_data != NULL)
      {
          GdkBitmap *mask;
          GdkPixmap *pixmap = GDK_PIXMAP_NEW_FROM_XPM_DATA(
            &mask, (guint8 **)icon_data
          );
          if(pixmap != NULL)
          {
            gint width, height;
            gdk_window_get_size(pixmap, &width, &height);
            p->icon_pm = w = gtk_pixmap_new(pixmap, mask);
            gtk_widget_set_usize(w, width, height);
            gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
            gtk_widget_show(w);

            GDK_PIXMAP_UNREF(pixmap);
            GDK_BITMAP_UNREF(mask);
          }
      }

      /* Create label? */
      if((label != NULL) &&
         (type != PDIALOG_PROMPT_TYPE_LABEL) &&
         (type != PDIALOG_PROMPT_TYPE_TOGGLE) &&
         (type != PDIALOG_PROMPT_TYPE_SEPARATOR)
      )
      {
          p->label = w = gtk_label_new(label);
          gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_RIGHT);
          gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
          gtk_widget_show(w);
      }
 
      /* Primary input widget */
      if(TRUE)
      {
          GtkWidget *w2;
          const GtkTargetEntry dnd_tar_types[] = {
{"text/plain",                      0,    0},
{"text/uri-list",             0,    1},
{"STRING",                    0,    2}
          };
          /* Create by prompt type */
          switch(type)
          {
            case PDIALOG_PROMPT_TYPE_LABEL:
            p->value = w = gtk_label_new((value != NULL) ? value : "");
            gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
            gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
            gtk_widget_show(w);
            break;

            case PDIALOG_PROMPT_TYPE_ENTRY:
            p->value = w = gtk_entry_new();
            gtk_entry_set_visibility(GTK_ENTRY(w), !hide_value);
            gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
            GUIDNDSetTar(
                w,
                dnd_tar_types,
                sizeof(dnd_tar_types) / sizeof(GtkTargetEntry),
                GDK_ACTION_COPY,          /* Actions */
                GDK_ACTION_COPY,          /* Default action if same */
                GDK_ACTION_COPY,          /* Default action */
                PDialogPromptDragDataReceivedCB,
                w
            );
            gtk_signal_connect_after(
                GTK_OBJECT(w), "drag_motion",
                GTK_SIGNAL_FUNC(PDialogPromptDragMotionCB), w
            );
            if(value != NULL)
            {
                gtk_entry_set_text(GTK_ENTRY(w), value);
                gtk_entry_set_position(GTK_ENTRY(w), -1);
            }
            gtk_signal_connect(
                GTK_OBJECT(w), "activate",
                GTK_SIGNAL_FUNC(PDialogEntryEnterCB), d
            );
            gtk_widget_show(w);
            break;

            case PDIALOG_PROMPT_TYPE_SPIN:
            p->value = w = gtk_spin_button_new(NULL, 1.0f, 0);
            gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
            gtk_signal_connect(
                GTK_OBJECT(w), "activate",
                GTK_SIGNAL_FUNC(PDialogEntryEnterCB), d
            );
            gtk_widget_show(w);
            break;

            case PDIALOG_PROMPT_TYPE_SCALE:
            p->value = w = gtk_hscale_new(NULL);
            gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
            gtk_widget_show(w);
            break;

            case PDIALOG_PROMPT_TYPE_COMBO:
            p->value = w = gtk_combo_new();
            gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
            gtk_combo_disable_activate(GTK_COMBO(w));
            w2 = GTK_COMBO(w)->entry;
            gtk_entry_set_visibility(GTK_ENTRY(w2), !hide_value);
            GUIDNDSetTar(
                w2,
                dnd_tar_types,
                sizeof(dnd_tar_types) / sizeof(GtkTargetEntry),
                GDK_ACTION_COPY,          /* Actions */
                GDK_ACTION_COPY,          /* Default action if same */
                GDK_ACTION_COPY,          /* Default action */
                PDialogPromptDragDataReceivedCB,
                w2
            );
            gtk_signal_connect_after(
                GTK_OBJECT(w2), "drag_motion",
                GTK_SIGNAL_FUNC(PDialogPromptDragMotionCB), w2
            );
            if(value != NULL)
            {
                gtk_entry_set_text(GTK_ENTRY(w2), value);
                gtk_entry_set_position(GTK_ENTRY(w2), -1);
            }
            gtk_signal_connect(
                GTK_OBJECT(w2), "activate",
                GTK_SIGNAL_FUNC(PDialogEntryEnterCB), d
            );
            gtk_widget_show(w);
            break;

            case PDIALOG_PROMPT_TYPE_RADIO:
            p->radio_toplevel = w = gtk_hbox_new(FALSE, border_major);
            gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
            gtk_widget_show(w);
            /* Do not create each radio button, they will be
             * created by the calling function
             */
            break;

           case PDIALOG_PROMPT_TYPE_TOGGLE:
            if(label != NULL)
                w = gtk_check_button_new_with_label(label);
            else
                w = gtk_check_button_new();
            p->value = w;
            gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
            gtk_widget_show(w);
            break;

            case PDIALOG_PROMPT_TYPE_SEPARATOR:
            p->value = w = gtk_hseparator_new();
            gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
            gtk_widget_show(w);
            break;
          }
      }

      /* Create browse button? */
      if(browse_cb != NULL)
      {
          /* Set browse callback function and client data */
          p->client_data = client_data;
          p->browse_cb = browse_cb;

          /* Create browse button */
          p->browse_btn = w = GUIButtonPixmap(
            (guint8 **)icon_browse_20x20_xpm
          );
          gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(PDialogBrowseButtonCB), d
          );
          gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
          GUISetWidgetTip(
            w,
#ifdef PROG_LANGUAGE_ENGLISH
            "Browse"
#endif
#ifdef PROG_LANGUAGE_SPANISH
            "Hojee"
#endif
#ifdef PROG_LANGUAGE_FRENCH
            "Naviguer"
#endif
#ifdef PROG_LANGUAGE_GERMAN
            "Brausen"
#endif
#ifdef PROG_LANGUAGE_ITALIAN
            "Curiosare"
#endif
#ifdef PROG_LANGUAGE_NORWEGIAN
            "Browse"
#endif
#ifdef PROG_LANGUAGE_PORTUGUESE
            "Olhe"
#endif
          );
          gtk_widget_show(w);
      }

      return(p); 
}



/*
 *    Deletes all widgets in the prompt structure and deallocates
 *    the prompt structure itself, regardless of the prompt's
 *    type.
 */
static void PDialogPromptDelete(pdialog_prompt_struct *p)
{
      gint i;

      if(p == NULL)
          return;

      for(i = 0; i < p->total_radios; i++)
      {
          GTK_WIDGET_DESTROY(p->radio[i])
          g_free(p->radio_label[i]);
      }
      g_free(p->radio);
      p->radio = NULL;
      g_free(p->radio_label);
      p->radio_label = NULL;
      p->total_radios = 0;
      GTK_WIDGET_DESTROY(p->radio_toplevel)

      GTK_WIDGET_DESTROY(p->browse_btn)
      GTK_WIDGET_DESTROY(p->value)
      GTK_WIDGET_DESTROY(p->label)
      GTK_WIDGET_DESTROY(p->icon_pm)
      GTK_WIDGET_DESTROY(p->toplevel)

      g_free(p);
}


/*
 *    Initializes the prompt dialog.
 */
gint PDialogInit(void)
{
      const gint border_major = 5;
      GdkBitmap *mask;
      GdkPixmap *pixmap;
      GdkWindow *window;
      GtkAccelGroup *accelgrp;
      GtkStyle *style;
      GtkWidget *w, *parent, *parent2, *parent3;
      pdialog_struct *d = &pdialog;

      /* Already initialized? */
      if(d->initialized)
          return(-2);

      /* Reset values */
      memset(d, 0x00, sizeof(pdialog_struct));

      d->initialized = TRUE;
      d->last_icon_code = PDIALOG_ICON_QUESTION;
      d->last_transient_for = NULL;
      d->block_loop_level = 0;
      d->response_val = NULL;
      d->response_nvals = 0;

      /* Keyboard accelerator group */
      d->accelgrp = accelgrp = gtk_accel_group_new();

      /* Toplevel */
      d->toplevel = w = gtk_window_new(GTK_WINDOW_DIALOG);
      gtk_window_set_title(GTK_WINDOW(w), "Enter Values");
#ifdef PROG_NAME
      gtk_window_set_wmclass(
          GTK_WINDOW(w), 
          "dialog",
          PROG_NAME
      );
#endif
      gtk_widget_realize(w);
      window = w->window;
      if(window != NULL)
      {
          GdkGeometry geo;

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

          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
          );
      }
      gtk_signal_connect(
          GTK_OBJECT(w), "delete_event",
          GTK_SIGNAL_FUNC(PDialogCloseCB), d
      );
      gtk_container_set_border_width(GTK_CONTAINER(w), 0);
      gtk_window_add_accel_group(GTK_WINDOW(w), accelgrp);
      style = gtk_widget_get_style(w);
      parent = w;


      /* Vbox */
      w = gtk_vbox_new(FALSE, 0);
      gtk_container_add(GTK_CONTAINER(parent), w);
      gtk_widget_show(w);
      parent = w;


      /* Hbox for holding the vboxes of icon and prompts */
      w = gtk_hbox_new(FALSE, 0);
      gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, border_major);
      gtk_widget_show(w);
      parent2 = w;

      /* Vbox for icon */
      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_question_32x32_xpm
      );
      if(pixmap != NULL)
      {
          gint width, height;
          gdk_window_get_size(pixmap, &width, &height);
          d->icon_pm = w = gtk_pixmap_new(pixmap, mask);
          gtk_widget_set_usize(w, width, height);
          gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
          gtk_widget_show(w);
          GDK_PIXMAP_UNREF(pixmap);
          GDK_BITMAP_UNREF(mask);
      }

      /* Vbox for message label and prompt widgets */
      d->main_vbox = w = gtk_vbox_new(FALSE, border_major);
      gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, border_major);
      gtk_widget_show(w);
      parent2 = w;

      /* Message hbox and label */
      d->message_label_hbox = w = gtk_hbox_new(FALSE, 0);
      gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
      gtk_widget_show(w);
      parent2 = w;
      d->message_label = w = gtk_label_new("");
      gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
      gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
      gtk_widget_show(w);


      /* Separator */
      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, border_major);
      gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, border_major);
      gtk_widget_show(w);
      parent2 = w;

      /* Submit button */
      d->submit_btn = w = GUIButtonPixmapLabelH(
          (guint8 **)icon_ok_20x20_xpm,
#ifdef PROG_LANGUAGE_ENGLISH
          "Submit",
#endif
#ifdef PROG_LANGUAGE_SPANISH
          "Sométase",
#endif
#ifdef PROG_LANGUAGE_FRENCH
          "Soumettre",
#endif
#ifdef PROG_LANGUAGE_GERMAN
          "Sie Ein",
#endif
#ifdef PROG_LANGUAGE_ITALIAN
          "Sottomettere",
#endif
#ifdef PROG_LANGUAGE_NORWEGIAN
          "Forelegg",
#endif
#ifdef PROG_LANGUAGE_PORTUGUESE
          "Submeta",
#endif
          &d->submit_btn_label
      );
      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(PDialogButtonCB), d
      );
      gtk_accel_group_add(
          accelgrp, GDK_Return, 0, GTK_ACCEL_VISIBLE,
          GTK_OBJECT(w), "clicked"
      );
      gtk_accel_group_add(
          accelgrp, GDK_3270_Enter, 0, GTK_ACCEL_VISIBLE,
          GTK_OBJECT(w), "clicked"
      );
      gtk_accel_group_add(
          accelgrp, GDK_KP_Enter, 0, GTK_ACCEL_VISIBLE,
          GTK_OBJECT(w), "clicked"
      );
      gtk_accel_group_add(
          accelgrp, GDK_ISO_Enter, 0, GTK_ACCEL_VISIBLE,
          GTK_OBJECT(w), "clicked"
      );

      /* Cancel button */
      d->cancel_btn = w = GUIButtonPixmapLabelH(
          (guint8 **)icon_cancel_20x20_xpm,
#ifdef PROG_LANGUAGE_ENGLISH
          "Cancel",
#endif
#ifdef PROG_LANGUAGE_SPANISH
          "Cancele",
#endif
#ifdef PROG_LANGUAGE_FRENCH
          "Annuler",
#endif
#ifdef PROG_LANGUAGE_GERMAN
          "Sie Auf",
#endif
#ifdef PROG_LANGUAGE_ITALIAN
          "Annullare",
#endif
#ifdef PROG_LANGUAGE_NORWEGIAN
          "Kanseller",
#endif
#ifdef PROG_LANGUAGE_PORTUGUESE
          "Cancelamento",
#endif
          &d->cancel_btn_label
      );
      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(PDialogButtonCB), d
      );
      gtk_accel_group_add(
          accelgrp, GDK_Escape, 0, GTK_ACCEL_VISIBLE,
          GTK_OBJECT(w), "clicked"
      );

      /* Help button */
      d->help_btn = w = GUIButtonPixmapLabelH(
          (guint8 **)icon_help_20x20_xpm,
#ifdef PROG_LANGUAGE_ENGLISH
          "Help",
#endif
#ifdef PROG_LANGUAGE_SPANISH
          "Ayuda",
#endif
#ifdef PROG_LANGUAGE_FRENCH
          "Aide",
#endif
#ifdef PROG_LANGUAGE_GERMAN
          "Hilfe",
#endif
#ifdef PROG_LANGUAGE_ITALIAN
          "L'Aiuto",
#endif
#ifdef PROG_LANGUAGE_NORWEGIAN
          "Hjelp",
#endif
#ifdef PROG_LANGUAGE_PORTUGUESE
          "Ajuda",
#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(PDialogButtonCB), d
      );


      return(0);
}

/*
 *    Sets the Dialog's style.
 */
void PDialogSetStyle(GtkRcStyle *rc_style)
{
      GtkWidget *w;
      pdialog_struct *d = &pdialog;

      if(!d->initialized)
          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 PDialogSetTransientFor(GtkWidget *w)
{
      pdialog_struct *d = &pdialog;

      if(!d->initialized)
          return;

      if(d->toplevel != NULL)
      {
          if(w != NULL)
          {
            if(!GTK_IS_WINDOW(GTK_OBJECT(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 Dialog is currently waiting for user input.
 */
gboolean PDialogIsQuery(void)
{
      pdialog_struct *d = &pdialog;
      return((d->block_loop_level > 0) ? TRUE : FALSE);
}

/*
 *    Breaks the Dialog's user input query (if any) and causes the
 *    querying function to return CDIALOG_RESPONSE_NOT_AVAILABLE.
 */
void PDialogBreakQuery(void)
{
      pdialog_struct *d = &pdialog;

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

/*
 *    Returns the Dialog's toplevel widget.
 */
GtkWidget *PDialogGetToplevel(void)
{
      pdialog_struct *d = &pdialog;
      return(d->toplevel);
}


/*
 *    Nexus for adding a prompt to the dialog.
 */
static pdialog_prompt_struct *PDialogAddPromptNexus(
      pdialog_prompt_type type,
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value,
      gboolean hide_value,          /* For passwords */
      gpointer client_data,
      gchar *(*browse_cb)(gpointer, gpointer, gint)
)
{
      gint n;
      GtkWidget *w, *parent;
      pdialog_struct *d = &pdialog;
      pdialog_prompt_struct *p = PDialogPromptNewNexus(
          type,
          icon_data, label, value, hide_value,
          d,
          client_data, browse_cb
      );
      if(p == NULL)
          return(NULL);

      if(d->total_prompts < 0)
          d->total_prompts = 0;

      for(n = 0; n < d->total_prompts; n++)
      {
          if(d->prompt[n] == NULL) 
            break; 
      }
      if(n < d->total_prompts)
      {
          d->prompt[n] = p;
      } 
      else
      {
          n = d->total_prompts;
          d->total_prompts++;
          d->prompt = (pdialog_prompt_struct **)g_realloc(
            d->prompt,
            d->total_prompts * sizeof(pdialog_prompt_struct *)
          );
          if(d->prompt == NULL)
          {
            PDialogPromptDelete(p);
            d->total_prompts = 0;
            return(NULL);
          }

          d->prompt[n] = p;
      }

      parent = d->main_vbox;
      w = p->toplevel;
      if((parent != NULL) && (w != NULL))
      {
          gtk_box_pack_start(GTK_BOX(parent), w, TRUE, FALSE, 0);
          gtk_widget_show(w);
      }

      return(p);
}

/*
 *    Adds a label to the dialog.
 */
void PDialogAddPromptLabel(const gchar *label)
{
      PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_LABEL,
          NULL, NULL, label, FALSE, NULL, NULL
      );
}

/*
 *    Adds a prompt to the dialog.
 */
void PDialogAddPrompt(
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value
)
{
      PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_ENTRY,
          icon_data, label, value, FALSE, NULL, NULL
      );
}

/*
 *    Adds a prompt (with the value hidden for passwords) to the
 *    dialog.
 */
void PDialogAddPromptPassword(
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value
)
{
      PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_ENTRY,
          icon_data, label, value, TRUE, NULL, NULL
      );
}

/*
 *    Adds a prompt with a browse button to the dialog.
 */
void PDialogAddPromptWithBrowse(
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value,
      gpointer client_data,
      gchar *(*browse_cb)(gpointer, gpointer, gint)
)
{
      PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_ENTRY,
          icon_data, label, value, FALSE, client_data, browse_cb
      );
}

/*
 *    Adds a spin prompt to the dialog.
 */
void PDialogAddPromptSpin(
      const guint8 **icon_data,
      const gchar *label,
      gfloat value, gfloat lower, gfloat upper,
      gfloat step_increment, gfloat page_increment,
      gfloat climb_rate, guint digits
)
{
      pdialog_prompt_struct *p = PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_SPIN,
          icon_data, label, NULL, FALSE, NULL, NULL
      );
      if(p != NULL)
      {
          GtkAdjustment *adj = (GtkAdjustment *)gtk_adjustment_new(
            value, lower, upper,
            step_increment, page_increment, 0.0f
          );
          GtkSpinButton *spin = GTK_SPIN_BUTTON(p->value);
          if((spin != NULL) && (adj != NULL))
            gtk_spin_button_configure(spin, adj, climb_rate, digits);
      }
}

/*
 *    Adds a scale prompt to the dialog.
 */
void PDialogAddPromptScale(
      const guint8 **icon_data,
      const gchar *label,
      gfloat value, gfloat lower, gfloat upper,
      gfloat step_increment, gfloat page_increment,
      gboolean show_value, guint digits
)
{
      pdialog_prompt_struct *p = PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_SCALE,
          icon_data, label, NULL, FALSE, NULL, NULL
      );
      if(p != NULL)
      {
          GtkScale *scale = GTK_SCALE(p->value);
          GtkRange *range = GTK_RANGE(scale);
          GtkAdjustment *adj = (range != NULL) ? range->adjustment : NULL;
          if(adj != NULL)
          {
            adj->value = value;
            adj->lower = lower;
            adj->upper = upper;
            adj->step_increment = step_increment;
            adj->page_increment = page_increment;
          }
          if(scale != NULL)
          {
            gtk_scale_set_value_pos(scale, GTK_POS_RIGHT);
            gtk_scale_set_draw_value(scale, show_value);
            gtk_scale_set_digits(scale, (gint)digits);
          }
      }
}

/*
 *    Adds a combo prompt to the dialog.
 *
 *    The given glist is not modified by this function.
 */
void PDialogAddPromptCombo(
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value,
      GList *list,
      gboolean editable, gboolean case_sensitive
)
{
      pdialog_prompt_struct *p = PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_COMBO,
          icon_data, label, value, FALSE, NULL, NULL
      );
      if(p != NULL)
      {
          GtkCombo *combo = GTK_COMBO(p->value);
          GtkEntry *entry = (combo != NULL) ? GTK_ENTRY(combo->entry) : NULL;
          gtk_entry_set_editable(entry, editable);
          gtk_combo_set_case_sensitive(combo, case_sensitive);
          gtk_combo_set_use_arrows_always(combo, TRUE);
          if(list != NULL)
            gtk_combo_set_popdown_strings(combo, list);
          if(value != NULL)
            gtk_entry_set_text(entry, value);
      }
}

/*
 *    Adds a radio prompt to the dialog.
 *
 *    The specified glist is not modified by this function.
 */
void PDialogAddPromptRadio(
      const guint8 **icon_data,
      const gchar *label,
      GList *list,            /* List of radio button names */
      gint start_num          /* Initial radio button to select */
)
{
      pdialog_prompt_struct *p = PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_RADIO,
          icon_data, label, NULL, FALSE, NULL, NULL
      );
      if(p != NULL)
      {
          gint i = 0;
          GSList *gslist = NULL;
          GList *glist = list;
          GtkWidget *w;

          /* Iterate through given list of values, creating a radio
           * button widget and recording the value as a string for
           * each value
           */
          while(glist != NULL)
          {
            p->total_radios = i + 1;      /* Increase total */

            /* Create a new radio button */
            p->radio = (GtkWidget **)g_realloc(
                p->radio, p->total_radios * sizeof(GtkWidget *)
            );
            p->radio[i] = w = gtk_radio_button_new_with_label(
                gslist, (const gchar *)glist->data
            );
            gtk_box_pack_start(GTK_BOX(p->radio_toplevel), w, FALSE, FALSE, 0);
            GTK_TOGGLE_BUTTON(w)->active = (i == start_num) ? TRUE : FALSE;
            gtk_widget_show(w);
            if(g_list_next(glist) != NULL)
                gslist = gtk_radio_button_group(GTK_RADIO_BUTTON(w));

            /* Record value as a the radio button label string */
            p->radio_label = (gchar **)g_realloc(
                p->radio_label, p->total_radios * sizeof(gchar *)
            );
            p->radio_label[i] = STRDUP((glist->data != NULL) ?
                (const gchar *)glist->data : ""
            );

            /* Go on to next value */
            glist = g_list_next(glist);
            i++;
          }
      }
}

/*
 *    Adds a toggle prompt to the dialog.
 */
void PDialogAddPromptToggle(
      const guint8 **icon_data,
      const gchar *label, gboolean value
)
{
      pdialog_prompt_struct *p = PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_TOGGLE,
          icon_data, label, "", FALSE, NULL, NULL
      );
      if(p != NULL)
          gtk_toggle_button_set_active(
            GTK_TOGGLE_BUTTON(p->value), value ? TRUE : FALSE
          );
}

/*
 *    Adds a separator to the dialog.
 */
void PDialogAddPromptSeparator(void)
{
      PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_SEPARATOR,
          NULL, NULL, NULL, FALSE, NULL, NULL
      );
}


/*
 *    Changes the value in the prompt entry or spin widget, changes
 *    the prompt's icon, and changes the label.
 *
 *    If any input is NULL then that value will be left unchanged.
 *
 *    If prompt_num is -1 then the last prompt will be used.
 */
void PDialogSetPromptValue(
      gint prompt_num,
      const guint8 **icon_data,
      const gchar *label,
      const gchar *value 
)
{
      GtkWidget *w;
      pdialog_prompt_struct *p;
      pdialog_struct *d = &pdialog;

      /* Last prompt? */
      if(prompt_num < 0)
          prompt_num = d->total_prompts - 1;

      /* Prompt valid? */
      p = ((prompt_num >= 0) && (prompt_num < d->total_prompts)) ?
          d->prompt[prompt_num] : NULL;
      if(p == NULL)
          return;

      /* Change icon? */
      w = p->icon_pm;
      if((icon_data != NULL) && (w != NULL))
      {
          GdkBitmap *mask;
          GdkPixmap *pixmap = GDK_PIXMAP_NEW_FROM_XPM_DATA(
            &mask, (guint8 **)icon_data
          );
          if(pixmap != NULL)
          {
            gint width, height;
            gdk_window_get_size(pixmap, &width, &height);
            gtk_pixmap_set(GTK_PIXMAP(w), pixmap, mask);
            gtk_widget_set_usize(w, width, height);

            GDK_PIXMAP_UNREF(pixmap);
            GDK_BITMAP_UNREF(mask);
          }
      }

      /* Change label? */
      w = p->label;
      if((label != NULL) && (w != NULL))
      {
          gtk_label_set_text(GTK_LABEL(w), label);
          gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_RIGHT);
      }

      /* Change value? */
      w = p->value;
      if((value != NULL) && (w != NULL))
      {
          switch(p->type)
          {
            case PDIALOG_PROMPT_TYPE_LABEL:
            if(GTK_IS_LABEL(w))
            {
                GtkLabel *label = GTK_LABEL(w);
                gtk_label_set_text(label, value);
            }
            break;

            case PDIALOG_PROMPT_TYPE_ENTRY:
            if(GTK_IS_ENTRY(w))
            {
                GtkEntry *entry = GTK_ENTRY(w);
                gtk_entry_set_text(entry, value);
                gtk_entry_set_position(entry, -1);
            }
            break;

            case PDIALOG_PROMPT_TYPE_SPIN:
            if(GTK_IS_SPIN_BUTTON(w))
            {
                GtkEntry *entry = GTK_ENTRY(w);
                gtk_entry_set_text(entry, value);
                gtk_entry_set_position(entry, -1);
            }
            break;

            case PDIALOG_PROMPT_TYPE_SCALE:
            if(GTK_IS_SCALE(w))
            {
                GtkRange *range = GTK_RANGE(w);
                GtkAdjustment *adj = range->adjustment;
                if(adj != NULL)
                {
                  adj->value = (gfloat)ATOF(value);
                  gtk_signal_emit_by_name(
                       GTK_OBJECT(adj), "value_changed"
                  );
                }
            }
            break;

            case PDIALOG_PROMPT_TYPE_COMBO:
            if(GTK_IS_COMBO(w))
            {
                GtkCombo *combo = GTK_COMBO(w);
                GtkEntry *entry = GTK_ENTRY(combo->entry);
                gtk_entry_set_text(entry, value);
                gtk_entry_set_position(entry, -1);
            }
            break;

            case PDIALOG_PROMPT_TYPE_RADIO:
            if(p->total_radios > 0)
            {
                gint i;
                const gchar *s;

                for(i = 0; i < p->total_radios; i++)
                {
                  w = p->radio[i];
                  s = p->radio_label[i];
                  if((w == NULL) || (s == NULL))
                      continue;

                  GTK_TOGGLE_BUTTON(w)->active =
                      (!strcmp(s, value)) ? TRUE : FALSE;
                }
            }
            break;

            case PDIALOG_PROMPT_TYPE_TOGGLE:
            if(GTK_IS_TOGGLE_BUTTON(w))
            {
                GtkToggleButton *tb = GTK_TOGGLE_BUTTON(w);
                if(!strcmp(value, "0") || (*value == '\0'))
                  gtk_toggle_button_set_active(tb, FALSE);
                else
                  gtk_toggle_button_set_active(tb, TRUE);
            }
            break;

            case PDIALOG_PROMPT_TYPE_SEPARATOR:
            break;
          }
      }
}

/*
 *    Sets the tip for the given prompt.
 *
 *    If any input is NULL then that value will be left unchanged.
 *
 *    If prompt_num is -1 then the last prompt will be used.
 */
void PDialogSetPromptTip(gint prompt_num, const gchar *tip)
{
      GtkWidget *w;
      pdialog_prompt_struct *p;
      pdialog_struct *d = &pdialog;


      if(prompt_num < 0)
          prompt_num = d->total_prompts - 1;

      p = ((prompt_num >= 0) && (prompt_num < d->total_prompts)) ?
          d->prompt[prompt_num] : NULL;

      if(p != NULL)
      {
          switch(p->type)
          {
            case PDIALOG_PROMPT_TYPE_LABEL:
            break;

            case PDIALOG_PROMPT_TYPE_ENTRY:
            w = p->value;
            GUISetWidgetTip(w, tip);
            break;

            case PDIALOG_PROMPT_TYPE_SPIN:
            w = p->value;
            GUISetWidgetTip(w, tip);
            break;

            case PDIALOG_PROMPT_TYPE_SCALE:
            w = p->value;
            GUISetWidgetTip(w, tip);
            break;

            case PDIALOG_PROMPT_TYPE_COMBO:
            w = p->value;
            if(w != NULL)
            {
                GtkCombo *combo = GTK_COMBO(w);
                GUISetWidgetTip(combo->entry, tip);
            }
            break;

            case PDIALOG_PROMPT_TYPE_RADIO:
/* Not sure how to set the tip for (each) radio?
            w = p->radio_toplevel;
            GUISetWidgetTip(w, tip);
 */
            break;

            case PDIALOG_PROMPT_TYPE_TOGGLE:
            w = p->value;
            GUISetWidgetTip(w, tip);
            break;

            case PDIALOG_PROMPT_TYPE_SEPARATOR:
            break;
          }
      }
}

/*
 *    Gets the value of the specified prompt as a string.
 *
 *    Can return NULL on error or if the prompt does not have a value
 *    to return.
 *
 *    If prompt_num is -1 then the last prompt will be used.
 */
const gchar *PDialogGetPromptValue(gint prompt_num)
{
      pdialog_prompt_struct *p;
      pdialog_struct *d = &pdialog;
      static gchar num_str[80];

      *num_str = '\0';

      if(prompt_num < 0)
          prompt_num = d->total_prompts - 1;

      p = ((prompt_num >= 0) && (prompt_num < d->total_prompts)) ?
          d->prompt[prompt_num] : NULL;

      if((p != NULL) ? (p->value != NULL) : FALSE)
      {
          GtkWidget *w = p->value;

          switch(p->type)
          {
            case PDIALOG_PROMPT_TYPE_LABEL:
            break;

            case PDIALOG_PROMPT_TYPE_ENTRY:
            if(GTK_IS_ENTRY(w))
                return(gtk_entry_get_text(GTK_ENTRY(w)));
            break;

            case PDIALOG_PROMPT_TYPE_SPIN:
            if(GTK_IS_SPIN_BUTTON(w))
                return(gtk_entry_get_text(GTK_ENTRY(w)));
            break;

            case PDIALOG_PROMPT_TYPE_SCALE:
            if(GTK_IS_SCALE(w))
            {
                GtkRange *range = GTK_RANGE(w);
                GtkAdjustment *adj = range->adjustment;
                if(adj != NULL)
                {
                  gchar fmt_str[80];
                  g_snprintf(
                      fmt_str, sizeof(fmt_str),
                      "%%.%if",
                      range->digits
                  );
                  g_snprintf(
                      num_str, sizeof(num_str),
                      fmt_str,
                      adj->value
                  );
                  return(num_str);
                }
            }
            break;

            case PDIALOG_PROMPT_TYPE_COMBO:
            if(GTK_IS_COMBO(w))
            {
                GtkCombo *combo = GTK_COMBO(w);
                w = combo->entry;
                return(gtk_entry_get_text(GTK_ENTRY(w)));
            }
            break;

            case PDIALOG_PROMPT_TYPE_RADIO:
            if(p->total_radios > 0)
            {
                gint i;
                for(i = 0; i < p->total_radios; i++)
                {
                  if(GTK_TOGGLE_BUTTON_GET_ACTIVE(p->radio[i]))
                      return(p->radio_label[i]);
                }
            }
            break;

            case PDIALOG_PROMPT_TYPE_TOGGLE:
            if(GTK_IS_TOGGLE_BUTTON(w))
            {
                GtkToggleButton *tb = GTK_TOGGLE_BUTTON(w);
                return((tb->active) ? "1" : "0");
            }
            break;

            case PDIALOG_PROMPT_TYPE_SEPARATOR:
            break;
          }
      }

      return(NULL);
}

/*
 *    Sets the prompt to accept the tab key to complete paths.
 *
 *    If prompt_num is -1 then the last prompt will be used.
 */
void PDialogSetPromptCompletePath(gint prompt_num)
{
      pdialog_prompt_struct *p;
      pdialog_struct *d = &pdialog;

      if(prompt_num < 0)
          prompt_num = d->total_prompts - 1;

      p = ((prompt_num >= 0) && (prompt_num < d->total_prompts)) ?
          d->prompt[prompt_num] : NULL;

      if(p != NULL)
      {
          GtkWidget *w = p->value;

          switch(p->type)
          {
            case PDIALOG_PROMPT_TYPE_LABEL:
            break;

            case PDIALOG_PROMPT_TYPE_ENTRY:
            if(GTK_IS_ENTRY(w))
            {
                gtk_signal_connect(
                  GTK_OBJECT(w), "key_press_event",
                  GTK_SIGNAL_FUNC(PDialogEntryCompletePathKeyCB), d
                );
                gtk_signal_connect(
                  GTK_OBJECT(w), "key_release_event",
                  GTK_SIGNAL_FUNC(PDialogEntryCompletePathKeyCB), d
                );
            }
            break;

            case PDIALOG_PROMPT_TYPE_SPIN:
            break;

            case PDIALOG_PROMPT_TYPE_SCALE:
            break;

            case PDIALOG_PROMPT_TYPE_COMBO:
            if(GTK_IS_COMBO(w))
            {
                GtkCombo *combo = GTK_COMBO(w);
                w = combo->entry;
                if(GTK_IS_ENTRY(w))
                {
                  gtk_signal_connect(
                      GTK_OBJECT(w), "key_press_event",
                      GTK_SIGNAL_FUNC(PDialogEntryCompletePathKeyCB), d
                  );
                  gtk_signal_connect(
                      GTK_OBJECT(w), "key_release_event",
                      GTK_SIGNAL_FUNC(PDialogEntryCompletePathKeyCB), d
                  );
                }
            }
            break;

            case PDIALOG_PROMPT_TYPE_RADIO:
            break;

            case PDIALOG_PROMPT_TYPE_TOGGLE:
            break;

            case PDIALOG_PROMPT_TYPE_SEPARATOR:
            break;
          }
      }
}

/*
 *    Destroys all prompts on prompt dialog.
 */
void PDialogDeleteAllPrompts(void)
{
      gint i;
      pdialog_struct *d = &pdialog;


      for(i = 0; i < d->total_prompts; i++)
          PDialogPromptDelete(d->prompt[i]);
      g_free(d->prompt);
      d->prompt = NULL;
      d->total_prompts = 0;
}


/*
 *    Block input and wait for response.
 *
 *    Returns an array of string values from the given prompts
 *    which must not be modified or deleted.
 *
 *    If NULL is returned then it means the user canceled.
 *
 *    If any values are set NULL then that value will not be modified
 *    from since the last usage.
 */
gchar **PDialogGetResponse(
      const gchar *title,
      const gchar *message,
      const gchar *explaination,
      pdialog_icon icon_code,
      const gchar *submit_label,
      const gchar *cancel_label,
      pdialog_btn_flags show_buttons,           /* Any of PDIALOG_BTNFLAG_* */
      pdialog_btn_flags default_button,   /* One of PDIALOG_BTNFLAG_* */
      gint *nvalues
)
{
      gboolean set_focus = FALSE;
      gint i;
      GtkWidget *w;
      pdialog_struct *d = &pdialog;

      /* Reset returns */
      if(nvalues != NULL)
          *nvalues = 0;

      /* Already waiting for response? */
      if(d->block_loop_level > 0)
          return(NULL);

      /* Reset responses */
      for(i = 0; i < d->response_nvals; i++)
          g_free(d->response_val[i]);
      g_free(d->response_val);
      d->response_val = NULL;
      d->response_nvals = 0;

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

      /* Set message label text */
      w = d->message_label;
      if(w != NULL)
          gtk_label_set_text(
            GTK_LABEL(w),
            (message != NULL) ? message : ""
          );
      w = d->message_label_hbox;
      if(w != NULL)
      {
          if(message != NULL)
            gtk_widget_show(w);
          else
            gtk_widget_hide(w);
      }

      /* Change icon? */
      if(icon_code != d->last_icon_code)
      {
          guint8 **icon_data = PDialogGetMessageIconDataFromCode(icon_code);
          d->last_icon_code = icon_code;
          PDialogSetIcon(d, icon_data);
      }

      /* Need to change button labels? */
      if(submit_label != NULL)
      {
          w = d->submit_btn_label;
          if(w != NULL)
            gtk_label_set_text(GTK_LABEL(w), submit_label);
      }
      if(cancel_label != NULL)
      {
          w = d->cancel_btn_label;
          if(w != NULL)
            gtk_label_set_text(GTK_LABEL(w), cancel_label);
      }


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

      w = d->submit_btn;
      if(show_buttons & PDIALOG_BTNFLAG_SUBMIT)
          DO_MAP_BUTTON
      else
          DO_UNMAP_BUTTON
      if(default_button & PDIALOG_BTNFLAG_SUBMIT)
          DO_DEFAULT_BUTTON
      else
          DO_UNDEFAULT_BUTTON

      w = d->cancel_btn;
      if(show_buttons & PDIALOG_BTNFLAG_CANCEL)
          DO_MAP_BUTTON
      else
          DO_UNMAP_BUTTON
      if(default_button & PDIALOG_BTNFLAG_CANCEL)
          DO_DEFAULT_BUTTON
      else
          DO_UNDEFAULT_BUTTON

      w = d->help_btn;
      if(show_buttons & PDIALOG_BTNFLAG_HELP)
          DO_MAP_BUTTON
      else
          DO_UNMAP_BUTTON
      if(default_button & PDIALOG_BTNFLAG_HELP)
          DO_DEFAULT_BUTTON
      else
          DO_UNDEFAULT_BUTTON

      /* The first prompt should be in focus */
      if(d->total_prompts > 0)
      {
          pdialog_prompt_struct *p = d->prompt[0];
          w = (p != NULL) ? p->value : NULL;
          if((w != NULL) ? GTK_WIDGET_CAN_FOCUS(w) : FALSE)
          {
            gtk_widget_grab_focus(w);
            set_focus = TRUE;
          }
      }

      if(!set_focus)
      {
          if(default_button & PDIALOG_BTNFLAG_SUBMIT)
          {
            w = d->submit_btn;
            if(w != NULL)
            {
                gtk_widget_grab_focus(w);
                set_focus = TRUE;
            }
          }
          else if(default_button & PDIALOG_BTNFLAG_CANCEL)
          {
            w = d->cancel_btn;
            if(w != NULL)
            {
                gtk_widget_grab_focus(w);
                set_focus = TRUE;
            }
          }
      }

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

      /* Widget sizes may have changed due to new values est, queue
       * resize for the toplevel
       */
      w = d->toplevel;
      if(w != NULL)
          gtk_widget_queue_resize(w);

      /* Map dialog */
      PDialogMap();

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

      /* Unmap dialog */
      PDialogUnmap();

      /* Break out of any subsequent main loops */
      while(d->block_loop_level > 0)
      {
          gtk_main_quit();
          d->block_loop_level--;
      }
      d->block_loop_level = 0;

      /* Update returns */
      if(nvalues != NULL)
          *nvalues = d->response_nvals;

      return(d->response_val);
}


/*
 *    Same as PDialogGetResponse() except that the icon is set by  
 *    the specified icon data.
 */
gchar **PDialogGetResponseIconData(
      const gchar *title,
      const gchar *message,
      const gchar *explaination,
      guint8 **icon_data,
      const gchar *submit_label,
      const gchar *cancel_label,
      pdialog_btn_flags show_buttons,           /* Any of PDIALOG_BTNFLAG_* */
      pdialog_btn_flags default_button,   /* One of PDIALOG_BTNFLAG_* */
      gint *nvalues
)
{
      gint i;
      GtkWidget *w;
      pdialog_struct *d = &pdialog;

      /* Reset returns */
      if(nvalues != NULL)
          *nvalues = 0;

      /* Already waiting for response? */
      if(d->block_loop_level > 0)
          return(NULL);
       
      /* Reset responses */
      for(i = 0; i < d->response_nvals; i++)
          g_free(d->response_val[i]);
      g_free(d->response_val);
      d->response_val = NULL;
      d->response_nvals = 0;

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

      /* Set message label text */
      w = d->message_label;
      if(w != NULL)
          gtk_label_set_text(
            GTK_LABEL(w),
            (message != NULL) ? message : ""
          );
      w = d->message_label_hbox;
      if(w != NULL)
      {
          if(message != NULL)
            gtk_widget_show(w);
          else
            gtk_widget_hide(w);
      }
       
      /* Change icon? */
      if(icon_data != NULL)
      {
          d->last_icon_code = PDIALOG_ICON_USER_DEFINED;
          PDialogSetIcon(d, icon_data);
      }

      /* Need to change button labels? */
      if(submit_label != NULL)
      {
          w = d->submit_btn_label;
          if(w != NULL)
            gtk_label_set_text(GTK_LABEL(w), submit_label);
      }
      if(cancel_label != NULL)
      {
          w = d->cancel_btn_label;
          if(w != NULL)
            gtk_label_set_text(GTK_LABEL(w), cancel_label);
      }


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

      w = d->submit_btn;
      if(show_buttons & PDIALOG_BTNFLAG_SUBMIT)
          DO_MAP_BUTTON
      else
          DO_UNMAP_BUTTON
      if(default_button & PDIALOG_BTNFLAG_SUBMIT)
          DO_DEFAULT_BUTTON
      else
          DO_UNDEFAULT_BUTTON

      w = d->cancel_btn;
      if(show_buttons & PDIALOG_BTNFLAG_CANCEL)
          DO_MAP_BUTTON
      else
          DO_UNMAP_BUTTON
      if(default_button & PDIALOG_BTNFLAG_CANCEL)
          DO_DEFAULT_BUTTON
      else
          DO_UNDEFAULT_BUTTON

      w = d->help_btn;
      if(show_buttons & PDIALOG_BTNFLAG_HELP)
          DO_MAP_BUTTON
      else
          DO_UNMAP_BUTTON
      if(default_button & PDIALOG_BTNFLAG_HELP)
          DO_DEFAULT_BUTTON
      else
          DO_UNDEFAULT_BUTTON

      /* Have first prompt to grab focus */
      if(d->total_prompts > 0)
      {
          pdialog_prompt_struct *p = d->prompt[0];
          w = (p != NULL) ? p->value : NULL;
          if(w != NULL)
            gtk_widget_grab_focus(w);
      }    

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

      /* Widget sizes may have changed due to new values est, queue
       * resize for the toplevel
       */
      if(d->toplevel != NULL)
          gtk_widget_queue_resize(d->toplevel);

      /* Map dialog */
      PDialogMap();

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

      /* Unmap dialog */
      PDialogUnmap();

      /* Break out of any subsequent main loops */
      while(d->block_loop_level > 0)
      {
          gtk_main_quit();
          d->block_loop_level--;
      }
      d->block_loop_level = 0;

      /* Update returns */
      if(nvalues != NULL)
          *nvalues = d->response_nvals;
                               
      return(d->response_val);
}


/*
 *    Sets the size of the toplevel window of the prompt dialog.
 */
void PDialogSetSize(gint width, gint height)
{
      pdialog_struct *d = &pdialog;
      GtkWidget *w = (d != NULL) ? d->toplevel : NULL;
      if(w == NULL)
          return;

      gtk_widget_set_usize(w, width, height);
}

/*
 *    Maps the PDialog.
 */
void PDialogMap(void)
{
      pdialog_struct *d = &pdialog;
      GtkWidget *w = (d != NULL) ? d->toplevel : NULL;
      if(w == NULL)
          return;

      gtk_widget_show_raise(w);
}

/*
 *    Unmaps the PDialog.
 */
void PDialogUnmap(void)
{
      pdialog_struct *d = &pdialog;
      GtkWidget *w = (d != NULL) ? d->toplevel : NULL;
      if(w == NULL)
          return;

      gtk_widget_hide(w);
}

/*
 *    Shuts down the PDialog.
 */
void PDialogShutdown(void)
{
      gint i;
      pdialog_struct *d = &pdialog;

      /* Reset responses */
      for(i = 0; i < d->response_nvals; i++)
          g_free(d->response_val[i]);
      g_free(d->response_val);
      d->response_val = NULL;
      d->response_nvals = 0;

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

      /* Unmap dialog */
      PDialogUnmap();

      /* Delete all prompts on dialog */
      PDialogDeleteAllPrompts();

      /* Begin destroying widgets */
      GTK_WIDGET_DESTROY(d->submit_btn)
      GTK_WIDGET_DESTROY(d->cancel_btn)
      GTK_WIDGET_DESTROY(d->help_btn)

      GTK_WIDGET_DESTROY(d->icon_pm)
      GTK_WIDGET_DESTROY(d->message_label)
      GTK_WIDGET_DESTROY(d->message_label_hbox)

      GTK_WIDGET_DESTROY(d->main_vbox)
      GTK_WIDGET_DESTROY(d->toplevel)

      GTK_ACCEL_GROUP_UNREF(d->accelgrp)

      memset(d, 0x00, sizeof(pdialog_struct));
}

Generated by  Doxygen 1.6.0   Back to index