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

pdialog.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

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

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

#ifdef MEMWATCH
# include "memwatch.h"
#endif


/* Message icons. */
#include "images/icon_info_32x32.xpm"
#include "images/icon_warning_32x32.xpm"
#include "images/icon_error_32x32.xpm"
#include "images/icon_question_32x32.xpm"
#include "images/icon_help_32x32.xpm"
#include "images/icon_wand_32x32.xpm"
#include "images/icon_search_32x32.xpm"
#include "images/icon_security_32x32.xpm"
#include "images/icon_print_32x32.xpm"
#include "images/icon_sound_32x32.xpm"
#include "images/icon_bulb_32x32.xpm"
#include "images/icon_power_32x32.xpm"
#include "images/icon_linux_32x32.xpm"
#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_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"

/* Need to work on these.
#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. */
#define PDIALOG_PROMPT_TYPE_ENTRY   0
#define PDIALOG_PROMPT_TYPE_SPIN    1
#define PDIALOG_PROMPT_TYPE_SCALE   2
#define PDIALOG_PROMPT_TYPE_COMBO   3
#define PDIALOG_PROMPT_TYPE_RADIO   4
#define PDIALOG_PROMPT_TYPE_TOGGLE  5
#define PDIALOG_PROMPT_TYPE_SEPARATOR     6

/* Prompt dialog's prompt structure. */
typedef struct {

      gint type;              /* One of PDIALOG_PROMPT_TYPE_*. */
      GtkWidget       *toplevel,      /* A table. */
                  *icon_pm,
                  *icon_fixed,
                  *label,
                  *entry,
                  *browse_btn,
                  *spin,
                  *scale,
                  *combo,
                  *radio_toplevel, **radio,     /* total_radios for total. */
                  *toggle,
                  *separator;
      gchar **radio_label;
      int total_radios;
  
      gpointer client_data;

      /* Args: pdialog, client_data, prompt_num. */
      gchar *(*browse_cb)(gpointer, gpointer, gint);

} pdialog_prompt_struct;

/* Prompt dialog structure. */
typedef struct {

      gbool initialized;
      gbool map_state;
      gint last_icon_code;

      GtkAccelGroup   *accelgrp;

      GtkWidget       *toplevel,
                  *main_vbox,     /* For holding the prompts. */
                  *icon_pm,
                  *icon_fixed,
                  *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_struct;


/* Callbacks. */
static void PDialogDestroyCB(GtkObject *object, gpointer data);
static gint PDialogCloseCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
);
static void PDialogBrowseButtonCB(GtkWidget *widget, gpointer data);
static void PDialogEntryEnterCB(GtkWidget *widget, 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
);

/* Private utils. */
static u_int8_t **PDialogGetMessageIconDataFromCode(gint icon_code);
static void PDialogSetIcon(pdialog_struct *d, u_int8_t **icon_data);
static pdialog_prompt_struct *PDialogPromptNewNexus(
      gint type,              /* One of PDIALOG_PROMPT_TYPE_*. */
      const u_int8_t **icon_data,
      const gchar *label,
      const gchar *value,
      gbool hide_value,       /* For passwords. */
      pdialog_struct *d,
      gpointer client_data,
      gchar *(*browse_cb)(gpointer, gpointer, gint)
);
static void PDialogPromptDelete(pdialog_prompt_struct *p);

/* Public. */
gint PDialogInit(void);
void PDialogSetTransientFor(GtkWidget *w);
gbool PDialogIsQuery(void);
void PDialogBreakQuery(void);
static pdialog_prompt_struct *PDialogAddPromptNexus(  /* Not public. */
      gint type,              /* One of PDIALOG_PROMPT_TYPE_*. */
      const u_int8_t **icon_data,
      const gchar *label,
      const gchar *value,
      gbool hide_value,               /* For passwords. */
      gpointer client_data,
      gchar *(*browse_cb)(gpointer, gpointer, gint)
);
void PDialogAddPrompt(
      const u_int8_t **icon_data,   /* Can be NULL. */
      const gchar *label,           /* Can be NULL. */
      const gchar *value            /* Can be NULL. */
);
void PDialogAddPromptPassword(
      const u_int8_t **icon_data,
      const gchar *label,
      const gchar *value
);
void PDialogAddPromptWithBrowse(
      const u_int8_t **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 u_int8_t **icon_data,
      const gchar *label,
      gfloat value, gfloat lower, gfloat upper,
      gfloat step_increment, gfloat page_increment,
      gdouble climb_rate, guint digits
);
void PDialogAddPromptScale(
      const u_int8_t **icon_data,
      const gchar *label,
      gfloat value, gfloat lower, gfloat upper,
      gfloat step_increment, gfloat page_increment,
      gbool show_value, guint digits
);
void PDialogAddPromptCombo(
      const u_int8_t **icon_data,
      const gchar *label,
      const gchar *value,
      GList *list,
      gbool editable, gbool case_sensitive
);

