Logo Search packages:      
Sourcecode: vertex version File versions

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