void PDialogAddPromptRadio(
      const u_int8_t **icon_data,
      const gchar *label,
      GList *list,            /* List of radio button names. */
      gint start_num          /* Initial radio button to select. */
);
void PDialogSetPromptValue(
      gint prompt_num,
      const u_int8_t **icon_data,
      const gchar *label,
      const gchar *value
);
void PDialogSetPromptTip(gint prompt_num, const gchar *tip);
gchar *PDialogGetPromptValue(gint prompt_num);
void PDialogDeleteAllPrompts(void);
gchar **PDialogGetResponse(
      const gchar *title,
      const gchar *message,
      const gchar *explaination,
      gint icon_code,
      const gchar *submit_label,
      const gchar *cancel_label,
      guint show_buttons,     /* Any of PDIALOG_BTNFLAG_*. */
      guint default_button,   /* One of PDIALOG_BTNFLAG_*. */
      gint *nvalues
);
void PDialogSetSize(gint width, gint height);
void PDialogMap(void);
void PDialogUnmap(void);
void PDialogShutdown(void);


#define STRDUP(s) (((s) != NULL) ? g_strdup(s) : NULL)

#define PDIALOG_BTN_WIDTH     (100 + (2 * 3))
#define PDIALOG_BTN_HEIGHT    (30 + (2 * 3))

#define PDIALOG_ENTRY_MAX     256


static gint response_code = PDIALOG_RESPONSE_NOT_AVAILABLE;
static gint block_loop_level;
static gchar **response_val = NULL;
static gint response_nvals = 0;
static pdialog_struct pdialog;


/*
 *    Dialog toplevel "destroy" signal callback.
 */
static void PDialogDestroyCB(GtkObject *object, gpointer data)
{
      return;
}

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

      response_code = PDIALOG_RESPONSE_CANCEL;
      gtk_main_quit();
      block_loop_level--;

      return(TRUE);
}

/*
 *    Dialog prompt browse button "clicked" callback.
 */
static void PDialogBrowseButtonCB(GtkWidget *widget, gpointer data)
{
      gint i;
      GtkWidget *w;
      const gchar *cstrptr;
      pdialog_prompt_struct *p;
      pdialog_struct *d = (pdialog_struct *)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)
          {
            cstrptr = (const gchar *)p->browse_cb(
                d,                  /* Prompt dialog. */
                p->client_data,     /* Client data. */
                i             /* Prompt number. */
            );
            w = p->entry;
            if((w != NULL) && (cstrptr != NULL))
                gtk_entry_set_text(GTK_ENTRY(w), cstrptr);
          }
          break;
      }
}

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

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

/*
 *    Dialog buttons (except browse) "clicked" callback.
 *
 *    widget will be compared with the other button pointers on the
 *    dialog structure to see which button was pressed.
 *
 *    If the submit button was pressed then the response values will
 *    be updated to the current values of the input widget on each
 *    prompt.
 */
static void PDialogButtonCB(GtkWidget *widget, gpointer data)
{
      pdialog_struct *d = (pdialog_struct *)data;
      if((widget == NULL) || (d == NULL))
          return;

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


          response_code = PDIALOG_RESPONSE_SUBMIT;

          /* Clear responses values list if any. */
          for(i = 0; i < response_nvals; i++)
            g_free(response_val[i]);
          g_free(response_val);
          response_val = NULL;
          response_nvals = 0;

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

            /* Fetch values for each response value, thus going
             * through each prompt.
             */
            for(i = 0; i < response_nvals; i++)
            {
                p = d->prompt[i];
                if(p != NULL)
                {
                  GtkWidget *w;

                  switch(p->type)
                  {
                    case PDIALOG_PROMPT_TYPE_ENTRY:
                      w = p->entry;
                      if(w != NULL)
                      {
                        const gchar *cstrptr = gtk_entry_get_text(GTK_ENTRY(w));
                        response_val[i] = STRDUP(
                            (cstrptr != NULL) ? cstrptr : ""
                        );
                      }
                      break;

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

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

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

                    case PDIALOG_PROMPT_TYPE_RADIO:
                      if(p->total_radios > 0)
                      {
                        int n;
                        for(n = 0; n < p->total_radios; n++)
                        {
                            w = p->radio[n];
                            if((w != NULL) ?
                              GTK_TOGGLE_BUTTON(w)->active : FALSE
                            )
                            {
                              const gchar *cstrptr = p->radio_label[n];
                              response_val[i] = STRDUP(
                                  (cstrptr != NULL) ? cstrptr : ""
                              );
                              break;
                            }
                        }
                      }
                      break;

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

                    case PDIALOG_PROMPT_TYPE_SEPARATOR:
                      /* Empty string for separator. */
                      response_val[i] = STRDUP("");
                      break;

                    default:
                      response_val[i] = STRDUP("");
                      break;
                  }
                }
                else
                {
                  response_val[i] = STRDUP("");
                }
            }
          }

      }
      else if(widget == d->cancel_btn)
      {
          response_code = PDIALOG_RESPONSE_CANCEL;
      }
      else if(widget == d->help_btn)
      {
          response_code = PDIALOG_RESPONSE_HELP;
          return; /* Return, do not break out of block loop. */
      }

      /* Need to break out of the blocked loop. */
      gtk_main_quit();
      block_loop_level--;
}

/*
 *    Prompt entry drag data received 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 entry "drag_motion" 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 a statically allocated pointer to the icon data
 *    that corresponds to the given icon_code.
 */
static u_int8_t **PDialogGetMessageIconDataFromCode(gint icon_code)
{
      u_int8_t **d = (u_int8_t **)icon_question_32x32_xpm;

      switch(icon_code)
      {
        case PDIALOG_ICON_INFO:
          d = (u_int8_t **)icon_info_32x32_xpm;
          break;
        case PDIALOG_ICON_WARNING:
          d = (u_int8_t **)icon_warning_32x32_xpm;
          break;
        case PDIALOG_ICON_ERROR:
          d = (u_int8_t **)icon_error_32x32_xpm;
          break;
        case PDIALOG_ICON_QUESTION:
          d = (u_int8_t **)icon_question_32x32_xpm;
          break;
        case PDIALOG_ICON_HELP:
          d = (u_int8_t **)icon_help_32x32_xpm;
          break;
        case PDIALOG_ICON_WIZARD:
          d = (u_int8_t **)icon_wand_32x32_xpm;
          break;
        case PDIALOG_ICON_SEARCH:
          d = (u_int8_t **)icon_search_32x32_xpm;
          break;
        case PDIALOG_ICON_SECURITY:
          d = (u_int8_t **)icon_security_32x32_xpm;
          break;
        case PDIALOG_ICON_PRINTER:
          d = (u_int8_t **)icon_print_32x32_xpm;
          break;
        case PDIALOG_ICON_SPEAKER:
          d = (u_int8_t **)icon_sound_32x32_xpm;
          break;
        case PDIALOG_ICON_BULB:
          d = (u_int8_t **)icon_bulb_32x32_xpm;
          break;
        case PDIALOG_ICON_POWER:
          d = (u_int8_t **)icon_power_32x32_xpm;
          break;
        case PDIALOG_ICON_LINUX:
          d = (u_int8_t **)icon_linux_32x32_xpm;
          break;
        case PDIALOG_ICON_TERMINAL:
          d = (u_int8_t **)icon_terminal_32x32_xpm;
          break;
        case PDIALOG_ICON_SETTINGS:
          d = (u_int8_t **)icon_tuning_32x32_xpm;
          break;
        case PDIALOG_ICON_TOOLS:
          d = (u_int8_t **)icon_tools_32x32_xpm;
          break;
        case PDIALOG_ICON_MONITOR:
          d = (u_int8_t **)icon_monitor_32x32_xpm;
          break;
        case PDIALOG_ICON_CLIPBOARD_EMPTY:
          d = (u_int8_t **)icon_clipboard_empty_32x32_xpm;
          break;
        case PDIALOG_ICON_CLIPBOARD_FULL:
          d = (u_int8_t **)icon_clipboard_32x32_xpm;
          break;
        case PDIALOG_ICON_EDIT:
          d = (u_int8_t **)icon_edit_32x32_xpm;
          break;

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

        case PDIALOG_ICON_FILE_MOVE:
          d = (u_int8_t **)icon_file_32x32_xpm;
          break;
        case PDIALOG_ICON_FILE_COPY:
          d = (u_int8_t **)icon_file_32x32_xpm;
          break;
        case PDIALOG_ICON_FILE_PROPERTIES:
          d = (u_int8_t **)icon_properties2_32x32_xpm;
          break;

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

/*
 *    Updates the icon for the dialog. Updates the member icon_pm
 *    as needed.
 */
static void PDialogSetIcon(pdialog_struct *d, u_int8_t **icon_data)
{
      GdkGC *gc;
      GtkWidget *w, *window, *pixmapwid;
      GdkPixmap *pixmap;
      GdkBitmap *mask;
      GtkStyle *style;
      gint width, height;


      if((d == NULL) || (icon_data == NULL))
          return;

      w = d->icon_fixed;
      if(w == NULL)
          return;

      window = d->toplevel;
      if(window == NULL)
          return;

      style = gtk_widget_get_default_style();
      gc = style->black_gc;


      /* Load pixmap and mask pair from the given data. */
      pixmap = gdk_pixmap_create_from_xpm_d(
          window->window, &mask,
          &style->bg[GTK_STATE_NORMAL],
          (gchar **)icon_data
      );
      if(pixmap == NULL)
          return;

      pixmapwid = gtk_pixmap_new(pixmap, mask);
      gdk_window_get_size((GdkWindow *)pixmap, &width, &height);

      /* Adjust size of fixed widget to fit pixmap. */
      gtk_widget_set_usize(w, width, height);

      /* Put GtkPixmap into fixed widget. */
      gtk_fixed_put(GTK_FIXED(w), pixmapwid, 0, 0);
      gtk_widget_shape_combine_mask(w, mask, 0, 0);
      gtk_widget_show(pixmapwid);

      gdk_pixmap_unref(pixmap);
      pixmap = NULL;
      if(mask != NULL)
      {
          gdk_bitmap_unref(mask);
          mask = NULL;
      }

      /* Destroy the previous GtkPixmap icon. */
      if(d->icon_pm != NULL)
          gtk_widget_destroy(d->icon_pm);

      /* Record new GtkPixmap as the icon. */
      d->icon_pm = pixmapwid;


      /* Set new WM icon for toplevel. */
      GUISetWMIcon(window->window, icon_data);                    
}

/*
 *    Allocates and creates a new prompt structure, but does not 
 *      add it to the prompt dialog.
 */
static pdialog_prompt_struct *PDialogPromptNewNexus(
      gint type,              /* One of PDIALOG_PROMPT_TYPE_*. */
      const u_int8_t **icon_data,
      const gchar *label,
      const gchar *value,
      gbool hide_value,       /* For passwords. */
      pdialog_struct *d,
      gpointer client_data,
      gchar *(*browse_cb)(gpointer, gpointer, gint)
)
{
      gint columns = MAX(
          ((icon_data != NULL) ? 1 : 0) + /* Icon. */
          ((label != NULL) ? 1 : 0) +           /* Label. */
          (1) +                     /* Input widget. */
          ((browse_cb != NULL) ? 1 : 0),  /* Browse button. */
          1
      );
      gint attach_x = 0;
      GtkWidget *w, *parent;
      GdkWindow *window;
      pdialog_prompt_struct *p = (pdialog_prompt_struct *)g_malloc0(
          sizeof(pdialog_prompt_struct)
      );
      if(p == NULL)
          return(p);

      /* Set the prompt's type. */
      p->type = type;

      /* Get window of dialog toplevel. */
      w = d->toplevel;
      window = (w != NULL) ? w->window : NULL;

      /* Prompt toplevel. */
      p->toplevel = parent = w = gtk_table_new(1, columns, FALSE);
      /* Do not show the prompt's toplevel table just yet. */

      /* Create icon? */
      if(icon_data != NULL)
      {
          GdkGC *gc;
          GtkWidget *pixmapwid;
          GdkPixmap *pixmap;
          GdkBitmap *mask;
          GtkStyle *style;
          gint width, height;

          /* Create fixed widget. */
          p->icon_fixed = w = gtk_fixed_new();
          gtk_table_attach(
            GTK_TABLE(parent), w,
            attach_x, attach_x + 1,
            0, 1,
            0,
            0,
            2, 0
          );
          gtk_widget_show(w);

          /* Get style from dialog toplevel. */
          if(d->toplevel == NULL)
            style = gtk_widget_get_default_style();
          else
            style = gtk_widget_get_style(d->toplevel);

          if(style != NULL)
            gc = style->black_gc;

          /* Load pixmap and mask pair from the given data. */
          pixmap = gdk_pixmap_create_from_xpm_d(
            window,     &mask,
            (style != NULL) ? &style->bg[GTK_STATE_NORMAL] : NULL,
            (gchar **)icon_data
          );
          if(pixmap != NULL)
          {
            pixmapwid = gtk_pixmap_new(pixmap, mask);
            gdk_window_get_size((GdkWindow *)pixmap, &width, &height);

            /* Adjust size of fixed widget to fit pixmap. */
            gtk_widget_set_usize(w, width, height);

            /* Put GtkPixmap into fixed widget. */
            gtk_fixed_put(GTK_FIXED(w), pixmapwid, 0, 0);
            gtk_widget_shape_combine_mask(w, mask, 0, 0);
            gtk_widget_show(pixmapwid);

            gdk_pixmap_unref(pixmap);
            if(mask != NULL)
                gdk_bitmap_unref(mask);

            /* Record new pixmap. */
            p->icon_pm = pixmapwid;
          }

          attach_x++;
      }

      /* Create label? */
      if((label != NULL) &&
         (type != PDIALOG_PROMPT_TYPE_TOGGLE)
      )
      {
          p->label = w = gtk_label_new(label);
          gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_RIGHT);
          gtk_table_attach(
            GTK_TABLE(parent), w,
            attach_x, attach_x + 1,
            0, 1,
            0,
            0,
            2, 0
          );
          gtk_widget_show(w);

          attach_x++;
      }
 
      /* Primary input widget. */
      if(1)
      {
          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_SPIN:
            p->spin = w = gtk_spin_button_new(NULL, 1.0, 0);
            gtk_signal_connect(
                GTK_OBJECT(w), "activate",
                GTK_SIGNAL_FUNC(PDialogEntryEnterCB),
                d           /* Pass the dialog structure. */
            );
            break;

            case PDIALOG_PROMPT_TYPE_SCALE:
            p->scale = w = gtk_hscale_new(NULL);
            break;

            case PDIALOG_PROMPT_TYPE_COMBO:
            p->combo = w = gtk_combo_new();
            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), w
            );
            if(value != NULL)
            {
                gtk_entry_set_text(GTK_ENTRY(w2), value);
                gtk_entry_set_position(GTK_ENTRY(w2), -1);
            }
            GTK_WIDGET_SET_FLAGS(w2, GTK_CAN_DEFAULT);
            gtk_signal_connect(
                GTK_OBJECT(w2), "activate",
                GTK_SIGNAL_FUNC(PDialogEntryEnterCB),
                d           /* Pass the dialog structure. */
            );
            break;

            case PDIALOG_PROMPT_TYPE_RADIO:
            p->radio_toplevel = w = gtk_hbox_new(FALSE, 5);
            /* Do not create each radio button, they will be
             * created by the calling function.
             */
            break;

           case PDIALOG_PROMPT_TYPE_TOGGLE:
            if(label != NULL)
                p->toggle = w = gtk_check_button_new_with_label(label);
            else
                p->toggle = w = gtk_check_button_new();
            break;

            case PDIALOG_PROMPT_TYPE_SEPARATOR:
            p->separator = w = gtk_hseparator_new();
            break;

            default:    /* All else assume PDIALOG_PROMPT_TYPE_ENTRY. */
            p->entry = w = gtk_entry_new();
            gtk_entry_set_visibility(GTK_ENTRY(w), !hide_value);
            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_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
            gtk_signal_connect(
                GTK_OBJECT(w), "activate",
                GTK_SIGNAL_FUNC(PDialogEntryEnterCB),
                d       /* Pass the dialog structure. */
            );
            break;
          }

          /* At this point w is the prompt's primary input widget. */
          gtk_table_attach(
            GTK_TABLE(parent), w,
            attach_x, attach_x + 1,
            0, 1,
            GTK_FILL | GTK_SHRINK | GTK_EXPAND,
            0,
            2, 0
          );
          gtk_widget_show(w);

          attach_x++;
      }

      /* 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((u_int8_t **)icon_browse_20x20_xpm);
          gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(PDialogBrowseButtonCB),
            d           /* Pass the dialog structure. */
          );
          gtk_table_attach(
            GTK_TABLE(parent), w,
            attach_x, attach_x + 1,
            0, 1,
            0,
            0,
            2, 0
          );
          GUISetWidgetTip(
            w,
#ifdef PROG_LANGUAGE_ENGLISH
            "Browse"
#endif
#ifdef PROG_LANGUAGE_SPANISH
            "Hojee"
#endif
#ifdef PROG_LANGUAGE_FRENCH
            "Brouter"
#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);

          attach_x++;
      }

      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;
      GtkWidget **w;


      if(p == NULL)
          return;

#define DO_DESTROY_WIDGET     \
{ if(*w != NULL) { gtk_widget_destroy(*w); *w = NULL; } }

      w = &p->separator;
      DO_DESTROY_WIDGET

      w = &p->toggle;
      DO_DESTROY_WIDGET

      for(i = 0; i < p->total_radios; i++)
      {
          w = &p->radio[i];
          DO_DESTROY_WIDGET
          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;
      w = &p->radio_toplevel;
      DO_DESTROY_WIDGET

      w = &p->combo;
      DO_DESTROY_WIDGET
      w = &p->scale;
      DO_DESTROY_WIDGET
      w = &p->spin;
      DO_DESTROY_WIDGET
      w = &p->browse_btn;
      DO_DESTROY_WIDGET
      w = &p->entry;
      DO_DESTROY_WIDGET

      w = &p->label;
      DO_DESTROY_WIDGET
      w = &p->icon_pm;
      DO_DESTROY_WIDGET
      w = &p->icon_fixed;
      DO_DESTROY_WIDGET
      w = &p->toplevel;
      DO_DESTROY_WIDGET

      g_free(p);
#undef DO_DESTROY_WIDGET
}


/*
 *    Initializes the prompt dialog.
 */
gint PDialogInit(void)
{
      gint border_major = 5;
      gpointer label_rtn;
      GtkWidget *w, *parent, *parent2, *parent3;
      GdkWindow *window;
      GtkAccelGroup *accelgrp;
      pdialog_struct *d = &pdialog;


      /* Reset globals. */
      response_code = PDIALOG_RESPONSE_NOT_AVAILABLE;
      block_loop_level = 0;
      response_val = NULL;
      response_nvals = 0;


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

      d->initialized = TRUE;
      d->map_state = FALSE;
      d->last_icon_code = PDIALOG_ICON_QUESTION;
      d->last_transient_for = NULL;

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

      /* Toplevel. */
      d->toplevel = w = gtk_window_new(GTK_WINDOW_DIALOG);
      gtk_widget_realize(w);
      window = w->window;
      if(window != NULL)
      {
          gdk_window_set_decorations(
            window,
            GDK_DECOR_TITLE | GDK_DECOR_MENU | GDK_DECOR_MINIMIZE
          );
          gdk_window_set_functions(
            window,
            GDK_FUNC_MOVE | GDK_FUNC_MINIMIZE | GDK_FUNC_CLOSE
          );
      }
      gtk_signal_connect(
          GTK_OBJECT(w), "destroy",
          GTK_SIGNAL_FUNC(PDialogDestroyCB), d
      );
      gtk_signal_connect(
          GTK_OBJECT(w), "delete_event",
          GTK_SIGNAL_FUNC(PDialogCloseCB), d
      );
      gtk_container_set_border_width(GTK_CONTAINER(w), 0);
      gtk_accel_group_attach(accelgrp, GTK_OBJECT(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;
      /* Fixed widget for holding icon pixmap. */
      d->icon_fixed = w = gtk_fixed_new();
      d->icon_pm = NULL;
      gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
      gtk_widget_realize(w);
      gtk_widget_show(w);


      /* 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(
          (u_int8_t **)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
          &label_rtn
      );
      d->submit_btn_label = GTK_WIDGET(label_rtn);
      gtk_widget_set_usize(w, PDIALOG_BTN_WIDTH, PDIALOG_BTN_HEIGHT);
      GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
      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(
          (u_int8_t **)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
          &label_rtn
      );
      d->cancel_btn_label = GTK_WIDGET(label_rtn);
      gtk_widget_set_usize(w, PDIALOG_BTN_WIDTH, PDIALOG_BTN_HEIGHT);
      GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
      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(
          (u_int8_t **)icon_help_20x20_xpm,
#ifdef PROG_LANGUAGE_ENGLISH
          "Help",
#endif
#ifdef PROG_LANGUAGE_SPANISH
          "Ayuda",
#endif
#ifdef PROG_LANGUAGE_FRENCH
          "L'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_usize(w, PDIALOG_BTN_WIDTH, PDIALOG_BTN_HEIGHT);
      GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
      gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
      gtk_signal_connect(
          GTK_OBJECT(w), "clicked",
          GTK_SIGNAL_FUNC(PDialogButtonCB), d
      );

      /* Set default icon. */
      PDialogSetIcon(d, (u_int8_t **)icon_question_32x32_xpm);

      return(0);
}

/*
 *    Sets dialog to be a transient for the given toplevel window
 *    widget w. If w is NULL then no 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;
          }
      }
}

/*
 *      Returns TRUE if currently blocking for query.
 */
gbool PDialogIsQuery(void)
{
      if(block_loop_level > 0)
          return(TRUE);
      else
          return(FALSE);
}

/*
 *      Ends query if any and returns a not available response.
 */
void PDialogBreakQuery(void)
{
      response_code = PDIALOG_RESPONSE_NOT_AVAILABLE;

      /* Break out of an additional blocking loops. */
      while(block_loop_level > 0)
      {
          gtk_main_quit();
          block_loop_level--;
      }
      block_loop_level = 0;
}

/*
 *    Nexus for adding a prompt to the dialog.
 */
static pdialog_prompt_struct *PDialogAddPromptNexus(
      gint type,              /* One of PDIALOG_PROMPT_TYPE_*. */
      const u_int8_t **icon_data,
      const gchar *label,
      const gchar *value,
      gbool 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 prompt to the dialog.
 */
void PDialogAddPrompt(
      const u_int8_t **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 u_int8_t **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 u_int8_t **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 u_int8_t **icon_data,
      const gchar *label,
      gfloat value, gfloat lower, gfloat upper,
      gfloat step_increment, gfloat page_increment,
      gdouble 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 = (GtkSpinButton *)p->spin;
          if((spin != NULL) && (adj != NULL))
            gtk_spin_button_configure(spin, adj, (gfloat)climb_rate, digits);
      }
}

/*
 *      Adds a scale prompt to the dialog.
 */
void PDialogAddPromptScale(
      const u_int8_t **icon_data,
      const gchar *label,
      gfloat value, gfloat lower, gfloat upper,
      gfloat step_increment, gfloat page_increment,
      gbool 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 = (GtkScale *)p->scale;
          GtkRange *range = (GtkRange *)scale;
          GtkAdjustment *adj = (GtkAdjustment *)(
            (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 u_int8_t **icon_data,
      const gchar *label,
      const gchar *value,
      GList *list,
      gbool editable, gbool case_sensitive
)
{
      pdialog_prompt_struct *p = PDialogAddPromptNexus(
          PDIALOG_PROMPT_TYPE_COMBO,
          icon_data, label, value, FALSE, NULL, NULL
      );
      if(p != NULL)
      {
          GtkCombo *combo = (GtkCombo *)p->combo;
          if(combo != NULL)
          {
            gtk_entry_set_editable(GTK_ENTRY(combo->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);
          }
      }
}

/*
 *      Adds a radio prompt to the dialog.
 *
 *      The given glist is not modified by this function.
 */
void PDialogAddPromptRadio(
      const u_int8_t **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(glist->next != 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 = glist->next;
            i++;
          }
      }
}

/*
 *      Adds a toggle prompt to the dialog.
 */
void PDialogAddPromptToggle(
      const u_int8_t **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)
      {
          GtkWidget *w = p->toggle;
          if(w != NULL)
            gtk_toggle_button_set_active(
                GTK_TOGGLE_BUTTON(w),
                value
            );
      }
}

/*
 *    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 u_int8_t **icon_data,
      const gchar *label,
      const gchar *value 
)
{
      GtkWidget *w, *parent;
      GdkWindow *window;
      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)
          return;

      /* Get window of dialog toplevel. */
      w = d->toplevel;
      window = (w != NULL) ? w->window : NULL;

      /* Change icon? */
      parent = p->icon_fixed;
      if((icon_data != NULL) && (parent != NULL))
      {
          GtkWidget *pixmapwid;
          GdkPixmap *pixmap;
          GdkBitmap *mask;
          GtkStyle *style;
          gint width, height;


          /* Get style from dialog toplevel. */
          if(d->toplevel == NULL)
            style = gtk_widget_get_default_style();
          else
            style = gtk_widget_get_style(d->toplevel);

          /* Load pixmap and mask pair from the given data. */
          pixmap = gdk_pixmap_create_from_xpm_d(
            window, &mask,
            (style != NULL) ? &style->bg[GTK_STATE_NORMAL] : NULL,
            (gchar **)icon_data
          );
          if(pixmap != NULL)
          {
            pixmapwid = gtk_pixmap_new(pixmap, mask);
            gdk_window_get_size((GdkWindow *)pixmap, &width, &height);

            /* Adjust size of fixed widget to fit pixmap. */
            gtk_widget_set_usize(parent, width, height);

            /* Put GtkPixmap into fixed widget. */
            gtk_fixed_put(GTK_FIXED(parent), pixmapwid, 0, 0);
            gtk_widget_shape_combine_mask(parent, mask, 0, 0);
            gtk_widget_show(pixmapwid);

            gdk_pixmap_unref(pixmap);
            pixmap = NULL;
            if(mask != NULL)
            {
                gdk_bitmap_unref(mask);
                mask = NULL;
            }

            /* Destroy the previous icon pixmap widget. */
            if(p->icon_pm != NULL)
                gtk_widget_destroy(p->icon_pm);
            p->icon_pm = pixmapwid;
          }
      }

      /* 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 prompt's primary input widget's value? */
      if(value != NULL)
      {
          switch(p->type)
          {
            case PDIALOG_PROMPT_TYPE_ENTRY:
            w = p->entry;
            if(w != NULL)
            {
                GtkEntry *entry = GTK_ENTRY(w);
                gtk_entry_set_text(entry, value);
                gtk_entry_set_position(entry, -1);
            }
            break;

            case PDIALOG_PROMPT_TYPE_SPIN:
            w = p->spin;
            if(w != NULL)
            {
                GtkEntry *entry = GTK_ENTRY(w);
                gtk_entry_set_text(entry, value);
                gtk_entry_set_position(entry, -1);
            }
            break;

            case PDIALOG_PROMPT_TYPE_SCALE:
            w = p->scale;
            if(w != NULL)
            {
                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:
            w = p->combo;
            if(w != NULL)
            {
                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:
            w = p->radio_toplevel;
            if((w != NULL) && (p->total_radios > 0))
            {
                gint i;
                const gchar *label;

                /* Iterate through radios, setting the ones with
                 * labels that do not match to inactive and the one
                 * that does match to active.
                 */
                for(i = 0; i < p->total_radios; i++)
                {
                  w = p->radio[i];
                  label = p->radio_label[i];
                  if((w == NULL) || (label == NULL))
                      continue;

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

            case PDIALOG_PROMPT_TYPE_TOGGLE:
            w = p->toggle;
            if(w != NULL)
            {
                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;

          }
      }
}

/*
 *    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_ENTRY:
            w = p->entry;
            GUISetWidgetTip(w, tip);
            break;

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

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

            case PDIALOG_PROMPT_TYPE_COMBO:
            w = p->combo;
            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->toggle;
            GUISetWidgetTip(w, tip);
            break;
          }
      }
}

/*
 *    Fetches the value of the specified prompt as a statically
 *    allocated string which must not be modified or deallocated.
 *
 *    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.
 */
gchar *PDialogGetPromptValue(gint prompt_num)
{
      GtkWidget *w;
      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)
      {
          switch(p->type)
          {
            case PDIALOG_PROMPT_TYPE_ENTRY:
            w = p->entry;
            if(w != NULL)
                return(gtk_entry_get_text(GTK_ENTRY(w)));
            break;

            case PDIALOG_PROMPT_TYPE_SPIN:
            w = p->spin;
            if(w != NULL)
                return(gtk_entry_get_text(GTK_ENTRY(w)));
            break;

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

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

            case PDIALOG_PROMPT_TYPE_RADIO:
            w = p->radio_toplevel;
            if((w != NULL) && (p->total_radios > 0))
            {
                gint i;

                for(i = 0; i < p->total_radios; i++)
                {
                  w = p->radio[i];
                  if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
                      return(p->radio_label[i]);
                }
            }
            break;

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

      return(NULL);
}


/*
 *    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 a response.
 *
 *    Returns an array of string values from the given prompts
 *    which must not be free'ed. If NULL is returned then it should
 *    be considered that the user clicked on cancel.
 *
 *    If any values are set NULL then that value will not be modified
 *    from since the last usage.
 */
gchar **PDialogGetResponse(
      const gchar *title,           /* Can be NULL. */
      const gchar *message,         /* Can be NULL. */
      const gchar *explaination,    /* Can be NULL. */
      gint icon_code,               /* One of PDIALOG_ICON_*. */
      const gchar *submit_label,    /* Can be NULL. */
      const gchar *cancel_label,    /* Can be NULL. */
      guint show_buttons,           /* Any of PDIALOG_FLAG_*. */
      guint default_button,         /* One of PDIALOG_FLAG_*. */
      gint *nvalues                 /* Number of string values return. */
)
{
      gint i;
      GtkWidget *w;
      pdialog_struct *d = &pdialog;


      /* Do not handle response if already waiting for a response,
       * return with a not available response code.
       */
      if(block_loop_level > 0)
      {
          if(nvalues != NULL)
            (*nvalues) = 0;

          return(NULL);
      }

      /* Reset responses. */
      response_code = PDIALOG_RESPONSE_NOT_AVAILABLE;
      for(i = 0; i < response_nvals; i++)
          g_free(response_val[i]);
      g_free(response_val);
      response_val = NULL;
      response_nvals = 0;


      /* Reset number of values return. */
      if(nvalues != NULL)
          (*nvalues) = response_nvals;

      /* Is dialog initialized? */
      if(!d->initialized)
          return(response_val);

      /* Change 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);
      }

      /* Need to update message icon? */
      if(icon_code != d->last_icon_code)
      {
          /* Update the last recorded icon code. */
          d->last_icon_code = icon_code;

          /* Now set the new message icon with the choosen icon data. */
          PDialogSetIcon(
            d,
            PDialogGetMessageIconDataFromCode(icon_code)
          );
      }

      /* 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 and grab default. */
      if(d->total_prompts > 0)
      {
          pdialog_prompt_struct *p = d->prompt[0];
          w = (p != NULL) ? p->entry : NULL;
          if(w != NULL)
          {
            gtk_widget_grab_focus(w);
            gtk_widget_grab_default(w);
          }
      }

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

      /* Since we've setted new values for the widgets, the size of
       * the entire dialog may need to change. Here we need to notify
       * GTK+ about the size change.
       */
      if(d->toplevel != NULL)
          gtk_widget_queue_resize(d->toplevel);

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

      /* Map dialog. */
      PDialogMap();

      /* Block GUI untill response. */
      block_loop_level++;
      gtk_main();

      /* Unmap dialog. */
      PDialogUnmap();

      /* Break out of an additional blocking loops. */
      while(block_loop_level > 0)
      {
          gtk_main_quit();
          block_loop_level--;
      }
      block_loop_level = 0;


      /* Update number of values return. */
      if(nvalues != NULL)
          (*nvalues) = response_nvals;

      return(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;


      if(!d->initialized)
          return;

      w = d->toplevel;
      if(w != NULL)
          gtk_widget_set_usize(w, width, height);
}

/*
 *    Maps the prompt dialog.
 */
void PDialogMap(void)
{
      pdialog_struct *d = &pdialog;
      GtkWidget *w;


      if(!d->initialized)
          return;

      w = d->toplevel;
      gtk_widget_show_raise(w);
      d->map_state = TRUE;
}

/*
 *    Unmaps the prompt dialog.
 */
void PDialogUnmap(void)
{
      pdialog_struct *d = &pdialog;
      GtkWidget *w;


      if(!d->initialized)
          return;

      if(d->map_state)
      {
          w = d->toplevel;
          if(w != NULL)
            gtk_widget_hide(w);

          d->map_state = FALSE;
      }
}

/*
 *    Shuts down the prompt dialog.
 */
void PDialogShutdown(void)
{
      gint i;
      GtkWidget **w;
      pdialog_struct *d = &pdialog;


      /* Reset globals. */
      response_code = PDIALOG_RESPONSE_NOT_AVAILABLE;
      for(i = 0; i < response_nvals; i++)
          g_free(response_val[i]);
      g_free(response_val);
      response_val = NULL;
      response_nvals = 0;

      /* Break out of an additional blocking loops. */
      while(block_loop_level > 0) 
      {
          gtk_main_quit();
          block_loop_level--;
      }
      block_loop_level = 0;

      /* Unmap dialog. */
      PDialogUnmap();

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

      if(d->initialized)
      {
#define DO_DESTROY_WIDGET       \
{ \
 if((*w) != NULL) \
 { \
  GtkWidget *tmp_w = *w; \
  (*w) = NULL; \
  gtk_widget_destroy(tmp_w); \
 } \
}
          /* Begin destroying widgets. */
          w = &d->submit_btn;
          DO_DESTROY_WIDGET
          w = &d->cancel_btn;
          DO_DESTROY_WIDGET
          w = &d->help_btn;
          DO_DESTROY_WIDGET

          w = &d->icon_pm;
          DO_DESTROY_WIDGET
          w = &d->icon_fixed;
          DO_DESTROY_WIDGET
          w = &d->message_label;
          DO_DESTROY_WIDGET
          w = &d->message_label_hbox;
          DO_DESTROY_WIDGET

          w = &d->main_vbox;
          DO_DESTROY_WIDGET
          w = &d->toplevel;
          DO_DESTROY_WIDGET

          if(d->accelgrp != NULL)
          {
            gtk_accel_group_unref(d->accelgrp);
            d->accelgrp = NULL;
          }

#undef DO_DESTROY_WIDGET
      }

      /* Clear prompt dialog structure. */
      memset(d, 0x00, sizeof(pdialog_struct));
}

Generated by  Doxygen 1.6.0   Back to index